@wtfalch/foundry 0.64.0 → 0.65.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/plan/executor.d.ts
CHANGED
|
@@ -1765,7 +1765,7 @@ export interface FoundryStepExecutorPorts {
|
|
|
1765
1765
|
/**
|
|
1766
1766
|
* The stage copy (`copy_prod_to_stage`, run by the release tick). The host supplies the dump download and the
|
|
1767
1767
|
* backup storage; foundry builds the restore port itself and reads production's address live from Coolify.
|
|
1768
|
-
* Without it a copy request is refused with `no-copy-port`. The host needs `pg_restore`
|
|
1768
|
+
* Without it a copy request is refused with `no-copy-port`. The host needs `pg_restore` on PATH, of the production database's Postgres version or newer (platform-archon-db runs 18).
|
|
1769
1769
|
*/
|
|
1770
1770
|
stageCopy?: StageCopyHostConfig;
|
|
1771
1771
|
/**
|
|
@@ -6237,7 +6237,7 @@ function assertSameDatabaseHost(key, liveUrl, dbInternalUrl) {
|
|
|
6237
6237
|
/**
|
|
6238
6238
|
* Throws when `liveUrl`, kept as it is on the app, names another database than
|
|
6239
6239
|
* {@link ARCHON_POSTGRES_DB}: a hand-set URL on the wrong path, or a platform
|
|
6240
|
-
* still on
|
|
6240
|
+
* still on a retired database. Names the two databases only, never the URL.
|
|
6241
6241
|
*/
|
|
6242
6242
|
function assertArchonDatabasePath(key, liveUrl) {
|
|
6243
6243
|
let database;
|
package/dist/release/run.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { decide, healthRange, } from './decide.js';
|
|
2
|
-
import { formatWeights, formatWindow, recordedFrom, releaseKeys, } from './state.js';
|
|
2
|
+
import { formatRefusals, formatWeights, formatWindow, recordedFrom, releaseKeys, } from './state.js';
|
|
3
3
|
import { isStageCopyAction } from './types.js';
|
|
4
4
|
const REFUSAL_TEXT = {
|
|
5
5
|
'no-copy-port': 'copy refused: this host cannot restore',
|
|
@@ -79,6 +79,10 @@ export async function runRelease(input) {
|
|
|
79
79
|
[k.window]: formatWindow(next.window, next.release),
|
|
80
80
|
[k.signal]: decision.signal ? JSON.stringify(decision.signal) : null,
|
|
81
81
|
};
|
|
82
|
+
// Part of the run's writes: persisted with them, so a failed persist leaves neither. A run with none keeps it.
|
|
83
|
+
const lines = [...refused, ...decision.blocked];
|
|
84
|
+
if (lines.length > 0)
|
|
85
|
+
writes[k.refused] = formatRefusals(stamp, lines);
|
|
82
86
|
for (const d of recorded.held)
|
|
83
87
|
if (!next.held.includes(d))
|
|
84
88
|
writes[k.held(d)] = null;
|
|
@@ -132,6 +136,7 @@ export function settleStageCopy(input) {
|
|
|
132
136
|
writes[k.stageCopy] = `${stamp}|refused|${result.reason}`;
|
|
133
137
|
writes[k.stageCopyRetry] = null;
|
|
134
138
|
refused.push(REFUSAL_TEXT[result.reason] ?? `copy refused: ${result.reason}`);
|
|
139
|
+
writes[k.refused] = formatRefusals(stamp, refused);
|
|
135
140
|
return { writes, refused, consume: true };
|
|
136
141
|
}
|
|
137
142
|
writes[k.stageCopy] = `${stamp}|failed|${result.step}`;
|
package/dist/release/state.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export declare function releaseKeys(entry: string): {
|
|
|
48
48
|
stageCopyHandled: string;
|
|
49
49
|
/** The id of a request whose copy failed once; a second failure consumes it. */
|
|
50
50
|
stageCopyRetry: string;
|
|
51
|
+
/** JSON `{ at, lines }`: the latest run that refused or blocked something (see {@link formatRefusals}). */
|
|
52
|
+
refused: string;
|
|
51
53
|
};
|
|
52
54
|
export declare function formatWeights(w: Record<Color, number>): string;
|
|
53
55
|
export declare function parseWeights(value: string | undefined): Record<Color, number> | null;
|
|
@@ -60,6 +62,13 @@ export declare function formatWindow(window: WindowState, release: Recorded['rel
|
|
|
60
62
|
export declare function recordedFrom(ids: Record<string, string>, entryKey: string): Recorded | null;
|
|
61
63
|
/** Reads `bg.<id>.stagecopy`; a damaged value reads as absent. */
|
|
62
64
|
export declare function parseStageCopy(value: string | undefined): StageCopyState | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* The value of `bg.<id>.refused`: the run time and its refused lines, then its blocked lines. Capped at 20 lines
|
|
67
|
+
* of 300 characters so a bad run cannot grow the row. Callers write it only when `lines` is not empty.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatRefusals(at: string, lines: readonly string[]): string;
|
|
70
|
+
/** Reads `bg.<id>.refused`; a damaged value reads as absent. */
|
|
71
|
+
export declare function parseRefusals(value: string | undefined): ReleaseState['refused'];
|
|
63
72
|
export declare function readSignal(ids: Record<string, string>, entryKey: string): ReleaseSignal | null;
|
|
64
73
|
/** C2: the release state of one hosting entry, or null before blue/green recorded anything. */
|
|
65
74
|
export declare function readReleaseState(store: ReleaseStore, input: {
|
package/dist/release/state.js
CHANGED
|
@@ -25,6 +25,8 @@ export function releaseKeys(entry) {
|
|
|
25
25
|
stageCopyHandled: `${p}.stagecopyhandled`,
|
|
26
26
|
/** The id of a request whose copy failed once; a second failure consumes it. */
|
|
27
27
|
stageCopyRetry: `${p}.stagecopyretry`,
|
|
28
|
+
/** JSON `{ at, lines }`: the latest run that refused or blocked something (see {@link formatRefusals}). */
|
|
29
|
+
refused: `${p}.refused`,
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
32
|
export function formatWeights(w) {
|
|
@@ -122,6 +124,26 @@ export function parseStageCopy(value) {
|
|
|
122
124
|
}
|
|
123
125
|
return undefined;
|
|
124
126
|
}
|
|
127
|
+
const REFUSED_MAX_LINES = 20;
|
|
128
|
+
const REFUSED_MAX_LINE = 300;
|
|
129
|
+
const refusedSchema = z.object({ at: z.string(), lines: z.array(z.string()) });
|
|
130
|
+
/**
|
|
131
|
+
* The value of `bg.<id>.refused`: the run time and its refused lines, then its blocked lines. Capped at 20 lines
|
|
132
|
+
* of 300 characters so a bad run cannot grow the row. Callers write it only when `lines` is not empty.
|
|
133
|
+
*/
|
|
134
|
+
export function formatRefusals(at, lines) {
|
|
135
|
+
return JSON.stringify({
|
|
136
|
+
at,
|
|
137
|
+
lines: lines.slice(0, REFUSED_MAX_LINES).map((l) => l.slice(0, REFUSED_MAX_LINE)),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** Reads `bg.<id>.refused`; a damaged value reads as absent. */
|
|
141
|
+
export function parseRefusals(value) {
|
|
142
|
+
const parsed = refusedSchema.safeParse(parseJson(value));
|
|
143
|
+
if (!parsed.success || Number.isNaN(Date.parse(parsed.data.at)))
|
|
144
|
+
return undefined;
|
|
145
|
+
return parsed.data;
|
|
146
|
+
}
|
|
125
147
|
export function readSignal(ids, entryKey) {
|
|
126
148
|
const parsed = signalSchema.safeParse(parseJson(ids[releaseKeys(entryKey).signal]));
|
|
127
149
|
return parsed.success ? parsed.data : null;
|
|
@@ -133,6 +155,7 @@ export async function readReleaseState(store, input) {
|
|
|
133
155
|
if (!r)
|
|
134
156
|
return null;
|
|
135
157
|
const stageCopy = parseStageCopy(ids[releaseKeys(input.entryKey).stageCopy]);
|
|
158
|
+
const refused = parseRefusals(ids[releaseKeys(input.entryKey).refused]);
|
|
136
159
|
return {
|
|
137
160
|
entryKey: input.entryKey,
|
|
138
161
|
live: r.live,
|
|
@@ -144,6 +167,7 @@ export async function readReleaseState(store, input) {
|
|
|
144
167
|
held: r.held,
|
|
145
168
|
config: resolveReleaseConfig(input.entry),
|
|
146
169
|
...(stageCopy ? { stageCopy } : {}),
|
|
170
|
+
...(refused ? { refused } : {}),
|
|
147
171
|
...stageDeployOf(ids[releaseKeys(input.entryKey).stageDeploy]),
|
|
148
172
|
};
|
|
149
173
|
}
|
package/dist/release/types.d.ts
CHANGED
|
@@ -59,6 +59,14 @@ export interface ReleaseState {
|
|
|
59
59
|
outcome: 'ok' | 'failed';
|
|
60
60
|
detail: string;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* The latest run that refused or blocked something (`bg.<id>.refused`): its time and its refused lines then its
|
|
64
|
+
* blocked lines, as decide's fixed texts (at most 20 lines of 300 characters). A run with none leaves it as is.
|
|
65
|
+
*/
|
|
66
|
+
refused?: {
|
|
67
|
+
at: string;
|
|
68
|
+
lines: string[];
|
|
69
|
+
};
|
|
62
70
|
}
|
|
63
71
|
/** C3: what the last `copy_prod_to_stage` or `undo_stage_copy` request did. `detail` is fixed text or an id. */
|
|
64
72
|
export interface StageCopyState {
|