@styleflow.app/flowpress-deploy 1.0.0-beta.2 → 1.0.0-beta.21
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/CHANGELOG.md +116 -0
- package/README.md +5 -0
- package/containers/cms/Dockerfile +35 -0
- package/containers/cms/Dockerfile.dockerignore +20 -0
- package/containers/cms/healthz.php +17 -0
- package/containers/cms/install-languages.sh +16 -0
- package/containers/cms/mpm.conf +10 -0
- package/containers/cms/php.ini +16 -0
- package/containers/cms/sanitize-integrations.php +14 -0
- package/containers/cms/sanitize.php +37 -0
- package/containers/cms/smtp.php +13 -0
- package/containers/cms/vhost.conf +61 -0
- package/containers/cms/wp-cli.yml +1 -0
- package/containers/local/cms/Dockerfile +18 -0
- package/containers/local/cms/entrypoint.sh +7 -0
- package/containers/local/cms/php.ini +8 -0
- package/containers/local/cms/vhost.conf +14 -0
- package/containers/local/web/Dockerfile +8 -0
- package/containers/local/web/entrypoint.sh +21 -0
- package/containers/php-runtime/Dockerfile +21 -0
- package/containers/web-ssr/Dockerfile +27 -0
- package/containers/web-ssr/Dockerfile.dockerignore +10 -0
- package/containers/web-static/Caddyfile +40 -0
- package/containers/web-static/Dockerfile +17 -0
- package/containers/web-static/Dockerfile.dockerignore +7 -0
- package/dist/development.d.ts +4 -0
- package/dist/development.d.ts.map +1 -0
- package/dist/development.js +10 -0
- package/dist/development.js.map +1 -0
- package/dist/node-fetch.d.ts +3 -0
- package/dist/node-fetch.d.ts.map +1 -0
- package/dist/node-fetch.js +20 -0
- package/dist/node-fetch.js.map +1 -0
- package/dist/ops/bootstrap.d.ts +21 -0
- package/dist/ops/bootstrap.d.ts.map +1 -0
- package/dist/ops/bootstrap.js +123 -0
- package/dist/ops/bootstrap.js.map +1 -0
- package/dist/ops/build.d.ts +39 -0
- package/dist/ops/build.d.ts.map +1 -0
- package/dist/ops/build.js +110 -0
- package/dist/ops/build.js.map +1 -0
- package/dist/ops/check.d.ts +18 -0
- package/dist/ops/check.d.ts.map +1 -0
- package/dist/ops/check.js +46 -0
- package/dist/ops/check.js.map +1 -0
- package/dist/ops/cli.d.ts +3 -0
- package/dist/ops/cli.d.ts.map +1 -0
- package/dist/ops/cli.js +166 -0
- package/dist/ops/cli.js.map +1 -0
- package/dist/ops/config.d.ts +54 -0
- package/dist/ops/config.d.ts.map +1 -0
- package/dist/ops/config.js +202 -0
- package/dist/ops/config.js.map +1 -0
- package/dist/ops/coolify.d.ts +2 -0
- package/dist/ops/coolify.d.ts.map +1 -0
- package/dist/ops/coolify.js +44 -0
- package/dist/ops/coolify.js.map +1 -0
- package/dist/ops/data.d.ts +31 -0
- package/dist/ops/data.d.ts.map +1 -0
- package/dist/ops/data.js +163 -0
- package/dist/ops/data.js.map +1 -0
- package/dist/ops/deploy.d.ts +38 -0
- package/dist/ops/deploy.d.ts.map +1 -0
- package/dist/ops/deploy.js +127 -0
- package/dist/ops/deploy.js.map +1 -0
- package/dist/ops/editorial.d.ts +23 -0
- package/dist/ops/editorial.d.ts.map +1 -0
- package/dist/ops/editorial.js +79 -0
- package/dist/ops/editorial.js.map +1 -0
- package/dist/ops/environment-files.d.ts +9 -0
- package/dist/ops/environment-files.d.ts.map +1 -0
- package/dist/ops/environment-files.js +125 -0
- package/dist/ops/environment-files.js.map +1 -0
- package/dist/ops/environment.d.ts +29 -0
- package/dist/ops/environment.d.ts.map +1 -0
- package/dist/ops/environment.js +159 -0
- package/dist/ops/environment.js.map +1 -0
- package/dist/ops/health.d.ts +26 -0
- package/dist/ops/health.d.ts.map +1 -0
- package/dist/ops/health.js +27 -0
- package/dist/ops/health.js.map +1 -0
- package/dist/ops/local.d.ts +161 -0
- package/dist/ops/local.d.ts.map +1 -0
- package/dist/ops/local.js +176 -0
- package/dist/ops/local.js.map +1 -0
- package/dist/ops/monitor.d.ts +23 -0
- package/dist/ops/monitor.d.ts.map +1 -0
- package/dist/ops/monitor.js +143 -0
- package/dist/ops/monitor.js.map +1 -0
- package/dist/ops/process.d.ts +9 -0
- package/dist/ops/process.d.ts.map +1 -0
- package/dist/ops/process.js +56 -0
- package/dist/ops/process.js.map +1 -0
- package/dist/ops/provision.d.ts +41 -0
- package/dist/ops/provision.d.ts.map +1 -0
- package/dist/ops/provision.js +268 -0
- package/dist/ops/provision.js.map +1 -0
- package/dist/ops/registry.d.ts +7 -0
- package/dist/ops/registry.d.ts.map +1 -0
- package/dist/ops/registry.js +73 -0
- package/dist/ops/registry.js.map +1 -0
- package/dist/ops/release.d.ts +26 -0
- package/dist/ops/release.d.ts.map +1 -0
- package/dist/ops/release.js +79 -0
- package/dist/ops/release.js.map +1 -0
- package/dist/ops/s3.d.ts +8 -0
- package/dist/ops/s3.d.ts.map +1 -0
- package/dist/ops/s3.js +38 -0
- package/dist/ops/s3.js.map +1 -0
- package/dist/ops/static-config.d.ts +14 -0
- package/dist/ops/static-config.d.ts.map +1 -0
- package/dist/ops/static-config.js +96 -0
- package/dist/ops/static-config.js.map +1 -0
- package/flowpress-deploy.php +2 -2
- package/includes/automatic-build.php +22 -5
- package/package.json +40 -6
- package/schema/deployment.schema.json +185 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { allowedComponents, loadState } from "./config.js";
|
|
3
|
+
import { build } from "./build.js";
|
|
4
|
+
import { deploy, deployedRelease } from "./deploy.js";
|
|
5
|
+
import { capture } from "./process.js";
|
|
6
|
+
import { acknowledgeBatch, validateBuildRequest } from "./editorial.js";
|
|
7
|
+
export function changedComponents(paths, available) {
|
|
8
|
+
if (!paths.length)
|
|
9
|
+
return [];
|
|
10
|
+
const relevant = paths.filter(path => !/^(docs\/|README|CHANGELOG)|\.md$/.test(path));
|
|
11
|
+
if (!relevant.length)
|
|
12
|
+
return [];
|
|
13
|
+
const cms = relevant.some(path => /^apps\/cms\//.test(path));
|
|
14
|
+
const web = relevant.some(path => /^apps\/web\//.test(path));
|
|
15
|
+
const shared = relevant.some(path => !/^apps\/(cms|web)\//.test(path));
|
|
16
|
+
return available.filter(component => shared || (component === "cms" ? cms : web));
|
|
17
|
+
}
|
|
18
|
+
export async function editorialCommit(root, manifest, payload) {
|
|
19
|
+
const request = validateBuildRequest(payload);
|
|
20
|
+
allowedComponents(manifest, request.target, ["web-static"]);
|
|
21
|
+
const app = loadState(root, request.target).apps?.["web-static"];
|
|
22
|
+
if (!app?.url)
|
|
23
|
+
throw new Error("No deployed static frontend for this editorial target.");
|
|
24
|
+
const res = await fetch(app.url + app.health + "?editorial=" + Date.now(), { redirect: "error", signal: AbortSignal.timeout(10000) });
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
if (!res.ok || data.status !== "ok" || !/^[a-f0-9]{40}$/.test(data.release || "") || data.backendTarget !== request.target)
|
|
27
|
+
throw new Error("Editorial target is not a healthy static frontend using this backend.");
|
|
28
|
+
return { request, sha: data.release };
|
|
29
|
+
}
|
|
30
|
+
export async function release(root, manifest, name, { component, sha, buildId, editorial = false } = {}) {
|
|
31
|
+
let selected = allowedComponents(manifest, name, component ? [component] : []);
|
|
32
|
+
const revision = sha || capture("git", ["rev-parse", "HEAD"], { cwd: root });
|
|
33
|
+
let request;
|
|
34
|
+
if (editorial) {
|
|
35
|
+
const event = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, "utf8"));
|
|
36
|
+
const live = await editorialCommit(root, manifest, event.client_payload);
|
|
37
|
+
if (live.request.target !== name || live.sha !== revision)
|
|
38
|
+
throw new Error("Editorial build must check out the exact deployed commit.");
|
|
39
|
+
request = live.request;
|
|
40
|
+
selected = ["web-static"];
|
|
41
|
+
}
|
|
42
|
+
else if (process.env.GITHUB_EVENT_NAME === "push" && process.env.GITHUB_EVENT_PATH) {
|
|
43
|
+
const event = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, "utf8"));
|
|
44
|
+
if (/^[a-f0-9]{40}$/.test(event.before || "") && !/^0+$/.test(event.before)) {
|
|
45
|
+
try {
|
|
46
|
+
selected = changedComponents(capture("git", ["diff", "--name-only", event.before, revision], { cwd: root }).split("\n").filter(Boolean), selected);
|
|
47
|
+
}
|
|
48
|
+
catch { /* shallow checkout: safely build all allowed components */ }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const results = [];
|
|
52
|
+
try {
|
|
53
|
+
for (const item of selected) {
|
|
54
|
+
if (name === "production" && item === "cms") {
|
|
55
|
+
const verified = await deployedRelease(root, "staging", "cms");
|
|
56
|
+
if (!verified || verified.sha !== revision)
|
|
57
|
+
throw new Error("Production CMS must promote the staging image for this SHA.");
|
|
58
|
+
results.push(await deploy(root, manifest, name, item, { release: { ...verified, environment: "production" } }));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
await build(root, manifest, name, item, { sha: revision, buildId, push: true });
|
|
62
|
+
results.push(await deploy(root, manifest, name, item));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (request)
|
|
66
|
+
await acknowledgeBatch({ request, backend: manifest.environments[name].backendUrl, token: process.env.CMS_BUILD_CALLBACK_TOKEN, status: "success" });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (request) {
|
|
70
|
+
try {
|
|
71
|
+
await acknowledgeBatch({ request, backend: manifest.environments[name].backendUrl, token: process.env.CMS_BUILD_CALLBACK_TOKEN, status: "failure" });
|
|
72
|
+
}
|
|
73
|
+
catch { /* original failure remains authoritative; batch is retained */ }
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
return { environment: name, components: selected, results };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/ops/release.js"],"names":[],"mappings":"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"}
|
package/dist/ops/s3.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function s3Put(bucket: any, key: any, file: any): void;
|
|
2
|
+
export function s3Get(bucket: any, key: any, file: any): void;
|
|
3
|
+
export function s3List(bucket: any, prefix: any, request?: (url: any) => any): {
|
|
4
|
+
key: any;
|
|
5
|
+
modified: any;
|
|
6
|
+
size: number;
|
|
7
|
+
}[];
|
|
8
|
+
//# sourceMappingURL=s3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/ops/s3.js"],"names":[],"mappings":"AAQA,8DAEC;AAED,8DAGC;AAID,4DAAkD,QAAG;;;;IAkBpD"}
|
package/dist/ops/s3.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { chmodSync } from "node:fs";
|
|
2
|
+
import { capture } from "./process.js";
|
|
3
|
+
function curl(bucket, args) {
|
|
4
|
+
return capture("curl", ["-K", "-", "--fail-with-body", "--max-time", "60", "-sS", "--aws-sigv4", "aws:amz:" + (bucket.region || "auto") + ":s3", ...args], {
|
|
5
|
+
input: `user = "${bucket.user}"\n`,
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function s3Put(bucket, key, file) {
|
|
9
|
+
curl(bucket, ["-T", file, `${bucket.endpoint}/${bucket.bucket}/${key}`]);
|
|
10
|
+
}
|
|
11
|
+
export function s3Get(bucket, key, file) {
|
|
12
|
+
curl(bucket, ["-o", file, `${bucket.endpoint}/${bucket.bucket}/${key}`]);
|
|
13
|
+
chmodSync(file, 0o600); // backups contain personal data and password hashes
|
|
14
|
+
}
|
|
15
|
+
const decodeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll(""", '"').replaceAll("'", "'");
|
|
16
|
+
export function s3List(bucket, prefix, request = (url) => curl(bucket, [url])) {
|
|
17
|
+
const objects = [];
|
|
18
|
+
const tokens = new Set();
|
|
19
|
+
let token;
|
|
20
|
+
do {
|
|
21
|
+
const query = new URLSearchParams({ "list-type": "2", prefix });
|
|
22
|
+
if (token)
|
|
23
|
+
query.set("continuation-token", token);
|
|
24
|
+
const xml = request(`${bucket.endpoint}/${bucket.bucket}?${query}`);
|
|
25
|
+
const field = (source, name) => decodeXml(source.match(new RegExp(`<${name}>([^<]*)</${name}>`))?.[1] ?? "");
|
|
26
|
+
objects.push(...[...xml.matchAll(/<Contents>(.*?)<\/Contents>/gs)].map(([, block]) => ({
|
|
27
|
+
key: field(block, "Key"), modified: field(block, "LastModified"), size: Number(field(block, "Size")),
|
|
28
|
+
})));
|
|
29
|
+
if (field(xml, "IsTruncated") !== "true")
|
|
30
|
+
break;
|
|
31
|
+
token = field(xml, "NextContinuationToken");
|
|
32
|
+
if (!token || tokens.has(token))
|
|
33
|
+
throw new Error("S3 returned an invalid pagination token.");
|
|
34
|
+
tokens.add(token);
|
|
35
|
+
} while (token);
|
|
36
|
+
return objects;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=s3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/ops/s3.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export function redirectsToCaddy(text: any): string[];
|
|
3
|
+
export function headersToCaddy(text: any): string[];
|
|
4
|
+
export function proxiesToCaddy({ media, backend }: {
|
|
5
|
+
media: any;
|
|
6
|
+
backend: any;
|
|
7
|
+
}): string[];
|
|
8
|
+
export function buildRoutesCaddy({ redirects, headers, media, backend }: {
|
|
9
|
+
redirects?: string | undefined;
|
|
10
|
+
headers?: string | undefined;
|
|
11
|
+
media: any;
|
|
12
|
+
backend: any;
|
|
13
|
+
}): string;
|
|
14
|
+
//# sourceMappingURL=static-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-config.d.ts","sourceRoot":"","sources":["../../src/ops/static-config.js"],"names":[],"mappings":";AAoBA,sDAwBC;AAED,oDAmBC;AAED;;;aAkBC;AAED;;;;;WAQC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Turns the static Astro build's Cloudflare-style `_redirects` and `_headers`
|
|
3
|
+
// into Caddy directives, plus the /media and /app/uploads proxies that the
|
|
4
|
+
// Pages Functions used to provide. Output: <dist>/.container/routes.caddy.
|
|
5
|
+
//
|
|
6
|
+
// APP_ENV=production node FlowPress Deploy apps/web/dist-production
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
function quote(value) {
|
|
11
|
+
if (/["\s{}]/.test(value) && !/^"[^"]*"$/.test(value)) {
|
|
12
|
+
return `"${value.replaceAll('"', '\\"')}"`;
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
// FlowPress routing only emits exact paths (see validateRedirects), so every
|
|
17
|
+
// line is "source target status". Both slash variants of a source redirect.
|
|
18
|
+
export function redirectsToCaddy(text) {
|
|
19
|
+
const lines = [];
|
|
20
|
+
let index = 0;
|
|
21
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
22
|
+
const line = raw.trim();
|
|
23
|
+
if (!line || line.startsWith("#"))
|
|
24
|
+
continue;
|
|
25
|
+
const [source, target, status = "301", ...rest] = line.split(/\s+/);
|
|
26
|
+
if (rest.length || !source?.startsWith("/") || !target) {
|
|
27
|
+
throw new Error(`Unsupported _redirects line: ${line}`);
|
|
28
|
+
}
|
|
29
|
+
if (/[*:]/.test(source)) {
|
|
30
|
+
throw new Error(`Splats and placeholders are not supported: ${line}`);
|
|
31
|
+
}
|
|
32
|
+
if (!["301", "302", "307", "308"].includes(status)) {
|
|
33
|
+
throw new Error(`Unsupported redirect status: ${line}`);
|
|
34
|
+
}
|
|
35
|
+
const variants = source === "/"
|
|
36
|
+
? ["/"]
|
|
37
|
+
: [source.replace(/\/+$/, ""), `${source.replace(/\/+$/, "")}/`];
|
|
38
|
+
index += 1;
|
|
39
|
+
lines.push(`@redirect${index} path ${variants.map(quote).join(" ")}`);
|
|
40
|
+
lines.push(`redir @redirect${index} ${quote(target)} ${status}`);
|
|
41
|
+
}
|
|
42
|
+
return lines;
|
|
43
|
+
}
|
|
44
|
+
export function headersToCaddy(text) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
let pattern = null;
|
|
47
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
48
|
+
if (!raw.trim() || raw.trim().startsWith("#"))
|
|
49
|
+
continue;
|
|
50
|
+
if (!/^\s/.test(raw)) {
|
|
51
|
+
pattern = raw.trim();
|
|
52
|
+
if (!pattern.startsWith("/"))
|
|
53
|
+
throw new Error(`Unsupported _headers pattern: ${pattern}`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (!pattern)
|
|
57
|
+
throw new Error(`Header without a path pattern: ${raw.trim()}`);
|
|
58
|
+
const separator = raw.indexOf(":");
|
|
59
|
+
if (separator < 0)
|
|
60
|
+
throw new Error(`Unsupported _headers line: ${raw.trim()}`);
|
|
61
|
+
const name = raw.slice(0, separator).trim();
|
|
62
|
+
const value = raw.slice(separator + 1).trim();
|
|
63
|
+
const matcher = pattern === "/*" ? "*" : pattern;
|
|
64
|
+
lines.push(`header ${matcher} ${name} ${quote(value)}`);
|
|
65
|
+
}
|
|
66
|
+
return lines;
|
|
67
|
+
}
|
|
68
|
+
export function proxiesToCaddy({ media, backend }) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
const mediaUrl = new URL(media);
|
|
71
|
+
const mediaBase = mediaUrl.pathname.replace(/\/+$/, "");
|
|
72
|
+
lines.push("@flowpress_media path_regexp flowpress_media ^/media(/.+\\.[a-zA-Z0-9]{1,8})$");
|
|
73
|
+
lines.push("handle @flowpress_media {");
|
|
74
|
+
lines.push(`\trewrite * ${mediaBase}{http.regexp.flowpress_media.1}`);
|
|
75
|
+
lines.push(`\treverse_proxy ${mediaUrl.origin} {`);
|
|
76
|
+
lines.push("\t\theader_up Host {upstream_hostport}");
|
|
77
|
+
lines.push("\t}");
|
|
78
|
+
lines.push("}");
|
|
79
|
+
const backendUrl = new URL(backend);
|
|
80
|
+
lines.push("handle /app/uploads/* {");
|
|
81
|
+
lines.push(`\treverse_proxy ${backendUrl.origin} {`);
|
|
82
|
+
lines.push("\t\theader_up Host {upstream_hostport}");
|
|
83
|
+
lines.push("\t}");
|
|
84
|
+
lines.push("}");
|
|
85
|
+
return lines;
|
|
86
|
+
}
|
|
87
|
+
export function buildRoutesCaddy({ redirects = "", headers = "", media, backend }) {
|
|
88
|
+
return [
|
|
89
|
+
"# Generated by FlowPress Deploy. Do not edit.",
|
|
90
|
+
...redirectsToCaddy(redirects),
|
|
91
|
+
...headersToCaddy(headers),
|
|
92
|
+
...proxiesToCaddy({ media, backend }),
|
|
93
|
+
"",
|
|
94
|
+
].join("\n");
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=static-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-config.js","sourceRoot":"","sources":["../../src/ops/static-config.js"],"names":[],"mappings":"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"}
|
package/flowpress-deploy.php
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Plugin Name: FlowPress Deploy
|
|
4
4
|
* Description: Revision-safe editorial build queue and deployment capability for FlowPress.
|
|
5
|
-
* Version: 1.0.0-beta.
|
|
5
|
+
* Version: 1.0.0-beta.5
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
if (! defined('ABSPATH')) {
|
|
9
9
|
exit;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
define('FLOWPRESS_DEPLOY_VERSION', '1.0.0-beta.
|
|
12
|
+
define('FLOWPRESS_DEPLOY_VERSION', '1.0.0-beta.5');
|
|
13
13
|
define('FLOWPRESS_DEPLOY_FILE', __FILE__);
|
|
14
14
|
|
|
15
15
|
require_once __DIR__ . '/includes/queue-provider.php';
|
|
@@ -55,16 +55,33 @@ function flowpress_deploy_taxonomy_affects_public_build(string $taxonomy): bool
|
|
|
55
55
|
return $object && (bool) apply_filters('flowpress_deploy_taxonomy_affects_public_build', $object->public, $taxonomy);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
/** Term-only changes bypass save_post, including a public-to-private transition. */
|
|
59
|
+
add_action('set_object_terms', static function (int $id, $terms, $tt_ids, string $taxonomy, bool $append, $old_tt_ids): void {
|
|
60
|
+
$post = get_post($id);
|
|
61
|
+
if (! $post instanceof WP_Post || $post->post_status !== 'publish'
|
|
62
|
+
|| ! (get_post_type_object($post->post_type)->public ?? false)) return;
|
|
63
|
+
$current = array_map('intval', (array) $tt_ids);
|
|
64
|
+
$previous = array_map('intval', (array) $old_tt_ids);
|
|
65
|
+
sort($current); sort($previous);
|
|
66
|
+
if (! $append && $current === $previous) return;
|
|
67
|
+
// Hidden visibility/recipient taxonomies also affect public artifacts.
|
|
68
|
+
// A global descriptor avoids placing private titles or URLs in the queue.
|
|
69
|
+
flowpress_enqueue_build_change('global', 0, '/', 'update', true);
|
|
70
|
+
flowpress_deploy_schedule_public_build();
|
|
71
|
+
}, 40, 6);
|
|
61
72
|
foreach (['created_term', 'edited_term', 'pre_delete_term'] as $hook) {
|
|
62
73
|
$callback = $hook === 'pre_delete_term'
|
|
63
74
|
? static function (int $id, string $taxonomy): void {
|
|
64
|
-
if (flowpress_deploy_taxonomy_affects_public_build($taxonomy))
|
|
75
|
+
if (flowpress_deploy_taxonomy_affects_public_build($taxonomy)) {
|
|
76
|
+
flowpress_enqueue_build_change('global', 0, '/', 'update', true);
|
|
77
|
+
flowpress_deploy_schedule_public_build();
|
|
78
|
+
}
|
|
65
79
|
}
|
|
66
80
|
: static function (int $id, int $tt_id, string $taxonomy): void {
|
|
67
|
-
if (flowpress_deploy_taxonomy_affects_public_build($taxonomy))
|
|
81
|
+
if (flowpress_deploy_taxonomy_affects_public_build($taxonomy)) {
|
|
82
|
+
flowpress_enqueue_build_change('global', 0, '/', 'update', true);
|
|
83
|
+
flowpress_deploy_schedule_public_build();
|
|
84
|
+
}
|
|
68
85
|
};
|
|
69
86
|
add_action($hook, $callback, 40, $hook === 'pre_delete_term' ? 2 : 3);
|
|
70
87
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@styleflow.app/flowpress-deploy",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.21",
|
|
4
4
|
"description": "Safe full and partial deployment primitives for FlowPress.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -28,6 +28,26 @@
|
|
|
28
28
|
"./worker-assets": {
|
|
29
29
|
"import": "./dist/worker-assets.js",
|
|
30
30
|
"types": "./dist/worker-assets.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./ops/environment": {
|
|
33
|
+
"import": "./dist/ops/environment.js",
|
|
34
|
+
"types": "./dist/ops/environment.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./ops": {
|
|
37
|
+
"import": "./dist/ops/config.js",
|
|
38
|
+
"types": "./dist/ops/config.d.ts"
|
|
39
|
+
},
|
|
40
|
+
"./node-fetch": {
|
|
41
|
+
"import": "./dist/node-fetch.js",
|
|
42
|
+
"types": "./dist/node-fetch.d.ts"
|
|
43
|
+
},
|
|
44
|
+
"./ops/environment-files": {
|
|
45
|
+
"import": "./dist/ops/environment-files.js",
|
|
46
|
+
"types": "./dist/ops/environment-files.d.ts"
|
|
47
|
+
},
|
|
48
|
+
"./development": {
|
|
49
|
+
"import": "./dist/development.js",
|
|
50
|
+
"types": "./dist/development.d.ts"
|
|
31
51
|
}
|
|
32
52
|
},
|
|
33
53
|
"files": [
|
|
@@ -37,15 +57,21 @@
|
|
|
37
57
|
"flowpress-deploy.php",
|
|
38
58
|
"composer.json",
|
|
39
59
|
"README.md",
|
|
40
|
-
"CHANGELOG.md"
|
|
60
|
+
"CHANGELOG.md",
|
|
61
|
+
"containers",
|
|
62
|
+
"schema"
|
|
41
63
|
],
|
|
42
64
|
"scripts": {
|
|
43
65
|
"build": "tsc -b",
|
|
44
66
|
"typecheck": "tsc -b --pretty false",
|
|
45
|
-
"test": "vitest run && node --test tests/*-regressions.mjs && php tests/php/queue-provider-test.php",
|
|
46
|
-
"release:check": "npm run typecheck && npm test && npm pack --dry-run",
|
|
67
|
+
"test": "vitest run tests/deploy.test.ts && node --test tests/*-regressions.mjs && php tests/php/queue-provider-test.php && node --test tests/ops-*.test.mjs",
|
|
68
|
+
"release:check": "npm run typecheck && npm test && npm run test:ops:database && npm run test:ops:caddy && npm run test:ops:sanitizer && node tests/ops-local-apache-integration.mjs && npm pack --dry-run",
|
|
47
69
|
"release:publish:next": "npm publish --access public --tag next",
|
|
48
|
-
"prepublishOnly": "npm run typecheck && npm test"
|
|
70
|
+
"prepublishOnly": "npm run typecheck && npm test",
|
|
71
|
+
"test:ops": "node --test tests/ops-*.test.mjs",
|
|
72
|
+
"test:ops:database": "node tests/ops-database-integration.mjs",
|
|
73
|
+
"test:ops:caddy": "node tests/ops-caddy-integration.mjs",
|
|
74
|
+
"test:ops:sanitizer": "node tests/ops-sanitizer-integration.mjs"
|
|
49
75
|
},
|
|
50
76
|
"devDependencies": {
|
|
51
77
|
"@types/node": "^22.19.3",
|
|
@@ -55,5 +81,13 @@
|
|
|
55
81
|
"engines": {
|
|
56
82
|
"node": ">=22.0.0"
|
|
57
83
|
},
|
|
58
|
-
"packageManager": "npm@10.9.3"
|
|
84
|
+
"packageManager": "npm@10.9.3",
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"dotenv": "17.4.2",
|
|
87
|
+
"dotenv-expand": "12.0.3",
|
|
88
|
+
"yaml": "2.9.1"
|
|
89
|
+
},
|
|
90
|
+
"bin": {
|
|
91
|
+
"flowpress-ops": "./dist/ops/cli.js"
|
|
92
|
+
}
|
|
59
93
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "FlowPress deployment manifest",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": [
|
|
6
|
+
"schemaVersion",
|
|
7
|
+
"platform",
|
|
8
|
+
"profile",
|
|
9
|
+
"database",
|
|
10
|
+
"media",
|
|
11
|
+
"environments"
|
|
12
|
+
],
|
|
13
|
+
"properties": {
|
|
14
|
+
"schemaVersion": {
|
|
15
|
+
"const": 1
|
|
16
|
+
},
|
|
17
|
+
"platform": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
20
|
+
},
|
|
21
|
+
"profile": {
|
|
22
|
+
"enum": [
|
|
23
|
+
"backend",
|
|
24
|
+
"static",
|
|
25
|
+
"headless-static",
|
|
26
|
+
"headless-ssr"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"database": {
|
|
30
|
+
"const": "shared"
|
|
31
|
+
},
|
|
32
|
+
"media": {
|
|
33
|
+
"enum": [
|
|
34
|
+
"local",
|
|
35
|
+
"s3"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"registryProject": {
|
|
39
|
+
"type": "string"
|
|
40
|
+
},
|
|
41
|
+
"sources": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"required": [
|
|
46
|
+
"ssh",
|
|
47
|
+
"user",
|
|
48
|
+
"path"
|
|
49
|
+
],
|
|
50
|
+
"properties": {
|
|
51
|
+
"ssh": {
|
|
52
|
+
"type": "string"
|
|
53
|
+
},
|
|
54
|
+
"user": {
|
|
55
|
+
"type": "string"
|
|
56
|
+
},
|
|
57
|
+
"path": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"pattern": "^/"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"additionalProperties": false
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"environments": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"propertyNames": {
|
|
68
|
+
"enum": [
|
|
69
|
+
"local",
|
|
70
|
+
"staging",
|
|
71
|
+
"production",
|
|
72
|
+
"preview"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
"additionalProperties": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"required": [
|
|
78
|
+
"publish"
|
|
79
|
+
],
|
|
80
|
+
"properties": {
|
|
81
|
+
"publish": {
|
|
82
|
+
"type": "array",
|
|
83
|
+
"uniqueItems": true,
|
|
84
|
+
"items": {
|
|
85
|
+
"enum": [
|
|
86
|
+
"cms",
|
|
87
|
+
"web-static",
|
|
88
|
+
"web-ssr"
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"profile": {
|
|
93
|
+
"enum": [
|
|
94
|
+
"backend",
|
|
95
|
+
"static",
|
|
96
|
+
"headless-static",
|
|
97
|
+
"headless-ssr"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
"frontendUrl": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"format": "uri"
|
|
103
|
+
},
|
|
104
|
+
"backendUrl": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"format": "uri"
|
|
107
|
+
},
|
|
108
|
+
"graphqlUrl": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"format": "uri"
|
|
111
|
+
},
|
|
112
|
+
"mediaUrl": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"format": "uri"
|
|
115
|
+
},
|
|
116
|
+
"backend": {
|
|
117
|
+
"enum": [
|
|
118
|
+
"local",
|
|
119
|
+
"staging",
|
|
120
|
+
"production"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"aliases": {
|
|
124
|
+
"type": "array",
|
|
125
|
+
"items": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"format": "uri"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"mode": {
|
|
131
|
+
"const": "on-demand"
|
|
132
|
+
},
|
|
133
|
+
"mail": {
|
|
134
|
+
"enum": [
|
|
135
|
+
"disabled",
|
|
136
|
+
"capture",
|
|
137
|
+
"smtp"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
"backendAliases": {
|
|
141
|
+
"type": "array",
|
|
142
|
+
"items": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"format": "uri"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"additionalProperties": false
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"development": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"ports": {
|
|
155
|
+
"type": "object",
|
|
156
|
+
"properties": {
|
|
157
|
+
"web": {
|
|
158
|
+
"type": "integer",
|
|
159
|
+
"minimum": 1,
|
|
160
|
+
"maximum": 65535
|
|
161
|
+
},
|
|
162
|
+
"cms": {
|
|
163
|
+
"type": "integer",
|
|
164
|
+
"minimum": 1,
|
|
165
|
+
"maximum": 65535
|
|
166
|
+
},
|
|
167
|
+
"https": {
|
|
168
|
+
"type": "integer",
|
|
169
|
+
"minimum": 1,
|
|
170
|
+
"maximum": 65535
|
|
171
|
+
},
|
|
172
|
+
"database": {
|
|
173
|
+
"type": "integer",
|
|
174
|
+
"minimum": 1,
|
|
175
|
+
"maximum": 65535
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"additionalProperties": false
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"additionalProperties": false
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"additionalProperties": false
|
|
185
|
+
}
|