@arjunkhera/atlas 0.4.26 → 0.4.27
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.
|
@@ -23,7 +23,7 @@ export const TOOLING_LABEL = 'atlas-helper';
|
|
|
23
23
|
|
|
24
24
|
// The only files the tooling writer may write: the check, its workflow, and
|
|
25
25
|
// the pull request template when the repo has none.
|
|
26
|
-
export const TOOLING_PATHS = Object.freeze([CHECK_PATH, WORKFLOW_PATH, '.github/workflows/atlas-jobs.yml', '.github/pull_request_template.md']);
|
|
26
|
+
export const TOOLING_PATHS = Object.freeze([CHECK_PATH, WORKFLOW_PATH, '.github/workflows/atlas-jobs.yml', '.github/workflows/atlas-upkeep.yml', '.github/pull_request_template.md']);
|
|
27
27
|
// The only files the tooling writer may remove: the workflow of check versions
|
|
28
28
|
// 1 to 5, which the gate workflow replaces (roadmap R7).
|
|
29
29
|
export const TOOLING_REMOVALS = Object.freeze([OLD_WORKFLOW_PATH]);
|
package/door/lib/tooling.mjs
CHANGED
|
@@ -42,25 +42,34 @@ const oldWorkflow = (root) => existsSync(join(root, OLD_WORKFLOW_PATH));
|
|
|
42
42
|
// repo backwards, and never replaces a hand edit at the same version.
|
|
43
43
|
export const JOBS_PATH = '.github/workflows/atlas-jobs.yml';
|
|
44
44
|
export const PACKAGE_JOBS_SOURCE = 'door/templates/atlas-jobs.yml';
|
|
45
|
+
// The upkeep check on each pull request (roadmap R41). The same pin rule holds.
|
|
46
|
+
// The Atlas repo keeps its own atlas-upkeep.yml, which runs the package of
|
|
47
|
+
// master and has no pin, so the writer keeps it and Atlas runs one upkeep job.
|
|
48
|
+
export const UPKEEP_PATH = '.github/workflows/atlas-upkeep.yml';
|
|
49
|
+
export const PACKAGE_UPKEEP_SOURCE = 'door/templates/atlas-upkeep.yml';
|
|
50
|
+
// The workflows the writer pins, in the order of its rows.
|
|
51
|
+
const PINNED = Object.freeze([[JOBS_PATH, PACKAGE_JOBS_SOURCE], [UPKEEP_PATH, PACKAGE_UPKEEP_SOURCE]]);
|
|
45
52
|
const VERSION_SLOT = '__ATLAS_VERSION__';
|
|
46
|
-
|
|
47
|
-
const full = join(packageRoot,
|
|
53
|
+
function packagedPinned(packageRoot, source) {
|
|
54
|
+
const full = join(packageRoot, source);
|
|
48
55
|
return existsSync(full) ? readFileSync(full, 'utf8').split(VERSION_SLOT).join(packagePackageVersion(packageRoot)) : null;
|
|
49
56
|
}
|
|
50
|
-
const
|
|
57
|
+
export const packagedJobsWorkflow = (packageRoot) => packagedPinned(packageRoot, PACKAGE_JOBS_SOURCE);
|
|
58
|
+
export const packagedUpkeepWorkflow = (packageRoot) => packagedPinned(packageRoot, PACKAGE_UPKEEP_SOURCE);
|
|
59
|
+
const pinOf = (text) => /@arjunkhera\/atlas@(\d+)\.(\d+)\.(\d+)\b/.exec(text)?.slice(1).map(Number) ?? null;
|
|
51
60
|
const older = (a, b) => { for (let i = 0; i < 3; i += 1) if (a[i] !== b[i]) return a[i] < b[i]; return false; };
|
|
52
|
-
// written, refreshed, unchanged or kept: what the writer does with
|
|
53
|
-
function
|
|
54
|
-
const wanted =
|
|
61
|
+
// written, refreshed, unchanged or kept: what the writer does with one pinned workflow.
|
|
62
|
+
function pinnedState(root, packageRoot, path, source) {
|
|
63
|
+
const wanted = packagedPinned(packageRoot, source);
|
|
55
64
|
if (wanted === null) return null;
|
|
56
|
-
const full = join(root,
|
|
65
|
+
const full = join(root, path);
|
|
57
66
|
if (!existsSync(full)) return 'written';
|
|
58
67
|
const was = readFileSync(full, 'utf8');
|
|
59
68
|
if (was === wanted) return 'unchanged';
|
|
60
|
-
const have =
|
|
61
|
-
return have && older(have,
|
|
69
|
+
const have = pinOf(was);
|
|
70
|
+
return have && older(have, pinOf(wanted)) ? 'refreshed' : 'kept';
|
|
62
71
|
}
|
|
63
|
-
const
|
|
72
|
+
const pinnedNeedWrite = (root, packageRoot) => PINNED.some(([path, source]) => ['written', 'refreshed'].includes(pinnedState(root, packageRoot, path, source)));
|
|
64
73
|
|
|
65
74
|
// The pull request template (roadmap R8). The writer puts it into a repo that
|
|
66
75
|
// has none, and never replaces a template the repo keeps.
|
|
@@ -113,7 +122,7 @@ export function mayWrite(root, packageRoot, { replaceUnknown = false, workflowOn
|
|
|
113
122
|
throw new ToolingRefusal(`this package's ${PACKAGE_CHECK_SOURCE} is ${pkg.row ? 'not the newest release' : 'in no release'} of the check, so it is not written into another repo. Use a released Atlas.`);
|
|
114
123
|
}
|
|
115
124
|
const now = status({ root, packageRoot });
|
|
116
|
-
if (now.state === 'current' && !workflowOnly && !templateMissing(root, packageRoot) && !
|
|
125
|
+
if (now.state === 'current' && !workflowOnly && !templateMissing(root, packageRoot) && !pinnedNeedWrite(root, packageRoot) && !oldWorkflow(root)) {
|
|
117
126
|
throw new ToolingRefusal(`this repo's check is already current. ${readWorkflow(root) === WORKFLOW_TEMPLATE || workflowKept(root) ? 'Both files match the package, so there is nothing to write.' : 'Its workflow file differs from the package; pass --workflow to rewrite only that file.'}`, { current: true });
|
|
118
127
|
}
|
|
119
128
|
if (now.state === 'unknown' && !replaceUnknown && !own) {
|
|
@@ -145,16 +154,17 @@ export function write(root, packageRoot, { dryRun = false, replaceUnknown = fals
|
|
|
145
154
|
if (!dryRun) rmSync(join(root, OLD_WORKFLOW_PATH));
|
|
146
155
|
rows.push({ path: OLD_WORKFLOW_PATH, state: 'removed', sha256: null, was: sha256(was) });
|
|
147
156
|
}
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
157
|
+
for (const [path, source] of workflowOnly ? [] : PINNED) {
|
|
158
|
+
const state = pinnedState(root, packageRoot, path, source);
|
|
159
|
+
if (state === null) continue;
|
|
160
|
+
const contents = packagedPinned(packageRoot, source);
|
|
161
|
+
const full = join(root, path);
|
|
152
162
|
const was = existsSync(full) ? readFileSync(full, 'utf8') : null;
|
|
153
|
-
if ((
|
|
163
|
+
if ((state === 'written' || state === 'refreshed') && !dryRun) {
|
|
154
164
|
mkdirSync(dirname(full), { recursive: true });
|
|
155
165
|
writeFileSync(full, contents);
|
|
156
166
|
}
|
|
157
|
-
rows.push({ path
|
|
167
|
+
rows.push({ path, state, sha256: sha256(state === 'kept' ? was : contents), was: was === null ? null : sha256(was) });
|
|
158
168
|
}
|
|
159
169
|
const template = workflowOnly ? null : packagedTemplate(packageRoot);
|
|
160
170
|
if (template !== null) {
|
|
@@ -180,7 +190,7 @@ export function changes(root, packageRoot, { replaceUnknown = false, workflowOnl
|
|
|
180
190
|
if (rows.every((row) => row.state === 'unchanged' || row.state === 'kept')) {
|
|
181
191
|
throw new ToolingRefusal('this repo is already current: its Atlas files match the package, so there is nothing to open.', { current: true });
|
|
182
192
|
}
|
|
183
|
-
const wanted = { ...packagedFiles(packageRoot), [JOBS_PATH]: packagedJobsWorkflow(packageRoot), [PR_TEMPLATE_PATH]: packagedTemplate(packageRoot) };
|
|
193
|
+
const wanted = { ...packagedFiles(packageRoot), [JOBS_PATH]: packagedJobsWorkflow(packageRoot), [UPKEEP_PATH]: packagedUpkeepWorkflow(packageRoot), [PR_TEMPLATE_PATH]: packagedTemplate(packageRoot) };
|
|
184
194
|
return rows
|
|
185
195
|
.filter((row) => row.state !== 'unchanged' && row.state !== 'kept')
|
|
186
196
|
.map((row) => (row.state === 'removed' ? {
|
|
@@ -196,8 +206,8 @@ export function changes(root, packageRoot, { replaceUnknown = false, workflowOnl
|
|
|
196
206
|
? `copied byte for byte from ${PACKAGE_CHECK_SOURCE}, check version ${CHECK_VERSION}, in Atlas ${version}`
|
|
197
207
|
: row.path === PR_TEMPLATE_PATH
|
|
198
208
|
? `copied from ${PACKAGE_TEMPLATE_SOURCE}, Atlas ${version}; the repo had no pull request template`
|
|
199
|
-
: row.path === JOBS_PATH
|
|
200
|
-
? `written from ${PACKAGE_JOBS_SOURCE}, with its pin set to Atlas ${version}`
|
|
209
|
+
: row.path === JOBS_PATH || row.path === UPKEEP_PATH
|
|
210
|
+
? `written from ${row.path === JOBS_PATH ? PACKAGE_JOBS_SOURCE : PACKAGE_UPKEEP_SOURCE}, with its pin set to Atlas ${version}`
|
|
201
211
|
: `written from the WORKFLOW_TEMPLATE constant in ${PACKAGE_CHECK_SOURCE}, Atlas ${version}`,
|
|
202
212
|
},
|
|
203
213
|
}));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: atlas-upkeep
|
|
2
|
+
# The Atlas upkeep check on each pull request: plain code, no model and no
|
|
3
|
+
# secret. `atlas tooling` wrote this file from the Atlas package; do not edit
|
|
4
|
+
# it by hand. A newer Atlas moves the pin below when `atlas tooling pr` runs.
|
|
5
|
+
#
|
|
6
|
+
# It stops drift at its source: the docs index lists each doc, every doc link
|
|
7
|
+
# resolves, each doc names its code, and the pull request names its tracker
|
|
8
|
+
# item, or says "no item:" and a reason. A repo with no docs/ folder passes
|
|
9
|
+
# the index part with one line.
|
|
10
|
+
#
|
|
11
|
+
# It runs a pinned Atlas release from npm, never code of the pull request. It
|
|
12
|
+
# runs on pull_request, not pull_request_target, so it holds only a read token
|
|
13
|
+
# and no secret, also for a pull request from a fork. npx runs outside the
|
|
14
|
+
# checkout, so an .npmrc in the pull request cannot pick the registry.
|
|
15
|
+
on:
|
|
16
|
+
pull_request:
|
|
17
|
+
types: [opened, edited, synchronize, reopened]
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: atlas-upkeep-${{ github.event.pull_request.number }}
|
|
24
|
+
cancel-in-progress: true
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
upkeep:
|
|
28
|
+
name: docs · upkeep check
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 5
|
|
31
|
+
steps:
|
|
32
|
+
# actions/checkout v7.0.1
|
|
33
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
34
|
+
with:
|
|
35
|
+
fetch-depth: 0
|
|
36
|
+
persist-credentials: false
|
|
37
|
+
# actions/setup-node v7.0.0
|
|
38
|
+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
|
39
|
+
with:
|
|
40
|
+
node-version: "22.22.0"
|
|
41
|
+
- name: Upkeep check
|
|
42
|
+
run: |
|
|
43
|
+
set -euo pipefail
|
|
44
|
+
cd "$RUNNER_TEMP"
|
|
45
|
+
npx --yes --ignore-scripts @arjunkhera/atlas@__ATLAS_VERSION__ upkeep check --root "$GITHUB_WORKSPACE" --event "$GITHUB_EVENT_PATH" | tee -a "$GITHUB_STEP_SUMMARY"
|
package/package.json
CHANGED