Skip to content

Update babel monorepo to v8 #81

Update babel monorepo to v8

Update babel monorepo to v8 #81

---
# Build the production website and publish it as a checksummed tarball on a
# per-deploy GitHub release, for deployment on grass.osgeo.org.
#
# The production server does not build the site. Its cronjob
# (grass-addons: utils/cronjobs_osgeo_lxd/hugo_clean_and_update_job.sh)
# downloads the tarball from the release marked "latest", verifies the
# checksum, and rsyncs it into the web root. This keeps the Hugo Extended +
# Dart Sass + Node toolchain pinned in CI only, so nothing has to be installed
# or upgraded on the server. Old releases are pruned to a bounded history, and
# a bad build can be rolled back by re-marking an older release as latest.
#
# Two jobs: "build" produces the tarball and hands it over as a workflow
# artifact; "deploy" (needs: build) publishes it to the release. A failed
# build therefore never touches the published assets, and only the deploy
# job holds a writable token.
name: Build production site artifact
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Runs the build job on pull requests as a merge gate; the deploy job is
# skipped for pull requests (see its `if` below).
pull_request:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Each job declares exactly what it needs.
permissions: {}
concurrency:
group: >-
production-site-${{ github.event_name == 'pull_request' &&
github.head_ref || github.ref }}
# Cancel in progress in pull requests.
# Otherwise, limit to one in progress and one queued for each ref.
# Only the latest queued run per ref is kept, older ones are cancelled.
# The already running publish is always allowed to complete, so a deploy is
# never killed mid-upload; the freshness gate in the deploy job then makes
# sure only the newest commit publishes.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
env:
# Toolchain version pins, kept current by Renovate (see the custom
# manager in renovate.json that matches these annotations).
# renovate: datasource=github-releases depName=gohugoio/hugo
HUGO_VERSION: 0.113.0
# renovate: datasource=github-releases depName=sass/dart-sass
DART_SASS_VERSION: 1.101.0
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Hugo CLI (extended)
env:
TEMP_DIR: ${{ runner.temp }}
run: |
# Hugo release assets have used two naming schemes; try both.
base="https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}"
wget -O "$TEMP_DIR/hugo.deb" "$base/hugo_extended_${HUGO_VERSION}_Linux-64bit.deb" \
|| wget -O "$TEMP_DIR/hugo.deb" "$base/hugo_extended_${HUGO_VERSION}_linux-amd64.deb"
sudo dpkg -i "$TEMP_DIR/hugo.deb"
# Pinned for reproducibility. Note: with Hugo 0.113 the site compiles via
# Hugo Extended's built-in libsass (head.html sets no "transpiler"
# option), so this binary is not exercised yet; it is pinned now so the
# planned Hugo/Dart Sass upgrade inherits a reproducible toolchain.
- name: Install Dart Sass
env:
TEMP_DIR: ${{ runner.temp }}
run: |
curl -fsSL -o "$TEMP_DIR/dart-sass.tar.gz" \
"https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -xzf "$TEMP_DIR/dart-sass.tar.gz" -C "$TEMP_DIR"
echo "$TEMP_DIR/dart-sass" >> "$GITHUB_PATH"
- name: Setup Node.js
if: ${{ hashFiles('.nvmrc') != '' }}
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
# Skipped when no lockfile exists (pre-migration master); fails the job
# if the install fails, so a broken artifact is never published.
- name: Install Node.js dependencies
if: ${{ hashFiles('package-lock.json', 'npm-shrinkwrap.json') != '' }}
run: npm ci
- name: Build with Hugo
env:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: hugo --minify
- name: Record build info
run: |
{
echo "commit: ${GITHUB_SHA}"
echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
} > public/BUILD_INFO
- name: Package and checksum
run: |
tar -czf grass-website.tar.gz -C public .
sha256sum grass-website.tar.gz > grass-website.tar.gz.sha256
# Handoff to the deploy job; short retention, this is not the published
# copy (the release assets are).
- name: Upload build for the deploy job
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: production-site
path: |
grass-website.tar.gz
grass-website.tar.gz.sha256
retention-days: 1
if-no-files-found: error
deploy:
# Pull requests only validate the build; publishing happens only from the
# default branch (pushes or manual dispatch on master). The environment
# adds platform-level enforcement on top: its deployment branch policy
# should allow master only, and protection rules (required reviewers) can
# gate publishes with approvals; both are configured in the repository
# settings under Environments.
if: >-
${{ github.event_name != 'pull_request' &&
github.ref == 'refs/heads/master' }}
runs-on: ubuntu-latest
needs: build
environment:
name: production
url: https://grass.osgeo.org/
permissions:
contents: write
steps:
# Only the newest commit of the ref may publish. If the ref moved while
# this run was building or queued, a newer run owns the publish and this
# one skips (as a success, not a failure).
- name: Check this run is still the newest commit
id: freshness
env:
GH_TOKEN: ${{ github.token }}
run: |
head_sha="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/$GITHUB_REF_NAME" --jq '.object.sha')"
if [[ "$head_sha" == "$GITHUB_SHA" ]]; then
echo "current=true" >> "$GITHUB_OUTPUT"
else
echo "current=false" >> "$GITHUB_OUTPUT"
echo "::notice::Skipping publish: $GITHUB_REF_NAME moved to ${head_sha};" \
"a newer run owns the publish (this run built ${GITHUB_SHA})."
fi
- name: Download build
if: ${{ steps.freshness.outputs.current == 'true' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: production-site
- name: Verify checksum
if: ${{ steps.freshness.outputs.current == 'true' }}
run: sha256sum -c grass-website.tar.gz.sha256
# Each deploy is its own immutable, calendar-dated release marked as
# "latest". The server downloads from the releases/latest/download
# shortcut, so a rollback is just re-marking an older release as latest
# ("gh release edit <tag> --latest"). Asset names are stable so the
# server always requests the same files.
- name: Publish a versioned production release
if: ${{ steps.freshness.outputs.current == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
short_sha="${GITHUB_SHA::7}"
tag="site-$(date -u +'%Y%m%d-%H%M%S')-${short_sha}"
title="Production site $(date -u +'%Y-%m-%d') (${short_sha})"
{
echo "Automated production build of grass.osgeo.org from ${short_sha}."
echo
echo "The server deploys the release marked \"latest\"; see BUILD_INFO"
echo "inside the tarball for provenance. Add \`[keep]\` to a release"
echo "title to exempt it from automatic pruning."
} > release-notes.md
gh release create "$tag" \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "$title" \
--notes-file release-notes.md \
--latest \
grass-website.tar.gz grass-website.tar.gz.sha256
# Bounded retention: keep the newest $KEEP builds plus any pinned with
# [keep] in the title, delete the rest (with their tags). This answers
# "how do old release assets get cleaned up".
- name: Prune old production releases
if: ${{ steps.freshness.outputs.current == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
KEEP: "10"
run: |
mapfile -t stale < <(
gh release list --repo "$GITHUB_REPOSITORY" --limit 500 \
--json tagName,name,createdAt \
| jq -r --argjson keep "$KEEP" '
[.[] | select(.tagName | startswith("site-"))]
| sort_by(.createdAt) | reverse | .[$keep:]
| .[] | select(.name | test("\\[keep\\]") | not) | .tagName'
)
for tag in "${stale[@]}"; do
echo "Pruning old release $tag"
gh release delete "$tag" --repo "$GITHUB_REPOSITORY" --cleanup-tag --yes
done
echo "Pruned ${#stale[@]} release(s); kept newest $KEEP plus any [keep]."