A dependency-free node20 action that triggers application.deploy or compose.deploy, then follows the deployment to a terminal status so a failed build fails the CI run. Snapshots the deployment list before triggering, so a concurrent deployment is never mistaken for this one. Optionally points the application at a freshly built image first, which is what lets a workflow lint, test, push and deploy the same artifact.
79 lines
2.1 KiB
JavaScript
79 lines
2.1 KiB
JavaScript
"use strict";
|
|
|
|
/** A DokployClient stand-in that records calls and replays canned answers. */
|
|
class FakeApi {
|
|
/**
|
|
* @param {object} handlers Procedure name -> value, or (input, call) => value.
|
|
* A value may be a function returning a promise, or an array consumed one
|
|
* entry per call so a poller can see a status change.
|
|
*/
|
|
constructor(handlers = {}) {
|
|
this.handlers = handlers;
|
|
this.calls = [];
|
|
this.counts = {};
|
|
}
|
|
|
|
#dispatch(kind, procedure, input) {
|
|
this.calls.push({ kind, procedure, input });
|
|
const index = (this.counts[procedure] = (this.counts[procedure] ?? 0) + 1) - 1;
|
|
|
|
if (!(procedure in this.handlers)) {
|
|
throw new Error(`FakeApi: unexpected ${kind} ${procedure}`);
|
|
}
|
|
const handler = this.handlers[procedure];
|
|
if (typeof handler === "function") return Promise.resolve(handler(input, index));
|
|
if (Array.isArray(handler) && handler.__sequence) {
|
|
return Promise.resolve(handler[Math.min(index, handler.length - 1)]);
|
|
}
|
|
return Promise.resolve(handler);
|
|
}
|
|
|
|
query(procedure, input) {
|
|
return this.#dispatch("query", procedure, input);
|
|
}
|
|
|
|
mutate(procedure, input) {
|
|
return this.#dispatch("mutate", procedure, input);
|
|
}
|
|
|
|
procedures() {
|
|
return this.calls.map((call) => call.procedure);
|
|
}
|
|
|
|
find(procedure) {
|
|
return this.calls.find((call) => call.procedure === procedure);
|
|
}
|
|
}
|
|
|
|
/** Marks an array as "one entry per call" rather than a literal return value. */
|
|
function sequence(values) {
|
|
const copy = [...values];
|
|
copy.__sequence = true;
|
|
return copy;
|
|
}
|
|
|
|
/** A clock that only moves when something sleeps, so tests never really wait. */
|
|
function fakeClock(start = 0) {
|
|
let current = start;
|
|
return {
|
|
now: () => current,
|
|
sleep: async (ms) => {
|
|
current += Math.max(ms, 1);
|
|
},
|
|
advance: (ms) => {
|
|
current += ms;
|
|
},
|
|
};
|
|
}
|
|
|
|
function collectingLog() {
|
|
const lines = [];
|
|
return {
|
|
lines,
|
|
info: (message) => lines.push(`info: ${message}`),
|
|
warning: (message) => lines.push(`warning: ${message}`),
|
|
};
|
|
}
|
|
|
|
module.exports = { FakeApi, sequence, fakeClock, collectingLog };
|