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

Add GitHub actions workflow to tag new releases from .github/piper-cut-cl.json #4223

Merged
merged 2 commits into from
Feb 26, 2025
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
114 changes: 114 additions & 0 deletions .github/ci_support/tag_release_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/bin/bash
set -e

err_exit() {
printf "$@\n" >&2
exit 1
}

usage_exit() {
cat <<_eof_
USAGE: $(basename "$0") PIPER_CUT_CL VERSION_ID

PIPER_CUT_CL - # of the CL where a release was cut
VERSION_ID - the id of the release, in the format vYYYYMMDD

_eof_
printf '====\n'
err_exit "$@"
}

# Expect a single argument specifying the release cut CL number
find_piper_cut_commit() {
local -r cut_cl=$1
# 1. Get git commit IDs and their corresponding CLs from the git log.
# 2. select and print the commit ID associated with the highest CL# that is
# still lower than the cut CL
git_commit_cl_log | last_commit_before_cl "$cut_cl"
}

# Read the git log and produce lines of the form
#
# `COMMIT_ID CL_NUMBER`
git_commit_cl_log() {
# PiperOrigin-RevId: indicates the CL number
git log master \
--format='format:%h %(trailers:key=PiperOrigin-RevId,separator=,valueonly=true)'
}

# Expect a single argument specifying the release cut CL number
#
# Expect input lines in the form:
# `COMMIT_ID [CL_NUMBER]`
#
# Further expect that the CL numbers are in decscending order.
#
# Print the first CL number we encounter that is lower than
# the argument CL number.
#
# Report an error and return a non-zero value if we are unable
# to print a result CL number for any reason.
last_commit_before_cl() {
awk -v cut_cl="$1" '
# In some cases there is no CL associated with a commit.
# We skip all of those by ignoring lines with only one field.
NF > 1 {
# force the CL to be interpreted as an integer
cl = + $2
if (cl <= cut_cl) {
found_commit = 1
print $1
# skip reading any more records
exit
}
}

END {
# This section always gets executed
if (!found_commit) {
printf "no commit found: Earliest CL seen is %d which is > %d\n",
cl, cut_cl > "/dev/stderr"
exit 1
}
}
'
}

main() {
local -r piper_cut_cl=$1
local -r version_id=$2

existing=$(git tag -l "$version_id")
# Check if the version ID is already tagged.
if [ -n "$existing" ]; then
echo "Tag already exists for version '$version_id'"
exit 0
fi

COMMIT=$(find_piper_cut_commit $piper_cut_cl)
# check that the commit variable is not empty
if [[ -z "$COMMIT" ]]; then
echo "No commit found prior to CL $piper_cut_cl"
exit 1
fi

echo "Tagging commit $COMMIT with version $version_id"
git tag -a "$version_id" -m "Release $version_id" "$COMMIT"
git push origin master "$version_id"
}

(( $# == 2 )) || usage_exit 'incorrect argument count\n' "$@"

readonly PIPER_CUT_CL=$1
readonly VERSION_ID=$2

if [[ ! "$PIPER_CUT_CL" =~ ^[0-9]+$ ]]; then
usage_exit "Invalid Piper cut CL number: '$PIPER_CUT_CL'"
fi

if [[ ! "$VERSION_ID" =~ ^v[0-9]+$ ]]; then
usage_exit "Invalid version ID: '$VERSION_ID'. Expected format is vYYYYMMDD."
fi

main "$PIPER_CUT_CL" "$VERSION_ID"

62 changes: 62 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,65 @@ jobs:
env:
SONATYPE_USERNAME: closure-compiler
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}

tag_release_version_id:
name: Tag Release Version ID
# Run on a push to master but not on a pull request
# Pull requests are not necessarily trusted to configure the
# correct release tag.
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
# Checkout the piper-cut-cl.json from the most recent two commits
- name: Checkout Current closure-compiler Commit
# https://github.com/marketplace/actions/checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
sparse-checkout: |
.github/piper-cut-cl.json
.github/ci_support/tag_release_version.sh
sparse-checkout-cone-mode: false

- id: detect_changes
run: |
PIPER_DIFF=$(git diff HEAD~1 -- .github/piper-cut-cl.json)
FOUND_NEW_RELEASE=$([ -n "$PIPER_DIFF" ] && echo "true" || echo "false")
echo "foundNewRelease=$FOUND_NEW_RELEASE" >> "$GITHUB_OUTPUT"
echo "foundNewRelease: $FOUND_NEW_RELEASE"

- id: set_piper_json_vars
if: ${{ steps.detect_changes.outputs.foundNewRelease == 'true' }}
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#steps-context
run: |
{
echo 'piperJson<<EOF'
cat ./.github/piper-cut-cl.json
echo EOF
} >> "$GITHUB_OUTPUT"

# Check out all historical commits
# This is much more expensive than just checking out the most recent
# 2 commits, as done above, so only do this if actually cutting a release
- name: Checkout all closure-compiler commits and tags
uses: actions/checkout@v4
if: ${{ steps.detect_changes.outputs.foundNewRelease == 'true' }}
with:
# a depth of 0 triggers a fetch of all historical commits/branches/tags
# https://github.com/marketplace/actions/checkout#Fetch-all-history-for-all-tags-and-branches
fetch-depth: 0

- name: Tag cut CL
id: tag_cut_cl
if: ${{ steps.detect_changes.outputs.foundNewRelease == 'true' }}
run: |
git config --global user.name "${GITHUB_ACTOR}"
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
.github/ci_support/tag_release_version.sh \
"${{ fromJson(env.piperJson).piper_cut_cl }}" \
"${{ fromJson(env.piperJson).version_id }}";
env:
piperJson: ${{ steps.set_piper_json_vars.outputs.piperJson }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading