@opengsd/gsd-core 1.20.0 → 1.21.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +33 -2
- package/agents/gsd-executor.md +1 -1
- package/agents/gsd-plan-checker.md +1 -1
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-verifier.md +2 -2
- package/bin/install.js +265 -161
- package/commands/gsd/autonomous.md +1 -1
- package/commands/gsd/new-milestone.md +2 -2
- package/commands/gsd/new-project.md +2 -2
- package/gsd-core/bin/gsd-tools.cjs +554 -823
- package/gsd-core/bin/lib/capability-activation.cjs +8 -2
- package/gsd-core/bin/lib/capability-command-router.cjs +6 -2
- package/gsd-core/bin/lib/capability-ledger.cjs +1 -1
- package/gsd-core/bin/lib/capability-lock.cjs +19 -27
- package/gsd-core/bin/lib/capability-registry.cjs +74 -71
- package/gsd-core/bin/lib/capability-validator.cjs +1 -0
- package/gsd-core/bin/lib/capability-writer.cjs +7 -4
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +142 -62
- package/gsd-core/bin/lib/claude-orchestration.cjs +214 -122
- package/gsd-core/bin/lib/cli-surface.cjs +545 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +356 -103
- package/gsd-core/bin/lib/commands.cjs +99 -2
- package/gsd-core/bin/lib/config-file-read.cjs +85 -0
- package/gsd-core/bin/lib/config-loader.cjs +23 -15
- package/gsd-core/bin/lib/config.cjs +139 -101
- package/gsd-core/bin/lib/configuration.cjs +41 -2
- package/gsd-core/bin/lib/criterion-baseline.cjs +346 -0
- package/gsd-core/bin/lib/criterion-replay.cjs +380 -0
- package/gsd-core/bin/lib/estimate-cli.cjs +5 -1
- package/gsd-core/bin/lib/gap-checker.cjs +12 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +593 -27
- package/gsd-core/bin/lib/gate-phase-context.cjs +16 -4
- package/gsd-core/bin/lib/graphify.cjs +19 -2
- package/gsd-core/bin/lib/gsd-tool-dir.cjs +134 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +5 -1
- package/gsd-core/bin/lib/init.cjs +20 -18
- package/gsd-core/bin/lib/install-effort-resolver.cjs +24 -4
- package/gsd-core/bin/lib/install-engine.cjs +20 -28
- package/gsd-core/bin/lib/install-fs-adapter.cjs +5 -1
- package/gsd-core/bin/lib/install-manifest-record.cjs +86 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -3
- package/gsd-core/bin/lib/install-profiles.cjs +4 -2
- package/gsd-core/bin/lib/io.cjs +6 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +62 -31
- package/gsd-core/bin/lib/markdown-table.cjs +39 -1
- package/gsd-core/bin/lib/milestone.cjs +8 -6
- package/gsd-core/bin/lib/model-resolver.cjs +8 -4
- package/gsd-core/bin/lib/phase-entry-grammar.cjs +14 -0
- package/gsd-core/bin/lib/phase-id.cjs +26 -9
- package/gsd-core/bin/lib/phase-locator.cjs +8 -3
- package/gsd-core/bin/lib/phase.cjs +170 -45
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +46 -23
- package/gsd-core/bin/lib/planning-snapshot.cjs +10 -6
- package/gsd-core/bin/lib/planning-workspace.cjs +20 -10
- package/gsd-core/bin/lib/profile-output.cjs +9 -6
- package/gsd-core/bin/lib/project-context.cjs +439 -0
- package/gsd-core/bin/lib/project-root.cjs +9 -230
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +1 -1
- package/gsd-core/bin/lib/report-parser.cjs +16 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +357 -50
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +24 -5
- package/gsd-core/bin/lib/roadmap.cjs +2 -2
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +317 -134
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +81 -3
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +6 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +279 -8
- package/gsd-core/bin/lib/runtime-slash.cjs +7 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +1010 -10
- package/gsd-core/bin/lib/stale-bake-guard.cjs +4 -1
- package/gsd-core/bin/lib/state-transition.cjs +103 -46
- package/gsd-core/bin/lib/state.cjs +448 -63
- package/gsd-core/bin/lib/surface.cjs +4 -7
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +10 -3
- package/gsd-core/bin/lib/verify-command-router.cjs +6 -1
- package/gsd-core/bin/lib/verify.cjs +49 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +4 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +32 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +8 -111
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/autonomous-smart-discuss.md +99 -18
- package/gsd-core/references/checkpoints.md +1 -1
- package/gsd-core/references/planner-guidance.md +11 -0
- package/gsd-core/references/planner-human-verify-mode.md +1 -1
- package/gsd-core/references/planner-reversibility.md +2 -0
- package/gsd-core/references/planner-verify-command-grounding.md +22 -6
- package/gsd-core/workflows/autonomous.md +4 -4
- package/gsd-core/workflows/code-review-fix.md +5 -7
- package/gsd-core/workflows/execute-phase.md +21 -7
- package/gsd-core/workflows/plan-phase/steps/plan-pre-dispatch.md +101 -0
- package/gsd-core/workflows/plan-phase.md +18 -19
- package/hooks/dist/gsd-agent-isolation-guard.js +4 -3
- package/hooks/dist/gsd-config-reload.js +2 -2
- package/hooks/dist/gsd-context-monitor.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +9 -6
- package/hooks/dist/gsd-read-injection-scanner.js +2 -2
- package/hooks/dist/gsd-secret-read-guard.js +141 -6
- package/hooks/dist/gsd-statusline.js +3 -2
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/lib/config-read.js +49 -0
- package/hooks/dist/lib/git-cmd.js +3 -1
- package/hooks/dist/lib/git-head-tree.js +474 -0
- package/hooks/dist/lib/isolation-sentinel.js +168 -13
- package/hooks/dist/lib/secret-read-exemptions.js +161 -0
- package/hooks/gsd-agent-isolation-guard.js +4 -3
- package/hooks/gsd-config-reload.js +2 -2
- package/hooks/gsd-context-monitor.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +9 -6
- package/hooks/gsd-read-injection-scanner.js +2 -2
- package/hooks/gsd-secret-read-guard.js +141 -6
- package/hooks/gsd-statusline.js +3 -2
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/lib/config-read.js +49 -0
- package/hooks/lib/git-cmd.js +3 -1
- package/hooks/lib/git-head-tree.js +474 -0
- package/hooks/lib/isolation-sentinel.js +168 -13
- package/hooks/lib/secret-read-exemptions.js +161 -0
- package/package.json +7 -2
- package/pi/package-agents/gsd-executor.md +1 -1
- package/pi/package-agents/gsd-plan-checker.md +1 -1
- package/pi/package-agents/gsd-planner.md +3 -3
- package/pi/package-agents/gsd-verifier.md +2 -2
- package/pi/package-agents/manifest.json +4 -4
- package/pi/package-skills/gsd-autonomous/SKILL.md +1 -1
- package/pi/package-skills/gsd-new-milestone/SKILL.md +1 -1
- package/pi/package-skills/gsd-new-project/SKILL.md +1 -1
- package/scripts/changeset/cli.cjs +2 -2
- package/scripts/changeset/lint.cjs +28 -3
- package/scripts/changeset/serialize.cjs +12 -2
- package/scripts/ci-compact-v8-coverage.cjs +204 -0
- package/scripts/ci-fix-next-rerun.cjs +149 -0
- package/scripts/ci-next-health.cjs +52 -9
- package/scripts/ci-test-scope.cjs +77 -71
- package/scripts/command-contract-helpers.cjs +56 -7
- package/scripts/docs-guard-registry.cjs +3 -0
- package/scripts/gen-cli-surface-manifest.cjs +287 -0
- package/scripts/gen-platform-conformance-tier.cjs +258 -19
- package/scripts/lib/macos-conformance-tier.generated.cjs +59 -47
- package/scripts/lib/platform-conformance-tier.generated.cjs +23 -64
- package/scripts/lib/shellcheck-fetch.cjs +71 -4
- package/scripts/lint-removed-but-needed.cjs +562 -50
- package/scripts/merge-commit-pr.cjs +186 -0
- package/scripts/release-ancestry.cjs +86 -0
- package/scripts/release-notes/changelog-release-notes.cjs +345 -0
- package/scripts/release-notes/discord-release-summary.cjs +82 -1
- package/scripts/release-pipeline-pr.cjs +92 -0
- package/scripts/require-issue-link-policy.cjs +18 -9
- package/scripts/sync-next-version.cjs +11 -2
- package/scripts/timeout-evidence-from-ci.cjs +964 -0
- package/skills/gsd-autonomous/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-new-project/SKILL.md +1 -1
- package/vscode/package.json +1 -1
|
@@ -11,6 +11,8 @@ const DEFAULT_MAX_CONTENT = 1850;
|
|
|
11
11
|
const SECTION_LIMITS = Object.freeze([
|
|
12
12
|
['Breaking', 4],
|
|
13
13
|
['Security', 4],
|
|
14
|
+
['Removed', 3],
|
|
15
|
+
['Deprecated', 3],
|
|
14
16
|
['Feature', 4],
|
|
15
17
|
['Fix', 4],
|
|
16
18
|
['Enhancement', 3],
|
|
@@ -49,6 +51,14 @@ function normalizeHeading(value) {
|
|
|
49
51
|
|
|
50
52
|
if (lower.includes('breaking')) return 'Breaking';
|
|
51
53
|
if (lower.includes('security')) return 'Security';
|
|
54
|
+
// Keep-a-Changelog headings (#5922): the release body is built from the
|
|
55
|
+
// CHANGELOG section, whose subsections use these names.
|
|
56
|
+
if (lower === 'added') return 'Feature';
|
|
57
|
+
if (lower === 'fixed') return 'Fix';
|
|
58
|
+
if (lower === 'changed') return 'Enhancement';
|
|
59
|
+
if (lower === 'deprecated') return 'Deprecated';
|
|
60
|
+
// Note: an old-format body with a `## Removed` heading now buckets under Removed (#5922).
|
|
61
|
+
if (lower === 'removed') return 'Removed';
|
|
52
62
|
if (lower === 'feature' || lower === 'features') return 'Feature';
|
|
53
63
|
if (lower === 'fix' || lower === 'fixes' || lower === 'bug fixes') return 'Fix';
|
|
54
64
|
if (lower === 'enhancement' || lower === 'enhancements' || lower === 'improvements') return 'Enhancement';
|
|
@@ -58,11 +68,21 @@ function normalizeHeading(value) {
|
|
|
58
68
|
return heading;
|
|
59
69
|
}
|
|
60
70
|
|
|
71
|
+
// A body built from a CHANGELOG section (#5922) carries Keep-a-Changelog
|
|
72
|
+
// subsection headings. GitHub-generated and formatter output never does, so
|
|
73
|
+
// its bullets keep the original (unchanged) handling.
|
|
74
|
+
const CHANGELOG_HEADING_RE = /^###\s+(?:Added|Changed|Deprecated|Removed|Fixed|Security)\s*$/m;
|
|
75
|
+
|
|
61
76
|
function collectSections(body) {
|
|
77
|
+
const text = normalizeNewlines(body);
|
|
78
|
+
return CHANGELOG_HEADING_RE.test(text) ? collectChangelogSections(text) : collectLegacySections(text);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function collectLegacySections(text) {
|
|
62
82
|
const sections = new Map();
|
|
63
83
|
let current = null;
|
|
64
84
|
|
|
65
|
-
for (const line of
|
|
85
|
+
for (const line of text.split('\n')) {
|
|
66
86
|
const trimmed = line.trim();
|
|
67
87
|
const heading = trimmed.match(/^#{2,3}\s+(.+)$/);
|
|
68
88
|
|
|
@@ -86,6 +106,67 @@ function collectSections(body) {
|
|
|
86
106
|
return sections;
|
|
87
107
|
}
|
|
88
108
|
|
|
109
|
+
function collectChangelogSections(text) {
|
|
110
|
+
const sections = new Map();
|
|
111
|
+
let current = null;
|
|
112
|
+
// Bullet in flight: CHANGELOG bullets wrap onto indented continuation lines
|
|
113
|
+
// that carry the trailing (#issue) (#pr) references.
|
|
114
|
+
let pending = null;
|
|
115
|
+
|
|
116
|
+
function flush() {
|
|
117
|
+
if (!pending) return;
|
|
118
|
+
if (!sections.has(pending.section)) sections.set(pending.section, []);
|
|
119
|
+
sections.get(pending.section).push(summarizeChangelogBullet(pending.text) || cleanBullet(pending.text));
|
|
120
|
+
pending = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const line of text.split('\n')) {
|
|
124
|
+
const trimmed = line.trim();
|
|
125
|
+
const heading = trimmed.match(/^#{2,3}\s+(.+)$/);
|
|
126
|
+
|
|
127
|
+
if (heading) {
|
|
128
|
+
flush();
|
|
129
|
+
current = normalizeHeading(heading[1]);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Indented bullets are nested detail of a CHANGELOG bullet, not entries.
|
|
134
|
+
if (/^\s+[*-]\s/.test(line)) {
|
|
135
|
+
flush();
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const bullet = trimmed.match(/^([*-])\s+(.+)$/);
|
|
140
|
+
if (!bullet || !current) {
|
|
141
|
+
if (pending && /^\s+\S/.test(line)) pending.text += ` ${trimmed}`;
|
|
142
|
+
else flush();
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
flush();
|
|
147
|
+
const section = current === "What's Changed" ? classifyTitle(trimmed) : current;
|
|
148
|
+
pending = { section, text: trimmed };
|
|
149
|
+
}
|
|
150
|
+
flush();
|
|
151
|
+
|
|
152
|
+
return sections;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* CHANGELOG bullets read `- **Headline** — long explanation (#issue) (#pr)`.
|
|
157
|
+
* The bold headline is the user-visible summary; keep it and the trailing
|
|
158
|
+
* issue/PR references. Returns null for any other bullet shape.
|
|
159
|
+
* @param {string} bulletLine
|
|
160
|
+
* @returns {string|null}
|
|
161
|
+
*/
|
|
162
|
+
function summarizeChangelogBullet(bulletLine) {
|
|
163
|
+
const m = bulletLine.match(/^[*-]\s+\*\*(.+?)\*\*\s+[—–-]\s/);
|
|
164
|
+
if (!m) return null;
|
|
165
|
+
const refs = bulletLine.match(/(?:\s\(#\d+\))+\s*$/);
|
|
166
|
+
const headline = cleanBullet(`- ${m[1]}`);
|
|
167
|
+
return refs ? `${headline}${refs[0].replace(/\s+/g, ' ').replace(/\s+$/, '')}` : headline;
|
|
168
|
+
}
|
|
169
|
+
|
|
89
170
|
function cleanBullet(value) {
|
|
90
171
|
let text = String(value)
|
|
91
172
|
.replace(/^[*-]\s+/, '')
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The release pipeline's own back-merge PRs (#5890).
|
|
5
|
+
*
|
|
6
|
+
* The pipeline opens three kinds of PR, and none of them has an issue to link:
|
|
7
|
+
*
|
|
8
|
+
* kind head branch base opened by
|
|
9
|
+
* release-merge release/X.Y.0 | hotfix/X.Y.Z (Z>0) main release.yml "merge release back to main"
|
|
10
|
+
* next-version-sync chore/sync-next-version-<version> next scripts/sync-next-version.cjs
|
|
11
|
+
* main-to-next-backmerge chore/backmerge-main-to-next-<sha> next auto-backmerge.yml (#1389)
|
|
12
|
+
*
|
|
13
|
+
* Callers, each with its trust model:
|
|
14
|
+
*
|
|
15
|
+
* - scripts/require-issue-link-policy.cjs (`Issue link required`) and
|
|
16
|
+
* .github/workflows/pr-title-validator.yml (`validate-title`) run on
|
|
17
|
+
* pull_request_target and load this module from a BASE-branch checkout,
|
|
18
|
+
* so a PR cannot edit the predicate that judges it.
|
|
19
|
+
* - scripts/changeset/lint.cjs (changeset-lint, #5903) runs on pull_request
|
|
20
|
+
* and executes PR-tree code, so the base-checkout guarantee does not apply
|
|
21
|
+
* (a PR could already edit lint.cjs itself). The fork guard is what blocks
|
|
22
|
+
* forgery: sameRepo is derived from the GitHub event payload.
|
|
23
|
+
*
|
|
24
|
+
* What each caller exempts:
|
|
25
|
+
*
|
|
26
|
+
* - `Issue link required`: the closing-reference requirement.
|
|
27
|
+
* - `validate-title`: only the missing-issue-ref verdict; the title's type
|
|
28
|
+
* prefix (`bad-prefix`) is still enforced on these PRs.
|
|
29
|
+
* - changeset-lint: the fragment requirement; a malformed fragment or `pr:`
|
|
30
|
+
* drift still fails.
|
|
31
|
+
*
|
|
32
|
+
* Anti-forgery (#1389): a branch name alone is attacker-chosen — a fork can
|
|
33
|
+
* name its branch anything. The exemption therefore also requires
|
|
34
|
+
* `sameRepo === true` (head.repo.full_name == the base repository), which only
|
|
35
|
+
* someone with push access to this repository can satisfy, and the exact base
|
|
36
|
+
* branch each kind targets.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const { isReleaseVersion, SYNC_BRANCH_PREFIX } = require('./sync-next-version.cjs');
|
|
40
|
+
|
|
41
|
+
const RELEASE_PIPELINE_PR_KIND = Object.freeze({
|
|
42
|
+
RELEASE_MERGE: 'release-merge',
|
|
43
|
+
NEXT_VERSION_SYNC: 'next-version-sync',
|
|
44
|
+
MAIN_TO_NEXT_BACKMERGE: 'main-to-next-backmerge',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// release.yml validate-version: X.Y.0 cuts release/X.Y.0; X.Y.Z with Z>0 cuts
|
|
48
|
+
// hotfix/X.Y.Z. Same no-leading-zero grammar as its `grep -qE` checks.
|
|
49
|
+
const RELEASE_BRANCH_RE = /^release\/(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.0$/;
|
|
50
|
+
const HOTFIX_BRANCH_RE = /^hotfix\/(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.[1-9][0-9]*$/;
|
|
51
|
+
|
|
52
|
+
// auto-backmerge.yml: BR="chore/backmerge-main-to-next-${SHORT_SHA}" (#1389),
|
|
53
|
+
// SHORT_SHA=$(git rev-parse --short origin/main): 7 to 40 lowercase hex.
|
|
54
|
+
const BACKMERGE_BRANCH_PREFIX = 'chore/backmerge-main-to-next-';
|
|
55
|
+
const BACKMERGE_SHA_RE = /^[0-9a-f]{7,40}$/;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Classify a PR as one of the release pipeline's own PRs.
|
|
59
|
+
*
|
|
60
|
+
* @param {{ headRef?: unknown, baseRef?: unknown, sameRepo?: unknown }} [pr]
|
|
61
|
+
* @returns {string|null} a RELEASE_PIPELINE_PR_KIND value, or null when the PR
|
|
62
|
+
* is not a release-pipeline PR (including every fork PR).
|
|
63
|
+
*/
|
|
64
|
+
function releasePipelinePrKind({ headRef, baseRef, sameRepo } = {}) {
|
|
65
|
+
if (sameRepo !== true) return null;
|
|
66
|
+
if (typeof headRef !== 'string' || typeof baseRef !== 'string') return null;
|
|
67
|
+
|
|
68
|
+
if (baseRef === 'main' && (RELEASE_BRANCH_RE.test(headRef) || HOTFIX_BRANCH_RE.test(headRef))) {
|
|
69
|
+
return RELEASE_PIPELINE_PR_KIND.RELEASE_MERGE;
|
|
70
|
+
}
|
|
71
|
+
if (baseRef === 'next' && headRef.startsWith(SYNC_BRANCH_PREFIX)
|
|
72
|
+
&& isReleaseVersion(headRef.slice(SYNC_BRANCH_PREFIX.length))) {
|
|
73
|
+
return RELEASE_PIPELINE_PR_KIND.NEXT_VERSION_SYNC;
|
|
74
|
+
}
|
|
75
|
+
if (baseRef === 'next' && headRef.startsWith(BACKMERGE_BRANCH_PREFIX)
|
|
76
|
+
&& BACKMERGE_SHA_RE.test(headRef.slice(BACKMERGE_BRANCH_PREFIX.length))) {
|
|
77
|
+
return RELEASE_PIPELINE_PR_KIND.MAIN_TO_NEXT_BACKMERGE;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** True iff the PR is one of the release pipeline's own PRs (see releasePipelinePrKind). */
|
|
83
|
+
function isReleasePipelinePr(pr) {
|
|
84
|
+
return releasePipelinePrKind(pr) !== null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = {
|
|
88
|
+
RELEASE_PIPELINE_PR_KIND,
|
|
89
|
+
BACKMERGE_BRANCH_PREFIX,
|
|
90
|
+
releasePipelinePrKind,
|
|
91
|
+
isReleasePipelinePr,
|
|
92
|
+
};
|
|
@@ -37,10 +37,14 @@ const ISSUE_LINK_REASON = Object.freeze({
|
|
|
37
37
|
FAIL_FILE_LIST_INCOMPLETE: 'fail_file_list_incomplete',
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
// #1389
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
40
|
+
// #1389 / #5890: the release pipeline's own back-merge PRs (release/hotfix ->
|
|
41
|
+
// main, chore/sync-next-version-* and chore/backmerge-main-to-next-* -> next)
|
|
42
|
+
// are opened by CI, never by a human or a fork, and have no issue to link, so
|
|
43
|
+
// they are exempt outright. The predicate lives in release-pipeline-pr.cjs —
|
|
44
|
+
// shared with pr-title-validator.yml so the two gates agree — and requires
|
|
45
|
+
// `sameRepo === true` plus the exact base branch, so a fork cannot forge it
|
|
46
|
+
// by naming its branch.
|
|
47
|
+
const { releasePipelinePrKind, BACKMERGE_BRANCH_PREFIX } = require('./release-pipeline-pr.cjs');
|
|
44
48
|
|
|
45
49
|
// #4196: Dependabot has no mechanism to link a PR it opens to a repo issue —
|
|
46
50
|
// its alerts live in the Security tab, not as issues, so there is nothing
|
|
@@ -135,7 +139,7 @@ function allPathsAreTestsOrDocs(changedFiles) {
|
|
|
135
139
|
});
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
function evaluateIssueLink({ prBody, headRef, sameRepo, authorLogin, changedFiles, changedFilesTotal }) {
|
|
142
|
+
function evaluateIssueLink({ prBody, headRef, baseRef, sameRepo, authorLogin, changedFiles, changedFilesTotal }) {
|
|
139
143
|
if (authorLogin === DEPENDABOT_LOGIN) {
|
|
140
144
|
return { ok: true, reason: ISSUE_LINK_REASON.OK_DEPENDABOT_EXEMPT };
|
|
141
145
|
}
|
|
@@ -144,10 +148,14 @@ function evaluateIssueLink({ prBody, headRef, sameRepo, authorLogin, changedFile
|
|
|
144
148
|
return { ok: true, reason: ISSUE_LINK_REASON.OK_CLOSING_KEYWORD };
|
|
145
149
|
}
|
|
146
150
|
|
|
147
|
-
// #1389: `sameRepo === true` is required, not just the branch
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
// #1389: `sameRepo === true` is required, not just the branch name — a fork
|
|
152
|
+
// PR could otherwise name its branch to forge this exemption (#5890 adds the
|
|
153
|
+
// base branch and the release/sync shapes; see release-pipeline-pr.cjs).
|
|
154
|
+
const releaseKind = releasePipelinePrKind({ headRef, baseRef, sameRepo });
|
|
155
|
+
if (releaseKind) {
|
|
156
|
+
// `kind` names which release-pipeline PR this is (the reason keeps its
|
|
157
|
+
// #1389 name so existing consumers of the enum are unchanged).
|
|
158
|
+
return { ok: true, reason: ISSUE_LINK_REASON.OK_BACKMERGE_EXEMPT, kind: releaseKind };
|
|
151
159
|
}
|
|
152
160
|
|
|
153
161
|
if (!hasFollowUpReference(prBody)) {
|
|
@@ -175,6 +183,7 @@ function main() {
|
|
|
175
183
|
const result = evaluateIssueLink({
|
|
176
184
|
prBody: process.env.PR_BODY || '',
|
|
177
185
|
headRef: process.env.HEAD_REF || '',
|
|
186
|
+
baseRef: process.env.BASE_REF || '',
|
|
178
187
|
sameRepo: process.env.SAME_REPO === 'true',
|
|
179
188
|
authorLogin: process.env.PR_AUTHOR_LOGIN || '',
|
|
180
189
|
changedFiles,
|
|
@@ -30,6 +30,15 @@ function isReleaseVersion(v) {
|
|
|
30
30
|
return typeof v === 'string' && RELEASE_VERSION.test(v);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// The branch syncViaPr opens. scripts/release-pipeline-pr.cjs exempts exactly
|
|
34
|
+
// this shape from the issue-link and PR-title gates (#5890).
|
|
35
|
+
const SYNC_BRANCH_PREFIX = 'chore/sync-next-version-';
|
|
36
|
+
|
|
37
|
+
/** The head branch of the sync PR for `version`. */
|
|
38
|
+
function syncBranchName(version) {
|
|
39
|
+
return `${SYNC_BRANCH_PREFIX}${version}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
/** Read the `version` field out of a package.json text blob. Throws on a missing/non-string version. */
|
|
34
43
|
function versionFromPackageJson(text) {
|
|
35
44
|
const parsed = JSON.parse(text);
|
|
@@ -76,7 +85,7 @@ function syncViaPr(version, { run = defaultRun } = {}) {
|
|
|
76
85
|
process.stdout.write(`next already at ${version} — nothing to sync\n`);
|
|
77
86
|
return 'noop';
|
|
78
87
|
}
|
|
79
|
-
const branch =
|
|
88
|
+
const branch = syncBranchName(version);
|
|
80
89
|
run('git', ['checkout', '-B', branch, 'origin/next'], { timeout: 15000 });
|
|
81
90
|
applyVersion(version, { run });
|
|
82
91
|
run('git', ['add', '-u'], { timeout: 15000 });
|
|
@@ -162,4 +171,4 @@ if (require.main === module) {
|
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
|
|
165
|
-
module.exports = { isReleaseVersion, versionFromPackageJson, applyVersion, syncViaPr, main, defaultRun };
|
|
174
|
+
module.exports = { isReleaseVersion, versionFromPackageJson, applyVersion, syncViaPr, main, defaultRun, SYNC_BRANCH_PREFIX, syncBranchName };
|