Files
OpenFrontIO/.github/workflows/release.yml
T
VariableVince 8e6c0c1132 Chore:Deprecation of Node 20: migrate actions in workflows to Node 24 versions (#3460)
## Description:

Node 20 will reach EOL in April 2026. Node.js 20 actions are deprecated
and will be forced to run on Node.js 24 starting June 2, 2026:
https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/

Update our workflows in this PR.

- For _deployment-action_ and _deployment-status_: stop using these and
. They seem quite unmaintained which could pose risks and there is no
Node 24 version yet:
https://github.com/chrnorm/deployment-action/issues/93 and
https://github.com/chrnorm/deployment-status/issues/53. It will probably
be updated to Node 24, but why wait if we don't actually need to be
dependent on them per se.

- Instead of the above, use actions/github-script@v8 with default API.
Maybe a bit more maintainance work, if any, but better than to be
dependent on unmaintained outside actions. For reference see
https://docs.github.com/en/rest/deployments/deployments?apiVersion=2026-03-10#create-a-deployment

- For _auto-author-assign_, use v3.0.1
(4d585cc37690897bd9015942ed6e766aa7cdb97f). From v3.0.0 it uses Node 24:
https://github.com/toshimaru/auto-author-assign/releases

- For _stale_, use v10.2.0 (b5d41d4e1d5dceea10e7104786b73624c18a190f).
From v10.0.0 it uses Node 24: https://github.com/actions/stale/releases

- For other actions, use their appropriate version for Node 24.

- Tested all with FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

tryout33
2026-03-19 21:32:32 -07:00

250 lines
9.2 KiB
YAML

name: 🏷️ Release
on:
release:
types:
- created
- edited
- published
permissions: {}
jobs:
build:
name: 🏗️ Build
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- name: 🔗 Log in to Docker Hub
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ vars.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- id: build
env:
GHCR_REPO: openfront-prod
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
RELEASE_BODY: ${{ github.event.release.body }}
RELEASE_NAME: ${{ github.event.release.name }}
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
ADDITIONAL_VERSION_TAG: ${{ github.event.action == 'published' && 'latest' || '' }}
run: |
set -euxo pipefail
cat <<EOF >> $GITHUB_STEP_SUMMARY
Name: ${RELEASE_NAME}
Tag: ${RELEASE_TAG_NAME}
Changelog:
${RELEASE_BODY}
EOF
./build.sh prod "${RELEASE_TAG_NAME}" "${RELEASE_NAME}" "${RELEASE_BODY}" /tmp/build-metadata.json
IMAGE_ID=$(jq -r '."containerimage.digest"' /tmp/build-metadata.json)
echo "IMAGE_ID=${IMAGE_ID}" >> $GITHUB_OUTPUT
echo "Image ID: \`${IMAGE_ID}\`" >> $GITHUB_STEP_SUMMARY
outputs:
IMAGE_ID: ${{ steps.build.outputs.IMAGE_ID }}
deploy-alpha:
name: 🧪 Deploy to alpha
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [build]
steps:
- uses: actions/checkout@v5
- name: 🔑 Create SSH private key
env:
SERVER_HOST_STAGING: ${{ secrets.SERVER_HOST_STAGING }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -euxo pipefail
mkdir -p ~/.ssh
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
test -n "$SERVER_HOST_STAGING" && ssh-keyscan -H "$SERVER_HOST_STAGING" >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: openfront-prod
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_STAGING: ${{ secrets.SERVER_HOST_STAGING }}
SSH_KEY: ~/.ssh/id_rsa
run: |
set -euxo pipefail
bash -x ./deploy.sh staging staging "${IMAGE_ID}" alpha
- name: ⏳ Wait for deployment to start
env:
FQDN: alpha.${{ vars.DOMAIN }}
run: |
echo "::group::Wait for deployment to start"
set -euxo pipefail
while [ "$(curl -s https://${FQDN}/commit.txt)" != "${GITHUB_SHA}" ]; do
if [ "$SECONDS" -ge 300 ]; then
echo "Timeout: deployment did not start within 5 minutes"
exit 1
fi
sleep 10
done
echo "Deployment started in ${SECONDS} seconds" >> $GITHUB_STEP_SUMMARY
echo "::endgroup::"
deploy-beta:
name: 🐞 Deploy to beta
runs-on: ubuntu-latest
needs: [build, deploy-alpha]
timeout-minutes: 30
environment: prod-beta
steps:
- uses: actions/checkout@v5
- name: 🔑 Create SSH private key
env:
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -euxo pipefail
mkdir -p ~/.ssh
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_KEY: ~/.ssh/id_rsa
run: |
set -euxo pipefail
./deploy.sh prod falk2 "${IMAGE_ID}" beta
- name: ⏳ Wait for deployment to start
env:
FQDN: beta.${{ vars.DOMAIN }}
run: |
echo "::group::Wait for deployment to start"
set -euxo pipefail
while [ "$(curl -s https://${FQDN}/commit.txt)" != "${GITHUB_SHA}" ]; do
if [ "$SECONDS" -ge 300 ]; then
echo "Timeout: deployment did not start within 5 minutes"
exit 1
fi
sleep 10
done
echo "Deployment started in ${SECONDS} seconds" >> $GITHUB_STEP_SUMMARY
echo "::endgroup::"
deploy-blue:
name: 🔵 Deploy to blue
runs-on: ubuntu-latest
needs: [build, deploy-alpha]
timeout-minutes: 30
environment: prod-blue
steps:
- uses: actions/checkout@v5
- name: 🔑 Create SSH private key
env:
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -euxo pipefail
mkdir -p ~/.ssh
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_KEY: ~/.ssh/id_rsa
run: |
set -euxo pipefail
./deploy.sh prod falk2 "${IMAGE_ID}" blue
- name: ⏳ Wait for deployment to start
env:
FQDN: blue.${{ vars.DOMAIN }}
run: |
echo "::group::Wait for deployment to start"
set -euxo pipefail
while [ "$(curl -s https://${FQDN}/commit.txt)" != "${GITHUB_SHA}" ]; do
if [ "$SECONDS" -ge 300 ]; then
echo "Timeout: deployment did not start within 5 minutes"
exit 1
fi
sleep 10
done
echo "Deployment started in ${SECONDS} seconds" >> $GITHUB_STEP_SUMMARY
echo "::endgroup::"
deploy-green:
name: 🟢 Deploy to green
runs-on: ubuntu-latest
needs: [build, deploy-alpha]
timeout-minutes: 30
environment: prod-green
steps:
- uses: actions/checkout@v5
- name: 🔑 Create SSH private key
env:
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -euxo pipefail
mkdir -p ~/.ssh
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
SSH_KEY: ~/.ssh/id_rsa
run: |
set -euxo pipefail
./deploy.sh prod falk2 "${IMAGE_ID}" green
- name: ⏳ Wait for deployment to start
env:
FQDN: green.${{ vars.DOMAIN }}
run: |
echo "::group::Wait for deployment to start"
set -euxo pipefail
while [ "$(curl -s https://${FQDN}/commit.txt)" != "${GITHUB_SHA}" ]; do
if [ "$SECONDS" -ge 300 ]; then
echo "Timeout: deployment did not start within 5 minutes"
exit 1
fi
sleep 10
done
echo "Deployment started in ${SECONDS} seconds" >> $GITHUB_STEP_SUMMARY
echo "::endgroup::"