@pnpm/deps.github-actions 1100.0.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/CHANGELOG.md +8 -0
- package/LICENSE +22 -0
- package/README.md +42 -0
- package/lib/index.js +347 -0
- package/package.json +57 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-2016 Rico Sta. Cruz and other contributors
|
|
4
|
+
Copyright (c) 2016-2026 Zoltan Kochan and other contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @pnpm/deps.github-actions
|
|
2
|
+
|
|
3
|
+
> Discover and update GitHub Actions dependencies
|
|
4
|
+
|
|
5
|
+
[](https://npmx.dev/package/@pnpm/deps.github-actions)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @pnpm/deps.github-actions
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {
|
|
17
|
+
findOutdatedGitHubActions,
|
|
18
|
+
updateGitHubActions,
|
|
19
|
+
} from '@pnpm/deps.github-actions'
|
|
20
|
+
|
|
21
|
+
const outdated = await findOutdatedGitHubActions({
|
|
22
|
+
dir: process.cwd(),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
await updateGitHubActions({
|
|
26
|
+
dir: process.cwd(),
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The package scans workflow files in `.github/workflows` and follows referenced local reusable workflows and composite actions. Only `uses` fields in jobs and steps are treated as dependencies.
|
|
31
|
+
|
|
32
|
+
Updates are always pinned to an exact commit SHA. The corresponding semantic version tag is written in a comment:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
By default, `updateGitHubActions` selects the newest caret-compatible release. This keeps `0.5.x` releases below `0.6.0`, since pre-1.0 minor releases may contain breaking changes. Set `latest: true` to allow incompatible updates. `findOutdatedGitHubActions` reports the newest release by default; set `compatible: true` to report only caret-compatible updates.
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import util from 'node:util';
|
|
4
|
+
import { PnpmError } from '@pnpm/error';
|
|
5
|
+
import { getRepoRefs } from '@pnpm/resolving.git-resolver';
|
|
6
|
+
import { isSubdir } from 'is-subdir';
|
|
7
|
+
import pLimit from 'p-limit';
|
|
8
|
+
import semver from 'semver';
|
|
9
|
+
import writeFileAtomic from 'write-file-atomic';
|
|
10
|
+
import YAML, { isMap, isNode, isScalar, isSeq } from 'yaml';
|
|
11
|
+
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
12
|
+
const limitRepoReads = pLimit(8);
|
|
13
|
+
export function isGitHubActionSelector(selector) {
|
|
14
|
+
const pattern = selector.startsWith('!') ? selector.slice(1) : selector;
|
|
15
|
+
return !pattern.startsWith('@') && pattern.includes('/');
|
|
16
|
+
}
|
|
17
|
+
export function normalizeGitHubActionSelector(selector) {
|
|
18
|
+
if (!isGitHubActionSelector(selector))
|
|
19
|
+
return selector;
|
|
20
|
+
const refSeparator = selector.lastIndexOf('@');
|
|
21
|
+
return refSeparator === -1 ? selector : selector.slice(0, refSeparator);
|
|
22
|
+
}
|
|
23
|
+
export async function findOutdatedGitHubActions(opts) {
|
|
24
|
+
const plans = await createUpdatePlan(opts);
|
|
25
|
+
const target = (plan) => opts.compatible ? plan.wanted : plan.latest;
|
|
26
|
+
return dedupeOutdated(plans
|
|
27
|
+
.filter((plan) => semver.lt(plan.current.version, target(plan).version))
|
|
28
|
+
.map((plan) => ({
|
|
29
|
+
current: plan.current.version.version,
|
|
30
|
+
latest: target(plan).version.version,
|
|
31
|
+
name: plan.action.name,
|
|
32
|
+
wanted: plan.wanted.version.version,
|
|
33
|
+
homepage: `https://github.com/${plan.action.repo}`,
|
|
34
|
+
})));
|
|
35
|
+
}
|
|
36
|
+
export async function updateGitHubActions(opts) {
|
|
37
|
+
const plans = await createUpdatePlan(opts);
|
|
38
|
+
const updates = plans.filter((plan) => {
|
|
39
|
+
const target = opts.latest ? plan.latest : plan.wanted;
|
|
40
|
+
return semver.lte(plan.current.version, target.version) &&
|
|
41
|
+
(plan.action.ref !== target.commit || plan.action.commentVersion !== target.tag);
|
|
42
|
+
});
|
|
43
|
+
const edits = new Map();
|
|
44
|
+
for (const plan of updates) {
|
|
45
|
+
const target = opts.latest ? plan.latest : plan.wanted;
|
|
46
|
+
const replacements = edits.get(plan.action.file) ?? [];
|
|
47
|
+
replacements.push({
|
|
48
|
+
range: plan.action.range,
|
|
49
|
+
value: renderTargetValue(plan.action, target),
|
|
50
|
+
});
|
|
51
|
+
edits.set(plan.action.file, replacements);
|
|
52
|
+
}
|
|
53
|
+
await Promise.all([...edits].map(async ([file, replacements]) => {
|
|
54
|
+
let source = file.source;
|
|
55
|
+
replacements.sort((left, right) => right.range[0] - left.range[0]);
|
|
56
|
+
for (const replacement of replacements) {
|
|
57
|
+
source = source.slice(0, replacement.range[0]) + replacement.value + source.slice(replacement.range[1]);
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
await writeFileAtomic(file.path, source);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw workflowError('WRITE', file.path, err);
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
return dedupeOutdated(updates.map((plan) => {
|
|
67
|
+
const target = opts.latest ? plan.latest : plan.wanted;
|
|
68
|
+
return {
|
|
69
|
+
current: plan.current.version.version,
|
|
70
|
+
latest: target.version.version,
|
|
71
|
+
name: plan.action.name,
|
|
72
|
+
wanted: plan.wanted.version.version,
|
|
73
|
+
homepage: `https://github.com/${plan.action.repo}`,
|
|
74
|
+
};
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
async function createUpdatePlan(opts) {
|
|
78
|
+
const actions = await discoverActions(opts.dir);
|
|
79
|
+
const selected = opts.match == null ? actions : actions.filter((action) => opts.match(action.name) || opts.match(action.repo));
|
|
80
|
+
const readRepoRefs = opts.readRepoRefs ?? readRefsWithGit;
|
|
81
|
+
const refsByRepo = new Map();
|
|
82
|
+
return (await Promise.all(selected.map(async (action) => {
|
|
83
|
+
let versionsPromise = refsByRepo.get(action.repo);
|
|
84
|
+
if (versionsPromise == null) {
|
|
85
|
+
versionsPromise = limitRepoReads(() => readRepoRefs(action.repo).then(parseRepoVersions));
|
|
86
|
+
refsByRepo.set(action.repo, versionsPromise);
|
|
87
|
+
}
|
|
88
|
+
const versions = await versionsPromise;
|
|
89
|
+
const current = findCurrentVersion(action, versions);
|
|
90
|
+
if (current == null)
|
|
91
|
+
return null;
|
|
92
|
+
const stable = versions.filter(({ version }) => version.prerelease.length === 0);
|
|
93
|
+
const candidates = current.version.prerelease.length === 0 ? stable : versions;
|
|
94
|
+
const latest = candidates.at(-1);
|
|
95
|
+
const wanted = candidates
|
|
96
|
+
.filter(({ version }) => semver.satisfies(version, `^${current.version.version}`))
|
|
97
|
+
.at(-1);
|
|
98
|
+
if (latest == null || wanted == null)
|
|
99
|
+
return null;
|
|
100
|
+
return { action, current, latest, wanted };
|
|
101
|
+
}))).filter((plan) => plan != null);
|
|
102
|
+
}
|
|
103
|
+
async function discoverActions(dir) {
|
|
104
|
+
let realRoot;
|
|
105
|
+
try {
|
|
106
|
+
realRoot = await fs.realpath(dir);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
throw workflowError('READ', dir, err);
|
|
110
|
+
}
|
|
111
|
+
const workflowDir = path.join(dir, '.github', 'workflows');
|
|
112
|
+
let entries;
|
|
113
|
+
try {
|
|
114
|
+
entries = await fs.readdir(workflowDir);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (isErrorCode(err, 'ENOENT'))
|
|
118
|
+
return [];
|
|
119
|
+
throw workflowError('READ', workflowDir, err);
|
|
120
|
+
}
|
|
121
|
+
const workflowFiles = entries
|
|
122
|
+
.filter((entry) => entry.endsWith('.yml') || entry.endsWith('.yaml'))
|
|
123
|
+
.map((entry) => path.join(workflowDir, entry));
|
|
124
|
+
const visited = new Set();
|
|
125
|
+
const actions = [];
|
|
126
|
+
await Promise.all(workflowFiles.map(scanFile));
|
|
127
|
+
return actions;
|
|
128
|
+
async function scanFile(filePath) {
|
|
129
|
+
let realFilePath;
|
|
130
|
+
try {
|
|
131
|
+
realFilePath = await fs.realpath(filePath);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
throw workflowError('READ', filePath, err);
|
|
135
|
+
}
|
|
136
|
+
if (!isSubdir(realRoot, realFilePath)) {
|
|
137
|
+
throw new PnpmError('GITHUB_ACTIONS_WORKFLOW_OUTSIDE_ROOT', `GitHub Actions workflow is outside the project root: ${filePath}`);
|
|
138
|
+
}
|
|
139
|
+
if (visited.has(realFilePath))
|
|
140
|
+
return;
|
|
141
|
+
visited.add(realFilePath);
|
|
142
|
+
let source;
|
|
143
|
+
try {
|
|
144
|
+
source = await fs.readFile(realFilePath, 'utf8');
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
throw workflowError('READ', realFilePath, err);
|
|
148
|
+
}
|
|
149
|
+
const document = YAML.parseDocument(source);
|
|
150
|
+
if (document.errors.length > 0)
|
|
151
|
+
throw workflowError('PARSE', realFilePath, document.errors[0]);
|
|
152
|
+
const file = { path: realFilePath, source };
|
|
153
|
+
const localReferences = [];
|
|
154
|
+
for (const node of findUsesScalars(document.contents)) {
|
|
155
|
+
const value = node.value;
|
|
156
|
+
if (value.startsWith('./')) {
|
|
157
|
+
localReferences.push(value);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const parsed = parseActionReference(value);
|
|
161
|
+
if (parsed == null)
|
|
162
|
+
continue;
|
|
163
|
+
if (node.range == null)
|
|
164
|
+
throw new Error(`Missing source range for GitHub Action in ${realFilePath}`);
|
|
165
|
+
const end = trimLineBreak(source, node.range[2] ?? node.range[1]);
|
|
166
|
+
actions.push({
|
|
167
|
+
...parsed,
|
|
168
|
+
commentVersion: getCommentVersion(node),
|
|
169
|
+
file,
|
|
170
|
+
flowStyle: isFlowStyle(source, node.range[1]),
|
|
171
|
+
indentation: getIndentation(source, node.range[0]),
|
|
172
|
+
originalValue: source.slice(node.range[0], end),
|
|
173
|
+
range: [node.range[0], end],
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const localFiles = await Promise.all(localReferences.map(async (reference) => resolveLocalReference(dir, reference)));
|
|
177
|
+
await Promise.all(localFiles.filter((local) => local != null).map(scanFile));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function findUsesScalars(node) {
|
|
181
|
+
if (!isMap(node))
|
|
182
|
+
return [];
|
|
183
|
+
const found = [];
|
|
184
|
+
const jobs = findMapValue(node, 'jobs');
|
|
185
|
+
if (isMap(jobs)) {
|
|
186
|
+
for (const job of jobs.items) {
|
|
187
|
+
if (!isMap(job.value))
|
|
188
|
+
continue;
|
|
189
|
+
const jobUses = findStringScalar(job.value, 'uses');
|
|
190
|
+
if (jobUses != null)
|
|
191
|
+
found.push(jobUses);
|
|
192
|
+
found.push(...findStepUses(findMapValue(job.value, 'steps')));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const runs = findMapValue(node, 'runs');
|
|
196
|
+
if (isMap(runs)) {
|
|
197
|
+
found.push(...findStepUses(findMapValue(runs, 'steps')));
|
|
198
|
+
}
|
|
199
|
+
return found;
|
|
200
|
+
}
|
|
201
|
+
function findStepUses(node) {
|
|
202
|
+
if (!isSeq(node))
|
|
203
|
+
return [];
|
|
204
|
+
return node.items.flatMap((item) => {
|
|
205
|
+
if (!isMap(item))
|
|
206
|
+
return [];
|
|
207
|
+
const uses = findStringScalar(item, 'uses');
|
|
208
|
+
return uses == null ? [] : [uses];
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function findMapValue(node, key) {
|
|
212
|
+
if (!isMap(node))
|
|
213
|
+
return null;
|
|
214
|
+
const value = node.items.find((pair) => isScalar(pair.key) && pair.key.value === key)?.value;
|
|
215
|
+
return isNode(value) ? value : null;
|
|
216
|
+
}
|
|
217
|
+
function findStringScalar(node, key) {
|
|
218
|
+
const value = findMapValue(node, key);
|
|
219
|
+
return isScalar(value) && typeof value.value === 'string' ? value : null;
|
|
220
|
+
}
|
|
221
|
+
async function resolveLocalReference(rootDir, reference) {
|
|
222
|
+
const target = path.resolve(rootDir, reference);
|
|
223
|
+
const candidate = target.endsWith('.yml') || target.endsWith('.yaml')
|
|
224
|
+
? await existingPath(target)
|
|
225
|
+
: (await Promise.all(['action.yml', 'action.yaml'].map(async (filename) => existingPath(path.join(target, filename)))))
|
|
226
|
+
.find((candidate) => candidate != null) ?? null;
|
|
227
|
+
if (candidate == null)
|
|
228
|
+
return null;
|
|
229
|
+
let realRoot;
|
|
230
|
+
let realCandidate;
|
|
231
|
+
try {
|
|
232
|
+
[realRoot, realCandidate] = await Promise.all([fs.realpath(rootDir), fs.realpath(candidate)]);
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
throw workflowError('READ', candidate, err);
|
|
236
|
+
}
|
|
237
|
+
return isSubdir(realRoot, realCandidate) ? realCandidate : null;
|
|
238
|
+
}
|
|
239
|
+
async function existingPath(candidate) {
|
|
240
|
+
try {
|
|
241
|
+
await fs.access(candidate);
|
|
242
|
+
return candidate;
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
if (!isErrorCode(err, 'ENOENT'))
|
|
246
|
+
throw workflowError('READ', candidate, err);
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function parseActionReference(value) {
|
|
251
|
+
if (value.startsWith('docker://'))
|
|
252
|
+
return null;
|
|
253
|
+
const at = value.lastIndexOf('@');
|
|
254
|
+
if (at <= 0 || at === value.length - 1)
|
|
255
|
+
return null;
|
|
256
|
+
const name = value.slice(0, at);
|
|
257
|
+
const parts = name.split('/');
|
|
258
|
+
if (parts.length < 2 || parts[0] === '' || parts[1] === '')
|
|
259
|
+
return null;
|
|
260
|
+
return { name, ref: value.slice(at + 1), repo: `${parts[0]}/${parts[1]}` };
|
|
261
|
+
}
|
|
262
|
+
function parseRepoVersions(refs) {
|
|
263
|
+
const versions = [];
|
|
264
|
+
for (const [ref, commit] of Object.entries(refs)) {
|
|
265
|
+
const match = /^refs\/tags\/(v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/.exec(ref);
|
|
266
|
+
if (match == null)
|
|
267
|
+
continue;
|
|
268
|
+
const version = semver.parse(match[1], { loose: true });
|
|
269
|
+
if (version == null)
|
|
270
|
+
continue;
|
|
271
|
+
versions.push({
|
|
272
|
+
commit: refs[`${ref}^{}`] ?? commit,
|
|
273
|
+
tag: match[1],
|
|
274
|
+
version,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return versions.sort((left, right) => semver.compare(left.version, right.version));
|
|
278
|
+
}
|
|
279
|
+
function findCurrentVersion(action, versions) {
|
|
280
|
+
if (SHA_PATTERN.test(action.ref) && action.commentVersion != null) {
|
|
281
|
+
const parsed = semver.parse(action.commentVersion, { loose: true });
|
|
282
|
+
if (parsed != null) {
|
|
283
|
+
const annotated = versions.find(({ commit, version }) => commit === action.ref && semver.eq(version, parsed));
|
|
284
|
+
if (annotated != null)
|
|
285
|
+
return annotated;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const parsed = semver.parse(action.ref, { loose: true });
|
|
289
|
+
if (parsed != null) {
|
|
290
|
+
return versions.find(({ version }) => semver.eq(version, parsed)) ?? null;
|
|
291
|
+
}
|
|
292
|
+
if (/^v?\d+$/.test(action.ref)) {
|
|
293
|
+
const major = Number(action.ref.replace(/^v/, ''));
|
|
294
|
+
return versions.filter(({ version }) => version.major === major && version.prerelease.length === 0).at(-1) ?? null;
|
|
295
|
+
}
|
|
296
|
+
if (SHA_PATTERN.test(action.ref)) {
|
|
297
|
+
return versions.filter(({ commit }) => commit === action.ref).at(-1) ?? null;
|
|
298
|
+
}
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
function getCommentVersion(node) {
|
|
302
|
+
const candidate = node.comment?.trimStart().split(/\s/, 1)[0];
|
|
303
|
+
return candidate != null && semver.valid(candidate, { loose: true }) != null ? candidate : undefined;
|
|
304
|
+
}
|
|
305
|
+
function renderTargetValue(action, target) {
|
|
306
|
+
const oldReference = `${action.name}@${action.ref}`;
|
|
307
|
+
const newReference = `${action.name}@${target.commit}`;
|
|
308
|
+
let value = action.originalValue.replace(oldReference, newReference);
|
|
309
|
+
if (action.commentVersion != null)
|
|
310
|
+
return value.replace(action.commentVersion, target.tag);
|
|
311
|
+
const comment = value.indexOf(' #');
|
|
312
|
+
if (comment === -1) {
|
|
313
|
+
return action.flowStyle
|
|
314
|
+
? `${value.trimEnd()} # ${target.tag}\n${action.indentation}`
|
|
315
|
+
: `${value} # ${target.tag}`;
|
|
316
|
+
}
|
|
317
|
+
return `${value.slice(0, comment + 2)}${target.tag} ${value.slice(comment + 2).trimStart()}`;
|
|
318
|
+
}
|
|
319
|
+
function isFlowStyle(source, end) {
|
|
320
|
+
const lineEnd = source.indexOf('\n', end);
|
|
321
|
+
const following = source.slice(end, lineEnd === -1 ? source.length : lineEnd).trimStart();
|
|
322
|
+
return following.startsWith('}') || following.startsWith(']') || following.startsWith(',');
|
|
323
|
+
}
|
|
324
|
+
function getIndentation(source, start) {
|
|
325
|
+
const lineStart = source.lastIndexOf('\n', start - 1) + 1;
|
|
326
|
+
return ' '.repeat(start - lineStart);
|
|
327
|
+
}
|
|
328
|
+
function trimLineBreak(source, end) {
|
|
329
|
+
while (end > 0 && (source[end - 1] === '\n' || source[end - 1] === '\r'))
|
|
330
|
+
end--;
|
|
331
|
+
return end;
|
|
332
|
+
}
|
|
333
|
+
function dedupeOutdated(actions) {
|
|
334
|
+
return [...new Map(actions.map((action) => [action.name, action])).values()]
|
|
335
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
336
|
+
}
|
|
337
|
+
async function readRefsWithGit(repo) {
|
|
338
|
+
return getRepoRefs(`https://github.com/${repo}.git`, null);
|
|
339
|
+
}
|
|
340
|
+
function workflowError(operation, filePath, cause) {
|
|
341
|
+
const detail = util.types.isNativeError(cause) ? cause.message : String(cause);
|
|
342
|
+
return new PnpmError(`GITHUB_ACTIONS_WORKFLOW_${operation}`, `Failed to ${operation.toLowerCase()} GitHub Actions workflow ${filePath}: ${detail}`, { cause });
|
|
343
|
+
}
|
|
344
|
+
function isErrorCode(err, code) {
|
|
345
|
+
return util.types.isNativeError(err) && 'code' in err && err.code === code;
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pnpm/deps.github-actions",
|
|
3
|
+
"version": "1100.0.1",
|
|
4
|
+
"description": "Discover and update GitHub Actions dependencies",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pnpm",
|
|
7
|
+
"pnpm11",
|
|
8
|
+
"github-actions"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"funding": "https://opencollective.com/pnpm",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/deps/github-actions"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/deps/github-actions#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/pnpm/pnpm/issues"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "lib/index.js",
|
|
22
|
+
"types": "lib/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": "./lib/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"lib",
|
|
28
|
+
"!*.map"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@pnpm/error": "1100.0.1",
|
|
32
|
+
"@pnpm/resolving.git-resolver": "1100.1.11",
|
|
33
|
+
"is-subdir": "^2.0.0",
|
|
34
|
+
"p-limit": "^7.3.0",
|
|
35
|
+
"semver": "^7.8.4",
|
|
36
|
+
"write-file-atomic": "^7.0.1",
|
|
37
|
+
"yaml": "^2.9.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@jest/globals": "30.4.1",
|
|
41
|
+
"@pnpm/deps.github-actions": "1100.0.1",
|
|
42
|
+
"@types/semver": "7.7.1",
|
|
43
|
+
"@types/write-file-atomic": "^4.0.3"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22.13"
|
|
47
|
+
},
|
|
48
|
+
"jest": {
|
|
49
|
+
"preset": "@pnpm/jest-config"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
53
|
+
"test": "pn compile && pn .test",
|
|
54
|
+
"compile": "tsgo --build && pn lint --fix",
|
|
55
|
+
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
56
|
+
}
|
|
57
|
+
}
|