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

Support publishing preview releases #19

Merged
merged 1 commit into from
Jan 9, 2024
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
106 changes: 95 additions & 11 deletions .github/workflows/reusable-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ jobs:
outputs:
key_fingerprint: ${{ steps.read-identifiers.outputs.key_fingerprint }}
key_email: ${{ steps.read-identifiers.outputs.key_email }}
release_type: ${{ steps.generate-version-suffix.outputs.release_type }}
version_suffix: ${{ steps.generate-version-suffix.outputs.version_suffix }}
steps:
- uses: actions/setup-java@v4
with:
Expand All @@ -59,6 +61,25 @@ jobs:
key_fingerprint=$key_fingerprint
key_email=$key_email
EndOfFile
- name: Check for default branch
id: generate-version-suffix
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
default_branch=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name ${{ github.repository }})

if [[ "$default_branch" = $GITHUB_REF_NAME ]]; then
release_type="FULL_MAIN_BRANCH"
version_suffix=""
else
release_type="PREVIEW_FEATURE_BRANCH"
version_suffix="-PREVIEW.${GITHUB_REF_NAME//[^[:alnum:-_]]/}.$(date +%Y-%m-%dT%H%M).${GITHUB_SHA:0:8}"
Copy link
Member Author

@rtyley rtyley Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of stuff going on in the version_suffix! :

  • Starting - hyphen - https://semver.org/#spec-item-9 says "9. A pre-release version MAY be denoted by appending a hyphen ..."
  • PREVIEW - this is recognised by IntelliJ & Scala Steward to mean 'non-stable-release, not suitable for auto-upgrading to', which is what we want 👍
  • ${GITHUB_REF_NAME//[^[:alnum:-_]]/} - this is the PR branch name, with most non-alphanumeric characters stripped out - in particular, stripping out slash (/), which some people use in Git branch names but which we couldn't have as part of the version, because Maven uses the version as part of the artifact url path.
  • $(date +%Y-%m-%dT%H%M) - this is the date, to the minute (eg 2024-01-04T1230), helping to differentiate and order mulitple preview releases for one PR.
  • ${GITHUB_SHA:0:8} - this is the first 8 digits of the hash id for the PR commit that the preview release was based on. This helps to differentiate and identify multiple preview release for one PR, but also is recognised by Scala Steward, again meaning 'non-stable-release, not suitable for auto-upgrading to', which is what we want 👍

Choice of version-suffix for preview releases

https://semver.org/#spec-item-9 says:

  1. A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z.--.

  2. Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3----117B344092BD.

How can we prevent tooling from thinking our preview releases are stable releases?

If we're not using the -SNAPSHOT suffix, there's a risk that tooling will assume that our preview releases are stable releases, and attempt to auto-upgrade to them.

Consequently, to be certain of being recognised as a pre-release, it seems wise to include these components in the version number:

  • 'PREVIEW'
  • a commit hash of at least 8 characters

NPM version numbers...

Some Guardian libraries are released simultaneously for both Scala and other platforms like NPM (for instance, content-api-models, see guardian/content-api-models#229).

Both NPM and sbt/Maven work well with simple three-number semver version numbers, but how well will NPM handle extended version number like 1.0.7-PREVIEW.feature1.2024-01-04T1230.42ed11d4 ?

For the time being, I'm happy enough to go ahead with this version-number structure, but alter it later if it causes problems.

'PREVIEW', 'BETA', 'ALPHA', or...?

Justin points out the 'PREVIEW' has a particular meaning for the Content Pipeline team ('Preview' vs 'Live' content) - could potentially cause some confusion.

I initially chose 'PREVIEW' (from the identifiers that IntelliJ & Scala Steward understand) partially because both 'BETA' & 'ALPHA' imply some meaning about the stage of development in the software release
cycle that may or may not be appropriate - it's not obvious which one truly reflects what we're doing when we make an early release from a PR, and it's annoying to have to choose. Additionally, looking at
the Wikipedia article that describes the different stages - the label 'pre-alpha' might even be more appropriate: https://en.wikipedia.org/wiki/Software_release_life_cycle

fi
echo "current branch: $GITHUB_REF_NAME, release_type: $release_type, version_suffix: $version_suffix"
cat << EndOfFile >> $GITHUB_OUTPUT
release_type=$release_type
version_suffix=$version_suffix
EndOfFile

generate-version-update-commits:
name: 🎊 Test & Version
Expand All @@ -77,7 +98,15 @@ jobs:
run: |
git config user.email "${{ needs.init.outputs.key_email }}"
git config user.name "$COMMITTER_NAME"
sbt "release with-defaults"

sbt_commands_file=$(mktemp)
cat << EndOfFile > $sbt_commands_file
set releaseVersion := releaseVersion.value.andThen(_ + "${{ needs.init.outputs.version_suffix }}")
release with-defaults
EndOfFile
cat $sbt_commands_file
sbt ";< $sbt_commands_file"

echo $GITHUB_WORKSPACE
cd `mktemp -d`
git clone --bare $GITHUB_WORKSPACE repo-with-unsigned-version-update-commits.git
Expand All @@ -100,6 +129,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.create-commit.outputs.release_tag }}
release_version: ${{ steps.create-commit.outputs.release_version }}
release_commit_id: ${{ steps.create-commit.outputs.release_commit_id }}
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -143,12 +173,24 @@ jobs:

cat << EndOfFile >> $GITHUB_OUTPUT
release_tag=$RELEASE_TAG
release_version=${RELEASE_TAG#"v"}
Copy link
Member Author

@rtyley rtyley Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we're using Bash Shell Parameter Expansion to strip the v off the front of the release tag (eg v1.0.6-PREVIEW.feature1.2023-12-31T1334.fd006d63) to get the release version (which is what you'd use when declaring the library as a dependency, eg 1.0.6-PREVIEW.feature1.2023-12-31T1334.fd006d63).

The RELEASE_VERSION is used later on in the workflow in the PR comment, as that's probably what people want, rather than the tag:

image

release_commit_id=$release_commit_id
EndOfFile

git log --format="%h %p %ce %s" --decorate=short -n3
git status
git push

if [ "${{ needs.init.outputs.release_type }}" == "FULL_MAIN_BRANCH" ]
then
echo "Full Main-Branch release, pushing 2 commits to the default branch"
git push # push 2 commits (non-snapshot release version, then new snapshot version) onto the default branch
else
tag_for_pushing="preliminary-${{ github.run_id }}"
echo "Preview Feature-Branch release, pushing 1 commit with the temporary tag $tag_for_pushing"
git tag -a -m "Tag created merely to allow _pushing_ the release commit, which gains the signed $RELEASE_TAG tag later on in the workflow" $tag_for_pushing $release_commit_id
git push origin $tag_for_pushing # push only the single release version commit with a disposable tag
fi


create-artifacts:
name: 🎊 Create artifacts
Expand Down Expand Up @@ -240,7 +282,7 @@ jobs:
echo "Message is..."
cat tag-message.txt

echo "Creating tag"
echo "Creating release tag (including artifact hashes)"
git tag -a -F tag-message.txt $RELEASE_TAG $RELEASE_COMMIT_ID

echo "RELEASE_TAG=$RELEASE_TAG"
Expand Down Expand Up @@ -289,20 +331,62 @@ jobs:
sbt "sonatypeBundleRelease"

github-release:
name: 🔒 GitHub Release
needs: [push-release-commit, sign]
name: 🔒 Update GitHub
needs: [init, push-release-commit, sign]
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
Copy link
Member Author

@rtyley rtyley Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order for the workflow to comment on PRs (notifying that a preview has been published), we need the pull-requests: write permission.

This also means updating all the release.yml files in the projects currently using gha-scala-library-release-workflow, so that they look like this:

    permissions: { contents: write, pull-requests: write }

...I've now done this, as you can see in guardian/etag-caching#33 and the associated commits on all the other repos.

