Skip to content

Commit 6f6169e

Browse files
committed
feat(gist): add support for backing up GitHub Gists to the backup tool
- Introduce a new backup type for GitHub Gists, allowing users to back up their Gists. - Update configuration examples and documentation to include Gist backup options. - Enhance the GitHub client to handle Gist API interactions and metadata extraction. - Add tests to ensure Gist functionality works as expected. - refactor `github.rs` to simplify the parsing logic for GitHubRepoSourceKind to improve readability and maintainability - add test cases for gists to ensure correct parsing of Gist identifiers - add validation test for Gist identifiers to ensure proper handling of Gist sources
1 parent 4353554 commit 6f6169e

15 files changed

Lines changed: 633 additions & 34 deletions

File tree

.github/workflows/rust.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ jobs:
5858
name: Test
5959
runs-on: ubuntu-latest
6060

61+
permissions:
62+
contents: read
63+
6164
steps:
6265
- uses: actions/checkout@v4
6366
- uses: dtolnay/rust-toolchain@stable

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/target
22
/backups
33
/.direnv
4-
/result
4+
/result
5+
.idea/

README.md

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -103,34 +103,47 @@ several operators and properties which can be used to control this process.
103103

104104
For `kind: github/repo` and `kind: github/star`
105105

106-
| Field | Type | Description (_Example_) |
107-
| --------------------- | --------- | ------------------------------------------------------------------------------------------------- |
108-
| `repo.name` | `string` | The name of the repository (_Hello-World_) |
109-
| `repo.fullname` | `string` | The full-name of the repository (_octocat/Hello-World_) |
110-
| `repo.private` | `boolean` | Whether the repository is private |
111-
| `repo.public` | `boolean` | Whether the repository is public |
112-
| `repo.fork` | `boolean` | Whether the repository is a fork |
113-
| `repo.size` | `integer` | The size of the repository, in kilobytes (_1024_). |
114-
| `repo.archived` | `boolean` | Whether the repository is archived |
115-
| `repo.disabled` | `boolean` | Returns whether or not this repository disabled |
116-
| `repo.default_branch` | `string` | The default branch of the repository (_main_) |
117-
| `repo.empty` | `boolean` | Whether the repository is empty (When a repository is initially created, `repo.empty` is `true`) |
118-
| `repo.template` | `boolean` | Whether this repository acts as a template that can be used to generate new repositories |
119-
| `repo.forks` | `integer` | The number of times this repository is forked |
120-
| `repo.stargazers` | `integer` | The number of people starred this repository |
106+
| Field | Type | Description (_Example_) |
107+
|------------------------|------------|----------------------------------------------------------------------------------------------------|
108+
| `repo.name` | `string` | The name of the repository (_Hello-World_) |
109+
| `repo.fullname` | `string` | The full-name of the repository (_octocat/Hello-World_) |
110+
| `repo.private` | `boolean` | Whether the repository is private |
111+
| `repo.public` | `boolean` | Whether the repository is public |
112+
| `repo.fork` | `boolean` | Whether the repository is a fork |
113+
| `repo.size` | `integer` | The size of the repository, in kilobytes (_1024_). |
114+
| `repo.archived` | `boolean` | Whether the repository is archived |
115+
| `repo.disabled` | `boolean` | Returns whether or not this repository disabled |
116+
| `repo.default_branch` | `string` | The default branch of the repository (_main_) |
117+
| `repo.empty` | `boolean` | Whether the repository is empty (When a repository is initially created, `repo.empty` is `true`) |
118+
| `repo.template` | `boolean` | Whether this repository acts as a template that can be used to generate new repositories |
119+
| `repo.forks` | `integer` | The number of times this repository is forked |
120+
| `repo.stargazers` | `integer` | The number of people starred this repository |
121121

122122
For `kind: github/release`
123123

