@astrale-os/sdk 0.6.0-beta.13 → 0.6.0-beta.14
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 +1 -6
- 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 +10 -8
- package/dist/deployment/adapter/legacy/prepare/context.d.ts +0 -2
- package/dist/deployment/adapter/release/context.d.ts +16 -2
- package/dist/deployment/address/index.d.ts +1 -1
- package/dist/deployment/address/index.js +1 -0
- package/dist/deployment/address/summary.d.ts +30 -0
- 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 +15 -10
- package/dist/deployment/release/legacy/index.js +15 -10
- 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 +7 -0
- package/dist/execution/identity/authentication.js +7 -1
- package/dist/execution/identity/delivery.d.ts +11 -4
- package/dist/execution/identity/delivery.js +47 -20
- package/dist/execution/identity/identity.d.ts +7 -3
- package/dist/execution/identity/identity.js +2 -2
- 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/project/define.js +57 -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 +0 -2
- package/dist/tooling/cli/arguments.js +22 -15
- 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 +19 -12
- package/dist/tooling/cli/deploy-mode.js +14 -32
- package/dist/tooling/cli/deploy-result.d.ts +10 -7
- package/dist/tooling/cli/deploy-result.js +4 -3
- package/dist/tooling/cli/development/candidate.d.ts +2 -3
- package/dist/tooling/cli/development/candidate.js +2 -9
- package/dist/tooling/cli/development/deployment.d.ts +2 -8
- package/dist/tooling/cli/development/deployment.js +2 -21
- package/dist/tooling/cli/development/develop.d.ts +4 -3
- package/dist/tooling/cli/development/develop.js +8 -112
- package/dist/tooling/cli/development/report.d.ts +1 -3
- package/dist/tooling/cli/development/report.js +1 -4
- package/dist/tooling/cli/help.js +28 -26
- 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 +2 -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/legacy/stable-target-adapter.d.ts +5 -3
- package/dist/tooling/cli/legacy/stable-target-deploy.d.ts +42 -0
- package/dist/tooling/cli/legacy/stable-target-deploy.js +104 -0
- package/dist/tooling/cli/orchestrate.js +46 -97
- package/dist/tooling/cli/secrets.d.ts +9 -0
- package/dist/tooling/cli/secrets.js +19 -0
- package/package.json +1 -1
- 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/release-evidence.d.ts +0 -4
- package/dist/tooling/cli/development/release-evidence.js +0 -10
- 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
|
@@ -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
|
+
}
|
|
@@ -8,8 +8,12 @@ import type { LoadedEnvironment } from './project.js';
|
|
|
8
8
|
* `deployRelease`, with a key generated for it, and zero Kernel calls.
|
|
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,32 @@ export type LegacyDirectReason =
|
|
|
31
35
|
| {
|
|
32
36
|
readonly reason: 'no-namespace';
|
|
33
37
|
}
|
|
34
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* An adapter that declares no `deployRelease` (the contract before adapter interface v2),
|
|
40
|
+
* adapter-astrale's instance mode among them until adapter-astrale implements it.
|
|
41
|
+
*/
|
|
35
42
|
| {
|
|
36
43
|
readonly reason: 'no-deploy-release';
|
|
37
44
|
};
|
|
38
45
|
export type CloudflareDirectParameter = 'route' | 'workerName' | 'identityIssuer' | 'addressing' | 'signingIdentity';
|
|
39
46
|
export interface DeployRefusal {
|
|
40
|
-
readonly reason: '
|
|
47
|
+
readonly reason: 'astrale-instance' | 'astrale-signing-identity' | 'mixed-parameters' | 'scheduled-triggers' | 'development-canonical';
|
|
41
48
|
/** The configuration or command to write instead, for the author. */
|
|
42
49
|
readonly guidance: string;
|
|
43
50
|
}
|
|
44
51
|
/** The commands that select a deploy mode. `publish` refuses every Environment that is not canonical. */
|
|
45
52
|
export type DeployModeCommand = 'deploy' | 'dev';
|
|
46
53
|
/**
|
|
47
|
-
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
54
|
+
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
48
55
|
* only, and has no effect.
|
|
49
56
|
*
|
|
50
|
-
* A refusal wins over every other reason
|
|
51
|
-
*
|
|
52
|
-
* pins an older SDK
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
57
|
+
* A refusal wins over every other reason. Once adapter-astrale deploys immutable deployments
|
|
58
|
+
* (`deployRelease`), its `instance` and `signingIdentity` are refused before any effect: their one
|
|
59
|
+
* consumer pins an older SDK (AM-72). Until then they select its instance mode, on the legacy path
|
|
60
|
+
* with every adapter that declares no `deployRelease`. Otherwise the Environment is on the legacy
|
|
61
|
+
* direct-mode path when adapter-cloudflare names a direct-mode parameter or no `namespace`, or
|
|
62
|
+
* when its adapter declares no `deployRelease`. Everything else is canonical, except under `dev`,
|
|
63
|
+
* which serves the legacy direct-mode path only.
|
|
56
64
|
*
|
|
57
65
|
* Within canonical adapter-cloudflare (with `namespace`), a direct-mode parameter is refused
|
|
58
66
|
* rather than silently selecting either mode, and so is `wrangler.triggers`: an immutable
|
|
@@ -63,5 +71,4 @@ export declare function selectDeployMode(input: {
|
|
|
63
71
|
readonly command: DeployModeCommand;
|
|
64
72
|
readonly environment: string;
|
|
65
73
|
readonly definition: LoadedEnvironment;
|
|
66
|
-
readonly deployOnly: boolean;
|
|
67
74
|
}): DeployMode;
|
|
@@ -1,3 +1,4 @@
|
|
|
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';
|
|
@@ -9,15 +10,16 @@ const CLOUDFLARE_DIRECT_PARAMETERS = [
|
|
|
9
10
|
'signingIdentity',
|
|
10
11
|
];
|
|
11
12
|
/**
|
|
12
|
-
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
13
|
+
* Select the deploy mode of one Environment (CT33). It reads the configuration and the command
|
|
13
14
|
* only, and has no effect.
|
|
14
15
|
*
|
|
15
|
-
* A refusal wins over every other reason
|
|
16
|
-
*
|
|
17
|
-
* pins an older SDK
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* A refusal wins over every other reason. Once adapter-astrale deploys immutable deployments
|
|
17
|
+
* (`deployRelease`), its `instance` and `signingIdentity` are refused before any effect: their one
|
|
18
|
+
* consumer pins an older SDK (AM-72). Until then they select its instance mode, on the legacy path
|
|
19
|
+
* with every adapter that declares no `deployRelease`. Otherwise the Environment is on the legacy
|
|
20
|
+
* direct-mode path when adapter-cloudflare names a direct-mode parameter or no `namespace`, or
|
|
21
|
+
* when its adapter declares no `deployRelease`. Everything else is canonical, except under `dev`,
|
|
22
|
+
* which serves the legacy direct-mode path only.
|
|
21
23
|
*
|
|
22
24
|
* Within canonical adapter-cloudflare (with `namespace`), a direct-mode parameter is refused
|
|
23
25
|
* rather than silently selecting either mode, and so is `wrangler.triggers`: an immutable
|
|
@@ -30,34 +32,15 @@ export function selectDeployMode(input) {
|
|
|
30
32
|
const parameters = definition.deployment.parameters;
|
|
31
33
|
const refusals = [];
|
|
32
34
|
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) {
|
|
35
|
+
const releases = 'deployRelease' in adapter && typeof adapter.deployRelease === 'function';
|
|
36
|
+
if (adapter.name === ASTRALE && releases) {
|
|
53
37
|
if (declares(parameters, 'instance')) {
|
|
54
38
|
refusals.push({
|
|
55
39
|
reason: 'astrale-instance',
|
|
56
40
|
guidance: `astrale({ instance: '${String(parameters.instance)}' }) deployed through that ` +
|
|
57
41
|
"instance's Services, which no longer hosts deployments. Remove `instance`: " +
|
|
58
42
|
`\`astrale-domain deploy ${environment}\` makes an immutable deployment on Admin's ` +
|
|
59
|
-
|
|
60
|
-
`${String(parameters.instance)}\` installs it.`,
|
|
43
|
+
`Services, and \`${installCommand(String(parameters.instance))}\` installs it.`,
|
|
61
44
|
});
|
|
62
45
|
}
|
|
63
46
|
if (declares(parameters, 'signingIdentity')) {
|
|
@@ -93,9 +76,8 @@ export function selectDeployMode(input) {
|
|
|
93
76
|
reasons.push(...direct.map((parameter) => ({ reason: 'direct-parameter', parameter })), { reason: 'no-namespace' });
|
|
94
77
|
}
|
|
95
78
|
}
|
|
96
|
-
if (!
|
|
79
|
+
if (!releases)
|
|
97
80
|
reasons.push({ reason: 'no-deploy-release' });
|
|
98
|
-
}
|
|
99
81
|
if (refusals.length > 0)
|
|
100
82
|
return Object.freeze({ kind: 'refused', refusals: freeze(refusals) });
|
|
101
83
|
if (reasons.length > 0)
|
|
@@ -108,7 +90,7 @@ export function selectDeployMode(input) {
|
|
|
108
90
|
reason: 'development-canonical',
|
|
109
91
|
guidance: `\`astrale-domain dev\` serves only legacy direct-mode Environments, and ${environment} ` +
|
|
110
92
|
`deploys immutable deployments. Run \`astrale-domain deploy ${environment}\`, then ` +
|
|
111
|
-
|
|
93
|
+
`\`${installCommand()}\`.`,
|
|
112
94
|
},
|
|
113
95
|
]),
|
|
114
96
|
});
|
|
@@ -6,9 +6,7 @@ export type { DeploymentSecretsState } from '../../deployment/index.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* `astrale-domain deploy <environment> --json` on stdout: the one deployment the deploy made or
|
|
8
8
|
* reused, which CI installs by its URL. Progress and warnings go to stderr. It names no instance
|
|
9
|
-
* and no version: a deploy numbers nothing
|
|
10
|
-
* nothing. A legacy environment that declares `installation` still installs while it deploys and
|
|
11
|
-
* reports that outcome on stderr only.
|
|
9
|
+
* and no version: a deploy numbers nothing and installs nothing.
|
|
12
10
|
*/
|
|
13
11
|
export interface DeployResultV1 {
|
|
14
12
|
readonly format: 'astrale.deploy-result';
|
|
@@ -62,14 +60,19 @@ export interface DeployResultV1 {
|
|
|
62
60
|
readonly secrets?: {
|
|
63
61
|
readonly state: DeploymentSecretsState;
|
|
64
62
|
};
|
|
65
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* The commit the deployment was built from, as its deployment record declares it: the commit of
|
|
65
|
+
* the deploy that created it. A reused deployment keeps its record, so this can be an earlier
|
|
66
|
+
* commit than the one the deploy ran from; the label covers the release, never the commit.
|
|
67
|
+
*/
|
|
66
68
|
readonly commit: DeploymentCommitV1 | null;
|
|
67
69
|
}
|
|
68
70
|
/**
|
|
69
71
|
* The deploy result of one immutable deployment, from the ready result of the adapter's
|
|
70
|
-
* `deployRelease`. Its release, build, Schema revision and URL are those
|
|
71
|
-
*
|
|
72
|
-
*
|
|
72
|
+
* `deployRelease`. Its release, build, Schema revision and URL are those the SDK sealed before
|
|
73
|
+
* deploying; the deployment record the adapter returned must declare exactly that release at that
|
|
74
|
+
* URL, so the result never names a release the deployment does not serve. Its commit is the
|
|
75
|
+
* record's, which a reused deployment kept from the deploy that created it.
|
|
73
76
|
*/
|
|
74
77
|
export declare function deployResult(input: {
|
|
75
78
|
readonly environment: string;
|
|
@@ -6,9 +6,10 @@ const SECRETS_BY_STATE = Object.freeze({
|
|
|
6
6
|
});
|
|
7
7
|
/**
|
|
8
8
|
* The deploy result of one immutable deployment, from the ready result of the adapter's
|
|
9
|
-
* `deployRelease`. Its release, build, Schema revision and URL are those
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* `deployRelease`. Its release, build, Schema revision and URL are those the SDK sealed before
|
|
10
|
+
* deploying; the deployment record the adapter returned must declare exactly that release at that
|
|
11
|
+
* URL, so the result never names a release the deployment does not serve. Its commit is the
|
|
12
|
+
* record's, which a reused deployment kept from the deploy that created it.
|
|
12
13
|
*/
|
|
13
14
|
export function deployResult(input) {
|
|
14
15
|
const { release, deployment } = input;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PreparedArtifact } from '../../../deployment/adapter/index.js';
|
|
2
2
|
import type { StableTargetAdapter } from '../legacy/stable-target-adapter.js';
|
|
3
3
|
export interface DevelopmentCandidate {
|
|
4
4
|
readonly adapter: StableTargetAdapter<object>;
|
|
5
5
|
readonly parameters: object;
|
|
6
|
-
readonly installation?: InstallationTarget;
|
|
7
6
|
readonly artifact: PreparedArtifact;
|
|
8
7
|
readonly secrets: Readonly<Record<string, string>>;
|
|
9
8
|
readonly sources: ReadonlySet<string>;
|
|
@@ -22,5 +21,5 @@ export declare class DevelopmentCandidateBuilder {
|
|
|
22
21
|
}
|
|
23
22
|
export declare function discoverRuntimePath(configPath: string): Promise<string>;
|
|
24
23
|
export declare function sameEnvironment(current: DevelopmentCandidate, candidate: DevelopmentCandidate): boolean;
|
|
25
|
-
/** Identify a rebuilt candidate that cannot change provider
|
|
24
|
+
/** Identify a rebuilt candidate that cannot change provider state. */
|
|
26
25
|
export declare function sameDeploymentCandidate(current: DevelopmentCandidate, candidate: DevelopmentCandidate): boolean;
|
|
@@ -84,9 +84,6 @@ export class DevelopmentCandidateBuilder {
|
|
|
84
84
|
const source = await adapter.prepare(parameters, {
|
|
85
85
|
projectDir: this.#projectDir,
|
|
86
86
|
environment: this.#environment,
|
|
87
|
-
...(environment.installation === undefined
|
|
88
|
-
? {}
|
|
89
|
-
: { installation: environment.installation }),
|
|
90
87
|
mode: 'release',
|
|
91
88
|
recordSource: sources.record,
|
|
92
89
|
signal,
|
|
@@ -102,9 +99,6 @@ export class DevelopmentCandidateBuilder {
|
|
|
102
99
|
return Object.freeze({
|
|
103
100
|
adapter,
|
|
104
101
|
parameters,
|
|
105
|
-
...(environment.installation === undefined
|
|
106
|
-
? {}
|
|
107
|
-
: { installation: environment.installation }),
|
|
108
102
|
artifact,
|
|
109
103
|
secrets: declared.values,
|
|
110
104
|
sources: sources.snapshot(),
|
|
@@ -125,10 +119,9 @@ export function sameEnvironment(current, candidate) {
|
|
|
125
119
|
candidate.adapter.version === current.adapter.version &&
|
|
126
120
|
candidate.artifact.build.schema.compiled.root.origin ===
|
|
127
121
|
current.artifact.build.schema.compiled.root.origin &&
|
|
128
|
-
stable(candidate.parameters) === stable(current.parameters)
|
|
129
|
-
stable(candidate.installation) === stable(current.installation));
|
|
122
|
+
stable(candidate.parameters) === stable(current.parameters));
|
|
130
123
|
}
|
|
131
|
-
/** Identify a rebuilt candidate that cannot change provider
|
|
124
|
+
/** Identify a rebuilt candidate that cannot change provider state. */
|
|
132
125
|
export function sameDeploymentCandidate(current, candidate) {
|
|
133
126
|
return (sameEnvironment(current, candidate) &&
|
|
134
127
|
candidate.artifact.build.schema.compiled.root.revision ===
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import type { ReadyDeployResult } from '../../../deployment/adapter/index.js';
|
|
2
|
-
import type { InstallationEvidence } from '../installation/index.js';
|
|
3
2
|
import type { DevelopmentCandidate } from './candidate.js';
|
|
4
3
|
export interface DevelopmentDeploymentInput {
|
|
5
4
|
readonly projectDir: string;
|
|
6
5
|
readonly environment: string;
|
|
7
|
-
readonly deployOnly: boolean;
|
|
8
6
|
readonly identity?: string;
|
|
9
7
|
readonly credential?: string;
|
|
10
|
-
readonly installationExecutable?: string;
|
|
11
8
|
}
|
|
12
|
-
/** Commit and verify one complete remote candidate
|
|
13
|
-
export declare function deployDevelopmentCandidate(candidate: DevelopmentCandidate, input: DevelopmentDeploymentInput, signal: AbortSignal): Promise<
|
|
14
|
-
readonly deployment: ReadyDeployResult;
|
|
15
|
-
readonly installation?: InstallationEvidence;
|
|
16
|
-
}>;
|
|
9
|
+
/** Commit and verify one complete remote candidate. A development deployment installs nothing. */
|
|
10
|
+
export declare function deployDevelopmentCandidate(candidate: DevelopmentCandidate, input: DevelopmentDeploymentInput, signal: AbortSignal): Promise<ReadyDeployResult>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { verifyDeployment } from '../../../deployment/index.js';
|
|
2
|
-
|
|
3
|
-
/** Commit and verify one complete remote candidate, then reconcile its optional installation. */
|
|
2
|
+
/** Commit and verify one complete remote candidate. A development deployment installs nothing. */
|
|
4
3
|
export async function deployDevelopmentCandidate(candidate, input, signal) {
|
|
5
4
|
const deployed = await candidate.adapter.deploy(candidate.parameters, {
|
|
6
5
|
projectDir: input.projectDir,
|
|
7
6
|
environment: input.environment,
|
|
8
|
-
...(candidate.installation === undefined ? {} : { installation: candidate.installation }),
|
|
9
7
|
...(input.identity === undefined ? {} : { identity: input.identity }),
|
|
10
8
|
...(input.credential === undefined ? {} : { credential: input.credential }),
|
|
11
9
|
secrets: candidate.secrets,
|
|
@@ -18,22 +16,5 @@ export async function deployDevelopmentCandidate(candidate, input, signal) {
|
|
|
18
16
|
cause: verified.error,
|
|
19
17
|
});
|
|
20
18
|
}
|
|
21
|
-
|
|
22
|
-
projectDir: input.projectDir,
|
|
23
|
-
environment: input.environment,
|
|
24
|
-
adapter: candidate.adapter,
|
|
25
|
-
deployment: verified,
|
|
26
|
-
...(candidate.installation === undefined ? {} : { installation: candidate.installation }),
|
|
27
|
-
deployOnly: input.deployOnly,
|
|
28
|
-
...(input.installationExecutable === undefined
|
|
29
|
-
? {}
|
|
30
|
-
: { installationExecutable: input.installationExecutable }),
|
|
31
|
-
...(input.identity === undefined ? {} : { identity: input.identity }),
|
|
32
|
-
...(input.credential === undefined ? {} : { credential: input.credential }),
|
|
33
|
-
signal,
|
|
34
|
-
});
|
|
35
|
-
return Object.freeze({
|
|
36
|
-
deployment: verified,
|
|
37
|
-
...(installation === undefined ? {} : { installation }),
|
|
38
|
-
});
|
|
19
|
+
return verified;
|
|
39
20
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Watch one Project Environment and serialize complete remote deployment generations. Each
|
|
3
|
+
* generation replaces the Environment's stable target in place; none installs anything.
|
|
4
|
+
*/
|
|
2
5
|
export declare function develop(input: {
|
|
3
6
|
readonly configPath: string;
|
|
4
7
|
readonly projectDir: string;
|
|
5
8
|
readonly environment: string;
|
|
6
|
-
readonly deployOnly: boolean;
|
|
7
9
|
readonly identity?: string;
|
|
8
10
|
readonly credentialFile?: string;
|
|
9
|
-
readonly sessionFile?: string;
|
|
10
11
|
readonly secretsFile?: string;
|
|
11
12
|
}): Promise<number>;
|