@treeseed/sdk 0.6.0 → 0.6.2
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/bootstrap-runner.d.ts +33 -0
- package/dist/operations/services/bootstrap-runner.js +136 -0
- package/dist/operations/services/config-runtime.d.ts +27 -8
- package/dist/operations/services/config-runtime.js +297 -124
- package/dist/operations/services/github-api.d.ts +33 -0
- package/dist/operations/services/github-api.js +118 -4
- package/dist/operations/services/github-automation.d.ts +30 -0
- package/dist/operations/services/github-automation.js +107 -1
- package/dist/operations/services/project-platform.d.ts +38 -2
- package/dist/operations/services/project-platform.js +281 -9
- package/dist/operations/services/railway-deploy.d.ts +6 -2
- package/dist/operations/services/railway-deploy.js +26 -18
- package/dist/operations/services/runtime-tools.d.ts +0 -2
- package/dist/operations/services/runtime-tools.js +0 -2
- package/dist/platform/env.yaml +68 -96
- package/dist/platform/environment.js +51 -0
- package/dist/reconcile/bootstrap-systems.d.ts +32 -0
- package/dist/reconcile/bootstrap-systems.js +175 -0
- package/dist/reconcile/builtin-adapters.js +24 -9
- package/dist/reconcile/desired-state.js +16 -14
- package/dist/reconcile/engine.d.ts +9 -4
- package/dist/reconcile/engine.js +57 -14
- package/dist/reconcile/index.d.ts +1 -0
- package/dist/reconcile/index.js +1 -0
- package/dist/scripts/config-treeseed.js +30 -0
- package/dist/scripts/package-tools.js +0 -2
- package/dist/scripts/tenant-deploy.js +16 -36
- package/dist/scripts/test-cloudflare-local.js +0 -2
- package/dist/workflow/operations.js +23 -4
- package/dist/workflow.d.ts +5 -0
- package/package.json +1 -1
- package/templates/github/deploy.workflow.yml +15 -15
|
@@ -3,9 +3,10 @@ import { spawnSync } from 'node:child_process';
|
|
|
3
3
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
5
|
import { applyTreeseedEnvironmentToProcess } from '../operations/services/config-runtime.js';
|
|
6
|
-
import {
|
|
6
|
+
import { createBranchPreviewDeployTarget, createPersistentDeployTarget, deployTargetLabel, finalizeDeploymentState, } from '../operations/services/deploy.js';
|
|
7
|
+
import { prepareTenantCloudflareDeploy, runTenantDataMigration, runTenantWebBuild, runTenantWebPublish, } from '../operations/services/project-platform.js';
|
|
7
8
|
import { currentManagedBranch, PRODUCTION_BRANCH, STAGING_BRANCH } from '../operations/services/git-workflow.js';
|
|
8
|
-
import {
|
|
9
|
+
import { resolveWranglerBin } from '../operations/services/runtime-tools.js';
|
|
9
10
|
import { runTenantDeployPreflight } from '../operations/services/save-deploy-preflight.js';
|
|
10
11
|
const tenantRoot = process.cwd();
|
|
11
12
|
const args = process.argv.slice(2);
|
|
@@ -165,14 +166,20 @@ async function main() {
|
|
|
165
166
|
}
|
|
166
167
|
if (scope === 'local') {
|
|
167
168
|
runTenantDeployPreflight({ cwd: tenantRoot, scope: 'local' });
|
|
168
|
-
|
|
169
|
+
await runTenantWebBuild({ tenantRoot, scope: 'local', dryRun: options.dryRun, env: process.env });
|
|
169
170
|
writeDeployReport({ ok: true, kind: 'success', scope, dryRun: options.dryRun, target: deployTargetLabel(target) });
|
|
170
171
|
console.log('Treeseed local deploy completed as a build-only publish target.');
|
|
171
172
|
return;
|
|
172
173
|
}
|
|
174
|
+
let context;
|
|
173
175
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
context = prepareTenantCloudflareDeploy({
|
|
177
|
+
tenantRoot,
|
|
178
|
+
scope,
|
|
179
|
+
target,
|
|
180
|
+
dryRun: options.dryRun,
|
|
181
|
+
env: process.env,
|
|
182
|
+
});
|
|
176
183
|
}
|
|
177
184
|
catch (error) {
|
|
178
185
|
writeDeployReport({
|
|
@@ -183,43 +190,16 @@ async function main() {
|
|
|
183
190
|
});
|
|
184
191
|
throw error;
|
|
185
192
|
}
|
|
186
|
-
const { wranglerPath } = ensureGeneratedWranglerConfig(tenantRoot, { target });
|
|
187
|
-
const deployConfig = loadCliDeployConfig(tenantRoot);
|
|
188
|
-
const deployState = loadDeployState(tenantRoot, deployConfig, { target });
|
|
189
|
-
const pagesProjectName = target.kind === 'persistent' ? deployState.pages?.projectName ?? null : null;
|
|
190
|
-
const pagesBranchName = target.kind === 'persistent'
|
|
191
|
-
? (target.scope === 'prod'
|
|
192
|
-
? deployState.pages?.productionBranch ?? 'main'
|
|
193
|
-
: deployState.pages?.stagingBranch ?? 'staging')
|
|
194
|
-
: null;
|
|
195
193
|
if (shouldRun('migrate')) {
|
|
196
|
-
const result =
|
|
194
|
+
const result = await runTenantDataMigration(context);
|
|
197
195
|
console.log(`${options.dryRun ? 'Planned' : 'Applied'} remote migrations for ${result.databaseName}.`);
|
|
198
196
|
}
|
|
199
197
|
if (shouldRun('build')) {
|
|
200
|
-
|
|
201
|
-
console.log('Dry run: skipped tenant build.');
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
runNodeScript(packageScriptPath('tenant-build'));
|
|
205
|
-
}
|
|
198
|
+
await runTenantWebBuild(context);
|
|
206
199
|
}
|
|
207
200
|
if (shouldRun('publish')) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.log(`Dry run: would deploy ${deployTargetLabel(target)} to Pages project ${pagesProjectName} from ${resolve(tenantRoot, 'dist')}.`);
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
console.log(`Dry run: would deploy ${deployTargetLabel(target)} with generated Wrangler config at ${resolve(wranglerPath)}.`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
if (pagesProjectName) {
|
|
218
|
-
runWranglerPagesDeploy(pagesProjectName, pagesBranchName, resolve(tenantRoot, 'dist'));
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
runWranglerDeploy(wranglerPath);
|
|
222
|
-
}
|
|
201
|
+
await runTenantWebPublish(context);
|
|
202
|
+
if (!options.dryRun) {
|
|
223
203
|
finalizeDeploymentState(tenantRoot, { target });
|
|
224
204
|
}
|
|
225
205
|
}
|
|
@@ -136,8 +136,6 @@ async function main() {
|
|
|
136
136
|
persistTo: PERSIST_TO,
|
|
137
137
|
envOverrides: {
|
|
138
138
|
TREESEED_LOCAL_DEV_MODE: 'cloudflare',
|
|
139
|
-
TREESEED_FORMS_LOCAL_BYPASS_TURNSTILE: 'true',
|
|
140
|
-
TREESEED_PUBLIC_FORMS_LOCAL_BYPASS_TURNSTILE: 'true',
|
|
141
139
|
TREESEED_FORMS_LOCAL_BYPASS_CLOUDFLARE_GUARDS: 'false',
|
|
142
140
|
TREESEED_FORMS_LOCAL_USE_MAILPIT: 'true',
|
|
143
141
|
TREESEED_MAILPIT_SMTP_HOST: '127.0.0.1',
|
|
@@ -89,7 +89,7 @@ import {
|
|
|
89
89
|
workspaceRoot
|
|
90
90
|
} from "../operations/services/workspace-tools.js";
|
|
91
91
|
import { resolveTreeseedWorkflowState } from "../workflow-state.js";
|
|
92
|
-
import { createTreeseedReconcileRegistry, deriveTreeseedDesiredUnits, planTreeseedReconciliation, reconcileTreeseedTarget } from "../reconcile/index.js";
|
|
92
|
+
import { createTreeseedReconcileRegistry, deriveTreeseedDesiredUnits, filterTreeseedDesiredUnitsByBootstrapSystems, planTreeseedReconciliation, resolveTreeseedBootstrapSelection, reconcileTreeseedTarget } from "../reconcile/index.js";
|
|
93
93
|
import {
|
|
94
94
|
acquireWorkflowLock,
|
|
95
95
|
createWorkflowRunJournal,
|
|
@@ -1031,6 +1031,9 @@ async function workflowConfig(helpers, input = {}) {
|
|
|
1031
1031
|
const bootstrapOnly = input.bootstrap === true;
|
|
1032
1032
|
const bootstrapPreflight = bootstrapOnly && input.preflight === true;
|
|
1033
1033
|
const nonInteractive = input.nonInteractive === true;
|
|
1034
|
+
const bootstrapSystemsInput = input.systems;
|
|
1035
|
+
const skipUnavailable = input.skipUnavailable;
|
|
1036
|
+
const bootstrapExecution = input.bootstrapExecution ?? "parallel";
|
|
1034
1037
|
const repairs = input.repair === false ? [] : resolveTreeseedWorkflowState(tenantRoot).deployConfigPresent ? applyTreeseedSafeRepairs(tenantRoot) : [];
|
|
1035
1038
|
const toolHealth = ensureTreeseedActVerificationTooling({
|
|
1036
1039
|
tenantRoot,
|
|
@@ -1143,8 +1146,18 @@ async function workflowConfig(helpers, input = {}) {
|
|
|
1143
1146
|
maybePrint(helpers.write, `Deriving desired units for ${scope}...`);
|
|
1144
1147
|
const target = createPersistentDeployTarget(scope);
|
|
1145
1148
|
const derived = deriveTreeseedDesiredUnits({ tenantRoot, target });
|
|
1149
|
+
const selection = resolveTreeseedBootstrapSelection({
|
|
1150
|
+
deployConfig: derived.deployConfig,
|
|
1151
|
+
env: contextSnapshot.valuesByScope[scope] ?? helpers.context.env ?? process.env,
|
|
1152
|
+
systems: bootstrapSystemsInput,
|
|
1153
|
+
skipUnavailable
|
|
1154
|
+
});
|
|
1155
|
+
const selectedUnits = filterTreeseedDesiredUnitsByBootstrapSystems(
|
|
1156
|
+
derived.units,
|
|
1157
|
+
selection.runnable.filter((system) => system !== "github")
|
|
1158
|
+
);
|
|
1146
1159
|
const registry = createTreeseedReconcileRegistry(derived.deployConfig);
|
|
1147
|
-
const capabilityMatrix =
|
|
1160
|
+
const capabilityMatrix = selectedUnits.map((unit) => {
|
|
1148
1161
|
const adapter = registry.get(unit.unitType, unit.provider);
|
|
1149
1162
|
return {
|
|
1150
1163
|
unitId: unit.unitId,
|
|
@@ -1170,10 +1183,12 @@ async function workflowConfig(helpers, input = {}) {
|
|
|
1170
1183
|
tenantRoot,
|
|
1171
1184
|
target,
|
|
1172
1185
|
env: helpers.context.env,
|
|
1186
|
+
systems: selection.runnable.filter((system) => system !== "github"),
|
|
1173
1187
|
write: (line) => maybePrint(helpers.write, line)
|
|
1174
1188
|
});
|
|
1175
1189
|
return {
|
|
1176
1190
|
scope,
|
|
1191
|
+
bootstrapSystems: selection,
|
|
1177
1192
|
resourceInventory: buildProvisioningSummary(derived.deployConfig, loadDeployState(tenantRoot, derived.deployConfig, { target }), target),
|
|
1178
1193
|
capabilityMatrix: await Promise.all(capabilityMatrix.map(async (entry) => ({
|
|
1179
1194
|
...entry,
|
|
@@ -1204,7 +1219,8 @@ async function workflowConfig(helpers, input = {}) {
|
|
|
1204
1219
|
secretSession,
|
|
1205
1220
|
context: contextSnapshot,
|
|
1206
1221
|
resourceInventoryByScope: Object.fromEntries(plansByScope.map((entry) => [entry.scope, entry.resourceInventory])),
|
|
1207
|
-
verificationPreflight: plansByScope
|
|
1222
|
+
verificationPreflight: plansByScope,
|
|
1223
|
+
bootstrapSystemsByScope: Object.fromEntries(plansByScope.map((entry) => [entry.scope, entry.bootstrapSystems]))
|
|
1208
1224
|
},
|
|
1209
1225
|
{
|
|
1210
1226
|
nextSteps: createNextSteps([
|
|
@@ -1250,7 +1266,10 @@ async function workflowConfig(helpers, input = {}) {
|
|
|
1250
1266
|
sync,
|
|
1251
1267
|
env: helpers.context.env,
|
|
1252
1268
|
checkConnections: bootstrapOnly || sync !== "none" || scopes.some((scope) => scope !== "local"),
|
|
1253
|
-
|
|
1269
|
+
systems: bootstrapSystemsInput,
|
|
1270
|
+
skipUnavailable,
|
|
1271
|
+
bootstrapExecution,
|
|
1272
|
+
onProgress: (line, stream) => maybePrint(helpers.write, line, stream)
|
|
1254
1273
|
});
|
|
1255
1274
|
const refreshedContext = collectTreeseedConfigContext({
|
|
1256
1275
|
tenantRoot,
|
package/dist/workflow.d.ts
CHANGED
|
@@ -126,9 +126,14 @@ export type TreeseedSwitchInput = {
|
|
|
126
126
|
dryRun?: boolean;
|
|
127
127
|
};
|
|
128
128
|
export type TreeseedConfigScope = 'all' | 'local' | 'staging' | 'prod';
|
|
129
|
+
export type TreeseedBootstrapSystem = 'all' | 'github' | 'data' | 'web' | 'api' | 'agents';
|
|
130
|
+
export type TreeseedBootstrapExecution = 'parallel' | 'sequential';
|
|
129
131
|
export type TreeseedConfigInput = {
|
|
130
132
|
target?: TreeseedConfigScope[] | TreeseedConfigScope;
|
|
131
133
|
environment?: TreeseedConfigScope[] | TreeseedConfigScope;
|
|
134
|
+
systems?: TreeseedBootstrapSystem[] | TreeseedBootstrapSystem;
|
|
135
|
+
skipUnavailable?: boolean;
|
|
136
|
+
bootstrapExecution?: TreeseedBootstrapExecution;
|
|
132
137
|
syncProviders?: 'none' | 'github' | 'cloudflare' | 'railway' | 'all';
|
|
133
138
|
sync?: 'none' | 'github' | 'cloudflare' | 'railway' | 'all';
|
|
134
139
|
bootstrap?: boolean;
|
package/package.json
CHANGED
|
@@ -188,12 +188,12 @@ __WORKING_DIRECTORY_BLOCK__
|
|
|
188
188
|
TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
|
|
189
189
|
TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
|
|
190
190
|
TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
|
|
191
|
-
TREESEED_SMTP_HOST: ${{
|
|
192
|
-
TREESEED_SMTP_PORT: ${{
|
|
193
|
-
TREESEED_SMTP_USERNAME: ${{
|
|
191
|
+
TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
|
|
192
|
+
TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
|
|
193
|
+
TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
|
|
194
194
|
TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
|
|
195
|
-
TREESEED_SMTP_FROM: ${{
|
|
196
|
-
TREESEED_SMTP_REPLY_TO: ${{
|
|
195
|
+
TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
|
|
196
|
+
TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
|
|
197
197
|
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
|
|
198
198
|
TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
|
|
199
199
|
TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
@@ -262,12 +262,12 @@ __WORKING_DIRECTORY_BLOCK__
|
|
|
262
262
|
TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
|
|
263
263
|
TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
|
|
264
264
|
TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
|
|
265
|
-
TREESEED_SMTP_HOST: ${{
|
|
266
|
-
TREESEED_SMTP_PORT: ${{
|
|
267
|
-
TREESEED_SMTP_USERNAME: ${{
|
|
265
|
+
TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
|
|
266
|
+
TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
|
|
267
|
+
TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
|
|
268
268
|
TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
|
|
269
|
-
TREESEED_SMTP_FROM: ${{
|
|
270
|
-
TREESEED_SMTP_REPLY_TO: ${{
|
|
269
|
+
TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
|
|
270
|
+
TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
|
|
271
271
|
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
|
|
272
272
|
TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
|
|
273
273
|
TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|
|
@@ -347,12 +347,12 @@ __WORKING_DIRECTORY_BLOCK__
|
|
|
347
347
|
TREESEED_EDITORIAL_PREVIEW_SECRET: ${{ secrets.TREESEED_EDITORIAL_PREVIEW_SECRET }}
|
|
348
348
|
TREESEED_PUBLIC_TURNSTILE_SITE_KEY: ${{ vars.TREESEED_PUBLIC_TURNSTILE_SITE_KEY }}
|
|
349
349
|
TREESEED_TURNSTILE_SECRET_KEY: ${{ secrets.TREESEED_TURNSTILE_SECRET_KEY }}
|
|
350
|
-
TREESEED_SMTP_HOST: ${{
|
|
351
|
-
TREESEED_SMTP_PORT: ${{
|
|
352
|
-
TREESEED_SMTP_USERNAME: ${{
|
|
350
|
+
TREESEED_SMTP_HOST: ${{ vars.TREESEED_SMTP_HOST }}
|
|
351
|
+
TREESEED_SMTP_PORT: ${{ vars.TREESEED_SMTP_PORT }}
|
|
352
|
+
TREESEED_SMTP_USERNAME: ${{ vars.TREESEED_SMTP_USERNAME }}
|
|
353
353
|
TREESEED_SMTP_PASSWORD: ${{ secrets.TREESEED_SMTP_PASSWORD }}
|
|
354
|
-
TREESEED_SMTP_FROM: ${{
|
|
355
|
-
TREESEED_SMTP_REPLY_TO: ${{
|
|
354
|
+
TREESEED_SMTP_FROM: ${{ vars.TREESEED_SMTP_FROM }}
|
|
355
|
+
TREESEED_SMTP_REPLY_TO: ${{ vars.TREESEED_SMTP_REPLY_TO }}
|
|
356
356
|
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
|
|
357
357
|
TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
|
|
358
358
|
TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
|