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
38 changes: 38 additions & 0 deletions .github/workflows/check_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

# Checks that every place that names hex_core's version names the version in
# src/hex_core.app.src

set -euo pipefail

version=$(erl -noshell -eval '{ok, [{application, hex_core, App}]} = file:consult("src/hex_core.app.src"), io:put_chars(proplists:get_value(vsn, App)), halt().')
failed=false

# Every line of $1 that matches the extended regex $2 must capture the version
# in the regex's first group, and at least one line must match
check() {
local file=$1 regex=$2 found
found=$(sed -nE "s/.*$regex.*/\\1/p" "$file")

if [ -z "$found" ]; then
echo "::error file=$file::$file has no line matching $regex"
failed=true
fi

for found_version in $found; do
if [ "$found_version" != "$version" ]; then
echo "::error file=$file::$file names version $found_version, src/hex_core.app.src has $version"
failed=true
fi
done
}

check src/hex_core.hrl '^-define\(HEX_CORE_VERSION, "([^"]*)"\)\.$'
check README.md '\{hex_core, "([^"]*)"\}'
check README.md '\{:hex_core, "~> ([^"]*)"\}'

if [ "$failed" = true ]; then
exit 1
fi

echo "Version $version matches in every file"
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ jobs:
- run: rebar3 as test proper
- run: rebar3 fmt --check
if: ${{ matrix.pair.lint }}
- run: .github/workflows/check_version.sh
if: ${{ matrix.pair.lint }}
62 changes: 45 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ name: Release

on:
push:
tags:
- "v*"
branches:
- main

permissions:
contents: read

# Two pushes in a row would otherwise both try to tag and publish the version
concurrency:
group: release

jobs:
release:
name: Release
Expand All @@ -16,11 +20,12 @@ jobs:
# The GitHub environment that hex_core's workload identity on hex.pm names
environment: release
permissions:
contents: write # create the GitHub release
contents: write # push the version tag and create the GitHub release
id-token: write # the OIDC token mix hex.publish exchanges with Workload Identity
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
Expand All @@ -34,20 +39,20 @@ jobs:
- name: Install Hex
run: mix archive.install github hexpm/hex ref 1d155e718aa76ab75d03f6f4bdcb0d8042f9a0ad --force

- name: Read the release notes from the changelog
env:
TAG: ${{ github.ref_name }}
- name: Check that every file names the same version
run: .github/workflows/check_version.sh

- name: Read the version and its release notes from the changelog
id: version
run: |
version=$(erl -noshell -eval '{ok, [{application, hex_core, App}]} = file:consult("src/hex_core.app.src"), io:put_chars(proplists:get_value(vsn, App)), halt().')
tag="v$version"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"

if [ "$TAG" != "v$version" ]; then
echo "::error::Tag $TAG doesn't match version $version in src/hex_core.app.src"
exit 1
fi

# The lines under "## $TAG (date)" up to the next "## " heading,
# The lines under "## $tag (date)" up to the next "## " heading,
# without leading and trailing blank lines
awk -v heading="## $TAG " '
awk -v heading="## $tag " '
/^## / {
if (found) exit
found = index($0, heading) == 1
Expand All @@ -63,18 +68,41 @@ jobs:
' CHANGELOG.md > "$RUNNER_TEMP/release_notes.md"

if [ ! -s "$RUNNER_TEMP/release_notes.md" ]; then
echo "::error::CHANGELOG.md has no section for $TAG"
echo "::error::CHANGELOG.md has no section for $tag"
exit 1
fi

- name: Tag the version
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ steps.version.outputs.tag }}
run: |
if [ -n "$(git tag -l "$TAG")" ]; then
echo "$TAG is already tagged"
else
gh api --method POST "repos/$GH_REPO/git/refs" -f "ref=refs/tags/$TAG" -f "sha=$GITHUB_SHA"
fi

- name: Publish to Hex
env:
MIX_EXS: publish.exs
run: mix hex.publish --yes
VERSION: ${{ steps.version.outputs.version }}
run: |
if mix hex.info hex_core "$VERSION"; then
echo "hex_core $VERSION is already published"
else
mix hex.publish --yes
fi

- name: Create the GitHub release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: gh release create "$TAG" --title "$TAG" --verify-tag --notes-file "$RUNNER_TEMP/release_notes.md"
TAG: ${{ steps.version.outputs.tag }}
run: |
if gh release view "$TAG" > /dev/null; then
echo "The $TAG release already exists"
else
gh release create "$TAG" --title "$TAG" --verify-tag --notes-file "$RUNNER_TEMP/release_notes.md"
fi
6 changes: 4 additions & 2 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

4. Commit changes above with title "Release v$VERSION"

5. Push main and the new tag `v$VERSION`
5. Push main

Pushing the tag runs the [Release workflow](.github/workflows/release.yml) in the `release` environment. It publishes the package and docs to Hex with Workload Identity and creates the GitHub release with the version's CHANGELOG section as its notes. To publish by hand instead, run `MIX_EXS=publish.exs mix hex.publish`.
Every push to main runs the [Release workflow](.github/workflows/release.yml) in the `release` environment. When the version in `src/hex_core.app.src` hasn't been released yet, it tags the pushed commit `v$VERSION`, publishes the package and docs to Hex with Workload Identity and creates the GitHub release with the version's CHANGELOG section as its notes. Each step is skipped when it's already done, so re-running a failed run picks up where it stopped. To publish by hand instead, run `MIX_EXS=publish.exs mix hex.publish`.

## Places where version is mentioned

Expand All @@ -19,3 +19,5 @@ src/hex_core.app.src
src/hex_core.hrl
README.md
```

[`check_version.sh`](.github/workflows/check_version.sh) fails when `src/hex_core.hrl` or `README.md` names a different version than `src/hex_core.app.src`. CI runs it, and the Release workflow runs it before tagging.
Loading