1
0

deploy changes
All checks were successful
Test / test (push) Successful in 10s
Publish Pages / publish (push) Successful in 20s

This commit is contained in:
Aiden
2026-06-11 16:16:29 +10:00
parent 4c8eed0bfe
commit a4bbd71b31

View File

@@ -23,6 +23,11 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Show runtime versions
run: |
node --version
npm --version
- name: Resolve settings - name: Resolve settings
run: | run: |
SITE_NAME="${SITE_NAME_OVERRIDE:-${GITHUB_REPOSITORY##*/}}" SITE_NAME="${SITE_NAME_OVERRIDE:-${GITHUB_REPOSITORY##*/}}"
@@ -57,13 +62,12 @@ jobs:
;; ;;
esac esac
- name: Install AWS CLI - name: Install R2 publisher
run: | run: |
if ! command -v aws >/dev/null 2>&1; then PUBLISHER_DIR="${RUNNER_TEMP:-/tmp}/f40-pages-publisher"
apt-get update mkdir -p "$PUBLISHER_DIR"
apt-get install -y --no-install-recommends awscli npm install --prefix "$PUBLISHER_DIR" --no-audit --no-fund @aws-sdk/client-s3
rm -rf /var/lib/apt/lists/* echo "PUBLISHER_DIR=$PUBLISHER_DIR" >> "$GITHUB_ENV"
fi
- name: Build static site - name: Build static site
run: sh -c "$BUILD_COMMAND" run: sh -c "$BUILD_COMMAND"
@@ -82,22 +86,137 @@ jobs:
env: env:
AWS_ACCESS_KEY_ID: ${{ secrets.F40_PAGES_R2_ACCESS_KEY_ID }} AWS_ACCESS_KEY_ID: ${{ secrets.F40_PAGES_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.F40_PAGES_R2_SECRET_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.F40_PAGES_R2_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: auto
run: | run: |
RUN_ATTEMPT="${GITHUB_RUN_ATTEMPT:-1}" RUN_ATTEMPT="${GITHUB_RUN_ATTEMPT:-1}"
RELEASE="${GITHUB_SHA}-${RUN_ATTEMPT}" RELEASE="${GITHUB_SHA}-${RUN_ATTEMPT}"
PREFIX="sites/${SITE_NAME}/releases/${RELEASE}" PREFIX="sites/${SITE_NAME}/releases/${RELEASE}"
PUBLISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" export RELEASE PREFIX
aws s3 sync "$OUTPUT_DIR/" "s3://${R2_BUCKET}/${PREFIX}/" \ cat > "$PUBLISHER_DIR/publish.mjs" <<'EOF'
--endpoint-url "$R2_ENDPOINT" \ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
--delete \ import { createReadStream } from "node:fs";
--cache-control "public,max-age=31536000,immutable" import { readdir, stat, writeFile } from "node:fs/promises";
import { join, relative, sep } from "node:path";
printf '{"site":"%s","release":"%s","sha":"%s","publishedAt":"%s"}\n' \ const required = [
"$SITE_NAME" "$RELEASE" "$GITHUB_SHA" "$PUBLISHED_AT" > current.json "AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"OUTPUT_DIR",
"PREFIX",
"R2_BUCKET",
"R2_ENDPOINT",
"RELEASE",
"GITHUB_SHA",
"SITE_NAME"
];
aws s3 cp current.json "s3://${R2_BUCKET}/sites/${SITE_NAME}/current.json" \ for (const name of required) {
--endpoint-url "$R2_ENDPOINT" \ if (!process.env[name]) {
--content-type application/json \ throw new Error(`${name} is required`);
--cache-control no-store }
}
const client = new S3Client({
endpoint: process.env.R2_ENDPOINT,
forcePathStyle: true,
region: "auto",
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
});
const contentTypes = new Map([
[".avif", "image/avif"],
[".css", "text/css; charset=utf-8"],
[".gif", "image/gif"],
[".html", "text/html; charset=utf-8"],
[".ico", "image/x-icon"],
[".jpeg", "image/jpeg"],
[".jpg", "image/jpeg"],
[".js", "text/javascript; charset=utf-8"],
[".json", "application/json; charset=utf-8"],
[".m4v", "video/mp4"],
[".mjs", "text/javascript; charset=utf-8"],
[".mov", "video/quicktime"],
[".mp4", "video/mp4"],
[".png", "image/png"],
[".svg", "image/svg+xml"],
[".txt", "text/plain; charset=utf-8"],
[".wasm", "application/wasm"],
[".webm", "video/webm"],
[".webp", "image/webp"],
[".xml", "application/xml; charset=utf-8"]
]);
async function walk(dir) {
const entries = await readdir(dir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const path = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await walk(path)));
} else if (entry.isFile()) {
files.push(path);
}
}
return files;
}
function contentTypeFor(path) {
const lower = path.toLowerCase();
const index = lower.lastIndexOf(".");
if (index === -1) {
return "application/octet-stream";
}
return contentTypes.get(lower.slice(index)) ?? "application/octet-stream";
}
const outputDir = process.env.OUTPUT_DIR;
const files = await walk(outputDir);
for (const file of files) {
const relativePath = relative(outputDir, file).split(sep).join("/");
const key = `${process.env.PREFIX}/${relativePath}`;
const metadata = await stat(file);
await client.send(
new PutObjectCommand({
Bucket: process.env.R2_BUCKET,
Key: key,
Body: createReadStream(file),
ContentLength: metadata.size,
ContentType: contentTypeFor(file),
CacheControl: "public,max-age=31536000,immutable"
})
);
console.log(`uploaded ${key}`);
}
const current = {
site: process.env.SITE_NAME,
release: process.env.RELEASE,
sha: process.env.GITHUB_SHA,
publishedAt: new Date().toISOString()
};
const currentPath = join(process.cwd(), "current.json");
await writeFile(currentPath, `${JSON.stringify(current)}\n`);
await client.send(
new PutObjectCommand({
Bucket: process.env.R2_BUCKET,
Key: `sites/${process.env.SITE_NAME}/current.json`,
Body: createReadStream(currentPath),
ContentType: "application/json; charset=utf-8",
CacheControl: "no-store"
})
);
console.log(`published ${process.env.SITE_NAME} release ${process.env.RELEASE}`);
EOF
node "$PUBLISHER_DIR/publish.mjs"