Skip to content

Auto Release

Auto Release #308

Workflow file for this run

name: Auto Release
on:
workflow_run:
workflows: ["Build"]
types: [completed]
concurrency:
group: auto-release-master
cancel-in-progress: false
jobs:
auto-release:
runs-on: ubuntu-latest
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'master' &&
!contains(github.event.workflow_run.head_commit.message, '[skip-release]')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
token: ${{ secrets.GR_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Get current version
id: current_version
run: |
CURRENT_VERSION=$(node -p "require('./package.json').version")
echo "current=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
- name: Determine version increment
id: version_increment
env:
COMMIT_MSG: ${{ github.event.workflow_run.head_commit.message }}
run: |
# Check commit message for version increment hints
if [[ "$COMMIT_MSG" == *"[major]"* ]]; then
INCREMENT_TYPE="major"
elif [[ "$COMMIT_MSG" == *"[minor]"* ]] || [[ "$COMMIT_MSG" == *"feat:"* ]] || [[ "$COMMIT_MSG" == *"feature:"* ]]; then
INCREMENT_TYPE="minor"
else
INCREMENT_TYPE="patch"
fi
echo "increment_type=$INCREMENT_TYPE" >> $GITHUB_OUTPUT
echo "Version increment type: $INCREMENT_TYPE"
- name: Calculate new version
id: new_version
run: |
CURRENT="${{ steps.current_version.outputs.current }}"
INCREMENT_TYPE="${{ steps.version_increment.outputs.increment_type }}"
# Split version into parts
IFS='.' read -ra VERSION_PARTS <<< "$CURRENT"
MAJOR=${VERSION_PARTS[0]}
MINOR=${VERSION_PARTS[1]}
PATCH=${VERSION_PARTS[2]}
# Increment based on type
case $INCREMENT_TYPE in
"major")
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
"minor")
MINOR=$((MINOR + 1))
PATCH=0
;;
"patch")
PATCH=$((PATCH + 1))
;;
esac
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Prepare release target
id: release_target
run: |
set -euo pipefail
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
WORKFLOW_SHA="${{ github.event.workflow_run.head_sha }}"
git fetch origin master:refs/remotes/origin/master --tags
REMOTE_SHA=$(git rev-parse origin/master)
if [ "$REMOTE_SHA" = "$WORKFLOW_SHA" ]; then
echo "should_release=true" >> "$GITHUB_OUTPUT"
echo "mode=create" >> "$GITHUB_OUTPUT"
echo "Release target is current master"
exit 0
fi
REMOTE_VERSION=$(git show origin/master:package.json | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).version")
REMOTE_SUBJECT=$(git log -1 --pretty=%s origin/master)
EXPECTED_SUBJECT="chore: bump version to v$NEW_VERSION [skip-release] [skip ci]"
if [ "$REMOTE_VERSION" = "$NEW_VERSION" ] && [ "$REMOTE_SUBJECT" = "$EXPECTED_SUBJECT" ]; then
git checkout -B release-target origin/master
echo "should_release=true" >> "$GITHUB_OUTPUT"
echo "mode=reuse" >> "$GITHUB_OUTPUT"
echo "Reusing release commit already on master"
exit 0
fi
echo "should_release=false" >> "$GITHUB_OUTPUT"
echo "mode=skip" >> "$GITHUB_OUTPUT"
echo "::notice ::Skipping release because master advanced from $WORKFLOW_SHA to $REMOTE_SHA"
echo "::notice ::Remote master version is $REMOTE_VERSION; planned version is $NEW_VERSION"
- name: Update package.json version
if: steps.release_target.outputs.mode == 'create'
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
npm version $NEW_VERSION --no-git-tag-version
echo "Updated package.json to version $NEW_VERSION"
- name: Set up Go
if: steps.release_target.outputs.should_release == 'true'
uses: actions/setup-go@v4
with:
go-version: "1.23.1"
- name: Cache Go modules
if: steps.release_target.outputs.should_release == 'true'
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Update Go module versions
if: steps.release_target.outputs.mode == 'create'
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
chmod +x ./release.sh
./release.sh $NEW_VERSION
echo "Updated Go modules to version $NEW_VERSION"
- name: Configure Git
if: steps.release_target.outputs.mode == 'create'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Commit version updates
if: steps.release_target.outputs.mode == 'create'
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
git add .
git commit -m "chore: bump version to v$NEW_VERSION [skip-release] [skip ci]"
- name: Create and push tags
id: push_release
if: steps.release_target.outputs.should_release == 'true'
run: |
set -euo pipefail
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
RELEASE_MODE="${{ steps.release_target.outputs.mode }}"
WORKFLOW_SHA="${{ github.event.workflow_run.head_sha }}"
tags=(
"auth/v$NEW_VERSION"
"cmd/v$NEW_VERSION"
"conf/v$NEW_VERSION"
"core/v$NEW_VERSION"
"plugin/otel/v$NEW_VERSION"
"serv/v$NEW_VERSION"
"tests/v$NEW_VERSION"
"v$NEW_VERSION"
)
tag_refs=()
# Delete existing local tags if they exist (handles re-runs gracefully).
for tag in "${tags[@]}"; do
git tag -d "$tag" 2>/dev/null || true
done
# Create all module tags.
for tag in "${tags[@]}"; do
git tag "$tag"
tag_refs+=("refs/tags/$tag")
done
if [ "$RELEASE_MODE" = "create" ]; then
git fetch origin master:refs/remotes/origin/master
REMOTE_SHA=$(git rev-parse origin/master)
if [ "$REMOTE_SHA" != "$WORKFLOW_SHA" ]; then
echo "pushed=false" >> "$GITHUB_OUTPUT"
echo "::notice ::Skipping release push because master advanced from $WORKFLOW_SHA to $REMOTE_SHA"
exit 0
fi
git push origin HEAD:master
fi
# Replace remote release tags only after the branch push is complete.
for tag in "${tags[@]}"; do
git push origin ":refs/tags/$tag" 2>/dev/null || true
done
git push origin "${tag_refs[@]}"
echo "pushed=true" >> "$GITHUB_OUTPUT"
echo "Created and pushed tags for version $NEW_VERSION"
- name: Delete existing release if any
if: steps.push_release.outputs.pushed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"
gh release delete "v$NEW_VERSION" --yes 2>/dev/null || true
- name: Import GPG key
if: steps.push_release.outputs.pushed == 'true'
id: import_gpg
uses: crazy-max/ghaction-import-gpg@v4
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Login to Docker Hub
if: steps.push_release.outputs.pushed == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Run GoReleaser
if: steps.push_release.outputs.pushed == 'true'
uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GR_TOKEN }}
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
KO_DOCKER_REPO: dosco/graphjin
- name: Publish to npm
if: steps.push_release.outputs.pushed == 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
npm publish --access public