env:
RELEASE_TAG: ${{ needs.push-release-commit.outputs.release_tag }}
RELEASE_VERSION: ${{ needs.push-release-commit.outputs.release_version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GITHUB_REPO_URL: ${{ github.server_url }}/${{ github.repository }}
steps:
- name: Common values
run: |
GITHUB_ACTIONS_PATH="$GITHUB_REPO_URL/actions"
GITHUB_WORKFLOW_FILE="release.yml" # Could be derived from $GITHUB_WORKFLOW_REF
GITHUB_WORKFLOW_URL="$GITHUB_ACTIONS_PATH/workflows/$GITHUB_WORKFLOW_FILE"

cat << EndOfFile >> $GITHUB_ENV
GITHUB_WORKFLOW_FILE=$GITHUB_WORKFLOW_FILE
GITHUB_WORKFLOW_LINK=[GitHub UI]($GITHUB_WORKFLOW_URL)
GITHUB_WORKFLOW_RUN_LINK=[#${{ github.run_number }}]($GITHUB_ACTIONS_PATH/runs/${{ github.run_id }})
EndOfFile
- name: Create Github Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
if: needs.init.outputs.release_type == 'FULL_MAIN_BRANCH'
run: |
gh release create $RELEASE_TAG --verify-tag --generate-notes --notes "Release run: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
- name: Job summary
gh release create $RELEASE_TAG --verify-tag --generate-notes --notes "Release run: $GITHUB_WORKFLOW_RUN_LINK"
echo "GitHub Release notes: [$RELEASE_TAG]($GITHUB_REPO_URL/releases/tag/$RELEASE_TAG)" >> $GITHUB_STEP_SUMMARY
- name: Update PR with comment
if: needs.init.outputs.release_type == 'PREVIEW_FEATURE_BRANCH'
run: |
echo "GitHub Release notes: [$RELEASE_TAG](${{ github.server_url }}/${{ github.repository }}/releases/tag/$RELEASE_TAG)" >> $GITHUB_STEP_SUMMARY
cat << EndOfFile > comment_body.txt
@${{github.actor}} has published a preview version of this PR with release workflow run $GITHUB_WORKFLOW_RUN_LINK, based on commit ${{ github.sha }}:

$RELEASE_VERSION

<details>
<summary>Want to make another preview release?</summary>

Click 'Run workflow' in the $GITHUB_WORKFLOW_LINK, specifying the $GITHUB_REF_NAME branch, or use the [GitHub CLI](https://cli.github.com/) command:

gh workflow run $GITHUB_WORKFLOW_FILE --ref $GITHUB_REF_NAME

</details>

<details>
<summary>Want to make a full release after this PR is merged?</summary>

Click 'Run workflow' in the $GITHUB_WORKFLOW_LINK, leaving the branch as the default, or use the [GitHub CLI](https://cli.github.com/) command:

gh workflow run $GITHUB_WORKFLOW_FILE

</details>
EndOfFile

cat comment_body.txt

gh pr comment ${{ github.ref_name }} --body-file comment_body.txt >> $GITHUB_STEP_SUMMARY
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problems with Bash interpreting backticks have meant that the comment message isn't quite as pretty as I'd like - ideally there would be backticks for styling code blocks, like this:

image

For the time being this PR avoids them in the generated PR comment.

5 changes: 4 additions & 1 deletion docs/making-a-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ https://github.com/guardian/gha-scala-library-release-workflow/assets/52038/ec18
![image](https://github.com/guardian/gha-scala-library-release-workflow/assets/52038/a9ee9dd8-5443-41f6-b335-3b9ecf3e3b1d)
* Click on `Run workflow` on the right-hand side of the blue _"This workflow has a workflow_dispatch event trigger."_ bar:<br>
![image](https://github.com/guardian/gha-scala-library-release-workflow/assets/52038/4f25745a-207d-4d40-b697-d488918930f0)
* Click on the green `Run workflow` button in the modal popup that appears:<br>
* In the modal popup that appears:
* For a normal full release on the main branch, leave the branch set to the default (ie `main`). If you're
making a 'preview' release of an unmerged PR, select the PR's branch from the `Branch:` dropdown.
* Click on the green `Run workflow` button:<br>
![image](https://github.com/guardian/gha-scala-library-release-workflow/assets/52038/b8669ae3-bb39-4ca6-b285-4eef3d3e341b)
* You've started a release! However, the GitHub UI can be slow to update, so **reload** the page, and then click on
the new workflow run to see its progress:<br>
Expand Down