Only the assets this workflow uploads are removed before a re-run, so a hand-attached asset on the release survives. jq is installed before the tag resolve that parses its output, the SASjs CLI is installed at the version the tag's sas/package.json pins, and the npmrc secret is appended rather than overwriting the file.
210 lines
7.8 KiB
YAML
210 lines
7.8 KiB
YAML
name: Release assets
|
|
run-name: Building and uploading the release assets
|
|
|
|
# Builds the downloadable artefacts for an existing release and uploads them.
|
|
#
|
|
# The release job cuts the tag before it builds, so a failure anywhere between
|
|
# the semantic-release step and the asset upload leaves a published release with
|
|
# no files - and that job cannot simply be re-run, because semantic-release
|
|
# refuses once the tag exists. This workflow rebuilds the artefacts from the tag
|
|
# and attaches them, so the release can be completed without cutting a new one.
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Release tag to build and upload (blank = the latest release)'
|
|
required: false
|
|
default: ''
|
|
|
|
env:
|
|
NODE_VERSION: '24.5.0'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
assets:
|
|
runs-on: ubuntu-latest
|
|
# Two runs uploading the same asset names would race the delete-then-upload
|
|
# below.
|
|
concurrency:
|
|
group: release-assets
|
|
cancel-in-progress: false
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
|
|
- name: Write .npmrc file
|
|
run: |
|
|
printf '%s\n' "$NPMRC" >> client/.npmrc
|
|
echo "legacy-peer-deps=true" >> client/.npmrc
|
|
shell: bash
|
|
env:
|
|
NPMRC: ${{ secrets.NPMRC }}
|
|
|
|
- name: Install system packages
|
|
# jq parses the release JSON below, so it is installed before the tag
|
|
# resolve.
|
|
run: |
|
|
apt-get update
|
|
apt-get install -y zip jq
|
|
|
|
- name: Resolve the release tag
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
REQUESTED_TAG: ${{ inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
AUTH_HEADER="Authorization: token $GITEA_TOKEN"
|
|
BASE="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}"
|
|
|
|
if [ -n "${REQUESTED_TAG}" ]; then
|
|
TAG="${REQUESTED_TAG}"
|
|
# Fail here rather than after a ten-minute build if the tag is not
|
|
# cut yet or has no release.
|
|
curl --fail-with-body -sS -H "$AUTH_HEADER" "$BASE/releases/tags/${TAG}" > /dev/null
|
|
else
|
|
TAG=$(curl --fail-with-body -sS -H "$AUTH_HEADER" "$BASE/releases/latest" | jq -r '.tag_name')
|
|
fi
|
|
echo "Building assets for ${TAG}"
|
|
echo "TAG=${TAG}" >> "$GITHUB_ENV"
|
|
|
|
- name: Check out the tag
|
|
run: |
|
|
set -euo pipefail
|
|
git fetch --force --tags origin "+refs/tags/${TAG}:refs/tags/${TAG}"
|
|
git checkout --force "refs/tags/${TAG}"
|
|
|
|
- name: Install the SASjs CLI the tag pins
|
|
run: |
|
|
cd sas
|
|
CLI_VERSION=$(node -p "require('./package.json').dependencies['@sasjs/cli']")
|
|
npm i -g "@sasjs/cli@${CLI_VERSION}"
|
|
|
|
- name: Frontend build
|
|
run: |
|
|
cd client
|
|
# Decrypt and Install sheet
|
|
echo "$SHEET_PWD" | gpg --batch --yes --passphrase-fd 0 ./libraries/sheet-crypto.tgz.gpg
|
|
npm ci
|
|
npm i webpack
|
|
npm run build
|
|
shell: bash
|
|
env:
|
|
SHEET_PWD: ${{ secrets.SHEET_PWD }}
|
|
|
|
- name: Build SAS9 EBI Release
|
|
run: |
|
|
cd sas
|
|
npm i
|
|
sasjs c -t sas9
|
|
rm -rf sasjsbuild/tests
|
|
sasjs b -t sas9
|
|
cp sasjsbuild/mysas9deploy.sas ./demostream_sas9.sas
|
|
# remove streamed component and rebuild SAS 9 services
|
|
rm -rf sasjsbuild/services/web9
|
|
rm sasjsbuild/services/clickme.sas
|
|
sasjs b -t sas9
|
|
cp sasjsbuild/mysas9deploy.sas ./sas9.sas
|
|
|
|
- name: Build SASjs Server Release
|
|
run: |
|
|
cd sas
|
|
cp sasjs/utils/favicon.ico ../client/dist/favicon.ico
|
|
sasjs c -t server
|
|
rm -rf sasjsbuild/tests
|
|
server_apploc="/Public/app/dc"
|
|
sed -i "s|apploc=\"[^\"]*\"|apploc=\"${server_apploc}\"|g" sasjsbuild/services/web/index.html
|
|
sasjs b -t server
|
|
cp sasjsbuild/server.json.zip ./sasjs_server.json.zip
|
|
|
|
- name: Build Viya Release
|
|
run: |
|
|
cd sas
|
|
sasjs c -t viya
|
|
rm -rf sasjsbuild/tests
|
|
sed -i -e 's/servertype="SASJS"/servertype="SASVIYA"/g' sasjsbuild/services/DC.html
|
|
sasjs b -t viya
|
|
cp sasjsbuild/viya.sas ./viya.sas
|
|
# compile Viya Full deploy (without web)
|
|
rm -rf sasjsbuild/services/web
|
|
rm sasjsbuild/services/DC.html
|
|
sasjs b -t viya
|
|
cp sasjsbuild/viya.sas ./viya_noweb.sas
|
|
cp sasjsbuild/viya.json ./viya_noweb.json
|
|
|
|
- name: Zip Frontend (including viya.json for full viya deploy)
|
|
run: |
|
|
cd sas
|
|
cp sasjsbuild/viya.json ../client/dist/viya.json
|
|
# Zip from *inside* dist so the archive holds the frontend files at its
|
|
# root rather than under a client/dist/ prefix (see #147).
|
|
cd ../client/dist
|
|
zip -r ../../frontend.zip .
|
|
|
|
- name: Upload assets to the release
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
AUTH_HEADER="Authorization: token $GITEA_TOKEN"
|
|
BASE="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}"
|
|
|
|
RELEASE_JSON=$(curl --fail-with-body -sS -H "$AUTH_HEADER" "$BASE/releases/tags/${TAG}")
|
|
RELEASE_ID=$(echo "$RELEASE_JSON" | jq -r '.id')
|
|
RELEASE_BODY=$(echo "$RELEASE_JSON" | jq -r '.body')
|
|
|
|
ASSETS=(frontend.zip
|
|
sas/demostream_sas9.sas
|
|
sas/viya.sas
|
|
sas/sasjs_server.json.zip
|
|
sas/sas9.sas
|
|
sas/viya_noweb.sas
|
|
sas/viya_noweb.json)
|
|
|
|
: > SHA256SUMS
|
|
for f in "${ASSETS[@]}"; do
|
|
sum=$(sha256sum "$f" | cut -d' ' -f1)
|
|
printf '%s %s\n' "$sum" "${f##*/}" >> SHA256SUMS
|
|
done
|
|
cat SHA256SUMS
|
|
|
|
# Replacing the assets means removing the ones this workflow uploads,
|
|
# and a second run must not append the verification section twice. An
|
|
# asset the release carries from another source is left alone.
|
|
OWNED=$(printf '%s\n' "${ASSETS[@]##*/}" SHA256SUMS)
|
|
echo "$RELEASE_JSON" | jq -r '.assets[]? | "\(.id) \(.name)"' |
|
|
while read -r asset_id asset_name; do
|
|
if printf '%s\n' "$OWNED" | grep -qxF -- "$asset_name"; then
|
|
echo "Removing previous ${asset_name}"
|
|
curl --fail-with-body -sS -X DELETE -H "$AUTH_HEADER" "$BASE/releases/${RELEASE_ID}/assets/${asset_id}"
|
|
else
|
|
echo "Leaving ${asset_name} in place: this workflow did not upload it"
|
|
fi
|
|
done
|
|
|
|
if echo "$RELEASE_BODY" | grep -q "## Verifying the download"; then
|
|
echo "Release body already carries the verification section"
|
|
else
|
|
VERIFY_SECTION=$(./.gitea/scripts/verify-section.sh)
|
|
NEW_BODY=$(jq -nr --arg body "$RELEASE_BODY" --arg verify "$VERIFY_SECTION" \
|
|
'$body + "\n" + $verify + "\n\nFor installation instructions, please visit https://docs.datacontroller.io/"')
|
|
curl --fail-with-body -sS -X PATCH \
|
|
-H "$AUTH_HEADER" \
|
|
-H 'Content-Type: application/json' \
|
|
--data "$(jq -n --arg body "$NEW_BODY" '{draft:false, body:$body}')" \
|
|
"$BASE/releases/$RELEASE_ID"
|
|
fi
|
|
|
|
URL="$BASE/releases/${RELEASE_ID}/assets"
|
|
for f in "${ASSETS[@]}"; do
|
|
echo "Uploading $f ..."
|
|
curl --fail-with-body -sS -H "$AUTH_HEADER" "$URL" -F "attachment=@$f"
|
|
done
|
|
echo "Uploading SHA256SUMS ..."
|
|
curl --fail-with-body -sS -H "$AUTH_HEADER" "$URL" -F "attachment=@SHA256SUMS"
|