@astrale-os/sdk 0.6.0-beta.13 → 0.6.0-beta.15
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/README.md +4 -0
- package/dist/deployment/adapter/adapter.d.ts +9 -11
- package/dist/deployment/adapter/legacy/adapter.d.ts +0 -10
- package/dist/deployment/adapter/legacy/deploy/context.d.ts +0 -2
- package/dist/deployment/adapter/legacy/deploy/result.d.ts +2 -3
- package/dist/deployment/adapter/legacy/index.d.ts +12 -12
- package/dist/deployment/adapter/legacy/prepare/context.d.ts +0 -2
- package/dist/deployment/adapter/release/context.d.ts +23 -3
- package/dist/deployment/adapter/release/index.d.ts +1 -0
- package/dist/deployment/adapter/release/list.d.ts +41 -0
- package/dist/deployment/adapter/release/list.js +1 -0
- package/dist/deployment/address/index.d.ts +1 -1
- package/dist/deployment/address/index.js +1 -0
- package/dist/deployment/address/summary.d.ts +31 -1
- package/dist/deployment/address/summary.js +117 -1
- package/dist/deployment/build/index.d.ts +1 -1
- package/dist/deployment/build/index.js +1 -1
- package/dist/deployment/build/manifest.d.ts +5 -0
- package/dist/deployment/build/manifest.js +10 -0
- package/dist/deployment/index.d.ts +1 -1
- package/dist/deployment/release/legacy/index.d.ts +17 -12
- package/dist/deployment/release/legacy/index.js +17 -12
- package/dist/deployment/verify/readiness/deployment.js +3 -13
- package/dist/deployment/verify/readiness/fetch.d.ts +13 -0
- package/dist/deployment/verify/readiness/fetch.js +26 -0
- package/dist/deployment/verify/readiness/identity.d.ts +3 -6
- package/dist/deployment/verify/readiness/identity.js +3 -3
- package/dist/deployment/verify/readiness/index.d.ts +12 -8
- package/dist/deployment/verify/readiness/index.js +15 -4
- package/dist/deployment/verify/readiness/legacy/index.d.ts +2 -0
- package/dist/deployment/verify/readiness/legacy/index.js +2 -0
- package/dist/deployment/verify/readiness/legacy/publication.d.ts +12 -0
- package/dist/deployment/verify/readiness/legacy/publication.js +23 -0
- package/dist/deployment/verify/readiness/release.d.ts +8 -0
- package/dist/deployment/verify/readiness/release.js +22 -0
- package/dist/execution/identity/authentication.d.ts +14 -3
- package/dist/execution/identity/authentication.js +16 -7
- package/dist/execution/identity/callback.d.ts +5 -2
- package/dist/execution/identity/callback.js +11 -5
- package/dist/execution/identity/delivery.d.ts +11 -4
- package/dist/execution/identity/delivery.js +47 -20
- package/dist/execution/identity/identity.d.ts +12 -6
- package/dist/execution/identity/identity.js +3 -3
- package/dist/execution/invocation/admission/authentication.d.ts +1 -2
- package/dist/execution/invocation/admission/authentication.js +1 -2
- package/dist/execution/invocation/admission/authority.d.ts +10 -4
- package/dist/execution/invocation/admission/authority.js +5 -1
- package/dist/execution/invocation/invocation.js +51 -14
- package/dist/execution/runtime/index.d.ts +1 -0
- package/dist/execution/runtime/index.js +1 -0
- package/dist/execution/runtime/load.d.ts +3 -3
- package/dist/execution/runtime/load.js +3 -2
- package/dist/execution/runtime/release.d.ts +22 -0
- package/dist/execution/runtime/release.js +14 -0
- package/dist/execution/serve.d.ts +2 -2
- package/dist/execution/service/create.js +9 -7
- package/dist/execution/service/release.d.ts +2 -2
- package/dist/execution/service/release.js +3 -2
- package/dist/execution/service/service.d.ts +9 -5
- package/dist/execution/service/serving/delivery.d.ts +6 -0
- package/dist/execution/service/{publication → serving}/delivery.js +5 -1
- package/dist/execution/service/{publication → serving}/index.d.ts +1 -1
- package/dist/execution/service/serving/installation.d.ts +4 -0
- package/dist/execution/service/serving/installation.js +9 -0
- package/dist/execution/service/serving/legacy/index.d.ts +15 -0
- package/dist/execution/service/serving/legacy/index.js +19 -0
- package/dist/execution/service/serving/source.d.ts +18 -0
- package/dist/execution/service/serving/source.js +19 -0
- package/dist/execution/workflows/run.js +1 -1
- package/dist/platform/versioning/name.d.ts +4 -3
- package/dist/platform/versioning/name.js +4 -3
- package/dist/project/define.js +58 -28
- package/dist/project/install-command.d.ts +10 -0
- package/dist/project/install-command.js +13 -0
- package/dist/project/project.d.ts +4 -2
- package/dist/tooling/cli/arguments.d.ts +1 -3
- package/dist/tooling/cli/arguments.js +51 -22
- package/dist/tooling/cli/commit.d.ts +23 -0
- package/dist/tooling/cli/commit.js +216 -0
- package/dist/tooling/cli/deploy-mode.d.ts +16 -13
- package/dist/tooling/cli/deploy-mode.js +45 -36
- package/dist/tooling/cli/deploy-result.d.ts +10 -7
- package/dist/tooling/cli/deploy-result.js +4 -3
- package/dist/tooling/cli/dotenv.d.ts +2 -2
- package/dist/tooling/cli/dotenv.js +3 -33
- package/dist/tooling/cli/help.js +73 -29
- package/dist/tooling/cli/immutable-deployment.d.ts +27 -0
- package/dist/tooling/cli/immutable-deployment.js +95 -0
- package/dist/tooling/cli/index.d.ts +3 -4
- package/dist/tooling/cli/index.js +2 -3
- package/dist/tooling/cli/legacy/deploy-result.d.ts +5 -3
- package/dist/tooling/cli/legacy/deploy-result.js +5 -3
- package/dist/tooling/cli/{development → legacy/development}/candidate.d.ts +3 -4
- package/dist/tooling/cli/{development → legacy/development}/candidate.js +7 -14
- package/dist/tooling/cli/legacy/development/deployment.d.ts +10 -0
- package/dist/tooling/cli/legacy/development/deployment.js +20 -0
- package/dist/tooling/cli/legacy/development/deprecation.d.ts +11 -0
- package/dist/tooling/cli/legacy/development/deprecation.js +13 -0
- package/dist/tooling/cli/legacy/development/develop.d.ts +15 -0
- package/dist/tooling/cli/legacy/development/develop.js +142 -0
- package/dist/tooling/cli/legacy/development/index.d.ts +21 -0
- package/dist/tooling/cli/legacy/development/index.js +21 -0
- package/dist/tooling/cli/legacy/development/report.d.ts +7 -0
- package/dist/tooling/cli/{development → legacy/development}/report.js +2 -5
- package/dist/tooling/cli/legacy/development/secrets-file.d.ts +2 -0
- package/dist/tooling/cli/legacy/development/secrets-file.js +33 -0
- package/dist/tooling/cli/legacy/stable-target-adapter.d.ts +5 -3
- package/dist/tooling/cli/legacy/stable-target-deploy.d.ts +40 -0
- package/dist/tooling/cli/legacy/stable-target-deploy.js +102 -0
- package/dist/tooling/cli/list.d.ts +114 -0
- package/dist/tooling/cli/list.js +297 -0
- package/dist/tooling/cli/orchestrate.d.ts +1 -1
- package/dist/tooling/cli/orchestrate.js +91 -95
- package/dist/tooling/cli/secrets.d.ts +9 -0
- package/dist/tooling/cli/secrets.js +19 -0
- package/package.json +7 -7
- package/dist/deployment/verify/readiness/publication.d.ts +0 -11
- package/dist/deployment/verify/readiness/publication.js +0 -41
- package/dist/execution/service/publication/delivery.d.ts +0 -2
- package/dist/execution/service/publication/installation.d.ts +0 -3
- package/dist/execution/service/publication/installation.js +0 -8
- package/dist/execution/service/publication/source.d.ts +0 -3
- package/dist/execution/service/publication/source.js +0 -11
- package/dist/tooling/cli/astrale/authority.d.ts +0 -5
- package/dist/tooling/cli/astrale/authority.js +0 -11
- package/dist/tooling/cli/astrale/executable.d.ts +0 -2
- package/dist/tooling/cli/astrale/executable.js +0 -47
- package/dist/tooling/cli/astrale/failure.d.ts +0 -6
- package/dist/tooling/cli/astrale/failure.js +0 -48
- package/dist/tooling/cli/astrale/instance.d.ts +0 -11
- package/dist/tooling/cli/astrale/instance.js +0 -52
- package/dist/tooling/cli/astrale/process.d.ts +0 -13
- package/dist/tooling/cli/astrale/process.js +0 -94
- package/dist/tooling/cli/astrale/version.d.ts +0 -18
- package/dist/tooling/cli/astrale/version.js +0 -55
- package/dist/tooling/cli/development/deployment.d.ts +0 -16
- package/dist/tooling/cli/development/deployment.js +0 -39
- package/dist/tooling/cli/development/develop.d.ts +0 -11
- package/dist/tooling/cli/development/develop.js +0 -243
- package/dist/tooling/cli/development/release-evidence.d.ts +0 -4
- package/dist/tooling/cli/development/release-evidence.js +0 -10
- package/dist/tooling/cli/development/report.d.ts +0 -9
- package/dist/tooling/cli/development/session-file.d.ts +0 -53
- package/dist/tooling/cli/development/session-file.js +0 -337
- package/dist/tooling/cli/development/target-lock.d.ts +0 -16
- package/dist/tooling/cli/development/target-lock.js +0 -68
- package/dist/tooling/cli/development/view.d.ts +0 -28
- package/dist/tooling/cli/development/view.js +0 -151
- package/dist/tooling/cli/environment-release.d.ts +0 -24
- package/dist/tooling/cli/environment-release.js +0 -46
- package/dist/tooling/cli/evidence.d.ts +0 -14
- package/dist/tooling/cli/evidence.js +0 -53
- package/dist/tooling/cli/installation/index.d.ts +0 -2
- package/dist/tooling/cli/installation/index.js +0 -1
- package/dist/tooling/cli/installation/observation.d.ts +0 -10
- package/dist/tooling/cli/installation/observation.js +0 -44
- package/dist/tooling/cli/installation/reconcile.d.ts +0 -32
- package/dist/tooling/cli/installation/reconcile.js +0 -122
- /package/dist/execution/service/{publication → serving}/index.js +0 -0
- /package/dist/tooling/cli/{credential.d.ts → legacy/development/credential.d.ts} +0 -0
- /package/dist/tooling/cli/{credential.js → legacy/development/credential.js} +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/lease.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/lease.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/lifecycle.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/lifecycle.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/project-imports.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/project-imports.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/project-lock.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/project-lock.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/rebuild.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/rebuild.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/source-watch.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/source-watch.js +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/sources.d.ts +0 -0
- /package/dist/tooling/cli/{development → legacy/development}/sources.js +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command that installs a deployed URL on an instance, as every SDK refusal and help text
|
|
3
|
+
* names it. A deploy never installs (DX [.81399], AM-72): `astrale-domain deploy <environment>`
|
|
4
|
+
* prints a URL, and this command installs it.
|
|
5
|
+
*
|
|
6
|
+
* `--direct` sends a URL install to the instance Kernel, which the astrale CLI requires today and
|
|
7
|
+
* accepts until D13. When the CLI retires it, this is the one SDK text to change; the adapter and
|
|
8
|
+
* scaffold READMEs and templates repeat it as prose.
|
|
9
|
+
*/
|
|
10
|
+
export declare function installCommand(instance?: string, identity?: string): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command that installs a deployed URL on an instance, as every SDK refusal and help text
|
|
3
|
+
* names it. A deploy never installs (DX [.81399], AM-72): `astrale-domain deploy <environment>`
|
|
4
|
+
* prints a URL, and this command installs it.
|
|
5
|
+
*
|
|
6
|
+
* `--direct` sends a URL install to the instance Kernel, which the astrale CLI requires today and
|
|
7
|
+
* accepts until D13. When the CLI retires it, this is the one SDK text to change; the adapter and
|
|
8
|
+
* scaffold READMEs and templates repeat it as prose.
|
|
9
|
+
*/
|
|
10
|
+
export function installCommand(instance = '<instance>', identity) {
|
|
11
|
+
return (`astrale domain install <url> --direct -i ${instance}` +
|
|
12
|
+
(identity === undefined ? '' : ` --as ${identity}`));
|
|
13
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { DomainDefinitionIdentity } from '../application/index.js';
|
|
2
|
-
import type { InstallationTarget } from '../deployment/adapter/index.js';
|
|
3
2
|
import type { Tests } from '../testing/index.js';
|
|
4
3
|
export interface ProjectEntrypoints {
|
|
5
4
|
readonly runtime: string;
|
|
6
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* One Environment of a Project: where and how its deployments are made. It never names an
|
|
8
|
+
* instance: a deploy installs nothing, and `astrale domain install <url>` installs a deployment.
|
|
9
|
+
*/
|
|
7
10
|
export interface ProjectEnvironment<DeploymentValue = unknown> {
|
|
8
11
|
readonly deployment: DeploymentValue;
|
|
9
|
-
readonly installation?: InstallationTarget;
|
|
10
12
|
}
|
|
11
13
|
/** The complete independently executable software-product definition in astrale.config.ts. */
|
|
12
14
|
export interface Project<DomainDefinitionValue extends DomainDefinitionIdentity = DomainDefinitionIdentity, EnvironmentsValue extends Readonly<Record<string, ProjectEnvironment>> = Readonly<Record<string, ProjectEnvironment>>, TestsValue extends Tests | undefined = undefined> {
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { LintReportFormat } from '../linter/index.js';
|
|
2
|
-
export declare const COMMANDS: readonly ['dev', 'build', 'deploy', 'test', 'lint', 'package', 'upgrade'];
|
|
2
|
+
export declare const COMMANDS: readonly ['dev', 'build', 'deploy', 'list', 'test', 'lint', 'package', 'upgrade'];
|
|
3
3
|
export type Command = (typeof COMMANDS)[number];
|
|
4
4
|
export interface ParsedArgs {
|
|
5
5
|
readonly command: Command;
|
|
6
6
|
readonly env: string;
|
|
7
7
|
readonly fix?: boolean;
|
|
8
8
|
readonly format?: LintReportFormat;
|
|
9
|
-
readonly deployOnly?: boolean;
|
|
10
9
|
readonly identity?: string;
|
|
11
10
|
readonly credentialFile?: string;
|
|
12
11
|
readonly suite?: string;
|
|
13
|
-
readonly sessionFile?: string;
|
|
14
12
|
readonly secretsFile?: string;
|
|
15
13
|
readonly channel?: string;
|
|
16
14
|
readonly check?: boolean;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { isAbsolute, normalize } from 'node:path';
|
|
2
|
-
|
|
2
|
+
import { installCommand } from '../../project/install-command.js';
|
|
3
|
+
export const COMMANDS = [
|
|
4
|
+
'dev',
|
|
5
|
+
'build',
|
|
6
|
+
'deploy',
|
|
7
|
+
'list',
|
|
8
|
+
'test',
|
|
9
|
+
'lint',
|
|
10
|
+
'package',
|
|
11
|
+
'upgrade',
|
|
12
|
+
];
|
|
3
13
|
/** Parse the frozen `astrale-domain` command grammar without performing effects. */
|
|
4
14
|
export function parseArgs(argv) {
|
|
5
15
|
const [command, ...rest] = argv;
|
|
@@ -8,7 +18,6 @@ export function parseArgs(argv) {
|
|
|
8
18
|
const fix = rest.includes('--fix');
|
|
9
19
|
const deployOnly = rest.includes('--deploy-only');
|
|
10
20
|
const json = rest.includes('--json');
|
|
11
|
-
let sessionFile;
|
|
12
21
|
let secretsFile;
|
|
13
22
|
let credentialFile;
|
|
14
23
|
let identity;
|
|
@@ -18,13 +27,7 @@ export function parseArgs(argv) {
|
|
|
18
27
|
const cleaned = [];
|
|
19
28
|
for (let index = 0; index < rest.length; index += 1) {
|
|
20
29
|
const argument = rest[index];
|
|
21
|
-
if (argument === '--
|
|
22
|
-
sessionFile = absoluteFilePath('--session-file', rest[++index]);
|
|
23
|
-
}
|
|
24
|
-
else if (argument.startsWith('--session-file=')) {
|
|
25
|
-
sessionFile = absoluteFilePath('--session-file', argument.slice('--session-file='.length));
|
|
26
|
-
}
|
|
27
|
-
else if (argument === '--credential-file') {
|
|
30
|
+
if (argument === '--credential-file') {
|
|
28
31
|
credentialFile = absoluteFilePath('--credential-file', rest[++index]);
|
|
29
32
|
}
|
|
30
33
|
else if (argument.startsWith('--credential-file=')) {
|
|
@@ -72,26 +75,29 @@ export function parseArgs(argv) {
|
|
|
72
75
|
}
|
|
73
76
|
if (fix && command !== 'lint')
|
|
74
77
|
throw new Error('`--fix` is only valid for `lint`.');
|
|
75
|
-
if (json && command !== 'build' && command !== 'deploy') {
|
|
76
|
-
throw new Error('`--json` is only valid for `build` or `
|
|
78
|
+
if (json && command !== 'build' && command !== 'deploy' && command !== 'list') {
|
|
79
|
+
throw new Error('`--json` is only valid for `build`, `deploy` or `list`.');
|
|
77
80
|
}
|
|
78
81
|
if (format !== undefined && command !== 'lint') {
|
|
79
82
|
throw new Error('`--format` is only valid for `lint`.');
|
|
80
83
|
}
|
|
81
|
-
if ((
|
|
82
|
-
|
|
83
|
-
throw new Error('`--session-file`, `--credential-file`, and `--secrets-file` are only valid for `dev`.');
|
|
84
|
+
if ((credentialFile !== undefined || secretsFile !== undefined) && command !== 'dev') {
|
|
85
|
+
throw new Error('`--credential-file` and `--secrets-file` are only valid for `dev`.');
|
|
84
86
|
}
|
|
85
87
|
if (identity !== undefined && credentialFile !== undefined) {
|
|
86
88
|
throw new Error('Choose either `--as` or `--credential-file`, not both.');
|
|
87
89
|
}
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
+
if (deployOnly && command !== 'dev' && command !== 'deploy')
|
|
91
|
+
refuseDeployOnly(undefined);
|
|
92
|
+
if (identity !== undefined && command !== 'dev' && command !== 'deploy' && command !== 'list') {
|
|
93
|
+
throw new Error('`--as` is only valid for `dev`, `deploy` or `list`.');
|
|
90
94
|
}
|
|
91
|
-
if (environment !== undefined &&
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
if (environment !== undefined &&
|
|
96
|
+
command !== 'dev' &&
|
|
97
|
+
command !== 'deploy' &&
|
|
98
|
+
command !== 'list' &&
|
|
99
|
+
command !== 'test') {
|
|
100
|
+
throw new Error('`--environment` is only valid for `dev`, `deploy`, `list` or `test`.');
|
|
95
101
|
}
|
|
96
102
|
if (suite !== undefined && command !== 'test') {
|
|
97
103
|
throw new Error('`--suite` is only valid for `test`.');
|
|
@@ -110,17 +116,28 @@ export function parseArgs(argv) {
|
|
|
110
116
|
if (!env) {
|
|
111
117
|
throw new Error(`\`${command}\` requires an Environment, e.g. \`${command} development\`.`);
|
|
112
118
|
}
|
|
119
|
+
if (deployOnly)
|
|
120
|
+
refuseDeployOnly(command, env);
|
|
113
121
|
return {
|
|
114
122
|
command,
|
|
115
123
|
env,
|
|
116
124
|
...(json ? { json: true } : {}),
|
|
117
|
-
...(deployOnly ? { deployOnly: true } : {}),
|
|
118
125
|
...(identity === undefined ? {} : { identity }),
|
|
119
126
|
...(credentialFile === undefined ? {} : { credentialFile }),
|
|
120
|
-
...(sessionFile === undefined ? {} : { sessionFile }),
|
|
121
127
|
...(secretsFile === undefined ? {} : { secretsFile }),
|
|
122
128
|
};
|
|
123
129
|
}
|
|
130
|
+
case 'list':
|
|
131
|
+
// Every Environment of the Project, or the one `--environment` names.
|
|
132
|
+
if (positionals.length > 0) {
|
|
133
|
+
throw new Error('`list` does not accept positional arguments; use `--environment`.');
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
command: 'list',
|
|
137
|
+
env: environment ?? '',
|
|
138
|
+
...(json ? { json: true } : {}),
|
|
139
|
+
...(identity === undefined ? {} : { identity }),
|
|
140
|
+
};
|
|
124
141
|
case 'build':
|
|
125
142
|
case 'package':
|
|
126
143
|
if (positionals.length > 0) {
|
|
@@ -149,6 +166,18 @@ export function parseArgs(argv) {
|
|
|
149
166
|
throw new Error(command ? `Unknown command "${command}".` : 'Missing command.');
|
|
150
167
|
}
|
|
151
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* `--deploy-only` suppressed the installation a deploy used to make. A deploy never installs
|
|
171
|
+
* (DX [.81399], AM-72), so the flag is refused before any effect, naming the commands that
|
|
172
|
+
* replace it. Its only consumer pins an SDK older than this refusal.
|
|
173
|
+
*/
|
|
174
|
+
function refuseDeployOnly(command, environment) {
|
|
175
|
+
const refusal = '`--deploy-only` is no longer accepted: a deploy never installs.';
|
|
176
|
+
if (command === undefined || environment === undefined)
|
|
177
|
+
throw new Error(refusal);
|
|
178
|
+
throw new Error(`${refusal} Run \`astrale-domain ${command} ${environment}\` without it, then install the ` +
|
|
179
|
+
`URL it prints with \`${installCommand()}\`.`);
|
|
180
|
+
}
|
|
152
181
|
function parseUpgrade(args) {
|
|
153
182
|
let channel = 'beta';
|
|
154
183
|
let check = false;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DeploymentCommitV1 } from '../../deployment/address/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The commit provenance a canonical deploy declares in its deployment record (CT18 `commit`): the
|
|
4
|
+
* commit of the repository the Project lives in, whether the working tree holds changes that
|
|
5
|
+
* commit does not, and the last release of the Domain before it, as `git describe` finds it.
|
|
6
|
+
*
|
|
7
|
+
* - `dirty` covers tracked changes and untracked files, over the whole working tree; ignored files
|
|
8
|
+
* never count. Unlike `git describe --dirty`, an untracked file counts, since a build can import
|
|
9
|
+
* it.
|
|
10
|
+
* - `base` is the nearest release tag of the package the Domain is released from: the
|
|
11
|
+
* release-please package that holds the Domain's runtime module (see {@link releaseTagPrefixes}).
|
|
12
|
+
* The tag prefix is stripped, and a tag whose rest is not a canonical SemVer version is left
|
|
13
|
+
* out, so the record never carries a base a deployment name would refuse (AM-57). A Domain no
|
|
14
|
+
* release line holds declares no base: it is never given another package's version.
|
|
15
|
+
* - Outside a git repository, without git, or in a repository whose commits are not SHA-1, the
|
|
16
|
+
* deploy declares no commit (`null`); a deploy never fails for want of provenance.
|
|
17
|
+
*/
|
|
18
|
+
export declare function deploymentCommit(input: {
|
|
19
|
+
readonly projectDir: string;
|
|
20
|
+
/** The Domain's runtime module, as the Project's `entrypoints.runtime` resolves it. */
|
|
21
|
+
readonly runtimeModule: string;
|
|
22
|
+
readonly signal: AbortSignal;
|
|
23
|
+
}): Promise<DeploymentCommitV1 | null>;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { isVersion } from '../../platform/versioning/version.js';
|
|
5
|
+
/** A commit as `DeploymentCommitV1` holds it: the full SHA-1 git prints, in lower case. */
|
|
6
|
+
const SHA = /^[0-9a-f]{40}$/u;
|
|
7
|
+
/** `git describe --long` output: `<tag>-<commits since the tag>-g<abbreviated commit>`. */
|
|
8
|
+
const DESCRIBED = /^(?<tag>.+)-(?<distance>\d+)-g[0-9a-f]+$/u;
|
|
9
|
+
/** A tag prefix this module can hand to `git describe --match` without escaping a glob. */
|
|
10
|
+
const LITERAL_PREFIX = /^[^*?[\]\\\s]*$/u;
|
|
11
|
+
/** The configuration files release-please reads at a repository root, the dotted name first. */
|
|
12
|
+
const RELEASE_PLEASE_CONFIGS = ['.release-please-config.json', 'release-please-config.json'];
|
|
13
|
+
const GIT_TIMEOUT_MS = 30_000;
|
|
14
|
+
/**
|
|
15
|
+
* The commit provenance a canonical deploy declares in its deployment record (CT18 `commit`): the
|
|
16
|
+
* commit of the repository the Project lives in, whether the working tree holds changes that
|
|
17
|
+
* commit does not, and the last release of the Domain before it, as `git describe` finds it.
|
|
18
|
+
*
|
|
19
|
+
* - `dirty` covers tracked changes and untracked files, over the whole working tree; ignored files
|
|
20
|
+
* never count. Unlike `git describe --dirty`, an untracked file counts, since a build can import
|
|
21
|
+
* it.
|
|
22
|
+
* - `base` is the nearest release tag of the package the Domain is released from: the
|
|
23
|
+
* release-please package that holds the Domain's runtime module (see {@link releaseTagPrefixes}).
|
|
24
|
+
* The tag prefix is stripped, and a tag whose rest is not a canonical SemVer version is left
|
|
25
|
+
* out, so the record never carries a base a deployment name would refuse (AM-57). A Domain no
|
|
26
|
+
* release line holds declares no base: it is never given another package's version.
|
|
27
|
+
* - Outside a git repository, without git, or in a repository whose commits are not SHA-1, the
|
|
28
|
+
* deploy declares no commit (`null`); a deploy never fails for want of provenance.
|
|
29
|
+
*/
|
|
30
|
+
export async function deploymentCommit(input) {
|
|
31
|
+
const head = await git(input.projectDir, input.signal, ['rev-parse', '--verify', 'HEAD']);
|
|
32
|
+
if (head === undefined || !SHA.test(head))
|
|
33
|
+
return null;
|
|
34
|
+
const status = await git(input.projectDir, input.signal, [
|
|
35
|
+
'status',
|
|
36
|
+
'--porcelain',
|
|
37
|
+
'--untracked-files=normal',
|
|
38
|
+
]);
|
|
39
|
+
if (status === undefined)
|
|
40
|
+
return null;
|
|
41
|
+
const prefixes = await releaseTagPrefixes(input);
|
|
42
|
+
const base = prefixes === undefined ? undefined : await describedBase(input, prefixes);
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
sha: head,
|
|
45
|
+
dirty: status.length > 0,
|
|
46
|
+
...(base === undefined ? {} : { base }),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The prefixes of the release tags of the package the Domain is released from, or nothing when
|
|
51
|
+
* no release line holds the Domain.
|
|
52
|
+
*
|
|
53
|
+
* In a repository with a release-please configuration at its root, that package is the configured
|
|
54
|
+
* package whose path is the nearest one holding the runtime module's directory, unless one of its
|
|
55
|
+
* `exclude-paths` holds it. Its tags are named as release-please names them: `<component>`, its
|
|
56
|
+
* `tag-separator` (`-`) and `v` before the version, without the component when
|
|
57
|
+
* `include-component-in-tag` is false and without the `v` when `include-v-in-tag` is false; the
|
|
58
|
+
* component is the package's `component`, else its unscoped `package-name`, else the unscoped name
|
|
59
|
+
* in its `package.json`. Root-level options are the packages' defaults, as in release-please.
|
|
60
|
+
*
|
|
61
|
+
* Without a configuration, the tags are those `npm version` writes (`v<version>`) and
|
|
62
|
+
* `<name>-v<version>`, where the name is the unscoped one in the Project's `package.json`.
|
|
63
|
+
*/
|
|
64
|
+
async function releaseTagPrefixes(input) {
|
|
65
|
+
const root = await git(input.projectDir, input.signal, ['rev-parse', '--show-toplevel']);
|
|
66
|
+
if (root === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
const config = await releasePleaseConfig(root);
|
|
69
|
+
if (config === undefined) {
|
|
70
|
+
const name = unscoped(await packageName(input.projectDir));
|
|
71
|
+
return literal(['v', ...(name === undefined ? [] : [`${name}-v`])]);
|
|
72
|
+
}
|
|
73
|
+
// Git names the module's directory relative to its repository, symbolic links resolved.
|
|
74
|
+
const located = await git(dirname(input.runtimeModule), input.signal, [
|
|
75
|
+
'rev-parse',
|
|
76
|
+
'--show-toplevel',
|
|
77
|
+
'--show-prefix',
|
|
78
|
+
]);
|
|
79
|
+
const [moduleRoot, prefix = ''] = located?.split('\n') ?? [];
|
|
80
|
+
if (moduleRoot !== root)
|
|
81
|
+
return undefined;
|
|
82
|
+
const path = prefix.replace(/\/$/u, '');
|
|
83
|
+
const found = releasePackage(config, path);
|
|
84
|
+
if (found === undefined)
|
|
85
|
+
return undefined;
|
|
86
|
+
const option = (key) => found.options[key] ?? config[key];
|
|
87
|
+
const v = option('include-v-in-tag') === false ? '' : 'v';
|
|
88
|
+
if (option('include-component-in-tag') === false)
|
|
89
|
+
return literal([v]);
|
|
90
|
+
const separator = option('tag-separator') ?? '-';
|
|
91
|
+
const component = option('component') ??
|
|
92
|
+
unscoped(option('package-name')) ??
|
|
93
|
+
unscoped(await packageName(join(root, found.path)));
|
|
94
|
+
if (typeof component !== 'string' || component.length === 0 || typeof separator !== 'string') {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return literal([`${component}${separator}${v}`]);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The configured package that holds `path` (relative to the repository root, `''` for the root),
|
|
101
|
+
* the nearest one first, or nothing when none holds it or its `exclude-paths` do.
|
|
102
|
+
*/
|
|
103
|
+
function releasePackage(config, path) {
|
|
104
|
+
const packages = config.packages;
|
|
105
|
+
if (packages === null || typeof packages !== 'object' || Array.isArray(packages))
|
|
106
|
+
return undefined;
|
|
107
|
+
let found;
|
|
108
|
+
for (const [key, options] of Object.entries(packages)) {
|
|
109
|
+
if (options === null || typeof options !== 'object' || Array.isArray(options))
|
|
110
|
+
continue;
|
|
111
|
+
const packagePath = key === '.' ? '' : key.replace(/^\.\//u, '').replace(/\/$/u, '');
|
|
112
|
+
if (!holds(packagePath, path))
|
|
113
|
+
continue;
|
|
114
|
+
if (found === undefined || packagePath.length > found.path.length) {
|
|
115
|
+
found = { path: packagePath, options: options };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (found === undefined)
|
|
119
|
+
return undefined;
|
|
120
|
+
const excluded = found.options['exclude-paths'] ?? config['exclude-paths'];
|
|
121
|
+
if (Array.isArray(excluded)) {
|
|
122
|
+
for (const exclusion of excluded) {
|
|
123
|
+
if (typeof exclusion !== 'string')
|
|
124
|
+
continue;
|
|
125
|
+
const relative = exclusion.replace(/^\.\//u, '').replace(/\/$/u, '');
|
|
126
|
+
if (holds(found.path === '' ? relative : `${found.path}/${relative}`, path))
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return found;
|
|
131
|
+
}
|
|
132
|
+
/** Whether the directory `outer` holds `inner`, both relative to the repository root. */
|
|
133
|
+
function holds(outer, inner) {
|
|
134
|
+
return outer === '' || inner === outer || inner.startsWith(`${outer}/`);
|
|
135
|
+
}
|
|
136
|
+
/** The canonical version and distance of the nearest tag with one of these prefixes, or nothing. */
|
|
137
|
+
async function describedBase(input, prefixes) {
|
|
138
|
+
const described = await git(input.projectDir, input.signal, [
|
|
139
|
+
'describe',
|
|
140
|
+
'--tags',
|
|
141
|
+
'--long',
|
|
142
|
+
'--abbrev=40',
|
|
143
|
+
...prefixes.flatMap((prefix) => ['--match', `${prefix}[0-9]*`]),
|
|
144
|
+
'HEAD',
|
|
145
|
+
]);
|
|
146
|
+
const match = described === undefined ? null : DESCRIBED.exec(described);
|
|
147
|
+
if (match?.groups === undefined)
|
|
148
|
+
return undefined;
|
|
149
|
+
const tag = match.groups.tag;
|
|
150
|
+
const distance = Number(match.groups.distance);
|
|
151
|
+
const version = prefixes
|
|
152
|
+
.filter((prefix) => tag.startsWith(prefix))
|
|
153
|
+
.map((prefix) => tag.slice(prefix.length))
|
|
154
|
+
.find((rest) => isVersion(rest));
|
|
155
|
+
if (version === undefined || !Number.isSafeInteger(distance))
|
|
156
|
+
return undefined;
|
|
157
|
+
return Object.freeze({ version, distance });
|
|
158
|
+
}
|
|
159
|
+
/** The repository's release-please configuration, if its root has one that is a JSON object. */
|
|
160
|
+
async function releasePleaseConfig(root) {
|
|
161
|
+
for (const name of RELEASE_PLEASE_CONFIGS) {
|
|
162
|
+
const config = await readJson(join(root, name));
|
|
163
|
+
if (config !== undefined)
|
|
164
|
+
return config;
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
/** The `name` of the `package.json` in a directory, if it has one. */
|
|
169
|
+
async function packageName(directory) {
|
|
170
|
+
return (await readJson(join(directory, 'package.json')))?.name;
|
|
171
|
+
}
|
|
172
|
+
/** A package name without its npm scope, as release-please makes a component of it. */
|
|
173
|
+
function unscoped(name) {
|
|
174
|
+
if (typeof name !== 'string' || name.length === 0)
|
|
175
|
+
return undefined;
|
|
176
|
+
return name.startsWith('@') ? name.slice(name.indexOf('/') + 1) || undefined : name;
|
|
177
|
+
}
|
|
178
|
+
/** The prefixes, unless one would be read as a glob by `git describe --match`. */
|
|
179
|
+
function literal(prefixes) {
|
|
180
|
+
return prefixes.every((prefix) => LITERAL_PREFIX.test(prefix)) ? prefixes : undefined;
|
|
181
|
+
}
|
|
182
|
+
async function readJson(path) {
|
|
183
|
+
let value;
|
|
184
|
+
try {
|
|
185
|
+
value = JSON.parse(await readFile(path, 'utf8'));
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
191
|
+
? value
|
|
192
|
+
: undefined;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Run one read-only git command in a directory and return its trimmed stdout, or nothing when git
|
|
196
|
+
* is missing or the command fails. An interrupted deploy still stops here.
|
|
197
|
+
*/
|
|
198
|
+
function git(cwd, signal, args) {
|
|
199
|
+
signal.throwIfAborted();
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
execFile('git', [...args], {
|
|
202
|
+
cwd,
|
|
203
|
+
// Never take the index lock: a deploy only reads the repository.
|
|
204
|
+
env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },
|
|
205
|
+
signal,
|
|
206
|
+
timeout: GIT_TIMEOUT_MS,
|
|
207
|
+
windowsHide: true,
|
|
208
|
+
}, (error, stdout) => {
|
|
209
|
+
if (signal.aborted) {
|
|
210
|
+
reject(signal.reason);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
resolve(error === null ? stdout.trim() : undefined);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
@@ -5,11 +5,15 @@ import type { LoadedEnvironment } from './project.js';
|
|
|
5
5
|
* that mode still has a consumer (AM-16, AM-72).
|
|
6
6
|
*
|
|
7
7
|
* - `canonical`: an immutable deployment of one sealed release through the adapter's
|
|
8
|
-
* `deployRelease`, with a key generated for it, and
|
|
8
|
+
* `deployRelease`, with a key generated for it, and no call to any instance.
|
|
9
9
|
* - `legacy-direct`: today's stable target, replaced in place through `prepare` and `deploy`, which
|
|
10
10
|
* serves a v3 Publication only. Its `reasons` name what selected it.
|
|
11
|
-
* - `refused`: a shape
|
|
12
|
-
*
|
|
11
|
+
* - `refused`: a shape no deploy of this SDK serves, refused before any effect. Each refusal
|
|
12
|
+
* carries the configuration or command to write instead.
|
|
13
|
+
*
|
|
14
|
+
* A deploy never installs, so two shapes are refused before a mode is selected at all: an
|
|
15
|
+
* Environment that declares `installation` by `defineProject`, and `--deploy-only` by the
|
|
16
|
+
* command-line parser (AM-72).
|
|
13
17
|
*/
|
|
14
18
|
export type DeployMode = {
|
|
15
19
|
readonly kind: 'canonical';
|
|
@@ -31,28 +35,28 @@ export type LegacyDirectReason =
|
|
|
31
35
|
| {
|
|
32
36
|
readonly reason: 'no-namespace';
|
|
33
37
|
}
|
|
34
|
-
/** An adapter that declares no `deployRelease
|
|
38
|
+
/** An adapter that declares no `deployRelease`: the contract before adapter interface v2. */
|
|
35
39
|
| {
|
|
36
40
|
readonly reason: 'no-deploy-release';
|
|
37
41
|
};
|
|
38
42
|
export type CloudflareDirectParameter = 'route' | 'workerName' | 'identityIssuer' | 'addressing' | 'signingIdentity';
|
|
39
43
|
export interface DeployRefusal {
|
|
40
|
-
readonly reason: '
|
|
44
|
+
readonly reason: 'astrale-instance' | 'astrale-signing-identity' | 'mixed-parameters' | 'scheduled-triggers' | 'development-canonical';
|
|
41
45
|
/** The configuration or command to write instead, for the author. */
|
|
42
46
|
readonly guidance: string;
|
|
43
47
|
}
|
|
44
48
|
/** The commands that select a deploy mode. `publish` refuses every Environment that is not canonical. */
|
|
45
49
|
export type DeployModeCommand = 'deploy' | 'dev';
|
|
46
50
|
/**
|
|
47
|
-
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
51
|
+
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
48
52
|
* only, and has no effect.
|
|
49
53
|
*
|
|
50
|
-
* A refusal wins over every other reason
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* the legacy direct-mode path when adapter-cloudflare names a direct-mode parameter or no
|
|
54
|
-
* `namespace`, or when its adapter declares no `deployRelease`. Everything else is canonical,
|
|
55
|
-
* under `dev`, which serves the legacy direct-mode path only.
|
|
54
|
+
* A refusal wins over every other reason. adapter-astrale deploys immutable deployments only
|
|
55
|
+
* (`deployRelease`): its removed instance mode's `instance` and `signingIdentity` are refused
|
|
56
|
+
* before any effect, since their one consumer pins an older SDK (AM-72). Otherwise the Environment
|
|
57
|
+
* is on the legacy direct-mode path when adapter-cloudflare names a direct-mode parameter or no
|
|
58
|
+
* `namespace`, or when its adapter declares no `deployRelease`. Everything else is canonical,
|
|
59
|
+
* except under `dev`, which serves the legacy direct-mode path only.
|
|
56
60
|
*
|
|
57
61
|
* Within canonical adapter-cloudflare (with `namespace`), a direct-mode parameter is refused
|
|
58
62
|
* rather than silently selecting either mode, and so is `wrangler.triggers`: an immutable
|
|
@@ -63,5 +67,4 @@ export declare function selectDeployMode(input: {
|
|
|
63
67
|
readonly command: DeployModeCommand;
|
|
64
68
|
readonly environment: string;
|
|
65
69
|
readonly definition: LoadedEnvironment;
|
|
66
|
-
readonly deployOnly: boolean;
|
|
67
70
|
}): DeployMode;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { installCommand } from '../../project/install-command.js';
|
|
1
2
|
/** The adapter names of the first-party adapters whose parameters CT33 classifies. */
|
|
2
3
|
const CLOUDFLARE = 'cloudflare';
|
|
3
4
|
const ASTRALE = 'astrale';
|
|
5
|
+
/** The one Environment adapter-astrale deploys without an explicit organisation (AM-7). */
|
|
6
|
+
const DEVELOPMENT = 'development';
|
|
7
|
+
/** The parameters that named the stable Service of adapter-astrale's removed instance mode. */
|
|
8
|
+
const ASTRALE_SERVICE_PARAMETERS = ['serviceKey', 'name'];
|
|
4
9
|
const CLOUDFLARE_DIRECT_PARAMETERS = [
|
|
5
10
|
'route',
|
|
6
11
|
'workerName',
|
|
@@ -9,15 +14,15 @@ const CLOUDFLARE_DIRECT_PARAMETERS = [
|
|
|
9
14
|
'signingIdentity',
|
|
10
15
|
];
|
|
11
16
|
/**
|
|
12
|
-
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
17
|
+
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
13
18
|
* only, and has no effect.
|
|
14
19
|
*
|
|
15
|
-
* A refusal wins over every other reason
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* the legacy direct-mode path when adapter-cloudflare names a direct-mode parameter or no
|
|
19
|
-
* `namespace`, or when its adapter declares no `deployRelease`. Everything else is canonical,
|
|
20
|
-
* under `dev`, which serves the legacy direct-mode path only.
|
|
20
|
+
* A refusal wins over every other reason. adapter-astrale deploys immutable deployments only
|
|
21
|
+
* (`deployRelease`): its removed instance mode's `instance` and `signingIdentity` are refused
|
|
22
|
+
* before any effect, since their one consumer pins an older SDK (AM-72). Otherwise the Environment
|
|
23
|
+
* is on the legacy direct-mode path when adapter-cloudflare names a direct-mode parameter or no
|
|
24
|
+
* `namespace`, or when its adapter declares no `deployRelease`. Everything else is canonical,
|
|
25
|
+
* except under `dev`, which serves the legacy direct-mode path only.
|
|
21
26
|
*
|
|
22
27
|
* Within canonical adapter-cloudflare (with `namespace`), a direct-mode parameter is refused
|
|
23
28
|
* rather than silently selecting either mode, and so is `wrangler.triggers`: an immutable
|
|
@@ -30,41 +35,22 @@ export function selectDeployMode(input) {
|
|
|
30
35
|
const parameters = definition.deployment.parameters;
|
|
31
36
|
const refusals = [];
|
|
32
37
|
const reasons = [];
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
refusals.push({
|
|
36
|
-
reason: 'installation',
|
|
37
|
-
guidance: `Environment ${environment} declares installation, and a deploy no longer installs. ` +
|
|
38
|
-
'Remove `installation` from the Environment, run ' +
|
|
39
|
-
`\`astrale-domain deploy ${environment}\`, then install the URL it prints with ` +
|
|
40
|
-
`\`astrale domain install <url> -i ${installation.instance}` +
|
|
41
|
-
`${installation.identity === undefined ? '' : ` --as ${installation.identity}`}\`.`,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
if (input.deployOnly) {
|
|
45
|
-
refusals.push({
|
|
46
|
-
reason: 'deploy-only',
|
|
47
|
-
guidance: '`--deploy-only` is no longer accepted: a deploy never installs. Run ' +
|
|
48
|
-
`\`astrale-domain ${command} ${environment}\` without it, then ` +
|
|
49
|
-
'`astrale domain install <url> -i <instance>`.',
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
if (adapter.name === ASTRALE) {
|
|
38
|
+
const releases = 'deployRelease' in adapter && typeof adapter.deployRelease === 'function';
|
|
39
|
+
if (adapter.name === ASTRALE && releases) {
|
|
53
40
|
if (declares(parameters, 'instance')) {
|
|
54
41
|
refusals.push({
|
|
55
42
|
reason: 'astrale-instance',
|
|
56
|
-
guidance:
|
|
57
|
-
"instance's Services, which no longer hosts deployments. Remove `instance`: " +
|
|
58
|
-
`\`astrale-domain deploy ${environment}\` makes an immutable deployment on Admin's ` +
|
|
59
|
-
'Services, and `astrale domain install <url> -i ' +
|
|
60
|
-
`${String(parameters.instance)}\` installs it.`,
|
|
43
|
+
guidance: astraleInstanceGuidance(parameters, environment),
|
|
61
44
|
});
|
|
62
45
|
}
|
|
63
46
|
if (declares(parameters, 'signingIdentity')) {
|
|
64
47
|
refusals.push({
|
|
65
48
|
reason: 'astrale-signing-identity',
|
|
66
49
|
guidance: 'astrale({ signingIdentity }) is no longer accepted: each deployment gets a signing key ' +
|
|
67
|
-
'generated when it is deployed. Remove `signingIdentity
|
|
50
|
+
'generated when it is deployed. Remove `signingIdentity`' +
|
|
51
|
+
// With `instance`, its own refusal already names the organisation.
|
|
52
|
+
(declares(parameters, 'instance') ? '' : organizationGuidance(parameters, environment)) +
|
|
53
|
+
'.',
|
|
68
54
|
});
|
|
69
55
|
}
|
|
70
56
|
}
|
|
@@ -93,9 +79,8 @@ export function selectDeployMode(input) {
|
|
|
93
79
|
reasons.push(...direct.map((parameter) => ({ reason: 'direct-parameter', parameter })), { reason: 'no-namespace' });
|
|
94
80
|
}
|
|
95
81
|
}
|
|
96
|
-
if (!
|
|
82
|
+
if (!releases)
|
|
97
83
|
reasons.push({ reason: 'no-deploy-release' });
|
|
98
|
-
}
|
|
99
84
|
if (refusals.length > 0)
|
|
100
85
|
return Object.freeze({ kind: 'refused', refusals: freeze(refusals) });
|
|
101
86
|
if (reasons.length > 0)
|
|
@@ -108,13 +93,37 @@ export function selectDeployMode(input) {
|
|
|
108
93
|
reason: 'development-canonical',
|
|
109
94
|
guidance: `\`astrale-domain dev\` serves only legacy direct-mode Environments, and ${environment} ` +
|
|
110
95
|
`deploys immutable deployments. Run \`astrale-domain deploy ${environment}\`, then ` +
|
|
111
|
-
|
|
96
|
+
`\`${installCommand()}\`.`,
|
|
112
97
|
},
|
|
113
98
|
]),
|
|
114
99
|
});
|
|
115
100
|
}
|
|
116
101
|
return Object.freeze({ kind: 'canonical' });
|
|
117
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* How an adapter-astrale Environment of the removed instance mode deploys now: without `instance`
|
|
105
|
+
* (nor `serviceKey` and `name`, which named its stable Service), outside development on a line its
|
|
106
|
+
* named organisation holds (AM-7), then installed by URL on the instance it used to deploy through.
|
|
107
|
+
*/
|
|
108
|
+
function astraleInstanceGuidance(parameters, environment) {
|
|
109
|
+
const instance = String(parameters.instance);
|
|
110
|
+
const service = ASTRALE_SERVICE_PARAMETERS.filter((name) => declares(parameters, name));
|
|
111
|
+
const removed = service.length === 0
|
|
112
|
+
? 'Remove `instance`'
|
|
113
|
+
: `Remove \`instance\` with ${service.map((name) => `\`${name}\``).join(' and ')}, ` +
|
|
114
|
+
`which named its stable Service`;
|
|
115
|
+
const organization = organizationGuidance(parameters, environment);
|
|
116
|
+
return (`astrale({ instance: '${instance}' }) deployed through that instance's Services, which no ` +
|
|
117
|
+
`longer hosts deployments. ${removed}${organization}: \`astrale-domain deploy ${environment}\` ` +
|
|
118
|
+
`makes an immutable deployment on Admin's Services, and \`${installCommand(instance)}\` ` +
|
|
119
|
+
'installs it.');
|
|
120
|
+
}
|
|
121
|
+
/** Outside development, an adapter-astrale Environment names the organisation of its line (AM-7). */
|
|
122
|
+
function organizationGuidance(parameters, environment) {
|
|
123
|
+
return environment === DEVELOPMENT || declares(parameters, 'organization')
|
|
124
|
+
? ''
|
|
125
|
+
: ", and name the organisation that holds the deployment line in `astrale({ organization: '<Identity id>' })`";
|
|
126
|
+
}
|
|
118
127
|
/** A parameter is declared when its value is not `undefined`, as optional adapter parameters read. */
|
|
119
128
|
function declares(parameters, name) {
|
|
120
129
|
return Object.hasOwn(parameters, name) && parameters[name] !== undefined;
|