124-
| Field | Type | Description (_Example_) |
125-
| -------------------- | --------- | ----------------------------------------------------------------- |
126-
| `release.tag` | `string` | The name of the tag (_v1.0.0_) |
127-
| `release.name` | `string` | The name of the release (_v1.0.0_) |
128-
| `release.draft` | `boolean` | Whether the release is a draft (unpublished) release |
129-
| `release.prerelease` | `boolean` | Whether to identify the release as a prerelease or a full release |
130-
| `release.published` | `boolean` | Whether the release is a published (not a draft) release |
131-
| `asset.name` | `string` | The file name of the asset (_github-backup-darwin-arm64_) |
132-
| `asset.size` | `integer` | The size of the asset, in kilobytes. (_1024_) |
133-
| `asset.downloaded` | `boolean` | If the asset was downloaded at least once from the GitHub Release |
124+
| Field | Type | Description (_Example_) |
125+
|-----------------------|------------|--------------------------------------------------------------------|
126+
| `release.tag` | `string` | The name of the tag (_v1.0.0_) |
127+
| `release.name` | `string` | The name of the release (_v1.0.0_) |
128+
| `release.draft` | `boolean` | Whether the release is a draft (unpublished) release |
129+
| `release.prerelease` | `boolean` | Whether to identify the release as a prerelease or a full release |
130+
| `release.published` | `boolean` | Whether the release is a published (not a draft) release |
131+
| `asset.name` | `string` | The file name of the asset (_github-backup-darwin-arm64_) |
132+
| `asset.size` | `integer` | The size of the asset, in kilobytes. (_1024_) |
133+
| `asset.downloaded` | `boolean` | If the asset was downloaded at least once from the GitHub Release |
134+
135+
For `kind: github/gist`
136+
137+
| Field | Type | Description |
138+
|-------------------------|-----------|------------------------------------------------|
139+
| `gist.public` | `boolean` | Whether the gist is public |
140+
| `gist.private` | `boolean` | Whether the gist is private |
141+
| `gist.comments_enabled` | `boolean` | Whether comments are enabled for the gist |
142+
| `gist.comments` | `integer` | Number of comments on the gist |
143+
| `gist.files` | `integer` | Number of files in the gist |
144+
| `gist.file_names` | `array` | List of file names in the gist |
145+
| `gist.languages` | `array` | List of programming languages used in the gist |
146+
| `gist.type` | `string` | Type of content in the gist |
134147

135148
### Examples
136149

