Add CI scripts and workflow for forgejo
This commit is contained in:
parent
ee99ab15dd
commit
9c95e4b1f6
6 changed files with 262 additions and 56 deletions
89
.forgejo/workflows/draft-release.yaml
Normal file
89
.forgejo/workflows/draft-release.yaml
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
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 module.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}}"
|
||||||
|
|
||||||
|
- name: Compress files
|
||||||
|
run: zip -r release.zip langs module styles templates README.md assets
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: https://data.forgejo.org/forgejo/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
module.json
|
||||||
|
release.zip
|
||||||
|
scripts/*.mjs
|
||||||
|
package-lock.json
|
||||||
|
package.json
|
||||||
|
retention-days: 7
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
|
||||||
|
forgejo-release:
|
||||||
|
name: "Create Forgejo release"
|
||||||
|
runs-on: act
|
||||||
|
needs:
|
||||||
|
- create-artifacts
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: https://data.forgejo.org/forgejo/download-artifact@v4
|
||||||
|
with:
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm i
|
||||||
|
|
||||||
|
- id: version
|
||||||
|
run: cat module.json | echo version=`jq -r ".version"` >> "$FORGEJO_OUTPUT"
|
||||||
|
|
||||||
|
- 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/module.json"
|
||||||
|
|
||||||
|
- name: Add manifest into release archive
|
||||||
|
run: zip release.zip --update module.json
|
||||||
|
|
||||||
|
- 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: "module.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}}"
|
||||||
51
.github/workflows/draft-release.yaml
vendored
51
.github/workflows/draft-release.yaml
vendored
|
|
@ -1,51 +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 module.json for the version
|
|
||||||
id: "version"
|
|
||||||
run: cat module.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: Update the manifest with the relevant properties
|
|
||||||
id: manifest-update
|
|
||||||
uses: microsoft/variable-substitution@v1
|
|
||||||
with:
|
|
||||||
files: "module.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 module.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: <img aria-hidden="true" src="https://img.shields.io/github/downloads/${{ github.repository }}/v${{ steps.version.outputs.version }}/release.zip?style=flat-square&color=%2300aa00">
|
|
||||||
generateReleaseNotes: true
|
|
||||||
artifacts: "release.zip,module.json"
|
|
||||||
54
scripts/createForgejoRelease.mjs
Normal file
54
scripts/createForgejoRelease.mjs
Normal file
|
|
@ -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: `<!-- Manifest URL: ${WEB_URL}/${REPO}/releases/download/${TAG}/system.json -->`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
@ -1,35 +1,46 @@
|
||||||
/*
|
/*
|
||||||
The intent of this script is to do all of the modifications of the manifest file
|
The intent of this script is to do all of the modifications of the
|
||||||
that we need to do in order to release the package. This can include removing
|
manifest file that we need to do in order to release the system.
|
||||||
dev-only fields/attributes that end users will never, and should never, care
|
This can include removing dev-only fields/attributes that end
|
||||||
about nor need.
|
users will never, and should never, care about nor need.
|
||||||
*/
|
*/
|
||||||
import { readFile, writeFile } from "fs/promises";
|
import { readFile, writeFile } from "fs/promises";
|
||||||
|
|
||||||
const MANIFEST_PATH = `module.json`;
|
const MANIFEST_PATH = `module.json`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
DOWNLOAD_URL,
|
||||||
|
LATEST_URL,
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
let manifest;
|
let manifest;
|
||||||
try {
|
try {
|
||||||
manifest = JSON.parse(await readFile(MANIFEST_PATH, `utf-8`));
|
manifest = JSON.parse(await readFile(MANIFEST_PATH, `utf-8`));
|
||||||
|
console.log(`Manifest loaded from disk`);
|
||||||
} catch {
|
} catch {
|
||||||
console.error(`Failed to parse manifest file.`);
|
console.error(`Failed to parse manifest file.`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(`Updating download/manifest URLs`);
|
||||||
|
manifest.download = DOWNLOAD_URL;
|
||||||
|
manifest.manifest = LATEST_URL;
|
||||||
|
|
||||||
// Filter out dev-only resources
|
// Filter out dev-only resources
|
||||||
if (manifest.esmodules) {
|
if (manifest.esmodules) {
|
||||||
|
console.log(`Removing dev-only esmodules`);
|
||||||
manifest.esmodules = manifest.esmodules.filter(
|
manifest.esmodules = manifest.esmodules.filter(
|
||||||
filepath => !filepath.startsWith(`dev/`)
|
filepath => !filepath.startsWith(`dev/`)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove dev flags
|
// Remove dev flags
|
||||||
|
console.log(`Cleaning up flags`);
|
||||||
delete manifest.flags?.hotReload;
|
delete manifest.flags?.hotReload;
|
||||||
delete manifest.flags?.inDev;
|
delete manifest.flags?.inDev;
|
||||||
|
|
||||||
if (Object.keys(manifest.flags).length === 0) {
|
if (Object.keys(manifest.flags).length === 0) {
|
||||||
delete manifest.flags;
|
delete manifest.flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
await writeFile(MANIFEST_PATH, JSON.stringify(manifest, undefined, `\t`));
|
await writeFile(MANIFEST_PATH, JSON.stringify(manifest, undefined, `\t`));
|
||||||
|
console.log(`Manifest written back to disk`);
|
||||||
|
|
|
||||||
38
scripts/tagExists.mjs
Normal file
38
scripts/tagExists.mjs
Normal file
|
|
@ -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();
|
||||||
65
scripts/uploadToS3.mjs
Normal file
65
scripts/uploadToS3.mjs
Normal file
|
|
@ -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();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue