From 1171f7c7d407b2b7b9eaa3f67a5536f883d07369 Mon Sep 17 00:00:00 2001 From: Daniele Date: Sun, 16 Nov 2025 11:33:45 +0100 Subject: [PATCH] Add GitHub Actions workflow to publish Gleam package Introduces a workflow for publishing the Gleam package to Hex when a tag matching v* is pushed or a PR is merged to main. The workflow includes steps for environment setup, dependency installation, build, test, version verification, Hex API key validation, publishing, and GitHub release creation. --- .github/workflows/publish-gleam.yml | 169 ++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 .github/workflows/publish-gleam.yml diff --git a/.github/workflows/publish-gleam.yml b/.github/workflows/publish-gleam.yml new file mode 100644 index 0000000..e3524c3 --- /dev/null +++ b/.github/workflows/publish-gleam.yml @@ -0,0 +1,169 @@ +name: Publish (Gleam) + +# Publish package using `gleam publish` when a tag matching v* is pushed. +# Steps: +# - checkout (full history) +# - setup OTP / Gleam +# - build & test +# - verify the tag version matches `gleam.toml` +# - verify HEX API key via HTTP +# - publish with `gleam publish --yes` (non-interactive) + +on: + push: + tags: + - 'v*' + pull_request: + types: [closed] + branches: [main] + +permissions: + contents: write + packages: write + id-token: write + +jobs: + publish: + name: Release to Hex + runs-on: ubuntu-latest + if: >- + contains(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.merged == true) + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup runtime + uses: ./.github/actions/ci-setup + with: + otp-version: '28.1' + gleam-version: '1.13.0' + + - name: Show versions + run: | + erl -version || true + gleam --version || true + + - name: Cache Gleam deps + uses: actions/cache@v4 + with: + path: | + ~/.cache/gleam + ~/.gleam + ./_gleam_deps + ./build + key: ${{ runner.os }}-gleam-1.13.0-otp28-publish-${{ hashFiles('**/gleam.toml') }} + restore-keys: | + ${{ runner.os }}-gleam-1.13.0-otp28-publish- + + - name: Install dependencies + run: | + set -eux + gleam deps download + + - name: Build + run: | + set -eux + gleam build + + - name: Run tests (sanity) + run: | + set -eux + gleam test + + - name: Determine version from tag + id: ver + run: | + TAG=${GITHUB_REF#refs/tags/} + VERSION=${TAG#v} + echo "Determined version ${VERSION} from tag ${TAG}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Create tag from gleam.toml (on merged PR) + if: github.event_name == 'pull_request' && github.event.pull_request.merged == true + run: | + set -euo pipefail + VERSION=$(grep '^version' gleam.toml | sed -E 's/.*= *"([^\"]+)".*/\1/') + TAG="v${VERSION}" + echo "Derived tag: ${TAG}" + git fetch origin --tags + if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then + echo "Tag ${TAG} already exists, skipping" + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -a "${TAG}" -m "Release ${TAG}" + git push origin "${TAG}" + echo "Pushed tag ${TAG} to origin" + + - name: Verify tag matches `gleam.toml` + run: | + VERSION="${{ steps.ver.outputs.version }}" + FILE_VER=$(grep '^version' gleam.toml | sed -E 's/.*= *"([^"]+)".*/\1/') || true + echo "gleam.toml version: ${FILE_VER}" + if [ -n "${FILE_VER}" ] && [ "${FILE_VER}" != "${VERSION}" ]; then + echo "Tag version (${VERSION}) does not match gleam.toml (${FILE_VER}). Aborting publish." + exit 1 + fi + + - name: Verify HEX API key via HTTP + env: + HEX_API_KEY: ${{ secrets.HEX_API_KEY }} + run: | + set -euo pipefail + if [ -z "${HEX_API_KEY:-}" ]; then + echo "HEX_API_KEY secret is not set; aborting" + exit 1 + fi + # ask for JSON explicitly + RES=$(curl -s -w "%{http_code}" -H "Authorization: Bearer ${HEX_API_KEY}" -H "Accept: application/vnd.hex+json; version=1.0" https://hex.pm/api/me) + HTTP=${RES: -3} + BODY=${RES:: -3} + echo "HTTP status: ${HTTP}" + if [ "${HTTP}" != "200" ]; then + echo "HEX API key invalid or API returned ${HTTP}. Response body preview:" + echo "${BODY}" | sed -n '1,40p' + exit 1 + fi + + - name: Check if version already published on Hex + run: | + set -euo pipefail + PACKAGE=$(grep '^name' gleam.toml | sed -E 's/.*= *"([^"]+)".*/\1/') + VERSION="${{ steps.ver.outputs.version }}" + echo "Checking Hex for package ${PACKAGE} version ${VERSION}" + if curl -s "https://hex.pm/api/packages/${PACKAGE}" | jq -e ".releases[] | select(.version==\"${VERSION}\")" > /dev/null; then + echo "Version ${VERSION} already exists on Hex. Skipping publish." + exit 0 + fi + + - name: Publish to Hex + if: startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.merged == true) + env: + HEX_API_KEY: ${{ secrets.HEX_API_KEY }} + run: | + set -euo pipefail + echo "Publishing with gleam publish --yes" + echo "I am not using semantic versioning" | gleam publish --yes + + - name: Create GitHub Release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + body: | + Release ${{ github.ref_name }} + + See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/CHANGELOG.md) for details. + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload package artifact (audit) + if: always() + uses: actions/upload-artifact@v4 + with: + name: gleam-hex-package + path: _build/default/lib/thrifty/hex/thrifty-*.tar || true