Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change CI release logic #452

Merged
merged 1 commit into from
Oct 16, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,14 @@ jobs:
skopeo copy --all oci-archive:fasttrackml-oci.tar:$tag docker://ghcr.io/${{ steps.repo.outputs.name }}:$tag
echo "::endgroup::"
done

release:
name: Release
needs: all-required-checks-done
if: ${{ !github.event.repository.fork && github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') }}
permissions:
contents: write
pages: write
id-token: write
secrets: inherit
uses: ./.github/workflows/release.yml
96 changes: 96 additions & 0 deletions .github/workflows/create.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Create release branch or tag

on:
workflow_dispatch:
inputs:
type:
description: "What to create (branch or tag)"
required: true
type: choice
options:
- "branch"
- "tag"
version:
description: "Version - major and minor for a branch (e.g. 0.3), semver for a tag (e.g. 0.3.1 or 0.3.1-rc.1)"
required: true

jobs:
create-release:
name: Create release branch from main
if: github.event.inputs.type == 'branch'
environment: create-release
runs-on: ubuntu-latest
steps:
- name: Check version
id: version
uses: actions/github-script@v6
with:
script: |
const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
const version = context.payload.inputs.version;
const match = version.match(semver);
if (match === null) {
core.setFailed('Invalid version format. Expected "MAJOR.MINOR".');
} else {
core.setOutput('branch', `release/${version}`);
}

- name: Generate an app token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: main
token: ${{ steps.app-token.outputs.token }}

- name: Push
run: |
branch=${{ steps.version.outputs.branch }}
git checkout -b $branch
git push origin $branch

create-tag:
name: Create release tag from release branch
if: github.event.inputs.type == 'tag'
environment: create-release
runs-on: ubuntu-latest
steps:
# Regex comes from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
- name: Check version
id: version
uses: actions/github-script@v6
with:
script: |
const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
const version = context.payload.inputs.version;
const match = version.match(semver);
if (match === null) {
core.setFailed('Invalid version format. Expected semver compliant version.');
} else {
core.setOutput('tag', `v${version}`);
core.setOutput('branch', `release/${match[1]}.${match[2]}`);
}

- name: Generate an app token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Checkout release branch
uses: actions/checkout@v4
with:
ref: ${{ steps.version.outputs.branch }}
token: ${{ steps.app-token.outputs.token }}

- name: Push
run: |
tag=${{ steps.version.outputs.tag }}
git tag $tag
git push origin $tag
97 changes: 32 additions & 65 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,96 +1,55 @@
name: Release

on:
workflow_run:
types: [completed]
workflows: [CI]
branches:
- main
- v*
workflow_call:

permissions:
contents: read

jobs:
validate:
name: Validate ref
if: github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success' && !github.event.repository.fork
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

# The given ref should belong to the main branch.
# If it's main, it shouldn't be more than 2 commits away (in case another push happened in the meantime).
# If it starts with 'v', it should be a tag and belong to the main branch.
# Anything else is invalid.
- name: Validate ref
run: |
ref='${{ github.event.workflow_run.head_branch }}'
sha='${{ github.event.workflow_run.head_sha }}'
case $ref in
main)
[ $(git branch --contains=$sha main | wc -l) -eq 1 ] &&
[ $(git rev-list --count $sha..main) -le 2 ]
;;
v?*)
[[ $ref =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] &&
[ $(git tag --points-at $sha | grep -E "^$ref\$" | wc -l) -eq 1 ] &&
[ $(git branch --contains=$sha main | wc -l) -eq 1 ]
;;
*)
false
;;
esac
if [ $? -ne 0 ]; then
echo "::error ::Invalid ref $ref $sha"
exit 1
fi

pypi-publish:
name: upload release to PyPI
needs: validate
if: github.event.workflow_run.head_branch != 'main'
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- name: Download artifact
run: gh run download ${{ github.event.workflow_run.id }} --repo ${{ github.event.workflow_run.repository.full_name }} --name fasttrackml-wheels --dir wheelhouse
env:
GH_TOKEN: ${{ github.token }}
uses: actions/download-artifact@v3
with:
name: fasttrackml-wheels
path: wheelhouse

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: wheelhouse/
packages-dir: wheelhouse

github-release:
name: Publish GitHub release
needs: validate
if: github.event.workflow_run.head_branch != 'main'
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifact
run: gh run download ${{ github.event.workflow_run.id }} --repo ${{ github.event.workflow_run.repository.full_name }} --name fasttrackml-archives --dir dist
env:
GH_TOKEN: ${{ github.token }}
uses: actions/download-artifact@v3
with:
name: fasttrackml-archives
path: dist

- name: Create release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: dist/*
tag_name: ${{ github.event.workflow_run.head_branch }}
prerelease: ${{ contains(github.ref, '-') }}

update-website:
name: Update website
needs: github-release
if: ${{ !contains(github.ref, '-') }}
permissions:
contents: read
pages: write
Expand All @@ -99,35 +58,43 @@ jobs:

docker-release:
name: Publish container image to DockerHub
needs: validate
if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: release
steps:
# We need to checkout the repo in order to determine the latest tag.
- name: Checkout
if: startsWith(github.ref, 'refs/tags/v')
uses: actions/checkout@v4
with:
fetch-depth: 0

# The main branch is tagged as "main" and "edge".
# Tags are named after the version, e.g. "v0.1.0" -> "0.1.0".
# The latest non-prerelease version is also tagged as "latest".
# This is achieved by sorting the tags by version number, then filtering
# out prereleases and taking the last tag.
- name: Compute tags
id: tags
run: |
ref='${{ github.event.workflow_run.head_branch }}'
ref='${{ github.ref }}'
case $ref in
main)
refs/heads/main)
tags=("main" "edge")
;;
v*)
tags=("${ref#v}")
if [ $(git describe --tags --abbrev=0) == $ref ]; then
refs/tags/v*)
tags=("${ref#refs/tags/v}")
if [ "$(git -c 'versionsort.suffix=-' for-each-ref --sort=version:refname --format='%(refname)' 'refs/tags/v*' | grep -v -- - | tail -n1)" == "$ref" ]; then
tags+=("latest")
fi
esac
echo "ref=${ref#refs/*/}" >> $GITHUB_OUTPUT
echo "tags=${tags[@]}" >> $GITHUB_OUTPUT

- name: Download artifact
run: gh run download ${{ github.event.workflow_run.id }} --name fasttrackml-oci-image
env:
GH_TOKEN: ${{ github.token }}
uses: actions/download-artifact@v3
with:
name: fasttrackml-oci-image

- name: Login to Docker Hub
uses: docker/login-action@v3
Expand All @@ -140,6 +107,6 @@ jobs:
for tag in ${{ steps.tags.outputs.tags }}
do
echo "::group::Pushing image to ${{ vars.DOCKER_REPO }}:$tag"
skopeo copy --all oci-archive:fasttrackml-oci.tar:${{ github.event.workflow_run.head_branch }} docker://${{ vars.DOCKER_REPO }}:$tag
skopeo copy --all oci-archive:fasttrackml-oci.tar:${{ steps.tags.outputs.ref }} docker://${{ vars.DOCKER_REPO }}:$tag
echo "::endgroup::"
done