@elia97/officina 0.11.0 → 0.13.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/README.md +92 -12
- package/dist/bin.js +4 -1
- package/dist/checks/bundle.js +13 -2
- package/dist/checks/doctor.js +13 -10
- package/dist/checks/migrate.d.ts +2 -0
- package/dist/checks/migrate.js +44 -0
- package/dist/checks/placeholders.js +15 -6
- package/dist/checks/secrets.d.ts +2 -0
- package/dist/checks/secrets.js +46 -0
- package/dist/checks/smoke.js +20 -4
- package/dist/index.d.ts +1 -0
- package/dist/lib/alignment.d.ts +1 -0
- package/dist/lib/alignment.js +4 -2
- package/dist/lib/bundle-css.d.ts +7 -0
- package/dist/lib/bundle-css.js +19 -0
- package/dist/lib/check-placeholders.d.ts +3 -1
- package/dist/lib/check-placeholders.js +9 -3
- package/dist/lib/check-routes.js +5 -3
- package/dist/lib/cli.d.ts +1 -0
- package/dist/lib/cli.js +1 -0
- package/dist/lib/config-gaps.js +1 -6
- package/dist/lib/config.d.ts +26 -1
- package/dist/lib/config.js +28 -2
- package/dist/lib/database-auth.d.ts +5 -0
- package/dist/lib/database-auth.js +81 -0
- package/dist/lib/env-schema.d.ts +8 -0
- package/dist/lib/env-schema.js +37 -0
- package/dist/lib/migrate.d.ts +11 -0
- package/dist/lib/migrate.js +29 -0
- package/dist/lib/routes.js +5 -3
- package/dist/lib/secrets.d.ts +10 -0
- package/dist/lib/secrets.js +53 -0
- package/dist/lib/smoke-on-demand.d.ts +8 -0
- package/dist/lib/smoke-on-demand.js +65 -0
- package/dist/lib/smoke-production.d.ts +4 -1
- package/dist/lib/smoke-production.js +2 -0
- package/dist/lib/validate.d.ts +2 -0
- package/dist/lib/validate.js +9 -1
- package/dist/lib/vercel-build.js +0 -1
- package/dist/lib/workflows.d.ts +14 -0
- package/dist/lib/workflows.js +44 -3
- package/dist/smoke.d.ts +1 -0
- package/dist/smoke.js +1 -0
- package/package.json +1 -1
- package/presets/biome.base.json +2 -1
package/dist/lib/validate.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export type Check = (value: unknown, path: string) => string[];
|
|
2
|
+
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
2
3
|
export declare function typeName(value: unknown): string;
|
|
3
4
|
export declare const problem: (path: string, expected: string, value: unknown) => string;
|
|
4
5
|
export declare const aString: Check;
|
|
5
6
|
export declare const aNumber: Check;
|
|
6
7
|
export declare const aFunction: Check;
|
|
7
8
|
export declare const aStringOrNull: Check;
|
|
9
|
+
export declare const anEnvName: Check;
|
|
8
10
|
export declare const anArrayOf: (item: Check) => Check;
|
|
9
11
|
export declare const aRecordOf: (item: Check) => Check;
|
|
10
12
|
export declare const oneOf: (expected: string, allowed: readonly unknown[]) => Check;
|
package/dist/lib/validate.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1
|
+
export const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2
2
|
const NAMES = new Map([
|
|
3
3
|
['string', 'una stringa'],
|
|
4
4
|
['number', 'un numero'],
|
|
@@ -18,6 +18,14 @@ export const aString = (value, path) => (typeof value === 'string' ? [] : [probl
|
|
|
18
18
|
export const aNumber = (value, path) => (typeof value === 'number' ? [] : [problem(path, 'un numero', value)]);
|
|
19
19
|
export const aFunction = (value, path) => typeof value === 'function' ? [] : [problem(path, 'una funzione', value)];
|
|
20
20
|
export const aStringOrNull = (value, path) => typeof value === 'string' || value === null ? [] : [problem(path, 'una stringa oppure null', value)];
|
|
21
|
+
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
22
|
+
export const anEnvName = (value, path) => {
|
|
23
|
+
if (typeof value !== 'string')
|
|
24
|
+
return [problem(path, 'una stringa', value)];
|
|
25
|
+
if (ENV_NAME.test(value))
|
|
26
|
+
return [];
|
|
27
|
+
return [`${path}: atteso il nome di una variabile d'ambiente, ricevuto ${JSON.stringify(value)}`];
|
|
28
|
+
};
|
|
21
29
|
export const anArrayOf = (item) => (value, path) => Array.isArray(value)
|
|
22
30
|
? value.flatMap((entry, index) => item(entry, `${path}[${index}]`))
|
|
23
31
|
: [problem(path, 'un array', value)];
|
package/dist/lib/vercel-build.js
CHANGED
|
@@ -115,7 +115,6 @@ export function ssrRoutes(files) {
|
|
|
115
115
|
const found = firstManifest(files);
|
|
116
116
|
return found === null ? null : routesOf(found.host, found.manifest, files);
|
|
117
117
|
}
|
|
118
|
-
// `routePattern` non legge i segmenti misti (`[slug].md`, `post-[id]`), che il pattern del manifest di Astro sì.
|
|
119
118
|
function astroPattern(route, pattern) {
|
|
120
119
|
if (typeof pattern === 'string') {
|
|
121
120
|
try {
|
package/dist/lib/workflows.d.ts
CHANGED
|
@@ -4,3 +4,17 @@ export declare const isLive: (line: string) => boolean;
|
|
|
4
4
|
export declare const mentions: (source: string | undefined, needle: string) => boolean;
|
|
5
5
|
/** Le action del progetto devono stare alla stessa versione del pacchetto installato. */
|
|
6
6
|
export declare function workflowGaps({ read }: ProjectFiles, version: string): ContractGap[];
|
|
7
|
+
export interface ActionInputs {
|
|
8
|
+
workflow: string;
|
|
9
|
+
action: string;
|
|
10
|
+
inputs: readonly {
|
|
11
|
+
name: string;
|
|
12
|
+
reason: string;
|
|
13
|
+
notFrom?: readonly {
|
|
14
|
+
secret: string;
|
|
15
|
+
reason: string;
|
|
16
|
+
}[];
|
|
17
|
+
}[];
|
|
18
|
+
}
|
|
19
|
+
/** Un workflow che non usa l'action lo segnala già `workflowGaps`. */
|
|
20
|
+
export declare function actionInputGaps({ read }: ProjectFiles, { workflow, action, inputs }: ActionInputs): ContractGap[];
|
package/dist/lib/workflows.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { parse } from 'yaml';
|
|
2
|
+
import { isRecord } from './validate.js';
|
|
3
3
|
export const isLive = (line) => !line.trimStart().startsWith('#');
|
|
4
4
|
const liveLines = (source) => source.split(/\r?\n/).filter(isLive);
|
|
5
5
|
export const mentions = (source, needle) => source !== undefined && liveLines(source).some((line) => line.includes(needle));
|
|
@@ -36,8 +36,9 @@ function refGap(line, ref, name, expected) {
|
|
|
36
36
|
? undefined
|
|
37
37
|
: `\`${name}@${ref.slice(0, 7)}… ${declared}\`: il pacchetto installato è la ${expected.slice(1)}`;
|
|
38
38
|
}
|
|
39
|
+
const actionName = (action) => `Elia97/officina/actions/${action}`;
|
|
39
40
|
function actionGap(source, action, version) {
|
|
40
|
-
const name =
|
|
41
|
+
const name = actionName(action);
|
|
41
42
|
if (source === undefined)
|
|
42
43
|
return `manca: i suoi passi arrivano da \`${name}\``;
|
|
43
44
|
const found = refOf(source, name);
|
|
@@ -50,3 +51,43 @@ export function workflowGaps({ read }, version) {
|
|
|
50
51
|
return message === undefined ? [] : [{ path: workflow, message }];
|
|
51
52
|
});
|
|
52
53
|
}
|
|
54
|
+
function parsed(source) {
|
|
55
|
+
try {
|
|
56
|
+
return { workflow: parse(source) };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
return { error: `non è YAML valido: ${String(error).replace(/\n[\s\S]*$/, '')}` };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function stepsUsing(source, action) {
|
|
63
|
+
const result = parsed(source);
|
|
64
|
+
if ('error' in result)
|
|
65
|
+
return result.error;
|
|
66
|
+
const { workflow } = result;
|
|
67
|
+
const jobs = isRecord(workflow) && isRecord(workflow.jobs) ? Object.values(workflow.jobs) : [];
|
|
68
|
+
return jobs
|
|
69
|
+
.flatMap((job) => (isRecord(job) && Array.isArray(job.steps) ? job.steps : []))
|
|
70
|
+
.filter((step) => isRecord(step) && String(step.uses).startsWith(`${actionName(action)}@`));
|
|
71
|
+
}
|
|
72
|
+
const inputValue = (step, input) => isRecord(step.with) ? step.with[input] : undefined;
|
|
73
|
+
const receives = (step, input) => {
|
|
74
|
+
const value = inputValue(step, input);
|
|
75
|
+
return value !== undefined && value !== null && value !== '';
|
|
76
|
+
};
|
|
77
|
+
const receivesFrom = (step, input, secret) => String(inputValue(step, input)).split(/\W/).includes(secret);
|
|
78
|
+
/** Un workflow che non usa l'action lo segnala già `workflowGaps`. */
|
|
79
|
+
export function actionInputGaps({ read }, { workflow, action, inputs }) {
|
|
80
|
+
const source = read(workflow);
|
|
81
|
+
if (source === undefined)
|
|
82
|
+
return [];
|
|
83
|
+
const steps = stepsUsing(source, action);
|
|
84
|
+
if (typeof steps === 'string')
|
|
85
|
+
return [{ path: workflow, message: steps }];
|
|
86
|
+
const gap = (message) => [{ path: workflow, message: `\`${actionName(action)}\` ${message}` }];
|
|
87
|
+
return inputs.flatMap(({ name, reason, notFrom = [] }) => {
|
|
88
|
+
if (steps.some((step) => !receives(step, name)))
|
|
89
|
+
return gap(`non riceve \`${name}\`: ${reason}`);
|
|
90
|
+
const wrong = notFrom.find(({ secret }) => steps.some((step) => receivesFrom(step, name, secret)));
|
|
91
|
+
return wrong === undefined ? [] : gap(`riceve \`${name}\` da \`${wrong.secret}\`: ${wrong.reason}`);
|
|
92
|
+
});
|
|
93
|
+
}
|
package/dist/smoke.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { NON_HTML_ROUTES } from './lib/routes.ts';
|
|
2
|
+
export { checkOnDemandPages } from './lib/smoke-on-demand.ts';
|
|
2
3
|
export { checkBotIdChallenge, checkCanonicalHost, checkPages, checkSecurityHeaders, checkTrailingSlash, DEFAULT_CHECKS, SECURITY_HEADERS, } from './lib/smoke-production.ts';
|
package/dist/smoke.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { NON_HTML_ROUTES } from './lib/routes.js';
|
|
2
|
+
export { checkOnDemandPages } from './lib/smoke-on-demand.js';
|
|
2
3
|
export { checkBotIdChallenge, checkCanonicalHost, checkPages, checkSecurityHeaders, checkTrailingSlash, DEFAULT_CHECKS, SECURITY_HEADERS, } from './lib/smoke-production.js';
|
package/package.json
CHANGED