From a6b57273f5fffff917107d711e89050694084738 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 24 Dec 2025 20:42:22 -0700 Subject: [PATCH] Add required scripts and move to using a forgejo action instead of Github action --- .forgejo/workflows/draft-release.yaml | 65 +++++++++++++++++++++++++++ .github/workflows/draft-release.yaml | 57 ----------------------- scripts/createForgejoRelease.mjs | 54 ++++++++++++++++++++++ scripts/prepareManifest.mjs | 45 +++++++++++++++++++ scripts/tagExists.mjs | 38 ++++++++++++++++ scripts/uploadToS3.mjs | 65 +++++++++++++++++++++++++++ 6 files changed, 267 insertions(+), 57 deletions(-) create mode 100644 .forgejo/workflows/draft-release.yaml delete mode 100644 .github/workflows/draft-release.yaml create mode 100644 scripts/createForgejoRelease.mjs create mode 100644 scripts/prepareManifest.mjs create mode 100644 scripts/tagExists.mjs create mode 100644 scripts/uploadToS3.mjs diff --git a/.forgejo/workflows/draft-release.yaml b/.forgejo/workflows/draft-release.yaml new file mode 100644 index 0000000..237faf9 --- /dev/null +++ b/.forgejo/workflows/draft-release.yaml @@ -0,0 +1,65 @@ +on: [ workflow_dispatch ] +jobs: + create-artifacts: + name: "Create artifacts" + runs-on: act + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: npm clean-install + + - id: version + run: cat system.json | echo version=`jq -r ".version"` >> "$FORGEJO_OUTPUT" + + - name: Assert that the tag doesn't exist + run: node scripts/tagExists.mjs + env: + TAG_NAME: "v${{steps.version.outputs.version}}" + + # Compendia steps + - name: Build compendia + run: "npm run data:build" + - name: Remove compendia source + run: "rm -rf packs/**/_source" + + - name: Compress files + run: zip -r release.zip langs module styles templates README.md assets + + - name: Update manifest + run: node scripts/prepareManifest.mjs + env: + DOWNLOAD_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/v${{steps.version.outputs.version}}/release.zip" + LATEST_URL: "${{forgejo.server_url}}/${{forgejo.repository}}/releases/download/latest/system.json" + + - name: Compress files + run: zip -r release.zip langs module styles templates README.md assets + + - name: Upload archive to s3 + run: node scripts/uploadToS3.mjs + env: + TAG: "v${{steps.version.outputs.version}}" + FILE: "release.zip" + S3_BUCKET: "${{vars.S3_BUCKET}}" + S3_REGION: "${{vars.S3_REGION}}" + S3_KEY: "${{secrets.S3_KEY}}" + S3_SECRET: "${{secrets.S3_SECRET}}" + S3_ENDPOINT: "${{vars.S3_ENDPOINT}}" + + - name: Upload manifest to s3 + run: node scripts/uploadToS3.mjs + env: + TAG: "v${{steps.version.outputs.version}}" + FILE: "system.json" + S3_BUCKET: "${{vars.S3_BUCKET}}" + S3_REGION: "${{vars.S3_REGION}}" + S3_KEY: "${{secrets.S3_KEY}}" + S3_SECRET: "${{secrets.S3_SECRET}}" + S3_ENDPOINT: "${{vars.S3_ENDPOINT}}" + + - name: Create draft release + run: node scripts/createForgejoRelease.mjs + env: + TAG: "v${{steps.version.outputs.version}}" + CDN_URL: "${{vars.CDN_URL}}" diff --git a/.github/workflows/draft-release.yaml b/.github/workflows/draft-release.yaml deleted file mode 100644 index eecafc4..0000000 --- a/.github/workflows/draft-release.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: Create Draft Release -on: [workflow_dispatch] -jobs: - everything: - runs-on: ubuntu-latest - steps: - # Checkout the repository - - uses: actions/checkout@v4 - - # Install node and NPM - - uses: actions/setup-node@v4 - with: - node-version: "19" - - # Install required packages - - run: npm install - - - name: Reading the system.json for the version - id: "version" - run: cat system.json | echo version=`jq -r ".version"` >> "$GITHUB_OUTPUT" - - # Check that tag doesn't exist - - uses: mukunku/tag-exists-action@v1.5.0 - id: check-tag - with: - tag: "v${{ steps.version.outputs.version }}" - - - name: "Ensure that the tag doesn't exist" - if: ${{ steps.check-tag.outputs.exists == 'true' }} - run: exit 1 - - - name: "Building compendia" - run: "npm run data:build" - - - name: "Removing compendium source" - run: "rm -rf packs/**/_source" - - - name: Update the manifest with the relevant properties - id: manifest-update - uses: microsoft/variable-substitution@v1 - with: - files: "system.json" - env: - download: "https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/release.zip" - - - name: Create the zip - run: zip -r release.zip system.json packs module langs assets templates README.md - - - name: Create the draft release - uses: ncipollo/release-action@v1 - with: - tag: "v${{ steps.version.outputs.version }}" - commit: ${{ github.ref }} - draft: true - body: - generateReleaseNotes: true - artifacts: "release.zip,system.json" \ No newline at end of file diff --git a/scripts/createForgejoRelease.mjs b/scripts/createForgejoRelease.mjs new file mode 100644 index 0000000..67a8629 --- /dev/null +++ b/scripts/createForgejoRelease.mjs @@ -0,0 +1,54 @@ +import axios from "axios"; + +const { + TAG, + FORGEJO_SERVER_URL: WEB_URL, + FORGEJO_API_URL: API, + FORGEJO_REPOSITORY: REPO, + FORGEJO_TOKEN: TOKEN, + CDN_URL, +} = process.env; + +async function addReleaseAsset(releaseID, name) { + return axios.post( + `${API}/repos/${REPO}/releases/${releaseID}/assets`, + { external_url: `${CDN_URL}/${REPO}/${TAG}/${name}`, }, + { + headers: { + Authorization: `token ${TOKEN}`, + "Content-Type": `multipart/form-data`, + }, + params: { name }, + } + ); +}; + +async function main() { + + // Initial Release Data + const release = await axios.post( + `${API}/repos/${REPO}/releases`, + { + name: TAG, + tag_name: TAG, + draft: true, + hide_archive_links: true, + body: ``, + }, + { + headers: { Authorization: `token ${TOKEN}` }, + } + ); + + try { + await addReleaseAsset(release.data.id, `release.zip`); + await addReleaseAsset(release.data.id, `system.json`); + } catch (e) { + console.error(`Failed to add assets to the release`); + process.exit(1); + }; + + console.log(`Release created`); +}; + +main(); diff --git a/scripts/prepareManifest.mjs b/scripts/prepareManifest.mjs new file mode 100644 index 0000000..34f4236 --- /dev/null +++ b/scripts/prepareManifest.mjs @@ -0,0 +1,45 @@ +/* +The intent of this script is to do all of the modifications of the +manifest file that we need to do in order to release the system. +This can include removing dev-only fields/attributes that end +users will never, and should never, care about nor need. +*/ +import { readFile, writeFile } from "fs/promises"; + +const MANIFEST_PATH = `system.json`; + +const { + DOWNLOAD_URL, + LATEST_URL, +} = process.env; + +let manifest; +try { + manifest = JSON.parse(await readFile(MANIFEST_PATH, `utf-8`)); + console.log(`Manifest loaded from disk`); +} catch { + console.error(`Failed to parse manifest file.`); + process.exit(1); +}; + +console.log(`Updating download/manifest URLs`) +manifest.download = DOWNLOAD_URL; +manifest.manifest = LATEST_URL; + +// Filter out dev-only resources +if (manifest.esmodules) { + console.log(`Removing dev-only esmodules`); + manifest.esmodules = manifest.esmodules.filter( + filepath => !filepath.startsWith(`dev/`) + ); +}; + +// Remove dev flags +console.log(`Cleaning up flags`); +delete manifest.flags?.hotReload; +if (Object.keys(manifest.flags).length === 0) { + delete manifest.flags; +}; + +await writeFile(MANIFEST_PATH, JSON.stringify(manifest, undefined, `\t`)); +console.log(`Manifest written back to disk`); diff --git a/scripts/tagExists.mjs b/scripts/tagExists.mjs new file mode 100644 index 0000000..2ddcdbd --- /dev/null +++ b/scripts/tagExists.mjs @@ -0,0 +1,38 @@ +import axios from "axios"; + +const { + TAG_NAME, + FORGEJO_API_URL: API_URL, + FORGEJO_REPOSITORY: REPO, + FORGEJO_TOKEN: TOKEN, +} = process.env; + + +async function main() { + + if (!TAG_NAME) { + console.log(`Tag name must not be blank`); + process.exit(1); + }; + + const requestURL = `${API_URL}/repos/${REPO}/tags/${TAG_NAME}`; + + const response = await axios.get( + requestURL, + { + headers: { Authorization: `token ${TOKEN}` }, + validateStatus: () => true, + }, + ); + + // We actually *want* an error when the tag exists, instead of when + // it doesn't + if (response.status === 200) { + console.log(`Tag with name "${TAG_NAME}" already exists`); + process.exit(1); + }; + + console.log(`Tag with name "${TAG_NAME}" not found, proceeding`); +}; + +main(); diff --git a/scripts/uploadToS3.mjs b/scripts/uploadToS3.mjs new file mode 100644 index 0000000..dacd2e8 --- /dev/null +++ b/scripts/uploadToS3.mjs @@ -0,0 +1,65 @@ +import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; +import { createReadStream } from "fs"; + +const requiredEnvVariables = [ + `TAG`, `FILE`, + `FORGEJO_REPOSITORY`, + `S3_BUCKET`, `S3_REGION`, `S3_KEY`, `S3_SECRET`, `S3_ENDPOINT`, +]; + +async function main() { + + // Assert all of the required env variables are present + const missing = []; + for (const envVar of requiredEnvVariables) { + if (!(envVar in process.env)) { + missing.push(envVar); + }; + }; + if (missing.length > 0) { + console.error(`Missing the following required environment variables: ${missing.join(`, `)}`); + process.exit(1); + }; + + const { + TAG, + S3_ENDPOINT, + S3_REGION, + S3_KEY, + S3_SECRET, + S3_BUCKET, + FILE, + FORGEJO_REPOSITORY: REPO, + } = process.env; + + const s3Client = new S3Client({ + endpoint: S3_ENDPOINT, + forcePathStyle: false, + region: S3_REGION, + credentials: { + accessKeyId: S3_KEY, + secretAccessKey: S3_SECRET + }, + }); + + const name = FILE.split(`/`).at(-1); + + const params = { + Bucket: S3_BUCKET, + Key: `${REPO}/${TAG}/${name}`, + Body: createReadStream(FILE), + ACL: "public-read", + METADATA: { + "x-repo-version": TAG, + }, + }; + + try { + const response = await s3Client.send(new PutObjectCommand(params)); + console.log("Upload successful"); + } catch (err) { + console.error("Upload to s3 failed"); + }; +}; + +main(); -- 2.49.1