@smoothbricks/cli 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +14 -0
- package/dist/github-ci/index.d.ts +12 -0
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +72 -4
- package/dist/monorepo/ci-workflow.d.ts +26 -0
- package/dist/monorepo/ci-workflow.d.ts.map +1 -0
- package/dist/monorepo/ci-workflow.js +201 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +97 -5
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +4 -2
- package/dist/monorepo/publish-workflow.d.ts +7 -1
- package/dist/monorepo/publish-workflow.d.ts.map +1 -1
- package/dist/monorepo/publish-workflow.js +59 -15
- package/managed/raw/git-format-staged.yml +4 -0
- package/package.json +2 -2
- package/src/cli.ts +35 -5
- package/src/github-ci/index.ts +94 -8
- package/src/monorepo/__tests__/ci-workflow.test.ts +34 -0
- package/src/monorepo/__tests__/publish-workflow.test.ts +65 -2
- package/src/monorepo/ci-workflow.ts +229 -0
- package/src/monorepo/managed-files.ts +115 -5
- package/src/monorepo/package-policy.test.ts +16 -6
- package/src/monorepo/package-policy.ts +4 -2
- package/src/monorepo/publish-workflow.ts +73 -16
- package/managed/templates/github/workflows/ci.yml +0 -102
package/dist/cli.js
CHANGED
|
@@ -252,6 +252,8 @@ function buildProgram() {
|
|
|
252
252
|
.requiredOption('--target <target>')
|
|
253
253
|
.option('--name <name>')
|
|
254
254
|
.option('--step <step>')
|
|
255
|
+
.option('--mode <mode>', 'auto, affected, or run-many', 'auto')
|
|
256
|
+
.option('--configuration <configuration>')
|
|
255
257
|
.action(async (options) => {
|
|
256
258
|
const { githubCiNxSmart } = await import('./github-ci/index.js');
|
|
257
259
|
await githubCiNxSmart(await findRepoRoot(), options);
|
|
@@ -260,10 +262,22 @@ function buildProgram() {
|
|
|
260
262
|
.command('nx-run-many')
|
|
261
263
|
.requiredOption('--targets <targets>')
|
|
262
264
|
.option('--projects <projects>')
|
|
265
|
+
.option('--configuration <configuration>')
|
|
263
266
|
.action(async (options) => {
|
|
264
267
|
const { githubCiNxRunMany } = await import('./github-ci/index.js');
|
|
265
268
|
await githubCiNxRunMany(await findRepoRoot(), options);
|
|
266
269
|
});
|
|
270
|
+
githubCi
|
|
271
|
+
.command('nx-deploy')
|
|
272
|
+
.requiredOption('--configuration <configuration>')
|
|
273
|
+
.option('--mode <mode>', 'auto, affected, or run-many', 'run-many')
|
|
274
|
+
.option('--name <name>')
|
|
275
|
+
.option('--step <step>')
|
|
276
|
+
.option('--verify', 'run build, lint, and test before deploy')
|
|
277
|
+
.action(async (options) => {
|
|
278
|
+
const { githubCiNxDeploy } = await import('./github-ci/index.js');
|
|
279
|
+
await githubCiNxDeploy(await findRepoRoot(), options);
|
|
280
|
+
});
|
|
267
281
|
return program;
|
|
268
282
|
}
|
|
269
283
|
function booleanOption(value) {
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
type NxSmartMode = 'auto' | 'affected' | 'run-many';
|
|
1
2
|
export declare function cleanupGithubCiCache(root: string): Promise<void>;
|
|
2
3
|
export declare function githubCiNxSmart(root: string, options: {
|
|
3
4
|
target: string;
|
|
4
5
|
name?: string;
|
|
5
6
|
step?: string;
|
|
7
|
+
mode?: NxSmartMode;
|
|
8
|
+
configuration?: string;
|
|
6
9
|
}): Promise<void>;
|
|
7
10
|
export declare function githubCiNxRunMany(root: string, options: {
|
|
8
11
|
targets: string;
|
|
9
12
|
projects?: string;
|
|
13
|
+
configuration?: string;
|
|
10
14
|
}): Promise<void>;
|
|
15
|
+
export declare function githubCiNxDeploy(root: string, options: {
|
|
16
|
+
configuration: string;
|
|
17
|
+
mode?: NxSmartMode;
|
|
18
|
+
name?: string;
|
|
19
|
+
step?: string;
|
|
20
|
+
verify?: boolean;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export {};
|
|
11
23
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAMA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE;AAmFD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAMA,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE;AAmFD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACpG,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrG,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
|
package/dist/github-ci/index.js
CHANGED
|
@@ -104,10 +104,12 @@ export async function githubCiNxSmart(root, options) {
|
|
|
104
104
|
const name = options.name ?? options.target;
|
|
105
105
|
const step = options.step ?? '';
|
|
106
106
|
await createGithubStatus(name, step);
|
|
107
|
-
const mode =
|
|
108
|
-
const nxArgs = mode === 'run-many'
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
const mode = resolveNxSmartMode(options.mode ?? 'auto');
|
|
108
|
+
const nxArgs = mode === 'run-many' ? ['run-many', '-t', options.target] : ['affected', '-t', options.target];
|
|
109
|
+
if (options.configuration) {
|
|
110
|
+
nxArgs.push(`--configuration=${options.configuration}`);
|
|
111
|
+
}
|
|
112
|
+
nxArgs.push('--parallel=5');
|
|
111
113
|
const status = await runStatus('nx', nxArgs, root);
|
|
112
114
|
await updateGithubStatus(name, status === 0 ? 'success' : 'failure', step);
|
|
113
115
|
if (status !== 0) {
|
|
@@ -119,8 +121,74 @@ export async function githubCiNxRunMany(root, options) {
|
|
|
119
121
|
if (options.projects) {
|
|
120
122
|
nxArgs.push(`--projects=${options.projects}`);
|
|
121
123
|
}
|
|
124
|
+
if (options.configuration) {
|
|
125
|
+
nxArgs.push(`--configuration=${options.configuration}`);
|
|
126
|
+
}
|
|
122
127
|
await run('nx', nxArgs, root);
|
|
123
128
|
}
|
|
129
|
+
export async function githubCiNxDeploy(root, options) {
|
|
130
|
+
const name = options.name ?? `Deploy ${options.configuration}`;
|
|
131
|
+
const step = options.step ?? '';
|
|
132
|
+
await createGithubStatus(name, step);
|
|
133
|
+
const mode = resolveNxSmartMode(options.mode ?? 'run-many');
|
|
134
|
+
const projects = await deployProjectsWithConfiguration(root, options.configuration, mode);
|
|
135
|
+
if (projects.length === 0) {
|
|
136
|
+
console.log(`No ${mode} deploy projects with configuration ${options.configuration}; skipping.`);
|
|
137
|
+
await updateGithubStatus(name, 'success', step);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const projectList = projects.join(',');
|
|
141
|
+
const targets = options.verify === true ? ['build', 'lint', 'test', 'deploy'] : ['deploy'];
|
|
142
|
+
for (const target of targets) {
|
|
143
|
+
const nxArgs = ['run-many', '-t', target, `--projects=${projectList}`, '--parallel=5'];
|
|
144
|
+
if (target === 'deploy') {
|
|
145
|
+
nxArgs.push(`--configuration=${options.configuration}`);
|
|
146
|
+
}
|
|
147
|
+
const status = await runStatus('nx', nxArgs, root);
|
|
148
|
+
if (status !== 0) {
|
|
149
|
+
await updateGithubStatus(name, 'failure', step);
|
|
150
|
+
throw new Error(`nx ${nxArgs.join(' ')} failed with exit code ${status}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
await updateGithubStatus(name, 'success', step);
|
|
154
|
+
}
|
|
155
|
+
function resolveNxSmartMode(mode) {
|
|
156
|
+
if (mode === 'affected' || mode === 'run-many') {
|
|
157
|
+
return mode;
|
|
158
|
+
}
|
|
159
|
+
return process.env.GITHUB_EVENT_NAME === 'push' && process.env.GITHUB_REF_NAME === 'main' ? 'run-many' : 'affected';
|
|
160
|
+
}
|
|
161
|
+
async function deployProjectsWithConfiguration(root, configuration, mode) {
|
|
162
|
+
const listArgs = mode === 'affected'
|
|
163
|
+
? ['show', 'projects', '--affected', '--withTarget', 'deploy', '--json']
|
|
164
|
+
: ['show', 'projects', '--withTarget', 'deploy', '--json'];
|
|
165
|
+
const result = await $ `nx ${listArgs}`.cwd(root).quiet();
|
|
166
|
+
const candidates = nxProjectList(decode(result.stdout));
|
|
167
|
+
const projects = [];
|
|
168
|
+
for (const project of candidates) {
|
|
169
|
+
if (await deployTargetHasConfiguration(root, project, configuration)) {
|
|
170
|
+
projects.push(project);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return projects.sort((a, b) => a.localeCompare(b));
|
|
174
|
+
}
|
|
175
|
+
async function deployTargetHasConfiguration(root, project, configuration) {
|
|
176
|
+
const result = await $ `nx show project ${project} --json`.cwd(root).quiet();
|
|
177
|
+
const parsed = JSON.parse(decode(result.stdout));
|
|
178
|
+
const targets = recordValue(parsed)?.targets;
|
|
179
|
+
const deploy = recordValue(targets)?.deploy;
|
|
180
|
+
const configurations = recordValue(deploy)?.configurations;
|
|
181
|
+
return recordValue(configurations)?.[configuration] !== undefined;
|
|
182
|
+
}
|
|
183
|
+
function nxProjectList(output) {
|
|
184
|
+
const parsed = JSON.parse(output);
|
|
185
|
+
return Array.isArray(parsed) ? parsed.filter((project) => typeof project === 'string') : [];
|
|
186
|
+
}
|
|
187
|
+
function recordValue(value) {
|
|
188
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
189
|
+
? value
|
|
190
|
+
: undefined;
|
|
191
|
+
}
|
|
124
192
|
async function createGithubStatus(name, step) {
|
|
125
193
|
await postGithubStatus(name, 'pending', `Running ${name}...`, step);
|
|
126
194
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare enum CiWorkflowStepKind {
|
|
2
|
+
Checkout = "checkout",
|
|
3
|
+
SetupDevenv = "setup-devenv",
|
|
4
|
+
SetNxShas = "set-nx-shas",
|
|
5
|
+
RestoreNxCache = "restore-nx-cache",
|
|
6
|
+
Build = "build",
|
|
7
|
+
Lint = "lint",
|
|
8
|
+
UnitTests = "unit-tests",
|
|
9
|
+
Deploy = "deploy",
|
|
10
|
+
SaveNxCache = "save-nx-cache",
|
|
11
|
+
UploadTraceDbs = "upload-trace-dbs",
|
|
12
|
+
SaveNixDevenv = "save-nix-devenv"
|
|
13
|
+
}
|
|
14
|
+
export interface CiWorkflowStep {
|
|
15
|
+
kind: CiWorkflowStepKind;
|
|
16
|
+
name: string;
|
|
17
|
+
number: number;
|
|
18
|
+
}
|
|
19
|
+
export interface CiWorkflowDefinitionOptions {
|
|
20
|
+
deploy: boolean;
|
|
21
|
+
deployProvider?: 'cloudflare';
|
|
22
|
+
pushBranches: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare function defineCiWorkflow(options: CiWorkflowDefinitionOptions): CiWorkflowStep[];
|
|
25
|
+
export declare function renderCiWorkflowYaml(options: CiWorkflowDefinitionOptions): string;
|
|
26
|
+
//# sourceMappingURL=ci-workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/ci-workflow.ts"],"names":[],"mappings":"AAAA,oBAAY,kBAAkB;IAC5B,QAAQ,aAAa;IACrB,WAAW,iBAAiB;IAC5B,SAAS,gBAAgB;IACzB,cAAc,qBAAqB;IACnC,KAAK,UAAU;IACf,IAAI,SAAS;IACb,SAAS,eAAe;IACxB,MAAM,WAAW;IACjB,WAAW,kBAAkB;IAC7B,cAAc,qBAAqB;IACnC,aAAa,oBAAoB;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,cAAc,EAAE,CAmBvF;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,MAAM,CAGjF"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
export var CiWorkflowStepKind;
|
|
2
|
+
(function (CiWorkflowStepKind) {
|
|
3
|
+
CiWorkflowStepKind["Checkout"] = "checkout";
|
|
4
|
+
CiWorkflowStepKind["SetupDevenv"] = "setup-devenv";
|
|
5
|
+
CiWorkflowStepKind["SetNxShas"] = "set-nx-shas";
|
|
6
|
+
CiWorkflowStepKind["RestoreNxCache"] = "restore-nx-cache";
|
|
7
|
+
CiWorkflowStepKind["Build"] = "build";
|
|
8
|
+
CiWorkflowStepKind["Lint"] = "lint";
|
|
9
|
+
CiWorkflowStepKind["UnitTests"] = "unit-tests";
|
|
10
|
+
CiWorkflowStepKind["Deploy"] = "deploy";
|
|
11
|
+
CiWorkflowStepKind["SaveNxCache"] = "save-nx-cache";
|
|
12
|
+
CiWorkflowStepKind["UploadTraceDbs"] = "upload-trace-dbs";
|
|
13
|
+
CiWorkflowStepKind["SaveNixDevenv"] = "save-nix-devenv";
|
|
14
|
+
})(CiWorkflowStepKind || (CiWorkflowStepKind = {}));
|
|
15
|
+
export function defineCiWorkflow(options) {
|
|
16
|
+
const steps = [
|
|
17
|
+
{ kind: CiWorkflowStepKind.Checkout, name: '📥 Checkout' },
|
|
18
|
+
{ kind: CiWorkflowStepKind.SetupDevenv, name: '🧱 Setup Nix/devenv' },
|
|
19
|
+
{ kind: CiWorkflowStepKind.SetNxShas, name: '🧭 Set Nx SHAs' },
|
|
20
|
+
{ kind: CiWorkflowStepKind.RestoreNxCache, name: '🧠 Restore Nx cache' },
|
|
21
|
+
{ kind: CiWorkflowStepKind.Build, name: '🔨 Build' },
|
|
22
|
+
{ kind: CiWorkflowStepKind.Lint, name: '🔍 Lint' },
|
|
23
|
+
{ kind: CiWorkflowStepKind.UnitTests, name: '🧪 Unit Tests' },
|
|
24
|
+
];
|
|
25
|
+
if (options.deploy) {
|
|
26
|
+
steps.push({ kind: CiWorkflowStepKind.Deploy, name: '🚀 Deploy Staging' });
|
|
27
|
+
}
|
|
28
|
+
steps.push({ kind: CiWorkflowStepKind.SaveNxCache, name: '💾 Save Nx cache' }, { kind: CiWorkflowStepKind.UploadTraceDbs, name: '📎 Upload trace DBs' }, { kind: CiWorkflowStepKind.SaveNixDevenv, name: '🧹 Cleanup and cache Nix/devenv' });
|
|
29
|
+
return steps.map((step, index) => ({ ...step, number: index + 2 }));
|
|
30
|
+
}
|
|
31
|
+
export function renderCiWorkflowYaml(options) {
|
|
32
|
+
const steps = defineCiWorkflow(options);
|
|
33
|
+
return `${renderCiWorkflowHeader(options)}${renderCiWorkflowSteps(steps, options)}`;
|
|
34
|
+
}
|
|
35
|
+
function renderCiWorkflowHeader(options) {
|
|
36
|
+
return `name: CI
|
|
37
|
+
|
|
38
|
+
on:
|
|
39
|
+
push:
|
|
40
|
+
branches:
|
|
41
|
+
${renderYamlList(options.pushBranches, 6)}
|
|
42
|
+
pull_request:
|
|
43
|
+
|
|
44
|
+
permissions:
|
|
45
|
+
actions: read
|
|
46
|
+
contents: read
|
|
47
|
+
statuses: write
|
|
48
|
+
|
|
49
|
+
defaults:
|
|
50
|
+
run:
|
|
51
|
+
working-directory: tooling/direnv
|
|
52
|
+
|
|
53
|
+
jobs:
|
|
54
|
+
main:
|
|
55
|
+
name: Validate
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
timeout-minutes: 45
|
|
58
|
+
env:
|
|
59
|
+
NIX_STORE_NAR: ${githubExpression('github.workspace')}/nix-store.nar
|
|
60
|
+
GH_TOKEN: ${githubExpression('github.token')}
|
|
61
|
+
steps:
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
function githubExpression(expression) {
|
|
65
|
+
return `$${`{{ ${expression} }}`}`;
|
|
66
|
+
}
|
|
67
|
+
function renderCiWorkflowSteps(steps, options) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
for (const step of steps) {
|
|
70
|
+
lines.push(...sectionLinesBefore(step));
|
|
71
|
+
lines.push(...commentLinesForStep(step));
|
|
72
|
+
lines.push(...yamlLinesForStep(step, options));
|
|
73
|
+
lines.push('');
|
|
74
|
+
}
|
|
75
|
+
return `${lines.join('\n').trimEnd()}\n`;
|
|
76
|
+
}
|
|
77
|
+
function sectionLinesBefore(step) {
|
|
78
|
+
if (step.kind === CiWorkflowStepKind.SetNxShas) {
|
|
79
|
+
return [' # --- Nx -----------------------------------------------------------------', ''];
|
|
80
|
+
}
|
|
81
|
+
if (step.kind === CiWorkflowStepKind.SaveNixDevenv) {
|
|
82
|
+
return [' # --- Cleanup ------------------------------------------------------------', ''];
|
|
83
|
+
}
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
function commentLinesForStep(step) {
|
|
87
|
+
if (step.kind === CiWorkflowStepKind.Checkout) {
|
|
88
|
+
return [' # Step 1: GitHub adds "Set up job" automatically', ' # Step 2'];
|
|
89
|
+
}
|
|
90
|
+
if (step.kind === CiWorkflowStepKind.SetupDevenv) {
|
|
91
|
+
return [
|
|
92
|
+
' # Step 3. Composite action internals do not affect top-level job step',
|
|
93
|
+
' # anchors; update the nx-smart --step values below if top-level steps move.',
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
if (step.kind === CiWorkflowStepKind.SetNxShas) {
|
|
97
|
+
return [` # Step ${step.number}`, ' # Sets the base and head SHAs required for the nx affected commands'];
|
|
98
|
+
}
|
|
99
|
+
if (step.kind === CiWorkflowStepKind.SaveNxCache) {
|
|
100
|
+
return [
|
|
101
|
+
` # Step ${step.number}`,
|
|
102
|
+
" # Nx's database cache needs artifact files and .nx/workspace-data DB",
|
|
103
|
+
' # metadata restored together; GitHub Actions cache is only the archive',
|
|
104
|
+
' # transport. Save runs only after prior required steps succeed on the default',
|
|
105
|
+
' # branch, so PRs may restore shared cache but cannot publish it.',
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
return [` # Step ${step.number}`];
|
|
109
|
+
}
|
|
110
|
+
function yamlLinesForStep(step, options) {
|
|
111
|
+
switch (step.kind) {
|
|
112
|
+
case CiWorkflowStepKind.Checkout:
|
|
113
|
+
return [
|
|
114
|
+
` - name: ${step.name}`,
|
|
115
|
+
' uses: actions/checkout@v6.0.2',
|
|
116
|
+
' with:',
|
|
117
|
+
' filter: blob:none',
|
|
118
|
+
' fetch-depth: 0',
|
|
119
|
+
];
|
|
120
|
+
case CiWorkflowStepKind.SetupDevenv:
|
|
121
|
+
return [` - name: ${step.name}`, ' id: setup', ' uses: ./.github/actions/setup-devenv'];
|
|
122
|
+
case CiWorkflowStepKind.SetNxShas:
|
|
123
|
+
return [
|
|
124
|
+
` - name: ${step.name}`,
|
|
125
|
+
' uses: nrwl/nx-set-shas@v5.0.1',
|
|
126
|
+
' with:',
|
|
127
|
+
' workflow-id: ci.yml',
|
|
128
|
+
];
|
|
129
|
+
case CiWorkflowStepKind.RestoreNxCache:
|
|
130
|
+
return [` - name: ${step.name}`, ' id: nx-cache', ' uses: ./.github/actions/cache-nx'];
|
|
131
|
+
case CiWorkflowStepKind.Build:
|
|
132
|
+
return nxSmartStep(step, 'build', 'Build');
|
|
133
|
+
case CiWorkflowStepKind.Lint:
|
|
134
|
+
return nxSmartStep(step, 'lint', 'Lint');
|
|
135
|
+
case CiWorkflowStepKind.UnitTests:
|
|
136
|
+
return nxSmartStep(step, 'test', 'Unit Tests');
|
|
137
|
+
case CiWorkflowStepKind.Deploy:
|
|
138
|
+
return [
|
|
139
|
+
` - name: ${step.name}`,
|
|
140
|
+
' if:',
|
|
141
|
+
" ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}',",
|
|
142
|
+
' github.event.repository.default_branch) }}',
|
|
143
|
+
...deployEnvLines(options),
|
|
144
|
+
` run: smoo github-ci nx-deploy --configuration staging --mode affected --name "Deploy Staging" --step ${step.number}`,
|
|
145
|
+
];
|
|
146
|
+
case CiWorkflowStepKind.SaveNxCache:
|
|
147
|
+
return [
|
|
148
|
+
` - name: ${step.name}`,
|
|
149
|
+
' if:',
|
|
150
|
+
" ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}',",
|
|
151
|
+
" github.event.repository.default_branch) && steps.nx-cache.outputs.cache-hit != 'true' }}",
|
|
152
|
+
' uses: actions/cache/save@v5.0.5',
|
|
153
|
+
' with:',
|
|
154
|
+
' path: |',
|
|
155
|
+
' .nx/cache',
|
|
156
|
+
' .nx/workspace-data/*.db*',
|
|
157
|
+
' key: ${{ runner.os }}-nx-db-v1-${{ github.sha }}',
|
|
158
|
+
];
|
|
159
|
+
case CiWorkflowStepKind.UploadTraceDbs:
|
|
160
|
+
return [
|
|
161
|
+
` - name: ${step.name}`,
|
|
162
|
+
' if: ${{ always() }}',
|
|
163
|
+
' uses: actions/upload-artifact@v7.0.1',
|
|
164
|
+
' with:',
|
|
165
|
+
' name: trace-results-${{ github.run_id }}',
|
|
166
|
+
' path: packages/*/.trace-results.db',
|
|
167
|
+
' if-no-files-found: ignore',
|
|
168
|
+
' retention-days: 14',
|
|
169
|
+
' include-hidden-files: true',
|
|
170
|
+
];
|
|
171
|
+
case CiWorkflowStepKind.SaveNixDevenv:
|
|
172
|
+
return [
|
|
173
|
+
` - name: ${step.name}`,
|
|
174
|
+
' if: ${{ always() }}',
|
|
175
|
+
' uses: ./.github/actions/save-nix-devenv',
|
|
176
|
+
' with:',
|
|
177
|
+
' nix-cache-hit: ${{ steps.setup.outputs.nix-cache-hit }}',
|
|
178
|
+
' devenv-cache-hit: ${{ steps.setup.outputs.devenv-cache-hit }}',
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function deployEnvLines(options) {
|
|
183
|
+
if (options.deployProvider !== 'cloudflare') {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
return [
|
|
187
|
+
' env:',
|
|
188
|
+
' CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}',
|
|
189
|
+
' CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}',
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
function nxSmartStep(step, target, name) {
|
|
193
|
+
return [
|
|
194
|
+
` - name: ${step.name}`,
|
|
195
|
+
` run: smoo github-ci nx-smart --target ${target} --name "${name}" --step ${step.number}`,
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
function renderYamlList(values, spaces) {
|
|
199
|
+
const indent = ' '.repeat(spaces);
|
|
200
|
+
return values.map((value) => `${indent}- ${value}`).join('\n');
|
|
201
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AAwFD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,EAAE,CAG/F;AA4KD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAIxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
1
2
|
import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
3
|
import { dirname, join, resolve } from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { listReleasePackages, readPackageJson } from '../lib/workspace.js';
|
|
6
|
+
import { renderCiWorkflowYaml } from './ci-workflow.js';
|
|
5
7
|
import { renderPublishWorkflowYaml } from './publish-workflow.js';
|
|
6
8
|
const managedFiles = [
|
|
7
9
|
{
|
|
@@ -34,8 +36,8 @@ const managedFiles = [
|
|
|
34
36
|
target: '.git-format-staged.yml',
|
|
35
37
|
},
|
|
36
38
|
{
|
|
37
|
-
kind: '
|
|
38
|
-
source: '
|
|
39
|
+
kind: 'generated',
|
|
40
|
+
source: 'ci-workflow',
|
|
39
41
|
target: '.github/workflows/ci.yml',
|
|
40
42
|
},
|
|
41
43
|
{
|
|
@@ -76,7 +78,7 @@ export function applyManagedFiles(root, mode) {
|
|
|
76
78
|
return managedFiles.map((file) => applyManagedFile(root, file, mode, context));
|
|
77
79
|
}
|
|
78
80
|
function applyManagedFile(root, file, mode, context) {
|
|
79
|
-
if (file.releasePackagesOnly === true && !context.hasReleasePackages) {
|
|
81
|
+
if (file.releasePackagesOnly === true && !context.hasReleasePackages && !context.hasProductionDeployTargets) {
|
|
80
82
|
return { target: file.target, action: 'skipped' };
|
|
81
83
|
}
|
|
82
84
|
const target = resolve(root, file.target);
|
|
@@ -107,8 +109,19 @@ function applyManagedFile(root, file, mode, context) {
|
|
|
107
109
|
}
|
|
108
110
|
function getManagedContent(file, context) {
|
|
109
111
|
if (file.kind === 'generated') {
|
|
112
|
+
if (file.source === 'ci-workflow') {
|
|
113
|
+
return renderCiWorkflowYaml({
|
|
114
|
+
deploy: context.hasStagingDeployTargets,
|
|
115
|
+
deployProvider: context.stagingDeployProvider,
|
|
116
|
+
pushBranches: context.ciPushBranches,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
110
119
|
if (file.source === 'publish-workflow') {
|
|
111
|
-
return renderPublishWorkflowYaml({
|
|
120
|
+
return renderPublishWorkflowYaml({
|
|
121
|
+
deploy: context.hasProductionDeployTargets,
|
|
122
|
+
deployProvider: context.productionDeployProvider,
|
|
123
|
+
repoName: context.repoName,
|
|
124
|
+
});
|
|
112
125
|
}
|
|
113
126
|
throw new Error(`Unknown generated managed file source ${file.source}`);
|
|
114
127
|
}
|
|
@@ -123,16 +136,95 @@ function getManagedContent(file, context) {
|
|
|
123
136
|
function getManagedFileContext(root) {
|
|
124
137
|
const packageJson = readPackageJson(join(root, 'package.json'));
|
|
125
138
|
const repoName = packageJson?.name ?? 'monorepo';
|
|
139
|
+
const ciPushBranches = getCiPushBranches(packageJson?.json);
|
|
140
|
+
const stagingDeploy = getDeployTargetInfo(root, 'staging');
|
|
141
|
+
const productionDeploy = getDeployTargetInfo(root, 'production');
|
|
126
142
|
const nodeModulesCacheKey = existsSync(join(root, 'bun.lock'))
|
|
127
143
|
? `$${"{{ hashFiles('bun.lock', 'package.json', 'packages/*/package.json') }}"}`
|
|
128
144
|
: `$${"{{ hashFiles('bun.lockb', 'package.json', 'packages/*/package.json') }}"}`;
|
|
129
|
-
return {
|
|
145
|
+
return {
|
|
146
|
+
hasReleasePackages: listReleasePackages(root, packageJson).length > 0,
|
|
147
|
+
hasStagingDeployTargets: stagingDeploy.exists,
|
|
148
|
+
hasProductionDeployTargets: productionDeploy.exists,
|
|
149
|
+
stagingDeployProvider: stagingDeploy.provider,
|
|
150
|
+
productionDeployProvider: productionDeploy.provider,
|
|
151
|
+
ciPushBranches,
|
|
152
|
+
nodeModulesCacheKey,
|
|
153
|
+
repoName,
|
|
154
|
+
};
|
|
130
155
|
}
|
|
131
156
|
function renderTemplate(context, template) {
|
|
132
157
|
return template
|
|
133
158
|
.replaceAll('{{REPO_NAME}}', context.repoName)
|
|
159
|
+
.replaceAll('__SMOO_CI_PUSH_BRANCHES__', renderYamlFlowList(context.ciPushBranches))
|
|
134
160
|
.replaceAll('{{NODE_MODULES_CACHE_KEY}}', context.nodeModulesCacheKey);
|
|
135
161
|
}
|
|
162
|
+
function getDeployTargetInfo(root, configuration) {
|
|
163
|
+
const output = execFileSync('nx', ['show', 'projects', '--withTarget', 'deploy', '--json'], {
|
|
164
|
+
cwd: root,
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
167
|
+
});
|
|
168
|
+
const projects = JSON.parse(output);
|
|
169
|
+
if (!Array.isArray(projects) || !projects.every((project) => typeof project === 'string')) {
|
|
170
|
+
return { exists: false };
|
|
171
|
+
}
|
|
172
|
+
let exists = false;
|
|
173
|
+
let provider;
|
|
174
|
+
for (const project of projects) {
|
|
175
|
+
const target = nxDeployTarget(root, project, configuration);
|
|
176
|
+
if (!target.exists) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
exists = true;
|
|
180
|
+
provider ??= target.provider;
|
|
181
|
+
}
|
|
182
|
+
return { exists, provider };
|
|
183
|
+
}
|
|
184
|
+
function nxDeployTarget(root, project, configuration) {
|
|
185
|
+
const output = execFileSync('nx', ['show', 'project', project, '--json'], {
|
|
186
|
+
cwd: root,
|
|
187
|
+
encoding: 'utf8',
|
|
188
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
189
|
+
});
|
|
190
|
+
const parsed = JSON.parse(output);
|
|
191
|
+
const projectJson = recordValue(parsed);
|
|
192
|
+
const targets = recordValue(projectJson?.targets);
|
|
193
|
+
const deploy = recordValue(targets?.deploy);
|
|
194
|
+
const configurations = recordValue(deploy?.configurations);
|
|
195
|
+
const config = recordValue(configurations?.[configuration]);
|
|
196
|
+
if (!config) {
|
|
197
|
+
return { exists: false };
|
|
198
|
+
}
|
|
199
|
+
const command = deployCommand(deploy, config);
|
|
200
|
+
return { exists: true, provider: command.includes('wrangler ') ? 'cloudflare' : undefined };
|
|
201
|
+
}
|
|
202
|
+
function deployCommand(deploy, config) {
|
|
203
|
+
const command = stringValue(config.command) ?? stringValue(recordValue(config.options)?.command);
|
|
204
|
+
return command ?? stringValue(recordValue(deploy?.options)?.command) ?? '';
|
|
205
|
+
}
|
|
206
|
+
function stringValue(value) {
|
|
207
|
+
return typeof value === 'string' ? value : undefined;
|
|
208
|
+
}
|
|
209
|
+
function getCiPushBranches(packageJson) {
|
|
210
|
+
const configured = readCiPushBranches(packageJson);
|
|
211
|
+
return configured.length > 0 ? configured : ['main'];
|
|
212
|
+
}
|
|
213
|
+
function readCiPushBranches(packageJson) {
|
|
214
|
+
const rootPackage = recordValue(packageJson);
|
|
215
|
+
const smoo = recordValue(rootPackage?.smoo);
|
|
216
|
+
const github = recordValue(smoo?.github);
|
|
217
|
+
const branches = Array.isArray(github?.pushBranches) ? github.pushBranches : [];
|
|
218
|
+
return branches.filter((branch) => typeof branch === 'string' && branch.length > 0);
|
|
219
|
+
}
|
|
220
|
+
function recordValue(value) {
|
|
221
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
222
|
+
? value
|
|
223
|
+
: undefined;
|
|
224
|
+
}
|
|
225
|
+
function renderYamlFlowList(values) {
|
|
226
|
+
return JSON.stringify(values);
|
|
227
|
+
}
|
|
136
228
|
function writeManagedFile(path, content, executable) {
|
|
137
229
|
mkdirSync(dirname(path), { recursive: true });
|
|
138
230
|
writeFileSync(path, content, { mode: executable ? 0o755 : 0o644 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;AA6BvD,YAAY,EAAE,0BAA0B,IAAI,iCAAiC,EAAE,sBAAsB,EAAE,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;AA6BvD,YAAY,EAAE,0BAA0B,IAAI,iCAAiC,EAAE,sBAAsB,EAAE,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,CAAC;AAYhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAuC7D;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI,CAwB7G;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoB7D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAezD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsC9D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyB3D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0DlE;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,MAAM,CAiC5G"}
|
|
@@ -9,10 +9,12 @@ import { getWorkspacePackageManifests, getWorkspacePackages, listPackageJsonReco
|
|
|
9
9
|
export { SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS };
|
|
10
10
|
const extraCommitScopes = ['release'];
|
|
11
11
|
const rootScriptPolicy = {
|
|
12
|
+
clean: 'nx run-many -t clean; nx reset',
|
|
13
|
+
'clean:node_modules': 'rm -rf node_modules && find e* t* p* -type d -name node_modules -print0 | xargs -0 rm -rvf',
|
|
14
|
+
'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
|
|
15
|
+
'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
|
|
12
16
|
lint: 'nx run-many -t lint',
|
|
13
17
|
'lint:fix': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --unstaged',
|
|
14
|
-
'format:staged': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml',
|
|
15
|
-
'format:changed': 'git-format-staged --config tooling/git-hooks/git-format-staged.yml --also-unstaged',
|
|
16
18
|
};
|
|
17
19
|
export function applyFixableMonorepoDefaults(root) {
|
|
18
20
|
applyRootScriptDefaults(root);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type PublishWorkflowBump = 'auto' | 'patch' | 'minor' | 'major' | 'prerelease';
|
|
2
|
-
export type PublishWorkflowCondition = 'version-mode-not-none' | 'failure' | 'always';
|
|
2
|
+
export type PublishWorkflowCondition = 'version-mode-not-none' | 'deploy-production' | 'failure' | 'always';
|
|
3
3
|
export type PublishWorkflowNxTarget = 'build' | 'lint' | 'test';
|
|
4
|
+
export type PublishWorkflowDeployEnvironment = 'none' | 'production';
|
|
4
5
|
export declare enum PublishWorkflowStepKind {
|
|
5
6
|
Checkout = "checkout",
|
|
6
7
|
SetupDevenv = "setup-devenv",
|
|
@@ -15,6 +16,7 @@ export declare enum PublishWorkflowStepKind {
|
|
|
15
16
|
UploadTraceDbs = "upload-trace-dbs",
|
|
16
17
|
ValidateMonorepoConfig = "validate-monorepo-config",
|
|
17
18
|
PublishRelease = "publish-release",
|
|
19
|
+
DeployProduction = "deploy-production",
|
|
18
20
|
SaveNixDevenv = "save-nix-devenv"
|
|
19
21
|
}
|
|
20
22
|
export interface PublishWorkflowStep {
|
|
@@ -29,10 +31,13 @@ export interface PublishWorkflowDefinition {
|
|
|
29
31
|
steps: PublishWorkflowStep[];
|
|
30
32
|
}
|
|
31
33
|
export interface PublishWorkflowDefinitionOptions {
|
|
34
|
+
deploy?: boolean;
|
|
35
|
+
deployProvider?: 'cloudflare';
|
|
32
36
|
repoName?: string;
|
|
33
37
|
}
|
|
34
38
|
export interface PublishWorkflowInputs {
|
|
35
39
|
bump: PublishWorkflowBump;
|
|
40
|
+
deployEnvironment: PublishWorkflowDeployEnvironment;
|
|
36
41
|
dryRun: boolean;
|
|
37
42
|
}
|
|
38
43
|
export interface PublishWorkflowVersionOutputs {
|
|
@@ -66,6 +71,7 @@ export interface PublishWorkflowCallbacks {
|
|
|
66
71
|
bump: PublishWorkflowBump;
|
|
67
72
|
dryRun: boolean;
|
|
68
73
|
}): Promise<void>;
|
|
74
|
+
deployProduction(): Promise<void>;
|
|
69
75
|
saveNixDevenv(input: PublishWorkflowSetupOutputs): Promise<void>;
|
|
70
76
|
}
|
|
71
77
|
export interface PublishWorkflowRunContext {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/publish-workflow.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC;AACtF,MAAM,MAAM,wBAAwB,GAAG,uBAAuB,GAAG,SAAS,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-workflow.d.ts","sourceRoot":"","sources":["../../src/monorepo/publish-workflow.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC;AACtF,MAAM,MAAM,wBAAwB,GAAG,uBAAuB,GAAG,mBAAmB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC5G,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAChE,MAAM,MAAM,gCAAgC,GAAG,MAAM,GAAG,YAAY,CAAC;AAErE,oBAAY,uBAAuB;IACjC,QAAQ,aAAa;IACrB,WAAW,iBAAiB;IAC5B,sBAAsB,6BAA6B;IACnD,kBAAkB,0BAA0B;IAC5C,qBAAqB,4BAA4B;IACjD,cAAc,oBAAoB;IAClC,yBAAyB,iCAAiC;IAC1D,KAAK,UAAU;IACf,IAAI,SAAS;IACb,SAAS,eAAe;IACxB,cAAc,qBAAqB;IACnC,sBAAsB,6BAA6B;IACnD,cAAc,oBAAoB;IAClC,gBAAgB,sBAAsB;IACtC,aAAa,oBAAoB;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gCAAgC;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,iBAAiB,EAAE,gCAAgC,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,WAAW,IAAI,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACpD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,qBAAqB,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,cAAc,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,mBAAmB,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;IAC9G,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,uBAAuB,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzF,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,cAAc,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,mBAAmB,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,aAAa,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,SAAS,EAAE,wBAAwB,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,6BAA6B,CAAC;IACvC,MAAM,EAAE,OAAO,CAAC;CACjB;AAID,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,gCAAqC,GAAG,yBAAyB,CAoE/G;AAMD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,yBAAyB,EACnC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAsEnC;AAoBD,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,gCAAqC,GAAG,MAAM,CAGhG"}
|