@treeseed/sdk 0.6.36 → 0.6.37
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/operations/services/git-workflow.js +2 -2
- package/dist/operations/services/github-automation.d.ts +6 -98
- package/dist/operations/services/github-automation.js +1 -74
- package/dist/operations/services/release-candidate.js +5 -11
- package/dist/operations/services/repository-save-orchestrator.js +7 -8
- package/dist/operations/services/save-deploy-preflight.d.ts +0 -5
- package/dist/operations/services/save-deploy-preflight.js +1 -9
- package/dist/scripts/workspace-command-e2e.js +3 -3
- package/dist/verification.js +0 -1
- package/dist/workflow/operations.js +14 -17
- package/package.json +1 -1
|
@@ -420,8 +420,8 @@ function createDeprecatedTaskTag(repoDir, branchName, message) {
|
|
|
420
420
|
return { tagName, head };
|
|
421
421
|
}
|
|
422
422
|
function waitForStagingAutomation(repoDir) {
|
|
423
|
-
if (process.env.TREESEED_STAGE_WAIT_MODE === "skip"
|
|
424
|
-
return { status: "skipped", reason: "
|
|
423
|
+
if (process.env.TREESEED_STAGE_WAIT_MODE === "skip") {
|
|
424
|
+
return { status: "skipped", reason: "disabled" };
|
|
425
425
|
}
|
|
426
426
|
try {
|
|
427
427
|
const gh = resolveTreeseedToolBinary("gh");
|
|
@@ -22,7 +22,7 @@ export interface TreeseedGitHubRepositoryTarget {
|
|
|
22
22
|
visibility: 'private' | 'public' | 'internal';
|
|
23
23
|
source: 'config' | 'origin' | 'default';
|
|
24
24
|
}
|
|
25
|
-
export declare function getGitHubAutomationMode():
|
|
25
|
+
export declare function getGitHubAutomationMode(): string;
|
|
26
26
|
export declare function parseGitHubRepositoryFromRemote(remoteUrl: any): string | null;
|
|
27
27
|
export declare function resolveGitHubRepositorySlug(tenantRoot: any): string;
|
|
28
28
|
export declare function maybeResolveGitHubRepositorySlug(tenantRoot: any): string | null;
|
|
@@ -51,17 +51,7 @@ export declare function ensureGitHubBootstrapRepository(tenantRoot: string, { va
|
|
|
51
51
|
pushed: boolean;
|
|
52
52
|
mode: string;
|
|
53
53
|
}>;
|
|
54
|
-
export declare function createGitHubRepository(input: any): Promise<import("./github-api.ts").GitHubRepositorySummary
|
|
55
|
-
visibility: any;
|
|
56
|
-
defaultBranch: string;
|
|
57
|
-
mode: string;
|
|
58
|
-
slug: string;
|
|
59
|
-
owner: string;
|
|
60
|
-
name: string;
|
|
61
|
-
sshUrl: string;
|
|
62
|
-
httpsUrl: string;
|
|
63
|
-
url: string;
|
|
64
|
-
}>;
|
|
54
|
+
export declare function createGitHubRepository(input: any): Promise<import("./github-api.ts").GitHubRepositorySummary>;
|
|
65
55
|
export declare function initializeGitHubRepositoryWorkingTree(cwd: any, repository: any, { defaultBranch, createStaging, commitMessage, remoteName, push, }?: {
|
|
66
56
|
defaultBranch?: string | undefined;
|
|
67
57
|
createStaging?: boolean | undefined;
|
|
@@ -74,14 +64,6 @@ export declare function initializeGitHubRepositoryWorkingTree(cwd: any, reposito
|
|
|
74
64
|
defaultBranch: string;
|
|
75
65
|
stagingBranch: string | null;
|
|
76
66
|
pushed: boolean;
|
|
77
|
-
mode: string;
|
|
78
|
-
} | {
|
|
79
|
-
repository: any;
|
|
80
|
-
remoteName: string;
|
|
81
|
-
defaultBranch: string;
|
|
82
|
-
stagingBranch: string | null;
|
|
83
|
-
pushed: boolean;
|
|
84
|
-
mode?: undefined;
|
|
85
67
|
};
|
|
86
68
|
export declare function resolveGitRepositoryRoot(tenantRoot: any): any;
|
|
87
69
|
export declare function requiredGitHubEnvironment(tenantRoot: any, { scope, purpose }?: {
|
|
@@ -99,38 +81,20 @@ export declare function renderHostedProjectWorkflow({ workingDirectory }: {
|
|
|
99
81
|
workingDirectory: any;
|
|
100
82
|
}): string;
|
|
101
83
|
export declare function ensureDeployWorkflow(tenantRoot: any): {
|
|
102
|
-
workflowPath: string;
|
|
103
|
-
changed: boolean;
|
|
104
|
-
workingDirectory: string;
|
|
105
|
-
mode: string;
|
|
106
|
-
} | {
|
|
107
84
|
workingDirectory: string;
|
|
108
85
|
workflowPath: string;
|
|
109
86
|
changed: boolean;
|
|
110
|
-
mode?: undefined;
|
|
111
87
|
};
|
|
112
88
|
export declare function ensureHostedProjectWorkflow(tenantRoot: any): {
|
|
113
|
-
workflowPath: string;
|
|
114
|
-
changed: boolean;
|
|
115
|
-
workingDirectory: string;
|
|
116
|
-
mode: string;
|
|
117
|
-
} | {
|
|
118
89
|
workingDirectory: string;
|
|
119
90
|
workflowPath: string;
|
|
120
91
|
changed: boolean;
|
|
121
|
-
mode?: undefined;
|
|
122
92
|
};
|
|
123
|
-
export declare function ensureStandardizedGitHubWorkflows(tenantRoot: any):
|
|
124
|
-
workflowPath: string;
|
|
125
|
-
changed: boolean;
|
|
126
|
-
workingDirectory: string;
|
|
127
|
-
mode: string;
|
|
128
|
-
} | {
|
|
93
|
+
export declare function ensureStandardizedGitHubWorkflows(tenantRoot: any): {
|
|
129
94
|
workingDirectory: string;
|
|
130
95
|
workflowPath: string;
|
|
131
96
|
changed: boolean;
|
|
132
|
-
|
|
133
|
-
})[];
|
|
97
|
+
}[];
|
|
134
98
|
export declare function listGitHubSecretNames(repository: any, tenantRoot: any): Promise<Set<string>>;
|
|
135
99
|
export declare function listGitHubVariableNames(repository: any, tenantRoot: any): Promise<Set<string>>;
|
|
136
100
|
export declare function formatMissingSecretsReport(repository: any, missingSecrets: any, reason?: string): string;
|
|
@@ -139,9 +103,6 @@ export declare function ensureGitHubSecrets(tenantRoot: any, { dryRun }?: {
|
|
|
139
103
|
}): Promise<{
|
|
140
104
|
existing: never[];
|
|
141
105
|
created: never[];
|
|
142
|
-
} | {
|
|
143
|
-
existing: never[];
|
|
144
|
-
created: never[];
|
|
145
106
|
} | {
|
|
146
107
|
existing: string[];
|
|
147
108
|
created: string[];
|
|
@@ -152,18 +113,6 @@ export declare function ensureGitHubEnvironment(tenantRoot: any, { dryRun, scope
|
|
|
152
113
|
purpose?: string | undefined;
|
|
153
114
|
valuesOverlay?: {} | undefined;
|
|
154
115
|
}): Promise<{
|
|
155
|
-
repository: string | null;
|
|
156
|
-
secrets: {
|
|
157
|
-
existing: never[];
|
|
158
|
-
created: never[];
|
|
159
|
-
};
|
|
160
|
-
variables: {
|
|
161
|
-
existing: never[];
|
|
162
|
-
created: never[];
|
|
163
|
-
};
|
|
164
|
-
skipped: string;
|
|
165
|
-
mode: string;
|
|
166
|
-
} | {
|
|
167
116
|
repository: null;
|
|
168
117
|
secrets: {
|
|
169
118
|
existing: never[];
|
|
@@ -174,7 +123,6 @@ export declare function ensureGitHubEnvironment(tenantRoot: any, { dryRun, scope
|
|
|
174
123
|
created: never[];
|
|
175
124
|
};
|
|
176
125
|
skipped: string;
|
|
177
|
-
mode?: undefined;
|
|
178
126
|
} | {
|
|
179
127
|
repository: string;
|
|
180
128
|
secrets: {
|
|
@@ -186,7 +134,6 @@ export declare function ensureGitHubEnvironment(tenantRoot: any, { dryRun, scope
|
|
|
186
134
|
created: string[];
|
|
187
135
|
};
|
|
188
136
|
skipped?: undefined;
|
|
189
|
-
mode?: undefined;
|
|
190
137
|
}>;
|
|
191
138
|
export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun, valuesOverlay }?: {
|
|
192
139
|
dryRun?: boolean | undefined;
|
|
@@ -194,33 +141,18 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun,
|
|
|
194
141
|
}): Promise<{
|
|
195
142
|
mode: string;
|
|
196
143
|
workflow: {
|
|
197
|
-
workflowPath: string;
|
|
198
|
-
changed: boolean;
|
|
199
|
-
workingDirectory: string;
|
|
200
|
-
mode: string;
|
|
201
|
-
} | {
|
|
202
144
|
workingDirectory: string;
|
|
203
145
|
workflowPath: string;
|
|
204
146
|
changed: boolean;
|
|
205
|
-
mode?: undefined;
|
|
206
147
|
};
|
|
207
|
-
workflows:
|
|
208
|
-
workflowPath: string;
|
|
209
|
-
changed: boolean;
|
|
210
|
-
workingDirectory: string;
|
|
211
|
-
mode: string;
|
|
212
|
-
} | {
|
|
148
|
+
workflows: {
|
|
213
149
|
workingDirectory: string;
|
|
214
150
|
workflowPath: string;
|
|
215
151
|
changed: boolean;
|
|
216
|
-
|
|
217
|
-
})[];
|
|
152
|
+
}[];
|
|
218
153
|
secrets: {
|
|
219
154
|
existing: never[];
|
|
220
155
|
created: never[];
|
|
221
|
-
} | {
|
|
222
|
-
existing: never[];
|
|
223
|
-
created: never[];
|
|
224
156
|
} | {
|
|
225
157
|
existing: string[];
|
|
226
158
|
created: string[];
|
|
@@ -228,26 +160,11 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun,
|
|
|
228
160
|
variables: {
|
|
229
161
|
existing: never[];
|
|
230
162
|
created: never[];
|
|
231
|
-
} | {
|
|
232
|
-
existing: never[];
|
|
233
|
-
created: never[];
|
|
234
163
|
} | {
|
|
235
164
|
existing: string[];
|
|
236
165
|
created: string[];
|
|
237
166
|
};
|
|
238
167
|
environment: {
|
|
239
|
-
repository: string | null;
|
|
240
|
-
secrets: {
|
|
241
|
-
existing: never[];
|
|
242
|
-
created: never[];
|
|
243
|
-
};
|
|
244
|
-
variables: {
|
|
245
|
-
existing: never[];
|
|
246
|
-
created: never[];
|
|
247
|
-
};
|
|
248
|
-
skipped: string;
|
|
249
|
-
mode: string;
|
|
250
|
-
} | {
|
|
251
168
|
repository: null;
|
|
252
169
|
secrets: {
|
|
253
170
|
existing: never[];
|
|
@@ -258,7 +175,6 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun,
|
|
|
258
175
|
created: never[];
|
|
259
176
|
};
|
|
260
177
|
skipped: string;
|
|
261
|
-
mode?: undefined;
|
|
262
178
|
} | {
|
|
263
179
|
repository: string;
|
|
264
180
|
secrets: {
|
|
@@ -270,7 +186,6 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun,
|
|
|
270
186
|
created: string[];
|
|
271
187
|
};
|
|
272
188
|
skipped?: undefined;
|
|
273
|
-
mode?: undefined;
|
|
274
189
|
};
|
|
275
190
|
}>;
|
|
276
191
|
export declare function waitForGitHubWorkflowCompletion(tenantRoot: any, { repository, workflow, headSha, branch, timeoutSeconds, pollSeconds, onProgress, }?: {
|
|
@@ -290,11 +205,4 @@ export declare function waitForGitHubWorkflowCompletion(tenantRoot: any, { repos
|
|
|
290
205
|
url: string | null;
|
|
291
206
|
jobs: import("./github-api.ts").GitHubWorkflowJobSummary[];
|
|
292
207
|
failedJobs: import("./github-api.ts").GitHubWorkflowJobSummary[];
|
|
293
|
-
} | {
|
|
294
|
-
status: string;
|
|
295
|
-
reason: string;
|
|
296
|
-
repository: any;
|
|
297
|
-
workflow: string;
|
|
298
|
-
headSha: any;
|
|
299
|
-
branch: any;
|
|
300
208
|
}>;
|
|
@@ -22,10 +22,7 @@ function slugifySegment(value, fallback = "project") {
|
|
|
22
22
|
return String(value ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0, 96) || fallback;
|
|
23
23
|
}
|
|
24
24
|
function getGitHubAutomationMode() {
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
function isGitHubAutomationStubbed() {
|
|
28
|
-
return getGitHubAutomationMode() === "stub";
|
|
25
|
+
return "real";
|
|
29
26
|
}
|
|
30
27
|
function parseGitHubRepositoryFromRemote(remoteUrl) {
|
|
31
28
|
if (!remoteUrl) {
|
|
@@ -170,17 +167,6 @@ async function ensureGitHubBootstrapRepository(tenantRoot, {
|
|
|
170
167
|
const remotes = resolveGitHubRemoteUrls(target.owner, target.name);
|
|
171
168
|
const slug = remotes.slug;
|
|
172
169
|
onProgress?.(`[local][github][repo] Preparing ${slug} from ${target.source}...`);
|
|
173
|
-
if (isGitHubAutomationStubbed()) {
|
|
174
|
-
onProgress?.(`[local][github][repo] Stubbed GitHub automation; repository ${slug} not changed.`);
|
|
175
|
-
return {
|
|
176
|
-
repository: slug,
|
|
177
|
-
target,
|
|
178
|
-
created: false,
|
|
179
|
-
remote: { changed: false, previous: null, next: remotes.sshUrl },
|
|
180
|
-
pushed: false,
|
|
181
|
-
mode: "stub"
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
170
|
const client = createGitHubApiClient({
|
|
185
171
|
env: {
|
|
186
172
|
GH_TOKEN: configuredValue(values, "GH_TOKEN") || configuredValue(values, "GITHUB_TOKEN"),
|
|
@@ -217,14 +203,6 @@ async function ensureGitHubBootstrapRepository(tenantRoot, {
|
|
|
217
203
|
async function createGitHubRepository(input) {
|
|
218
204
|
const visibility = input.visibility ?? "private";
|
|
219
205
|
const remotes = resolveGitHubRemoteUrls(input.owner, input.name);
|
|
220
|
-
if (isGitHubAutomationStubbed()) {
|
|
221
|
-
return {
|
|
222
|
-
...remotes,
|
|
223
|
-
visibility,
|
|
224
|
-
defaultBranch: "main",
|
|
225
|
-
mode: "stub"
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
206
|
return await ensureGitHubRepository({
|
|
229
207
|
owner: remotes.owner,
|
|
230
208
|
name: remotes.name,
|
|
@@ -243,16 +221,6 @@ function initializeGitHubRepositoryWorkingTree(cwd, repository, {
|
|
|
243
221
|
remoteName = "origin",
|
|
244
222
|
push = true
|
|
245
223
|
} = {}) {
|
|
246
|
-
if (isGitHubAutomationStubbed()) {
|
|
247
|
-
return {
|
|
248
|
-
repository,
|
|
249
|
-
remoteName,
|
|
250
|
-
defaultBranch,
|
|
251
|
-
stagingBranch: createStaging ? "staging" : null,
|
|
252
|
-
pushed: false,
|
|
253
|
-
mode: "stub"
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
224
|
runGit(["init", "-b", defaultBranch], { cwd, allowFailure: true });
|
|
257
225
|
ensureGitIdentity(cwd);
|
|
258
226
|
const currentRemote = runGit(["remote", "get-url", remoteName], { cwd, allowFailure: true }).stdout?.trim() ?? "";
|
|
@@ -348,14 +316,6 @@ function ensureWorkflowFile(tenantRoot, fileName, expected) {
|
|
|
348
316
|
return { workflowPath, changed: true };
|
|
349
317
|
}
|
|
350
318
|
function ensureDeployWorkflow(tenantRoot) {
|
|
351
|
-
if (isGitHubAutomationStubbed()) {
|
|
352
|
-
return {
|
|
353
|
-
workflowPath: resolve(tenantRoot, ".github", "workflows", "deploy.yml"),
|
|
354
|
-
changed: false,
|
|
355
|
-
workingDirectory: ".",
|
|
356
|
-
mode: "stub"
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
319
|
const repositoryRoot = resolveGitRepositoryRoot(tenantRoot);
|
|
360
320
|
const workingDirectory = relative(repositoryRoot, tenantRoot).replaceAll("\\", "/") || ".";
|
|
361
321
|
const expected = renderDeployWorkflow({ workingDirectory });
|
|
@@ -365,14 +325,6 @@ function ensureDeployWorkflow(tenantRoot) {
|
|
|
365
325
|
};
|
|
366
326
|
}
|
|
367
327
|
function ensureHostedProjectWorkflow(tenantRoot) {
|
|
368
|
-
if (isGitHubAutomationStubbed()) {
|
|
369
|
-
return {
|
|
370
|
-
workflowPath: resolve(tenantRoot, ".github", "workflows", "hosted-project.yml"),
|
|
371
|
-
changed: false,
|
|
372
|
-
workingDirectory: ".",
|
|
373
|
-
mode: "stub"
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
328
|
const repositoryRoot = resolveGitRepositoryRoot(tenantRoot);
|
|
377
329
|
const workingDirectory = relative(repositoryRoot, tenantRoot).replaceAll("\\", "/") || ".";
|
|
378
330
|
const expected = renderHostedProjectWorkflow({ workingDirectory });
|
|
@@ -419,21 +371,6 @@ function nonEmptyValues(values = {}) {
|
|
|
419
371
|
);
|
|
420
372
|
}
|
|
421
373
|
async function ensureGitHubEnvironment(tenantRoot, { dryRun = false, scope = "prod", purpose = "save", valuesOverlay = {} } = {}) {
|
|
422
|
-
if (isGitHubAutomationStubbed()) {
|
|
423
|
-
return {
|
|
424
|
-
repository: maybeResolveGitHubRepositorySlug(tenantRoot),
|
|
425
|
-
secrets: {
|
|
426
|
-
existing: [],
|
|
427
|
-
created: []
|
|
428
|
-
},
|
|
429
|
-
variables: {
|
|
430
|
-
existing: [],
|
|
431
|
-
created: []
|
|
432
|
-
},
|
|
433
|
-
skipped: "stubbed",
|
|
434
|
-
mode: "stub"
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
374
|
const repository = maybeResolveGitHubRepositorySlug(tenantRoot);
|
|
438
375
|
if (!repository) {
|
|
439
376
|
if (dryRun) {
|
|
@@ -518,16 +455,6 @@ async function waitForGitHubWorkflowCompletion(tenantRoot, {
|
|
|
518
455
|
pollSeconds = 5,
|
|
519
456
|
onProgress
|
|
520
457
|
} = {}) {
|
|
521
|
-
if (isGitHubAutomationStubbed()) {
|
|
522
|
-
return {
|
|
523
|
-
status: "skipped",
|
|
524
|
-
reason: "stubbed",
|
|
525
|
-
repository: repository ?? maybeResolveGitHubRepositorySlug(tenantRoot),
|
|
526
|
-
workflow,
|
|
527
|
-
headSha: headSha ?? null,
|
|
528
|
-
branch: branch ?? null
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
458
|
const repo = repository ?? resolveGitHubRepositorySlug(tenantRoot);
|
|
532
459
|
return await waitForGitHubWorkflowRunCompletion(repo, {
|
|
533
460
|
client: createGitHubApiClient(),
|
|
@@ -4,7 +4,7 @@ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, write
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, join, relative, resolve } from "node:path";
|
|
6
6
|
import { isTreeseedEnvironmentEntryRelevant, isTreeseedEnvironmentEntryRequired } from "../../platform/environment.js";
|
|
7
|
-
import {
|
|
7
|
+
import { maybeResolveGitHubRepositorySlug } from "./github-automation.js";
|
|
8
8
|
import { createGitHubApiClient, listGitHubEnvironmentSecretNames, listGitHubEnvironmentVariableNames } from "./github-api.js";
|
|
9
9
|
import { collectInternalDevReferenceIssues } from "./package-reference-policy.js";
|
|
10
10
|
import { collectTreeseedEnvironmentContext, resolveTreeseedMachineEnvironmentValues, validateTreeseedCommandEnvironment } from "./config-runtime.js";
|
|
@@ -123,9 +123,6 @@ function packageReadinessChecks(root, selectedPackageNames, failures) {
|
|
|
123
123
|
if (selectedPackageNames.length === 0) {
|
|
124
124
|
return { name: "package-release-readiness", status: "skipped", detail: "No packages are selected for this release." };
|
|
125
125
|
}
|
|
126
|
-
if (getGitHubAutomationMode() === "stub") {
|
|
127
|
-
return { name: "package-release-readiness", status: "skipped", detail: "GitHub automation is stubbed." };
|
|
128
|
-
}
|
|
129
126
|
const selected = new Set(selectedPackageNames);
|
|
130
127
|
const packages = workspacePackages(root).filter((pkg) => selected.has(pkg.name));
|
|
131
128
|
for (const pkg of packages) {
|
|
@@ -266,8 +263,8 @@ function buildRehearsalWorkspacePackageArtifacts(root) {
|
|
|
266
263
|
}
|
|
267
264
|
}
|
|
268
265
|
function runProductionDependencyRehearsal(root, plannedVersions, selectedPackageNames, failures) {
|
|
269
|
-
if (
|
|
270
|
-
return "Skipped clean install rehearsal
|
|
266
|
+
if (process.env.TREESEED_RELEASE_CANDIDATE_REHEARSAL_MODE === "skip") {
|
|
267
|
+
return "Skipped clean install rehearsal by request.";
|
|
271
268
|
}
|
|
272
269
|
const selectedPackageSet = new Set(selectedPackageNames);
|
|
273
270
|
let tempParent = null;
|
|
@@ -379,9 +376,6 @@ function localConfigCheck(root, scope, failures) {
|
|
|
379
376
|
}
|
|
380
377
|
}
|
|
381
378
|
async function githubRemoteConfigCheck(root, scope, failures) {
|
|
382
|
-
if (getGitHubAutomationMode() === "stub") {
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
379
|
const repository = maybeResolveGitHubRepositorySlug(root);
|
|
386
380
|
if (!repository) {
|
|
387
381
|
addFailure(failures, {
|
|
@@ -490,8 +484,8 @@ function providerResourceIdentifierCheck(root, scope, failures) {
|
|
|
490
484
|
}
|
|
491
485
|
}
|
|
492
486
|
async function configParityChecks(root, failures) {
|
|
493
|
-
if (
|
|
494
|
-
return { name: "config-parity", status: "skipped", detail: "
|
|
487
|
+
if (process.env.TREESEED_RELEASE_CANDIDATE_CONFIG_PARITY_MODE === "skip") {
|
|
488
|
+
return { name: "config-parity", status: "skipped", detail: "Remote config parity skipped by request." };
|
|
495
489
|
}
|
|
496
490
|
const before = failures.length;
|
|
497
491
|
localConfigCheck(root, "staging", failures);
|
|
@@ -2,7 +2,6 @@ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "no
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { basename, resolve, relative } from "node:path";
|
|
4
4
|
import { spawn, spawnSync } from "node:child_process";
|
|
5
|
-
import { getGitHubAutomationMode } from "./github-automation.js";
|
|
6
5
|
import {
|
|
7
6
|
ensureSshPushUrlForOrigin,
|
|
8
7
|
remoteWriteUrl,
|
|
@@ -578,7 +577,7 @@ function applyPackageVersion(node, version) {
|
|
|
578
577
|
return true;
|
|
579
578
|
}
|
|
580
579
|
function shouldSkipNetworkInstall() {
|
|
581
|
-
return
|
|
580
|
+
return process.env.TREESEED_SAVE_NPM_INSTALL_MODE === "skip";
|
|
582
581
|
}
|
|
583
582
|
function shouldSkipGitDependencySmoke(options) {
|
|
584
583
|
return shouldSkipNetworkInstall() || process.env.TREESEED_GIT_DEPENDENCY_SMOKE === "skip" || options?.verifyMode === "skip";
|
|
@@ -628,7 +627,7 @@ async function runGitDependencySmoke(node, options, reference) {
|
|
|
628
627
|
async function runNpmInstallWithRetry(node, options, gitDependencyRefreshSpecs = []) {
|
|
629
628
|
if (shouldSkipNetworkInstall()) {
|
|
630
629
|
emitProgress(options, node, "install", "Skipped npm install because network install mode is disabled.");
|
|
631
|
-
return { status: "skipped", attempts: 0, reason: "
|
|
630
|
+
return { status: "skipped", attempts: 0, reason: "disabled" };
|
|
632
631
|
}
|
|
633
632
|
let lastError = null;
|
|
634
633
|
const packageJson = node.packageJson ?? (existsSync(resolve(node.path, "package.json")) ? readJson(resolve(node.path, "package.json")) : null);
|
|
@@ -678,7 +677,7 @@ async function validateRepositoryLockfile(node, options) {
|
|
|
678
677
|
const commandText = `${command} ${args.join(" ")}`;
|
|
679
678
|
if (shouldSkipNetworkInstall()) {
|
|
680
679
|
emitProgress(options, node, "lockfile", `Skipped ${commandText} because network install mode is disabled.`);
|
|
681
|
-
return { status: "skipped", command: commandText, issues: [], error: "
|
|
680
|
+
return { status: "skipped", command: commandText, issues: [], error: "disabled" };
|
|
682
681
|
}
|
|
683
682
|
try {
|
|
684
683
|
runCapturedCommand(node, options, "lockfile", command, args, { timeoutMs: 12e4, emitOutputOnSuccess: false });
|
|
@@ -710,9 +709,9 @@ async function runScript(node, options, scriptName) {
|
|
|
710
709
|
await runStreamingCommand(node, options, "verify", "npm", ["run", scriptName]);
|
|
711
710
|
}
|
|
712
711
|
async function runRepoVerification(node, options, verifyMode) {
|
|
713
|
-
if (verifyMode === "skip"
|
|
714
|
-
emitProgress(options, node, "verify",
|
|
715
|
-
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error:
|
|
712
|
+
if (verifyMode === "skip") {
|
|
713
|
+
emitProgress(options, node, "verify", "Skipped verification by request.");
|
|
714
|
+
return { mode: verifyMode, status: "skipped", primary: null, fallbackUsed: false, error: null };
|
|
716
715
|
}
|
|
717
716
|
if (node.kind !== "package") {
|
|
718
717
|
emitProgress(options, node, "verify", "Skipped package verification for project repository.");
|
|
@@ -897,7 +896,7 @@ function ensureRemoteAccessBeforeVerification(node, options, state) {
|
|
|
897
896
|
}
|
|
898
897
|
}
|
|
899
898
|
function shouldSkipRemoteAccessPreflight() {
|
|
900
|
-
return
|
|
899
|
+
return process.env.TREESEED_SAVE_REMOTE_PREFLIGHT === "skip";
|
|
901
900
|
}
|
|
902
901
|
function localTreeseedTagWasCreatedByThisRun(node, tagName, workflowRunId) {
|
|
903
902
|
const message = localTagMessage(node.path, tagName);
|
|
@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { packageScriptPath } from "./runtime-tools.js";
|
|
3
3
|
import { applyTreeseedEnvironmentToProcess, assertTreeseedCommandEnvironment } from "./config-runtime.js";
|
|
4
4
|
import { collectCliPreflight } from "./workspace-preflight.js";
|
|
5
|
-
import {
|
|
5
|
+
import { requiredGitHubEnvironment } from "./github-automation.js";
|
|
6
6
|
function runStep(label, scriptName, { cwd, env } = {}) {
|
|
7
7
|
const result = spawnSync(process.execPath, [packageScriptPath(scriptName)], {
|
|
8
8
|
cwd,
|
|
@@ -25,14 +25,6 @@ function missingRequiredEnv(requiredKeys) {
|
|
|
25
25
|
function validateSaveAutomationPrerequisites({ cwd }) {
|
|
26
26
|
applyTreeseedEnvironmentToProcess({ tenantRoot: cwd, scope: "prod", override: true });
|
|
27
27
|
assertTreeseedCommandEnvironment({ tenantRoot: cwd, scope: "prod", purpose: "save" });
|
|
28
|
-
if (getGitHubAutomationMode() !== "real") {
|
|
29
|
-
return {
|
|
30
|
-
ok: true,
|
|
31
|
-
mode: "stub",
|
|
32
|
-
missingEnv: [],
|
|
33
|
-
preflight: null
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
28
|
const preflight = collectCliPreflight({ cwd, requireAuth: true });
|
|
37
29
|
if (!preflight.ok) {
|
|
38
30
|
const error = new Error("Treeseed save prerequisites failed: required GitHub, Cloudflare, or Railway tokens are missing.");
|
|
@@ -346,7 +346,7 @@ function appendSaveMarker(filePath, marker) {
|
|
|
346
346
|
}
|
|
347
347
|
function writeWorkspaceStub(repoDir) {
|
|
348
348
|
writeFileSync(resolve(repoDir, 'package.json'), `${JSON.stringify({
|
|
349
|
-
name: 'treeseed-save-
|
|
349
|
+
name: 'treeseed-save-local',
|
|
350
350
|
private: true,
|
|
351
351
|
workspaces: ['packages/*'],
|
|
352
352
|
}, null, 2)}\n`, 'utf8');
|
|
@@ -556,7 +556,7 @@ async function runLocalSuite() {
|
|
|
556
556
|
rmSync(clonedWorkspace.cloneRoot, { recursive: true, force: true });
|
|
557
557
|
}
|
|
558
558
|
});
|
|
559
|
-
await withStep('save success: local bare origin with
|
|
559
|
+
await withStep('save success: local bare origin with local-only install checks', async () => {
|
|
560
560
|
const clonedWorkspace = cloneLocalWorkspaceWithBareOrigin();
|
|
561
561
|
try {
|
|
562
562
|
const notePath = resolve(clonedWorkspace.workingRoot, 'src/content/notes/first-note.mdx');
|
|
@@ -566,7 +566,7 @@ async function runLocalSuite() {
|
|
|
566
566
|
cwd: clonedWorkspace.workingRoot,
|
|
567
567
|
env: {
|
|
568
568
|
...cacheEnv(),
|
|
569
|
-
|
|
569
|
+
TREESEED_SAVE_NPM_INSTALL_MODE: 'skip',
|
|
570
570
|
TREESEED_SAVE_REPORT_PATH: saveReportPath,
|
|
571
571
|
},
|
|
572
572
|
timeoutMs: 1800000,
|
package/dist/verification.js
CHANGED
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
squashMergeBranchIntoStaging,
|
|
69
69
|
syncBranchWithOrigin
|
|
70
70
|
} from "../operations/services/git-workflow.js";
|
|
71
|
-
import {
|
|
71
|
+
import { resolveGitHubRepositorySlug } from "../operations/services/github-automation.js";
|
|
72
72
|
import {
|
|
73
73
|
formatGitHubActionsGateFailure,
|
|
74
74
|
inspectGitHubActionsVerification,
|
|
@@ -338,9 +338,6 @@ function shouldDispatchSwitchToManagedWorktree(root, input, env) {
|
|
|
338
338
|
return !isManagedWorkflowWorktree(root) && effectiveWorkflowWorktreeMode(input.worktreeMode, env) === "on";
|
|
339
339
|
}
|
|
340
340
|
function assertHostedGitHubWorkflowAuthReady(operation, root) {
|
|
341
|
-
if (getGitHubAutomationMode() === "stub") {
|
|
342
|
-
return null;
|
|
343
|
-
}
|
|
344
341
|
const tools = collectTreeseedToolStatus({
|
|
345
342
|
tenantRoot: root,
|
|
346
343
|
env: process.env
|
|
@@ -372,7 +369,7 @@ function assertHostedGitHubWorkflowAuthReady(operation, root) {
|
|
|
372
369
|
}
|
|
373
370
|
async function waitForWorkflowGates(operation, gates, ciMode, options = {}) {
|
|
374
371
|
if (ciMode === "off" || process.env.TREESEED_STAGE_WAIT_MODE === "skip") {
|
|
375
|
-
return gates.map((gate) => skippedGitHubActionsGate(gate,
|
|
372
|
+
return gates.map((gate) => skippedGitHubActionsGate(gate, "disabled"));
|
|
376
373
|
}
|
|
377
374
|
if (gates.length === 0) {
|
|
378
375
|
return [];
|
|
@@ -452,10 +449,10 @@ function recordHostedDeploymentStatesFromRootGates(root, rootRelease, workflowGa
|
|
|
452
449
|
return reports;
|
|
453
450
|
}
|
|
454
451
|
function ensureTreeseedCommandReadiness(root) {
|
|
455
|
-
if (
|
|
452
|
+
if (process.env.TREESEED_COMMAND_READINESS_MODE === "skip") {
|
|
456
453
|
return {
|
|
457
454
|
status: "skipped",
|
|
458
|
-
reason: "
|
|
455
|
+
reason: "disabled",
|
|
459
456
|
checks: [],
|
|
460
457
|
missing: []
|
|
461
458
|
};
|
|
@@ -1368,9 +1365,6 @@ function failWorkflowRun(root, runId, error, recovery) {
|
|
|
1368
1365
|
releaseWorkflowLock(root, runId);
|
|
1369
1366
|
}
|
|
1370
1367
|
function validatePackageReleaseWorkflows(root, packageNames) {
|
|
1371
|
-
if (process.env.TREESEED_GITHUB_AUTOMATION_MODE === "stub") {
|
|
1372
|
-
return;
|
|
1373
|
-
}
|
|
1374
1368
|
const missing = checkedOutWorkspacePackageRepos(root).filter((pkg) => packageNames.includes(pkg.name)).filter((pkg) => !existsSync(resolve(pkg.dir, ".github", "workflows", "publish.yml"))).map((pkg) => pkg.name);
|
|
1375
1369
|
if (missing.length > 0) {
|
|
1376
1370
|
workflowError("release", "workflow_contract_missing", `Treeseed release requires .github/workflows/publish.yml in: ${missing.join(", ")}.`, {
|
|
@@ -1381,7 +1375,7 @@ function validatePackageReleaseWorkflows(root, packageNames) {
|
|
|
1381
1375
|
}
|
|
1382
1376
|
}
|
|
1383
1377
|
function validateStagingWorkflowContracts(root) {
|
|
1384
|
-
if (process.env.
|
|
1378
|
+
if (process.env.TREESEED_STAGE_WAIT_MODE === "skip") {
|
|
1385
1379
|
return;
|
|
1386
1380
|
}
|
|
1387
1381
|
const missing = [];
|
|
@@ -1397,11 +1391,11 @@ function validateStagingWorkflowContracts(root) {
|
|
|
1397
1391
|
}
|
|
1398
1392
|
}
|
|
1399
1393
|
function shouldSkipReleaseInstall() {
|
|
1400
|
-
return process.env.
|
|
1394
|
+
return process.env.TREESEED_SAVE_NPM_INSTALL_MODE === "skip";
|
|
1401
1395
|
}
|
|
1402
1396
|
function runReleaseNpmInstall(repoDir, options = {}) {
|
|
1403
1397
|
if (shouldSkipReleaseInstall()) {
|
|
1404
|
-
return { status: "skipped", reason: "
|
|
1398
|
+
return { status: "skipped", reason: "disabled" };
|
|
1405
1399
|
}
|
|
1406
1400
|
const args = repoDir === options.workspaceRoot ? ["install", "--package-lock-only", "--ignore-scripts"] : ["install", "--package-lock-only", "--ignore-scripts", "--workspaces=false"];
|
|
1407
1401
|
run("npm", args, { cwd: repoDir });
|
|
@@ -1590,8 +1584,8 @@ function collectReleasePlanBlockers(session, mode, selectedPackageNames) {
|
|
|
1590
1584
|
}
|
|
1591
1585
|
return blockers;
|
|
1592
1586
|
}
|
|
1593
|
-
function assertReleaseGitHubAutomationReady(root, selectedPackageNames) {
|
|
1594
|
-
if (
|
|
1587
|
+
function assertReleaseGitHubAutomationReady(root, selectedPackageNames, ciMode) {
|
|
1588
|
+
if (ciMode === "off") {
|
|
1595
1589
|
return;
|
|
1596
1590
|
}
|
|
1597
1591
|
assertHostedGitHubWorkflowAuthReady("release", root);
|
|
@@ -3494,7 +3488,10 @@ async function workflowRelease(helpers, input) {
|
|
|
3494
3488
|
const freshPreparation = freshRelease && executionMode === "execute" ? prepareFreshReleaseRun(root, session.branchName, rootRepo, packageReports) : { archived: [], blockers: [] };
|
|
3495
3489
|
const autoResumeRun = executionMode === "execute" && !explicitResumeRunId && !freshRelease ? findAutoResumableReleaseRun(root, session.branchName, rootRepo, packageReports) : null;
|
|
3496
3490
|
const planAutoResumeRun = executionMode === "plan" && input.fresh !== true ? findAutoResumableReleaseRun(root, session.branchName, rootRepo, packageReports) : null;
|
|
3497
|
-
const effectiveInput = autoResumeRun ?
|
|
3491
|
+
const effectiveInput = autoResumeRun ? {
|
|
3492
|
+
...autoResumeRun.input,
|
|
3493
|
+
ciMode: input.ciMode ?? autoResumeRun.input.ciMode
|
|
3494
|
+
} : input;
|
|
3498
3495
|
const level = effectiveInput.bump ?? "patch";
|
|
3499
3496
|
const ciMode = normalizeCiMode(effectiveInput.ciMode, "release");
|
|
3500
3497
|
const isResume = Boolean(explicitResumeRunId || autoResumeRun);
|
|
@@ -3584,7 +3581,7 @@ async function workflowRelease(helpers, input) {
|
|
|
3584
3581
|
const effectiveVersions = releasePlanVersionMap(releasePlan.plannedVersions);
|
|
3585
3582
|
const rootVersion = String(releasePlan.rootVersion);
|
|
3586
3583
|
applyTreeseedEnvironmentToProcess({ tenantRoot: root, scope: "staging", override: true });
|
|
3587
|
-
assertReleaseGitHubAutomationReady(root, effectiveSelectedPackageNames);
|
|
3584
|
+
assertReleaseGitHubAutomationReady(root, effectiveSelectedPackageNames, ciMode);
|
|
3588
3585
|
const releaseCandidate = await executeJournalStep(root, workflowRun.runId, "release-candidate", () => runReleaseCandidateForPlan("release", root, releasePlan, { allowReuse: true }));
|
|
3589
3586
|
if (!isResume) {
|
|
3590
3587
|
assertSessionBranchSafety("release", session, { requireCleanPackages: true, requireCurrentBranch: true });
|