@studiometa/forge-cli 0.5.1 → 0.5.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/README.md +70 -1
- package/dist/cli.js +985 -43
- package/dist/cli.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/sites/apply/apply.d.ts +54 -0
- package/dist/commands/sites/apply/apply.d.ts.map +1 -0
- package/dist/commands/sites/apply/handler.d.ts +8 -0
- package/dist/commands/sites/apply/handler.d.ts.map +1 -0
- package/dist/commands/sites/apply/ownership.d.ts +88 -0
- package/dist/commands/sites/apply/ownership.d.ts.map +1 -0
- package/dist/commands/sites/apply/plan.d.ts +128 -0
- package/dist/commands/sites/apply/plan.d.ts.map +1 -0
- package/dist/commands/sites/apply/site-file.d.ts +69 -0
- package/dist/commands/sites/apply/site-file.d.ts.map +1 -0
- package/dist/commands/sites/apply/test-fixtures.d.ts +74 -0
- package/dist/commands/sites/apply/test-fixtures.d.ts.map +1 -0
- package/dist/commands/sites/command.d.ts.map +1 -1
- package/dist/commands/sites/help.d.ts.map +1 -1
- package/dist/commands/ssh-keys/sync.d.ts.map +1 -1
- package/dist/context.d.ts +15 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/{error-handler-Adi84RcF.js → error-handler-s-BOJ1-h.js} +16 -4
- package/dist/error-handler-s-BOJ1-h.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/utils/args.d.ts.map +1 -1
- package/dist/utils/resolve.d.ts +19 -13
- package/dist/utils/resolve.d.ts.map +1 -1
- package/package.json +6 -4
- package/schemas/site.schema.json +122 -0
- package/dist/error-handler-Adi84RcF.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0zBH,wBAAgB,kBAAkB,IAAI,IAAI,CA2CzC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAM,GACxD,IAAI,CAoEN"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the state of Forge for a site file, and run a plan against Forge.
|
|
3
|
+
*/
|
|
4
|
+
import type { CliExecutorContext } from "../../../context.ts";
|
|
5
|
+
import { CliError } from "../../../errors.ts";
|
|
6
|
+
import { type Change, type Plan, type RemoteState, type Site } from "./plan.ts";
|
|
7
|
+
import type { SiteFile } from "./site-file.ts";
|
|
8
|
+
/** Error of `apply` that is not a validation error, e.g. a site that never gets installed. */
|
|
9
|
+
export declare class ApplyError extends CliError {
|
|
10
|
+
readonly code = "APPLY_ERROR";
|
|
11
|
+
readonly isRecoverable = false;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the server of the site file, always with an exact name (never a partial match).
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveApplyServer(server: string | number, ctx: CliExecutorContext): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* The site named `domain` on the server, compared without case. A partial match never counts.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findSite(sites: Site[], domain: string): Site | null;
|
|
21
|
+
/**
|
|
22
|
+
* Read from Forge what the site file manages, and nothing else.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readRemoteState(file: SiteFile, serverId: string, ctx: CliExecutorContext): Promise<RemoteState>;
|
|
25
|
+
/**
|
|
26
|
+
* Exit with a validation error when the site does not exist and the site file cannot create it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function assertCanCreateSite(file: SiteFile, state: RemoteState): void;
|
|
29
|
+
/** A random password for a database user: 32 characters, letters and digits only. */
|
|
30
|
+
export declare function generatePassword(): string;
|
|
31
|
+
/** Write a value for a .env file, quoted when it needs quotes. */
|
|
32
|
+
export declare function formatEnvValue(value: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Set .env variables: replace the line of a variable that exists, append the others.
|
|
35
|
+
*/
|
|
36
|
+
export declare function setEnvValues(content: string, values: Map<string, string>): string;
|
|
37
|
+
export interface ApplyOptions {
|
|
38
|
+
/** Wait between two reads of a new site; injectable for tests. */
|
|
39
|
+
sleep?: (ms: number) => Promise<void>;
|
|
40
|
+
/** Time between two reads of a new site, in ms. */
|
|
41
|
+
pollIntervalMs?: number;
|
|
42
|
+
/** Time to wait for a new site to be installed, in ms. */
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
/** Called before each change. */
|
|
45
|
+
onChange?: (change: Change) => void;
|
|
46
|
+
/** Generate a password; injectable for tests. */
|
|
47
|
+
generatePassword?: () => string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Apply a site file: create the site when it does not exist and wait until Forge installs it,
|
|
51
|
+
* then read the state again and run the other changes. Returns the plan that ran first.
|
|
52
|
+
*/
|
|
53
|
+
export declare function applySiteFile(file: SiteFile, serverId: string, ctx: CliExecutorContext, options?: ApplyOptions): Promise<Plan>;
|
|
54
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/apply.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAmB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,EAAa,MAAM,WAAW,CAAC;AAC3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,8FAA8F;AAC9F,qBAAa,UAAW,SAAQ,QAAQ;IACtC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,aAAa,SAAS;CAChC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEnE;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,WAAW,CAAC,CAkCtB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAQ5E;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,IAAI,MAAM,CAUzC;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAiBjF;AAED,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;CACjC;AA6LD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,kBAAkB,EACvB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CommandContext } from "../../../context.ts";
|
|
2
|
+
import { type ApplyOptions } from "./apply.ts";
|
|
3
|
+
/**
|
|
4
|
+
* `forge sites apply --file site.json [--check]`: make a Forge site match a site file.
|
|
5
|
+
* With `--check`, print the plan and exit 1 when Forge differs, without any change.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sitesApply(ctx: CommandContext, applyOptions?: ApplyOptions): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EACL,KAAK,YAAY,EAKlB,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,cAAc,EACnB,YAAY,GAAE,YAAiB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path and command helpers of `forge sites apply`: normalize commands so that
|
|
3
|
+
* equivalent spellings compare equal, and find which site owns a daemon or a scheduled job.
|
|
4
|
+
*
|
|
5
|
+
* Ownership is strict on purpose: `apply` deletes the workers and scheduled jobs of a site
|
|
6
|
+
* that the site file does not declare, and a server often hosts many sites.
|
|
7
|
+
*/
|
|
8
|
+
/** A site, as far as ownership is concerned. */
|
|
9
|
+
export interface SiteRoots {
|
|
10
|
+
id: number;
|
|
11
|
+
/** Absolute paths that belong to the site, e.g. `/home/forge/example.com`. */
|
|
12
|
+
roots: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Normalize an absolute path: resolve `.` and `..`, collapse repeated slashes
|
|
16
|
+
* and drop the trailing slash.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizePath(path: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether `path` is `root` or inside it, compared on whole path segments:
|
|
21
|
+
* `/home/forge/a.com` contains `/home/forge/a.com/current` but not `/home/forge/a.com-staging`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isPathInside(path: string, root: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve `path` against `base` when it is relative.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolvePath(base: string, path: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Whether a shell command uses `root` as a whole path: `root` must start the command or follow
|
|
30
|
+
* a space, a quote, `=` or a shell operator, and must end the command or be followed by `/`,
|
|
31
|
+
* a space, a quote or a shell operator. `/home/forge/a.com` is not found in
|
|
32
|
+
* `/home/forge/a.com-staging/artisan`, `/home/forge/a.com.old` or `/home/forge/*`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function commandUsesPath(command: string, root: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Split a shell command into words, with the quoting rules of a POSIX shell:
|
|
37
|
+
* single quotes keep everything, double quotes and a backslash escape one character.
|
|
38
|
+
*/
|
|
39
|
+
export declare function splitCommand(command: string): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Quote a word for a POSIX shell when it needs quotes.
|
|
42
|
+
*/
|
|
43
|
+
export declare function quoteWord(word: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Write a command in one canonical form, so that equivalent spellings compare equal:
|
|
46
|
+
* quotes only where needed, single spaces, and a relative `artisan` (or `./artisan`)
|
|
47
|
+
* replaced by its absolute path in `directory`.
|
|
48
|
+
*
|
|
49
|
+
* `php artisan queue:work 'database' --queue="default"` in `/home/forge/example.com/`
|
|
50
|
+
* gives `php /home/forge/example.com/artisan queue:work database --queue=default`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function canonicalCommand(command: string, directory: string | null): string;
|
|
53
|
+
/**
|
|
54
|
+
* The site whose root holds `path`: the most specific root wins, so a site in
|
|
55
|
+
* `/home/forge/a.com/admin` is not owned by `/home/forge/a.com`. Returns null when no site holds it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function siteOfPath(path: string, sites: SiteRoots[]): number | null;
|
|
58
|
+
/**
|
|
59
|
+
* The sites whose roots a command uses as a path.
|
|
60
|
+
*/
|
|
61
|
+
export declare function sitesOfCommand(command: string, sites: SiteRoots[]): number[];
|
|
62
|
+
/**
|
|
63
|
+
* Who owns a daemon or a scheduled job, from the point of view of one site:
|
|
64
|
+
* - `site`: it belongs to the site; `apply` can match it, and delete it when it is not declared
|
|
65
|
+
* - `ambiguous`: it may belong to the site; `apply` can match it but never deletes it
|
|
66
|
+
* - `other`: it belongs to another site, to the server, or to nobody known; `apply` ignores it
|
|
67
|
+
*/
|
|
68
|
+
export type Ownership = "site" | "ambiguous" | "other";
|
|
69
|
+
/**
|
|
70
|
+
* Ownership of a daemon (a Forge background process).
|
|
71
|
+
*
|
|
72
|
+
* - With a directory: the site that holds the directory (see {@link siteOfPath}).
|
|
73
|
+
* - Without a directory: `ambiguous` when the command uses the site root, `site` only when
|
|
74
|
+
* the command uses no other site root and Forge also associates the daemon with the site.
|
|
75
|
+
*/
|
|
76
|
+
export declare function daemonOwnership(daemon: {
|
|
77
|
+
directory: string | null;
|
|
78
|
+
command: string;
|
|
79
|
+
}, siteId: number, sites: SiteRoots[], associatedWithSite: boolean): Ownership;
|
|
80
|
+
/**
|
|
81
|
+
* Ownership of a scheduled job. Forge lists the jobs of a site on a site route: those
|
|
82
|
+
* belong to the site. A job of the server belongs to the site when its command uses the
|
|
83
|
+
* site root and no other site root; when it uses several site roots, it is `ambiguous`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function scheduledJobOwnership(job: {
|
|
86
|
+
command: string;
|
|
87
|
+
}, siteId: number, sites: SiteRoots[], listedOnSite: boolean): Ownership;
|
|
88
|
+
//# sourceMappingURL=ownership.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownership.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/ownership.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKhE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAMD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAsCtD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAUlF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CAW1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAI5E;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACrD,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,EAAE,EAClB,kBAAkB,EAAE,OAAO,GAC1B,SAAS,CAQX;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,EAAE,EAClB,YAAY,EAAE,OAAO,GACpB,SAAS,CAKX"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare a site file with the state of Forge and list the changes that `apply` makes.
|
|
3
|
+
* Pure functions: no API call here.
|
|
4
|
+
*/
|
|
5
|
+
import type { BackgroundProcessAttributes, DatabaseAttributes, DatabaseUserAttributes, ScheduledJobAttributes, SiteAttributes } from "@studiometa/forge-api";
|
|
6
|
+
import type { SiteFile } from "./site-file.ts";
|
|
7
|
+
import { type SiteRoots } from "./ownership.ts";
|
|
8
|
+
export type Site = SiteAttributes & {
|
|
9
|
+
id: number;
|
|
10
|
+
};
|
|
11
|
+
export type Daemon = BackgroundProcessAttributes & {
|
|
12
|
+
id: number;
|
|
13
|
+
};
|
|
14
|
+
export type ScheduledJob = ScheduledJobAttributes & {
|
|
15
|
+
id: number;
|
|
16
|
+
};
|
|
17
|
+
export type Database = DatabaseAttributes & {
|
|
18
|
+
id: number;
|
|
19
|
+
};
|
|
20
|
+
export type DatabaseUser = DatabaseUserAttributes & {
|
|
21
|
+
id: number;
|
|
22
|
+
};
|
|
23
|
+
/** Shown in place of a generated password. */
|
|
24
|
+
export declare const GENERATED = "<generated>";
|
|
25
|
+
/** What `apply` reads from Forge. A list is undefined when the site file does not manage it. */
|
|
26
|
+
export interface RemoteState {
|
|
27
|
+
/** All sites of the server. */
|
|
28
|
+
sites: Site[];
|
|
29
|
+
/** The site of the file, or null when it does not exist yet. */
|
|
30
|
+
site: Site | null;
|
|
31
|
+
databases?: Database[];
|
|
32
|
+
databaseUsers?: DatabaseUser[];
|
|
33
|
+
/** Content of the site .env; null when the site does not exist. */
|
|
34
|
+
env?: string | null;
|
|
35
|
+
/** All daemons of the server. */
|
|
36
|
+
daemons?: Daemon[];
|
|
37
|
+
/** IDs of the daemons that Forge associates with the site. */
|
|
38
|
+
siteDaemonIds?: ReadonlySet<number>;
|
|
39
|
+
/** All scheduled jobs of the server, with the jobs of the site. */
|
|
40
|
+
jobs?: ScheduledJob[];
|
|
41
|
+
/** IDs of the scheduled jobs that Forge lists on the site. */
|
|
42
|
+
siteJobIds?: ReadonlySet<number>;
|
|
43
|
+
}
|
|
44
|
+
export interface SiteSettings {
|
|
45
|
+
type?: string;
|
|
46
|
+
php_version?: string;
|
|
47
|
+
web_directory?: string;
|
|
48
|
+
source_control_provider?: string;
|
|
49
|
+
repository?: string;
|
|
50
|
+
branch?: string;
|
|
51
|
+
}
|
|
52
|
+
export type Change = {
|
|
53
|
+
action: "create-site";
|
|
54
|
+
name: string;
|
|
55
|
+
settings: SiteSettings;
|
|
56
|
+
} | {
|
|
57
|
+
action: "update-site";
|
|
58
|
+
changes: Array<{
|
|
59
|
+
field: string;
|
|
60
|
+
from: string | null;
|
|
61
|
+
to: string;
|
|
62
|
+
}>;
|
|
63
|
+
} | {
|
|
64
|
+
action: "add-alias";
|
|
65
|
+
name: string;
|
|
66
|
+
} | {
|
|
67
|
+
action: "create-database";
|
|
68
|
+
name: string;
|
|
69
|
+
} | {
|
|
70
|
+
action: "create-database-user";
|
|
71
|
+
name: string;
|
|
72
|
+
database: string;
|
|
73
|
+
} | {
|
|
74
|
+
action: "add-env";
|
|
75
|
+
keys: string[];
|
|
76
|
+
generated: string[];
|
|
77
|
+
} | {
|
|
78
|
+
action: "create-worker";
|
|
79
|
+
command: string;
|
|
80
|
+
directory: string;
|
|
81
|
+
processes: number;
|
|
82
|
+
} | {
|
|
83
|
+
action: "delete-worker";
|
|
84
|
+
id: number;
|
|
85
|
+
command: string;
|
|
86
|
+
directory: string | null;
|
|
87
|
+
processes: number;
|
|
88
|
+
} | {
|
|
89
|
+
action: "create-job";
|
|
90
|
+
command: string;
|
|
91
|
+
frequency: string;
|
|
92
|
+
cron?: string;
|
|
93
|
+
} | {
|
|
94
|
+
action: "delete-job";
|
|
95
|
+
id: number;
|
|
96
|
+
command: string;
|
|
97
|
+
frequency: string;
|
|
98
|
+
cron: string;
|
|
99
|
+
onSite: boolean;
|
|
100
|
+
};
|
|
101
|
+
export interface Plan {
|
|
102
|
+
changes: Change[];
|
|
103
|
+
/** Differences that `apply` does not change, e.g. a different .env value. */
|
|
104
|
+
warnings: string[];
|
|
105
|
+
}
|
|
106
|
+
/** The path of the site folder, e.g. `/home/forge/example.com`. */
|
|
107
|
+
export declare function siteHome(site: Pick<Site, "user" | "name">): string;
|
|
108
|
+
/** The directory that workers run in and relative `artisan` resolves against. */
|
|
109
|
+
export declare function siteWorkDirectory(site: Pick<Site, "user" | "name" | "root_directory">): string;
|
|
110
|
+
/** The paths that belong to each site, for ownership. */
|
|
111
|
+
export declare function siteRoots(sites: Site[]): SiteRoots[];
|
|
112
|
+
/** `PHP 8.3`, `php83` and `php8.3` all give `php83`. */
|
|
113
|
+
export declare function normalizePhp(version: string | null | undefined): string | null;
|
|
114
|
+
/**
|
|
115
|
+
* Compare the site file with the state of Forge. Keys that the file does not have are not
|
|
116
|
+
* compared. The plan creates and updates what differs, and deletes only the workers and
|
|
117
|
+
* scheduled jobs that surely belong to the site and that the file does not declare.
|
|
118
|
+
*/
|
|
119
|
+
export declare function buildPlan(file: SiteFile, state: RemoteState): Plan;
|
|
120
|
+
/**
|
|
121
|
+
* One line per change, for human output. Values of .env keys never show.
|
|
122
|
+
*/
|
|
123
|
+
export declare function describeChange(change: Change): string;
|
|
124
|
+
/**
|
|
125
|
+
* The plan as text: one line per change, then the warnings.
|
|
126
|
+
*/
|
|
127
|
+
export declare function formatPlan(plan: Plan): string;
|
|
128
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/plan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,2BAA2B,EAC3B,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAEL,KAAK,SAAS,EAOf,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,IAAI,GAAG,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,MAAM,GAAG,2BAA2B,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,sBAAsB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AACnE,MAAM,MAAM,QAAQ,GAAG,kBAAkB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,sBAAsB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,8CAA8C;AAC9C,eAAO,MAAM,SAAS,gBAAgB,CAAC;AAEvC,gGAAgG;AAChG,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,gEAAgE;IAChE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,mEAAmE;IACnE,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IACtB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,MAAM,GACd;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,GAC/D;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAC7F;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,sBAAsB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1D;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClF;IACE,MAAM,EAAE,eAAe,CAAC;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E;IACE,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEN,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,mEAAmE;AACnE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAElE;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAC,GAAG,MAAM,CAE9F;AAcD,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE,CAKpD;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAE9E;AA6TD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAclE;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgCrD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK7C"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The site file of `forge sites apply`: a JSON file that declares one Forge site.
|
|
3
|
+
* A key that is absent is not managed; only `server` and `domain` are required.
|
|
4
|
+
*/
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
/** URL of the JSON Schema of the site file, published with the package. */
|
|
7
|
+
export declare const SITE_FILE_SCHEMA_URL = "https://unpkg.com/@studiometa/forge-cli/schemas/site.schema.json";
|
|
8
|
+
export declare const SITE_TYPES: readonly ["laravel", "symfony", "statamic", "wordpress", "phpmyadmin", "php", "nextjs", "nuxtjs", "static-html", "other", "custom"];
|
|
9
|
+
export declare const SOURCE_CONTROL_PROVIDERS: readonly ["github", "gitlab", "bitbucket", "gitlab-custom", "custom"];
|
|
10
|
+
export declare const SCHEDULE_FREQUENCIES: readonly ["minutely", "hourly", "nightly", "weekly", "monthly", "reboot", "custom"];
|
|
11
|
+
export declare const WorkerSchema: v.StrictObjectSchema<{
|
|
12
|
+
readonly command: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
13
|
+
readonly processes: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, 1>;
|
|
14
|
+
readonly directory: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
15
|
+
}, undefined>;
|
|
16
|
+
export declare const ScheduledJobSchema: v.SchemaWithPipe<readonly [v.StrictObjectSchema<{
|
|
17
|
+
readonly command: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
18
|
+
readonly frequency: v.PicklistSchema<readonly ["minutely", "hourly", "nightly", "weekly", "monthly", "reboot", "custom"], undefined>;
|
|
19
|
+
readonly cron: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
20
|
+
}, undefined>, v.CheckAction<{
|
|
21
|
+
command: string;
|
|
22
|
+
frequency: "custom" | "hourly" | "minutely" | "monthly" | "nightly" | "reboot" | "weekly";
|
|
23
|
+
cron?: string | undefined;
|
|
24
|
+
}, "cron is required with the custom frequency, and only with it">]>;
|
|
25
|
+
export declare const SiteFileSchema: v.StrictObjectSchema<{
|
|
26
|
+
readonly $schema: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
27
|
+
readonly server: v.UnionSchema<[v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>], undefined>;
|
|
28
|
+
readonly domain: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
29
|
+
readonly aliases: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>, undefined>;
|
|
30
|
+
readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["laravel", "symfony", "statamic", "wordpress", "phpmyadmin", "php", "nextjs", "nuxtjs", "static-html", "other", "custom"], undefined>, undefined>;
|
|
31
|
+
readonly php: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "php must look like php83">]>, undefined>;
|
|
32
|
+
readonly webDirectory: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
33
|
+
readonly repository: v.OptionalSchema<v.StrictObjectSchema<{
|
|
34
|
+
readonly provider: v.PicklistSchema<readonly ["github", "gitlab", "bitbucket", "gitlab-custom", "custom"], undefined>;
|
|
35
|
+
readonly url: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
36
|
+
readonly branch: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
37
|
+
}, undefined>, undefined>;
|
|
38
|
+
readonly database: v.OptionalSchema<v.StrictObjectSchema<{
|
|
39
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
40
|
+
readonly user: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
41
|
+
}, undefined>, undefined>;
|
|
42
|
+
readonly env: v.OptionalSchema<v.RecordSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "invalid .env variable name">]>, v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>, v.BooleanSchema<undefined>], undefined>, undefined>, undefined>;
|
|
43
|
+
readonly workers: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
|
|
44
|
+
readonly command: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
45
|
+
readonly processes: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, 1>;
|
|
46
|
+
readonly directory: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
47
|
+
}, undefined>, undefined>, undefined>;
|
|
48
|
+
readonly schedule: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StrictObjectSchema<{
|
|
49
|
+
readonly command: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>;
|
|
50
|
+
readonly frequency: v.PicklistSchema<readonly ["minutely", "hourly", "nightly", "weekly", "monthly", "reboot", "custom"], undefined>;
|
|
51
|
+
readonly cron: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.NonEmptyAction<string, undefined>]>, undefined>;
|
|
52
|
+
}, undefined>, v.CheckAction<{
|
|
53
|
+
command: string;
|
|
54
|
+
frequency: "custom" | "hourly" | "minutely" | "monthly" | "nightly" | "reboot" | "weekly";
|
|
55
|
+
cron?: string | undefined;
|
|
56
|
+
}, "cron is required with the custom frequency, and only with it">]>, undefined>, undefined>;
|
|
57
|
+
}, undefined>;
|
|
58
|
+
export type SiteFile = v.InferOutput<typeof SiteFileSchema>;
|
|
59
|
+
export type WorkerDeclaration = v.InferOutput<typeof WorkerSchema>;
|
|
60
|
+
export type ScheduledJobDeclaration = v.InferOutput<typeof ScheduledJobSchema>;
|
|
61
|
+
/**
|
|
62
|
+
* Validate parsed JSON as a site file. Throws a ValidationError that lists every issue.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseSiteFile(data: unknown, source?: string): SiteFile;
|
|
65
|
+
/**
|
|
66
|
+
* Read and validate a site file from disk.
|
|
67
|
+
*/
|
|
68
|
+
export declare function readSiteFile(path: string): SiteFile;
|
|
69
|
+
//# sourceMappingURL=site-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-file.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/site-file.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAI7B,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,qEACmC,CAAC;AAIrE,eAAO,MAAM,UAAU,YACrB,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,OAAO,EACP,QAAQ,CACA,CAAC;AAEX,eAAO,MAAM,wBAAwB,YACnC,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,eAAe,EACf,QAAQ,CACA,CAAC;AAEX,eAAO,MAAM,oBAAoB,YAC/B,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,CACA,CAAC;AAEX,eAAO,MAAM,YAAY;;;;aAIvB,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;oEAU9B,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAwBzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,YAAY,CAAC,CAAC;AACnE,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE/E;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,SAAc,GAAG,QAAQ,CAU3E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAkBnD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixtures of Forge resources for the tests of `forge sites apply`.
|
|
3
|
+
*/
|
|
4
|
+
import type { CliExecutorContext } from "../../../context.ts";
|
|
5
|
+
import type { Daemon, ScheduledJob, Site } from "./plan.ts";
|
|
6
|
+
export declare function site(id: number, name: string, overrides?: Partial<Site>): Site;
|
|
7
|
+
export declare function daemon(id: number, command: string, directory: string | null, overrides?: Partial<Daemon>): Daemon;
|
|
8
|
+
export declare function job(id: number, command: string, overrides?: Partial<ScheduledJob>): ScheduledJob;
|
|
9
|
+
type Call = [method: string, url: string, body?: unknown];
|
|
10
|
+
export interface FakeForge {
|
|
11
|
+
sites: Site[];
|
|
12
|
+
daemons: Daemon[];
|
|
13
|
+
siteDaemonIds: number[];
|
|
14
|
+
jobs: ScheduledJob[];
|
|
15
|
+
siteJobIds: number[];
|
|
16
|
+
databases: Array<{
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
}>;
|
|
20
|
+
users: Array<{
|
|
21
|
+
id: number;
|
|
22
|
+
name: string;
|
|
23
|
+
}>;
|
|
24
|
+
env: string;
|
|
25
|
+
/** Statuses a new site goes through, one per read. */
|
|
26
|
+
newSiteStatuses: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A fake Forge API client, enough for `apply`. It records every call.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fakeForge(initial?: Partial<FakeForge>): {
|
|
32
|
+
ctx: CliExecutorContext;
|
|
33
|
+
calls: Call[];
|
|
34
|
+
state: FakeForge;
|
|
35
|
+
client: {
|
|
36
|
+
get: import("vitest").Mock<(url: string) => Promise<{
|
|
37
|
+
data: {
|
|
38
|
+
id: string;
|
|
39
|
+
type: string;
|
|
40
|
+
attributes: {};
|
|
41
|
+
}[];
|
|
42
|
+
links: {};
|
|
43
|
+
meta: {
|
|
44
|
+
per_page: number;
|
|
45
|
+
next_cursor: null;
|
|
46
|
+
prev_cursor: null;
|
|
47
|
+
};
|
|
48
|
+
} | {
|
|
49
|
+
data: {
|
|
50
|
+
id: string;
|
|
51
|
+
type: string;
|
|
52
|
+
attributes: {};
|
|
53
|
+
};
|
|
54
|
+
}>>;
|
|
55
|
+
post: import("vitest").Mock<(raw: string, body: Record<string, unknown>) => Promise<{
|
|
56
|
+
data: {
|
|
57
|
+
id: string;
|
|
58
|
+
type: string;
|
|
59
|
+
attributes: {};
|
|
60
|
+
};
|
|
61
|
+
}>>;
|
|
62
|
+
put: import("vitest").Mock<(raw: string, body: Record<string, unknown>) => Promise<{
|
|
63
|
+
data: {
|
|
64
|
+
id: string;
|
|
65
|
+
type: string;
|
|
66
|
+
attributes: {};
|
|
67
|
+
};
|
|
68
|
+
} | null>>;
|
|
69
|
+
delete: import("vitest").Mock<(url: string) => Promise<void>>;
|
|
70
|
+
patch: import("vitest").Mock<import("@vitest/spy").Procedure>;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=test-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-fixtures.d.ts","sourceRoot":"","sources":["../../../../src/commands/sites/apply/test-fixtures.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5D,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,CAAC,IAAI,CAAM,GAAG,IAAI,CAmClF;AAED,wBAAgB,MAAM,CACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,MAAM,CAWR;AAED,wBAAgB,GAAG,CACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,OAAO,CAAC,YAAY,CAAM,GACpC,YAAY,CAcd;AAED,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AAsD1D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,OAAO,CAAC,SAAS,CAAM;;;;;yCAiB/B,MAAM;;;;;;;;gBA5ErB,QAAQ;gBAAM,WAAW;gBAAQ,WAAW;;;;;;;;;0CA6H5B,MAAM,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;yCAsCtC,MAAM,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;4CASlC,MAAM;;;EAYnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/command.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,6GAU7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAwFvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh-keys/sync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh-keys/sync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA8K3E;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgHpE"}
|
package/dist/context.d.ts
CHANGED
|
@@ -7,13 +7,27 @@
|
|
|
7
7
|
import type { HttpClient } from "@studiometa/forge-api";
|
|
8
8
|
import type { ExecutorContext } from "@studiometa/forge-core";
|
|
9
9
|
import { OutputFormatter } from "./output.ts";
|
|
10
|
+
/**
|
|
11
|
+
* Executor context of the CLI. It also tells the resolvers of --server and --site
|
|
12
|
+
* how to match names.
|
|
13
|
+
*/
|
|
14
|
+
export interface CliExecutorContext extends ExecutorContext {
|
|
15
|
+
/** Accept only a numeric ID or an exact name (`--exact` or `FORGE_EXACT_MATCH=1`). */
|
|
16
|
+
readonly exactMatch: boolean;
|
|
17
|
+
}
|
|
10
18
|
export interface CommandOptions {
|
|
11
19
|
[key: string]: string | boolean | string[] | undefined;
|
|
12
20
|
format?: string;
|
|
13
21
|
f?: string;
|
|
14
22
|
token?: string;
|
|
15
23
|
"no-color"?: boolean;
|
|
24
|
+
exact?: boolean;
|
|
16
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Whether --server and --site must match an exact name: the `--exact` flag or the
|
|
28
|
+
* `FORGE_EXACT_MATCH` environment variable (`1` or `true`) turns it on.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isExactMatch(options: CommandOptions, env?: Record<string, string | undefined>): boolean;
|
|
17
31
|
/**
|
|
18
32
|
* Context containing all dependencies needed by command handlers.
|
|
19
33
|
*/
|
|
@@ -23,7 +37,7 @@ export interface CommandContext {
|
|
|
23
37
|
/** Raw CLI options */
|
|
24
38
|
readonly options: CommandOptions;
|
|
25
39
|
/** Create an ExecutorContext from this command context */
|
|
26
|
-
createExecutorContext(token: string):
|
|
40
|
+
createExecutorContext(token: string): CliExecutorContext;
|
|
27
41
|
/** Resolve the API token or throw ConfigError */
|
|
28
42
|
getToken(): string;
|
|
29
43
|
}
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,sFAAsF;IACtF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAGT;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,0DAA0D;IAC1D,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACzD,iDAAiD;IACjD,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,cAAc,CAkC1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE;IAC3C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,GAAG,cAAc,CA8BjB"}
|
|
@@ -319,17 +319,28 @@ var OutputFormatter = class {
|
|
|
319
319
|
//#endregion
|
|
320
320
|
//#region src/context.ts
|
|
321
321
|
/**
|
|
322
|
+
* Whether --server and --site must match an exact name: the `--exact` flag or the
|
|
323
|
+
* `FORGE_EXACT_MATCH` environment variable (`1` or `true`) turns it on.
|
|
324
|
+
*/
|
|
325
|
+
function isExactMatch(options, env = process.env) {
|
|
326
|
+
const value = env.FORGE_EXACT_MATCH?.trim().toLowerCase();
|
|
327
|
+
return options.exact === true || value === "1" || value === "true";
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
322
330
|
* Creates a command context from CLI options.
|
|
323
331
|
*/
|
|
324
332
|
function createContext(options = {}) {
|
|
325
333
|
const rawFormat = options.format ?? options.f ?? "human";
|
|
334
|
+
const formatter = new OutputFormatter(isOutputFormat(rawFormat) ? rawFormat : "human", options["no-color"] === true);
|
|
335
|
+
const exactMatch = isExactMatch(options);
|
|
326
336
|
return {
|
|
327
|
-
formatter
|
|
337
|
+
formatter,
|
|
328
338
|
options,
|
|
329
339
|
createExecutorContext(token) {
|
|
330
340
|
return {
|
|
331
341
|
client: new HttpClient({ token }),
|
|
332
|
-
organizationSlug: typeof options.org === "string" && options.org || getOrganizationSlug(createConfigStore$1()) || void 0
|
|
342
|
+
organizationSlug: typeof options.org === "string" && options.org || getOrganizationSlug(createConfigStore$1()) || void 0,
|
|
343
|
+
exactMatch
|
|
333
344
|
};
|
|
334
345
|
},
|
|
335
346
|
getToken() {
|
|
@@ -364,7 +375,8 @@ function createTestContext(overrides) {
|
|
|
364
375
|
if (!overrides.mockClient) throw new Error("createTestContext: provide mockClient to use createExecutorContext in tests");
|
|
365
376
|
return {
|
|
366
377
|
client: overrides.mockClient,
|
|
367
|
-
organizationSlug: "test-org"
|
|
378
|
+
organizationSlug: "test-org",
|
|
379
|
+
exactMatch: isExactMatch(opts, {})
|
|
368
380
|
};
|
|
369
381
|
},
|
|
370
382
|
getToken() {
|
|
@@ -440,4 +452,4 @@ function exitWithValidationError(field, usage, formatter) {
|
|
|
440
452
|
//#endregion
|
|
441
453
|
export { isOutputFormat as C, isCliError as S, setToken as _, runCommand as a, ConfigError as b, OutputFormatter as c, createConfigStore$1 as d, deleteToken as f, setOrganizationSlug as g, getToken$1 as h, handleError as i, colors as l, getOrganizationSlug as m, exitWithError as n, createContext as o, getConfig as p, exitWithValidationError as r, createTestContext as s, ExitCode as t, setColorEnabled as u, ApiError as v, ValidationError as x, CliError as y };
|
|
442
454
|
|
|
443
|
-
//# sourceMappingURL=error-handler-
|
|
455
|
+
//# sourceMappingURL=error-handler-s-BOJ1-h.js.map
|