Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
name: Release

# Push a tag `vX.Y.Z` (matching @version in mix.exs) to verify, create the
# GitHub release and publish to Hex. Run it manually (Actions -> Release ->
# Run workflow) for a dry run: only the verify job runs; nothing is published.
#
# Requires the HEX_API_KEY repository secret
# (Settings -> Secrets and variables -> Actions).

on:
push:
tags: ["v*"]
workflow_dispatch:

permissions:
contents: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

env:
ELIXIR_VERSION: "1.19.5"
OTP_VERSION: "28.3.1"

jobs:
verify:
name: Verify release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
prerelease: ${{ steps.version.outputs.prerelease }}
steps:
- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ env.ELIXIR_VERSION }}
otp-version: ${{ env.OTP_VERSION }}

- name: Read version
id: version
shell: bash
run: |
set -euo pipefail
version="$(sed -n 's/^ @version "\(.*\)"/\1/p' mix.exs | head -n1)"
if [[ -z "${version}" ]]; then
echo "::error::Could not read @version from mix.exs"
exit 1
fi

if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" != "v${version}" ]]; then
echo "::error::Tag ${GITHUB_REF_NAME} does not match mix.exs version ${version} (expected v${version})"
exit 1
fi

if ! grep -q "^## \[${version}\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md has no '## [${version}]' entry"
exit 1
fi

prerelease=false
[[ "${version}" == *-* ]] && prerelease=true
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "prerelease=${prerelease}" >> "$GITHUB_OUTPUT"
echo "Releasing ${version} (prerelease: ${prerelease})"

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: release-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ hashFiles('mix.lock') }}

- name: Install dependencies
run: mix deps.get

- name: Check formatting
run: mix format --check-formatted

- name: Compile
env:
MIX_ENV: test
run: mix compile --warnings-as-errors

- name: Run tests
run: mix test

- name: Build docs
run: mix docs --warnings-as-errors

- name: Build package
run: mix hex.build

github_release:
name: Create GitHub release
needs: verify
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Write release notes
shell: bash
env:
VERSION: ${{ needs.verify.outputs.version }}
run: |
set -euo pipefail
notes_file="docs/release_notes_v${VERSION//./_}.md"
if [[ -f "${notes_file}" ]]; then
cp "${notes_file}" release_notes.md
else
# The version's CHANGELOG section, up to the next "## [" heading.
awk -v v="${VERSION}" '
index($0, "## [" v "]") == 1 { found = 1; next }
found && /^## \[/ { exit }
found { print }
' CHANGELOG.md > release_notes.md
fi
test -s release_notes.md

- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PRERELEASE: ${{ needs.verify.outputs.prerelease }}
shell: bash
run: |
set -euo pipefail
if gh release view "${GITHUB_REF_NAME}" > /dev/null 2>&1; then
echo "Release ${GITHUB_REF_NAME} already exists; leaving it as is."
exit 0
fi

flags=(--verify-tag --title "ExZarr ${GITHUB_REF_NAME}" --notes-file release_notes.md)
[[ "${PRERELEASE}" == "true" ]] && flags+=(--prerelease)
gh release create "${GITHUB_REF_NAME}" "${flags[@]}"

publish_hex:
name: Publish to Hex
needs: [verify, github_release]
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ env.ELIXIR_VERSION }}
otp-version: ${{ env.OTP_VERSION }}

- name: Install dependencies
run: mix deps.get

- name: Publish
env:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${HEX_API_KEY}" ]]; then
echo "::error::HEX_API_KEY secret is not set"
exit 1
fi
mix hex.publish --yes
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ defmodule ExZarr.MixProject do
{:sweet_xml, "~> 0.7", optional: true},
{:goth, "~> 1.4", optional: true},
{:azure_sdk, "~> 0.4.1", optional: true},
# override: azure_sdk 0.4.1 still declares req ~> 0.5; CVE-2026-49755 needs >= 0.6.1
{:req, "~> 0.6.1", optional: true, override: true},
# >= 0.6.1 for CVE-2026-49755 (azure_sdk and ex_aws both allow 0.6)
{:req, "~> 0.6.1", optional: true},

# Database storage backends (optional)
{:mongodb_driver, "~> 1.4", optional: true},
Expand Down
Loading