docs/.vuepress/config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export default defineUserConfig({
5757
text: "Reference",
5858
children: [
5959
'/reference/repo.md',
60-
'/reference/release.md'
60+
'/reference/release.md',
61+
'/reference/gist.md'
6162
]
6263
},
6364
{
@@ -81,7 +82,8 @@ export default defineUserConfig({
8182
text: "Reference",
8283
children: [
8384
'/reference/repo.md',
84-
'/reference/release.md'
85+
'/reference/release.md',
86+
'/reference/gist.md'
8587
]
8688
},
8789
{

docs/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ backups:
8484
from: "repos/my-org/repo"
8585
to: /backups/releases
8686
filter: '!release.prerelease'
87+
88+
# Backup all GitHub Gists for your authenticated user
89+
- kind: github/gist
90+
from: "user"
91+
to: /backups/gists
92+
credentials: !Token "your_github_token"
93+
94+
# Backup public GitHub Gist of another user
95+
- kind: github/gist
96+
from: "users/another-user"
97+
to: /backups/gists
8798
```
8899
89100
<ClientOnly>

docs/guide/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ backups:
140140
- kind: github/star
141141
from: "users/<username>"
142142
to: /backups/github
143+
144+
# Backup all GitHub Gist accessible to the user associated with the provided credentials
145+
- kind: github/gist
146+
from: "users/<username>"
147+
to: /backups/gists
148+
credentials: !Token "your_github_pat"
149+
150+
# Backup all of the public GitHub Gist by a specific user
151+
- kind: github/gist
152+
from: "users/<username>"
153+
to: /backups/gists
143154
```
144155

145156
## Filtering

docs/reference/gist.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# GitHub Gists
2+
The `github-backup` tool can also be used to back up GitHub Gists.
3+
This is done using the `github/gist` backup type in your configuration file,
4+
along with an appropriate `from` directive to define the source of the gists
5+
you wish to back up.
6+
7+
::: note
8+
GitHub Gists don't have explicit "names" — instead, they are identified by a unique *gist ID*.
9+
While GitHub displays a filename as the Gist name in the UI, it's actually just the name of the
10+
*first* file in the Gist, which can change over time.
11+
12+
When backing up a Gist, the repository name will be based on the stable gist ID rather than a
13+
filename. This avoids issues where users rename files or add new ones, which could otherwise
14+
result in the same Gist being backed up multiple times under different names.
15+
16+
If you choose to back up GitHub Gists, be aware that the resulting repositories will be named
17+
using their gist ID rather than the more human-readable names shown on the GitHub website.
18+
:::
19+
20+
## Examples
21+
The following examples show how you can combine the `kind` and `from` directives
22+
to back up gists from GitHub.
23+
24+
::: warning
25+
Not every combination of `kind` and `from` is supported due to limitations in
26+
GitHub's API. If you use an unsupported combination, the tool will fail to
27+
run and provide an error message explaining why.
28+
:::
29+
30+
```yaml{5-6,11-12,16-17,22-23,27-28} title="config.yaml"
31+
schedule: "0 * * * *"
32+
33+
backups:
34+
# Backup all of the gist accessible to the user associated with the provided credentials
35+
- kind: github/gist
36+
from: "user"
37+
to: /backups/github/gist
38+
credentials: !Token "your_github_pat"
39+
40+
# Backup all of the public gist owned by the specified user
41+
- kind: github/gist
42+
from: "users/<username>"
43+
to: /backups/github/gist
44+
```
45+
46+
## Filter Fields
47+
Regardless of which backup kind and source you choose, you may use the following fields
48+
in your filter to determine which gists should be included in your backup. These fields
49+
are accessed using the `gist.<field>` syntax, for example `gist.public` to determine if
50+
the gist is public or not.
51+
52+
::: tip
53+
These fields are also available when using [`github/repo`](./repo.md) or [`github/release`](./release.md) backups.
54+
:::
55+
56+
57+
| Field | Type | Description |
58+
|-------------------------|-----------|------------------------------------------------|
59+
| `gist.public` | `boolean` | Whether the gist is public |
60+
| `gist.private` | `boolean` | Whether the gist is private |
61+
| `gist.comments_enabled` | `boolean` | Whether comments are enabled for the gist |
62+
| `gist.comments` | `integer` | Number of comments on the gist |
63+
| `gist.files` | `integer` | Number of files in the gist |
64+
| `gist.forks` | `integer` | The number of times this gist is forked |
65+
| `gist.file_names` | `array` | List of file names in the gist |
66+
| `gist.languages` | `array` | List of programming languages used in the gist |
67+
| `gist.type` | `string` | MIME-Type of content in the gist |

docs/reference/release.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ When backing up release artifacts, you may use the following fields in your filt
4343
expressions. These fields are accessed using the `release.<field>` syntax, for example
4444
`release.prerelease` to determine if a release is a pre-release.
4545

46+
For `kind: github/release`
47+
48+
| Field | Type | Description (_Example_) |
49+
|-----------------------|------------|--------------------------------------------------------------------|
50+
| `release.tag` | `string` | The name of the tag (_v1.0.0_) |
51+
| `release.name` | `string` | The name of the release (_v1.0.0_) |
52+
| `release.draft` | `boolean` | Whether the release is a draft (unpublished) release |
53+
| `release.prerelease` | `boolean` | Whether to identify the release as a prerelease or a full release |
54+
| `release.published` | `boolean` | Whether the release is a published (not a draft) release |
55+
| `asset.name` | `string` | The file name of the asset (_github-backup-darwin-arm64_) |
56+
| `asset.size` | `integer` | The size of the asset, in kilobytes. (_1024_) |
57+
| `asset.downloaded` | `boolean` | If the asset was downloaded at least once from the GitHub Release |
58+
4659
```json
4760
{
4861
// Describes the repository from which releases are being sourced
@@ -99,4 +112,4 @@ expressions. These fields are accessed using the `release.<field>` syntax, for e
99112
"downloaded": true
100113
}
101114
}
102-
```
115+
```

docs/reference/repo.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,26 @@ are accessed using the `repo.<field>` syntax, for example `repo.fork` to determi
5353
is a fork.
5454

5555
::: tip
56-
These fields are also available when using [`github/release`](./release.md) backups.
56+
These fields are also available when using [`github/release`](./release.md) or [`github/gist`](./gist.md) backups.
5757
:::
5858

59+
60+
| Field | Type | Description (_Example_) |
61+
|------------------------|------------|----------------------------------------------------------------------------------------------------|
62+
| `repo.name` | `string` | The name of the repository (_Hello-World_) |
63+
| `repo.fullname` | `string` | The full-name of the repository (_octocat/Hello-World_) |
64+
| `repo.private` | `boolean` | Whether the repository is private |
65+
| `repo.public` | `boolean` | Whether the repository is public |
66+
| `repo.fork` | `boolean` | Whether the repository is a fork |
67+
| `repo.size` | `integer` | The size of the repository, in kilobytes (_1024_). |
68+
| `repo.archived` | `boolean` | Whether the repository is archived |
69+
| `repo.disabled` | `boolean` | Returns whether or not this repository disabled |
70+
| `repo.default_branch` | `string` | The default branch of the repository (_main_) |
71+
| `repo.empty` | `boolean` | Whether the repository is empty (When a repository is initially created, `repo.empty` is `true`) |
72+
| `repo.template` | `boolean` | Whether this repository acts as a template that can be used to generate new repositories |
73+
| `repo.forks` | `integer` | The number of times this repository is forked |
74+
| `repo.stargazers` | `integer` | The number of people starred this repository |
75+
5976
```json
6077
{
6178
"repo": {
@@ -87,4 +104,4 @@ These fields are also available when using [`github/release`](./release.md) back
87104
"stargazers": 501
88105
}
89106
}
90-
```
107+
```

src/filter/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ mod tests {
116116
name: "John Doe".to_string(),
117117
age: 30,
118118
alive: true,
119-
tags: vec!["red"],
119+
tags: vec!["red", "black"],
120120
}
121121
}
122122
}
@@ -156,8 +156,8 @@ mod tests {
156156
#[case("age < 31", true)]
157157
#[case("age >= 30", true)]
158158
#[case("age <= 30", true)]
159-
#[case("tags == [\"red\"]", true)]
160-
#[case("tags != [\"red\"]", false)]
159+
#[case("tags == [\"red\",\"black\"]", true)]
160+
#[case("tags != [\"red\",\"black\"]", false)]
161161
#[case("tags == [\"blue\"]", false)]
162162
#[case("tags contains \"red\"", true)]
163163
#[case("tags contains \"blue\"", false)]

0 commit comments

Comments
 (0)