actions-up 1.0.0 ā 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +7 -1
- package/dist/core/api/check-updates.js +1 -1
- package/dist/core/api/client.d.ts +8 -6
- package/dist/core/api/client.js +137 -137
- package/dist/package.js +1 -1
- package/package.json +1 -2
- package/readme.md +15 -37
package/dist/cli/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import pc from "picocolors";
|
|
|
10
10
|
import cac from "cac";
|
|
11
11
|
function run() {
|
|
12
12
|
let cli = cac("actions-up");
|
|
13
|
-
cli.help().version(version).option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (options) => {
|
|
13
|
+
cli.help().version(version).option("--yes, -y", "Skip all confirmations").option("--dry-run", "Preview changes without applying them").command("", "Update GitHub Actions").action(async (options) => {
|
|
14
14
|
console.info(pc.cyan("\nš Actions Up!\n"));
|
|
15
15
|
let spinner = createSpinner("Scanning GitHub Actions...").start();
|
|
16
16
|
try {
|
|
@@ -33,6 +33,12 @@ function run() {
|
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
spinner.success(`Found ${pc.yellow(outdated.length)} updates available${breaking.length > 0 ? ` (${pc.red(breaking.length)} breaking)` : ""}`);
|
|
36
|
+
if (options.dryRun) {
|
|
37
|
+
console.info(pc.yellow("\nš Dry Run - No changes will be made\n"));
|
|
38
|
+
for (let update of outdated) console.info(`${pc.cyan(update.action.file ?? "unknown")}:\n${update.action.name}: ${pc.red(update.currentVersion)} ā ${pc.green(update.latestVersion)} ${update.latestSha ? pc.gray(`(${update.latestSha.slice(0, 7)})`) : ""}\n`);
|
|
39
|
+
console.info(pc.gray(`\n${outdated.length} actions would be updated\n`));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
36
42
|
if (options.yes) {
|
|
37
43
|
let toUpdate = outdated.filter((update) => update.latestSha);
|
|
38
44
|
if (toUpdate.length === 0) {
|
|
@@ -69,7 +69,7 @@ async function checkUpdates(actions, token) {
|
|
|
69
69
|
}
|
|
70
70
|
}), Promise.resolve([]));
|
|
71
71
|
if (sharedState.rateLimitError) {
|
|
72
|
-
let error = /* @__PURE__ */ new Error("GitHub API rate limit exceeded. Please set GITHUB_TOKEN environment variable to increase the limit.\nSee: https://github.com/azat-io/actions-up?tab=readme-ov-file#
|
|
72
|
+
let error = /* @__PURE__ */ new Error("GitHub API rate limit exceeded. Please set GITHUB_TOKEN environment variable to increase the limit.\nSee: https://github.com/azat-io/actions-up?tab=readme-ov-file#using-github-token-for-higher-rate-limits");
|
|
73
73
|
error.name = "GitHubRateLimitError";
|
|
74
74
|
throw error;
|
|
75
75
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Processed release information with normalized types. */
|
|
2
1
|
interface ReleaseInfo {
|
|
3
2
|
/** Release description or null if not provided. */
|
|
4
3
|
description: string | null;
|
|
@@ -19,18 +18,19 @@ interface ReleaseInfo {
|
|
|
19
18
|
interface TagInfo {
|
|
20
19
|
/** Tag or commit message, null if not provided. */
|
|
21
20
|
message: string | null;
|
|
21
|
+
/** Git commit SHA that this tag points to. */
|
|
22
|
+
sha: string | null;
|
|
22
23
|
/** Date when the tag was created or committed. */
|
|
23
24
|
date: Date | null;
|
|
24
25
|
/** Tag name (e.g., 'v1.2.3'). */
|
|
25
26
|
tag: string;
|
|
26
|
-
/** Git commit SHA that this tag points to. */
|
|
27
|
-
sha: string;
|
|
28
27
|
}
|
|
29
|
-
/** GitHub
|
|
28
|
+
/** GitHub REST API client with optional authentication. */
|
|
30
29
|
export declare class Client {
|
|
31
|
-
private readonly
|
|
32
|
-
private
|
|
30
|
+
private readonly baseUrl;
|
|
31
|
+
private readonly token;
|
|
33
32
|
private rateLimitReset;
|
|
33
|
+
private rateLimitRemaining;
|
|
34
34
|
/**
|
|
35
35
|
* Creates a new GitHub API client.
|
|
36
36
|
*
|
|
@@ -75,5 +75,7 @@ export declare class Client {
|
|
|
75
75
|
* @returns True if rate limit is below threshold.
|
|
76
76
|
*/
|
|
77
77
|
shouldWaitForRateLimit(threshold?: number): boolean;
|
|
78
|
+
private makeRequest;
|
|
79
|
+
private updateRateLimitInfo;
|
|
78
80
|
}
|
|
79
81
|
export {};
|
package/dist/core/api/client.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { GraphqlResponseError, graphql } from "@octokit/graphql";
|
|
2
1
|
var GitHubRateLimitError = class extends Error {
|
|
3
2
|
constructor(resetAt) {
|
|
4
3
|
let resetTime = resetAt.toLocaleTimeString();
|
|
@@ -7,73 +6,76 @@ var GitHubRateLimitError = class extends Error {
|
|
|
7
6
|
}
|
|
8
7
|
};
|
|
9
8
|
var Client = class Client {
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
baseUrl = "https://api.github.com";
|
|
10
|
+
token;
|
|
12
11
|
rateLimitReset = /* @__PURE__ */ new Date();
|
|
12
|
+
rateLimitRemaining = 60;
|
|
13
13
|
constructor(token) {
|
|
14
|
-
|
|
15
|
-
this.
|
|
16
|
-
|
|
14
|
+
this.token = token ?? process.env["GITHUB_TOKEN"];
|
|
15
|
+
if (!this.token) console.warn("No GitHub token found. API rate limits will be restricted.");
|
|
16
|
+
this.rateLimitRemaining = this.token ? 5e3 : 60;
|
|
17
17
|
}
|
|
18
18
|
static isRateLimitError(error) {
|
|
19
|
-
if (error
|
|
20
|
-
|
|
19
|
+
if (error && typeof error === "object") {
|
|
20
|
+
let maybeAny = error;
|
|
21
|
+
let message = typeof maybeAny.message === "string" ? maybeAny.message.toLowerCase() : "";
|
|
22
|
+
let status = typeof maybeAny.status === "number" ? maybeAny.status : void 0;
|
|
23
|
+
return message.includes("rate limit") || message.includes("api rate limit") || status === 403;
|
|
24
|
+
}
|
|
21
25
|
return false;
|
|
22
26
|
}
|
|
23
27
|
async getTagInfo(owner, repo, tag) {
|
|
24
28
|
try {
|
|
25
|
-
let qualifiedTag = tag.startsWith("refs/tags/") ? tag : `refs/tags/${tag}`;
|
|
26
29
|
let displayTag = tag.replace(/^refs\/tags\//u, "");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
};
|
|
30
|
+
try {
|
|
31
|
+
let releaseResp = await this.makeRequest(`/repos/${owner}/${repo}/releases/tags/${displayTag}`);
|
|
32
|
+
let releaseData = releaseResp.data;
|
|
33
|
+
let sha = null;
|
|
34
|
+
if (releaseData.target_commitish) try {
|
|
35
|
+
let commitResp = await this.makeRequest(`/repos/${owner}/${repo}/commits/${releaseData.target_commitish}`);
|
|
36
|
+
let commitData = commitResp.data;
|
|
37
|
+
({sha} = commitData);
|
|
38
|
+
} catch {
|
|
39
|
+
sha = releaseData.target_commitish;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
date: releaseData.published_at ? new Date(releaseData.published_at) : null,
|
|
43
|
+
sha: sha ?? releaseData.target_commitish,
|
|
44
|
+
message: releaseData.body ?? null,
|
|
45
|
+
tag: displayTag
|
|
46
|
+
};
|
|
47
|
+
} catch (releaseError) {
|
|
48
|
+
if (releaseError && typeof releaseError === "object" && "status" in releaseError && releaseError.status === 404) try {
|
|
49
|
+
let referenceResp = await this.makeRequest(`/repos/${owner}/${repo}/git/refs/tags/${displayTag}`);
|
|
50
|
+
let referenceData = referenceResp.data;
|
|
51
|
+
let { sha } = referenceData.object;
|
|
52
|
+
let message = null;
|
|
53
|
+
let date = null;
|
|
54
|
+
if (referenceData.object.type === "tag") try {
|
|
55
|
+
let tagResp = await this.makeRequest(`/repos/${owner}/${repo}/git/tags/${sha}`);
|
|
56
|
+
let tagData = tagResp.data;
|
|
57
|
+
({sha} = tagData.object);
|
|
58
|
+
({message} = tagData);
|
|
59
|
+
date = tagData.tagger.date ? new Date(tagData.tagger.date) : null;
|
|
60
|
+
} catch {}
|
|
61
|
+
else try {
|
|
62
|
+
let commitResp = await this.makeRequest(`/repos/${owner}/${repo}/git/commits/${sha}`);
|
|
63
|
+
let commitData = commitResp.data;
|
|
64
|
+
({message} = commitData);
|
|
65
|
+
date = commitData.author.date ? new Date(commitData.author.date) : null;
|
|
66
|
+
} catch {}
|
|
67
|
+
return {
|
|
68
|
+
tag: displayTag,
|
|
69
|
+
message,
|
|
70
|
+
date,
|
|
71
|
+
sha
|
|
72
|
+
};
|
|
73
|
+
} catch (tagError) {
|
|
74
|
+
if (tagError && typeof tagError === "object" && "status" in tagError && tagError.status === 404) return null;
|
|
75
|
+
throw tagError;
|
|
76
|
+
}
|
|
77
|
+
throw releaseError;
|
|
78
|
+
}
|
|
77
79
|
} catch (error) {
|
|
78
80
|
if (Client.isRateLimitError(error)) throw new GitHubRateLimitError(this.rateLimitReset);
|
|
79
81
|
throw error;
|
|
@@ -81,49 +83,28 @@ var Client = class Client {
|
|
|
81
83
|
}
|
|
82
84
|
async getAllReleases(owner, repo, limit = 10) {
|
|
83
85
|
try {
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
rateLimit {
|
|
105
|
-
remaining
|
|
106
|
-
resetAt
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
`;
|
|
110
|
-
let response = await this.graphqlWithAuth(query, {
|
|
111
|
-
owner,
|
|
112
|
-
limit,
|
|
113
|
-
repo
|
|
114
|
-
});
|
|
115
|
-
this.rateLimitRemaining = response.rateLimit.remaining;
|
|
116
|
-
this.rateLimitReset = new Date(response.rateLimit.resetAt);
|
|
117
|
-
if (!response.repository?.releases?.nodes) return [];
|
|
118
|
-
return response.repository.releases.nodes.map((release) => ({
|
|
119
|
-
sha: release.tagCommit?.oid ?? null,
|
|
120
|
-
publishedAt: new Date(release.publishedAt),
|
|
121
|
-
description: release.description ?? null,
|
|
122
|
-
name: release.name ?? release.tagName,
|
|
123
|
-
isPrerelease: release.isPrerelease,
|
|
124
|
-
url: release.url,
|
|
125
|
-
version: release.tagName
|
|
86
|
+
let releasesResp = await this.makeRequest(`/repos/${owner}/${repo}/releases?per_page=${limit}`);
|
|
87
|
+
let releases = releasesResp.data;
|
|
88
|
+
let releaseInfos = [];
|
|
89
|
+
await Promise.all(releases.map(async (release) => {
|
|
90
|
+
let sha = null;
|
|
91
|
+
if (release.tag_name) try {
|
|
92
|
+
let tagInfo = await this.getTagInfo(owner, repo, release.tag_name);
|
|
93
|
+
if (tagInfo) ({sha} = tagInfo);
|
|
94
|
+
} catch {
|
|
95
|
+
sha = release.target_commitish;
|
|
96
|
+
}
|
|
97
|
+
releaseInfos.push({
|
|
98
|
+
publishedAt: new Date(release.published_at),
|
|
99
|
+
name: release.name ?? release.tag_name,
|
|
100
|
+
description: release.body ?? null,
|
|
101
|
+
isPrerelease: release.prerelease,
|
|
102
|
+
version: release.tag_name,
|
|
103
|
+
url: release.html_url,
|
|
104
|
+
sha
|
|
105
|
+
});
|
|
126
106
|
}));
|
|
107
|
+
return releaseInfos;
|
|
127
108
|
} catch (error) {
|
|
128
109
|
if (Client.isRateLimitError(error)) throw new GitHubRateLimitError(this.rateLimitReset);
|
|
129
110
|
throw error;
|
|
@@ -131,45 +112,26 @@ var Client = class Client {
|
|
|
131
112
|
}
|
|
132
113
|
async getLatestRelease(owner, repo) {
|
|
133
114
|
try {
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
description
|
|
144
|
-
isPrerelease
|
|
145
|
-
publishedAt
|
|
146
|
-
url
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
rateLimit {
|
|
150
|
-
remaining
|
|
151
|
-
resetAt
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
`;
|
|
155
|
-
let response = await this.graphqlWithAuth(query, {
|
|
156
|
-
owner,
|
|
157
|
-
repo
|
|
158
|
-
});
|
|
159
|
-
this.rateLimitRemaining = response.rateLimit.remaining;
|
|
160
|
-
this.rateLimitReset = new Date(response.rateLimit.resetAt);
|
|
161
|
-
if (!response.repository?.latestRelease) return null;
|
|
162
|
-
let release = response.repository.latestRelease;
|
|
115
|
+
let releaseResp = await this.makeRequest(`/repos/${owner}/${repo}/releases/latest`);
|
|
116
|
+
let release = releaseResp.data;
|
|
117
|
+
let sha = null;
|
|
118
|
+
if (release.tag_name) try {
|
|
119
|
+
let tagInfo = await this.getTagInfo(owner, repo, release.tag_name);
|
|
120
|
+
if (tagInfo) ({sha} = tagInfo);
|
|
121
|
+
} catch {
|
|
122
|
+
sha = release.target_commitish;
|
|
123
|
+
}
|
|
163
124
|
return {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
description: release.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
url: release.
|
|
170
|
-
|
|
125
|
+
publishedAt: new Date(release.published_at),
|
|
126
|
+
name: release.name ?? release.tag_name,
|
|
127
|
+
description: release.body ?? null,
|
|
128
|
+
isPrerelease: release.prerelease,
|
|
129
|
+
version: release.tag_name,
|
|
130
|
+
url: release.html_url,
|
|
131
|
+
sha
|
|
171
132
|
};
|
|
172
133
|
} catch (error) {
|
|
134
|
+
if (error && typeof error === "object" && "status" in error && error.status === 404) return null;
|
|
173
135
|
if (Client.isRateLimitError(error)) throw new GitHubRateLimitError(this.rateLimitReset);
|
|
174
136
|
throw error;
|
|
175
137
|
}
|
|
@@ -183,5 +145,43 @@ var Client = class Client {
|
|
|
183
145
|
shouldWaitForRateLimit(threshold = 100) {
|
|
184
146
|
return this.rateLimitRemaining < threshold;
|
|
185
147
|
}
|
|
148
|
+
async makeRequest(path, options = {}) {
|
|
149
|
+
let headers = {
|
|
150
|
+
Accept: "application/vnd.github.v3+json",
|
|
151
|
+
"User-Agent": "actions-up",
|
|
152
|
+
...options.headers
|
|
153
|
+
};
|
|
154
|
+
if (this.token) headers["Authorization"] = `Bearer ${this.token}`;
|
|
155
|
+
let response = await fetch(`${this.baseUrl}${path}`, {
|
|
156
|
+
...options,
|
|
157
|
+
headers
|
|
158
|
+
});
|
|
159
|
+
let responseHeaders = {};
|
|
160
|
+
for (let [key, value] of response.headers.entries()) responseHeaders[key] = value;
|
|
161
|
+
this.updateRateLimitInfo(responseHeaders);
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
let error = /* @__PURE__ */ new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
164
|
+
error.status = response.status;
|
|
165
|
+
if (response.status === 403) {
|
|
166
|
+
let text = await response.text();
|
|
167
|
+
if (text.includes("rate limit") || text.includes("API rate limit")) error.message = "API rate limit exceeded";
|
|
168
|
+
}
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
let data = await response.json();
|
|
172
|
+
return {
|
|
173
|
+
headers: responseHeaders,
|
|
174
|
+
data
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
updateRateLimitInfo(headers) {
|
|
178
|
+
let remaining = headers["x-ratelimit-remaining"];
|
|
179
|
+
if (remaining !== void 0) this.rateLimitRemaining = typeof remaining === "string" ? Number.parseInt(remaining, 10) : remaining;
|
|
180
|
+
let reset = headers["x-ratelimit-reset"];
|
|
181
|
+
if (reset !== void 0) {
|
|
182
|
+
let resetTime = typeof reset === "string" ? Number.parseInt(reset, 10) : reset;
|
|
183
|
+
this.rateLimitReset = /* @__PURE__ */ new Date(resetTime * 1e3);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
186
|
};
|
|
187
187
|
export { Client };
|
package/dist/package.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const version = "1.
|
|
1
|
+
const version = "1.1.1";
|
|
2
2
|
export { version };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "actions-up",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Interactive CLI tool to update GitHub Actions to latest versions with SHA pinning",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"./dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@octokit/graphql": "^9.0.1",
|
|
40
39
|
"cac": "^6.7.14",
|
|
41
40
|
"enquirer": "^2.4.1",
|
|
42
41
|
"nanospinner": "^1.2.2",
|
package/readme.md
CHANGED
|
@@ -66,18 +66,6 @@ Actions Up transforms a painful manual process into a delightful experience:
|
|
|
66
66
|
| Risk using vulnerable versions | SHA pinning for maximum security |
|
|
67
67
|
| 30+ minutes per repository | Under 1 minute total |
|
|
68
68
|
|
|
69
|
-
## GitHub Token Required
|
|
70
|
-
|
|
71
|
-
> **Important**: GitHub API has strict rate limits (60 requests/hour without token vs 5000 with token).
|
|
72
|
-
> A GitHub token is **practically required** for using Actions Up.
|
|
73
|
-
|
|
74
|
-
### Quick Token Setup
|
|
75
|
-
|
|
76
|
-
[Create a GitHub Personal Access Token](https://github.com/settings/tokens/new?scopes=public_repo&description=actions-up).
|
|
77
|
-
|
|
78
|
-
- For public repositories: Select `public_repo` scope
|
|
79
|
-
- For private repositories: Select `repo` scope
|
|
80
|
-
|
|
81
69
|
## Installation
|
|
82
70
|
|
|
83
71
|
Quick use (no installation)
|
|
@@ -102,10 +90,10 @@ npm install --save-dev actions-up
|
|
|
102
90
|
|
|
103
91
|
### Interactive Mode (Default)
|
|
104
92
|
|
|
105
|
-
Run in your repository root
|
|
93
|
+
Run in your repository root:
|
|
106
94
|
|
|
107
95
|
```bash
|
|
108
|
-
|
|
96
|
+
npx actions-up
|
|
109
97
|
```
|
|
110
98
|
|
|
111
99
|
This will:
|
|
@@ -120,30 +108,9 @@ This will:
|
|
|
120
108
|
Skip all prompts and update everything:
|
|
121
109
|
|
|
122
110
|
```bash
|
|
123
|
-
|
|
111
|
+
npx actions-up --yes
|
|
124
112
|
# or
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Pro Tips
|
|
129
|
-
|
|
130
|
-
### Shell Aliases
|
|
131
|
-
|
|
132
|
-
Add to your `.zshrc`, `.bashrc` or `.config/fish/config.fish`:
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
# Basic alias with token from environment
|
|
136
|
-
export GITHUB_TOKEN=ghp_xxxx # Add this once to your shell config
|
|
137
|
-
alias actions-up='GITHUB_TOKEN=$GITHUB_TOKEN npx actions-up'
|
|
138
|
-
|
|
139
|
-
# With token from file
|
|
140
|
-
alias actions-up='GITHUB_TOKEN=$(cat ~/.github-token) npx actions-up'
|
|
141
|
-
|
|
142
|
-
# With 1Password CLI
|
|
143
|
-
alias actions-up='GITHUB_TOKEN=$(op read "op://Personal/GitHub/token") npx actions-up'
|
|
144
|
-
|
|
145
|
-
# With macOS Keychain
|
|
146
|
-
alias actions-up='GITHUB_TOKEN=$(security find-generic-password -w -s "github-token") npx actions-up'
|
|
113
|
+
npx actions-up -y
|
|
147
114
|
```
|
|
148
115
|
|
|
149
116
|
## Example
|
|
@@ -158,6 +125,17 @@ alias actions-up='GITHUB_TOKEN=$(security find-generic-password -w -s "github-to
|
|
|
158
125
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
159
126
|
```
|
|
160
127
|
|
|
128
|
+
## Advanced Usage
|
|
129
|
+
|
|
130
|
+
### Using GitHub Token for Higher Rate Limits
|
|
131
|
+
|
|
132
|
+
While Actions Up works without authentication, providing a GitHub token increases API rate limits from 60 to 5000 requests per hour, useful for large projects:
|
|
133
|
+
|
|
134
|
+
[Create a GitHub Personal Access Token](https://github.com/settings/tokens/new?scopes=public_repo&description=actions-up).
|
|
135
|
+
|
|
136
|
+
- For public repositories: Select `public_repo` scope
|
|
137
|
+
- For private repositories: Select `repo` scope
|
|
138
|
+
|
|
161
139
|
## Security
|
|
162
140
|
|
|
163
141
|
Actions Up promotes security best practices:
|