Skip to content

Use Github App for pushing commits #7

Use Github App for pushing commits

Use Github App for pushing commits #7

name: Scala Library Release Workflow
on:
workflow_call:
inputs:
GITHUB_APP_ID:
description:
"App ID for a GitHub App that is allowed to push directly to the default branch. Eg, App ID on:
https://github.com/organizations/guardian/settings/apps/gu-scala-library-release"
default: '807361' # Only for use by the Guardian!
required: true
type: string
SONATYPE_PROFILE_NAME:
description: 'Sonatype account profile name, eg "com.gu", "org.xerial", etc (not your Sonatype username)'
default: 'com.gu' # Only for use by the Guardian!
required: false # Must be supplied if used by a non-Guardian project
type: string
SONATYPE_CREDENTIAL_HOST:
description: 'The host of your SONATYPE_PROFILE_NAME, either "oss.sonatype.org" or "s01.oss.sonatype.org"'
default: 'oss.sonatype.org' # The default host is going to be whatever "com.gu" is using
required: false # ...but if you're not the Guardian, you'll want to set this explicitly
type: string
SONATYPE_USERNAME:
description: 'Sonatype username'
default: 'guardian.automated.maven.release' # Only for use by the Guardian!
required: false # Must be supplied if used by a non-Guardian project
type: string
secrets:
SONATYPE_PASSWORD:
description: 'Password for the SONATYPE_USERNAME account - used to authenticate when uploading artifacts'
required: true
PGP_PRIVATE_KEY:
description:
"A passphrase-less PGP private key used to sign artifacts, commits, & tags.
Should be in normal plaintext 'BEGIN PGP PUBLIC KEY BLOCK' (ASCII-armored) format, with no additional BASE64-encoding.
The passphrase can be removed from an existing key using 'gpg --edit-key <key-id> passwd' : https://unix.stackexchange.com/a/550538/46453"
required: true
GITHUB_APP_PRIVATE_KEY:
description:
"See https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#generating-private-keys
Should be in normal plaintext '-----BEGIN RSA PRIVATE KEY-----' format"
required: true
outputs:
RELEASE_VERSION:
description: "The un-prefixed version number of the release, eg '3.0.1'"
value: ${{ jobs.push-release-commit.outputs.release_version }}
RELEASE_TYPE:
description: "Either 'FULL_MAIN_BRANCH' or 'PREVIEW_FEATURE_BRANCH' - whether this is a full release or a pre-release"
value: ${{ jobs.init.outputs.release_type }}
env:
LOCAL_ARTIFACTS_STAGING_PATH: /tmp/artifact_staging
COMMITTER_NAME: "@${{github.actor}} using gha-scala-library-release-workflow"
RUN_ATTEMPT_UID: ${{ github.run_id }}-${{ github.run_attempt }}
jobs:
init:
name: 🔒 Init
runs-on: ubuntu-latest
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:
distribution: corretto
java-version: 17
gpg-private-key: ${{ secrets.PGP_PRIVATE_KEY }}
- name: Read Identifiers from Signing Key
id: read-identifiers
run: |
key_fingerprint_and_email=$(gpg2 --list-secret-keys --list-options show-only-fpr-mbox)
key_fingerprint=$(echo $key_fingerprint_and_email | awk '{print $1}')
key_email=$(echo $key_fingerprint_and_email | awk '{print $2}')
echo "key_fingerprint=$key_fingerprint"
cat << EndOfFile >> $GITHUB_OUTPUT
key_fingerprint=$key_fingerprint
key_email=$key_email
EndOfFile
if ! [[ "$key_fingerprint" =~ ^[[:xdigit:]]{8,}$ ]]; then
echo "::error title=Missing PGP key::Has PGP_PRIVATE_KEY been set correctly? https://github.com/guardian/gha-scala-library-release-workflow/blob/main/docs/credentials/supplying-credentials.md"
exit 1
fi
- 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}"
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
needs: init
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4 # don't 'cache: sbt', at least until https://github.com/actions/setup-java/pull/564 is merged
with:
distribution: corretto
java-version: 17
# - name: Debug MIMA assessment
# run: |
# sbt "show versionPolicyFindIssues"
- name: Use sbt-release to construct version.sbt updates
run: |
git config user.email "${{ needs.init.outputs.key_email }}"
git config user.name "$COMMITTER_NAME"
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
rm -Rf $GITHUB_WORKSPACE/*
mv repo-with-unsigned-version-update-commits.git $GITHUB_WORKSPACE/
ls -lR $GITHUB_WORKSPACE
- name: Job summary
run: |
echo "# Release $(git describe --tags --abbrev=0)" >> $GITHUB_STEP_SUMMARY
- uses: actions/cache/save@v4
with:
path: repo-with-unsigned-version-update-commits.git
key: repo-with-unsigned-version-update-commits-${{ env.RUN_ATTEMPT_UID }}
push-release-commit:
name: 🔒 Push Release Commit
needs: [generate-version-update-commits, init]
permissions:
contents: write
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:
- id: generate-github-app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ inputs.GITHUB_APP_ID }}
private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} }
- uses: actions/checkout@v4
with:
path: repo
token: ${{ steps.generate-github-app-token.outputs.token }}
persist-credentials: true # Allow us to push as the GitHub App, and bypass branch ruleset
- uses: actions/cache/restore@v4
with:
path: repo-with-unsigned-version-update-commits.git
key: repo-with-unsigned-version-update-commits-${{ env.RUN_ATTEMPT_UID }}
fail-on-cache-miss: true
- uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 17
gpg-private-key: ${{ secrets.PGP_PRIVATE_KEY }}
- name: Create commit
id: create-commit
env:
KEY_FINGERPRINT: ${{ needs.init.outputs.key_fingerprint }}
KEY_EMAIL: ${{ needs.init.outputs.key_email }}
run: |
echo "GITHUB_REF_NAME=$GITHUB_REF_NAME"
echo "GITHUB_REF=$GITHUB_REF"
cd repo-with-unsigned-version-update-commits.git
RELEASE_TAG=$(git describe --tags --abbrev=0)
cd ../repo
git status
git config user.email "$KEY_EMAIL"
git config user.name "$COMMITTER_NAME"
git config commit.gpgsign true
git config user.signingkey "$KEY_FINGERPRINT"
git remote add unsigned ../repo-with-unsigned-version-update-commits.git
git fetch unsigned
git cherry-pick -S$KEY_FINGERPRINT $GITHUB_REF_NAME..unsigned/$GITHUB_REF_NAME
git status
release_commit_id=$(git rev-parse HEAD^)
cat << EndOfFile >> $GITHUB_OUTPUT
release_tag=$RELEASE_TAG
release_version=${RELEASE_TAG#"v"}
release_commit_id=$release_commit_id
EndOfFile
git log --format="%h %p %ce %s" --decorate=short -n3
git status
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
needs: [init, push-release-commit]
runs-on: ubuntu-latest
outputs:
ARTIFACT_SHA256SUMS: ${{ steps.record-hashes.outputs.ARTIFACT_SHA256SUMS }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.push-release-commit.outputs.release_commit_id }}
- uses: actions/setup-java@v4 # don't 'cache: sbt', at least until https://github.com/actions/setup-java/pull/564 is resolved
with:
distribution: corretto
java-version: 17
- name: Generate artifacts
run: |
cat << EndOfFile > sbt-commands.txt
set every sonatypeProjectHosting := Some(xerial.sbt.Sonatype.GitHubHosting("$GITHUB_REPOSITORY_OWNER", "${GITHUB_REPOSITORY#*/}", "${{ needs.init.outputs.key_email }}"))
set ThisBuild / publishTo := Some(Resolver.file("foobar", file("$LOCAL_ARTIFACTS_STAGING_PATH")))
EndOfFile
cat sbt-commands.txt
sbt ";< sbt-commands.txt; +publish"
- name: Record SHA-256 hashes of artifacts
id: record-hashes
run: |
sudo apt-get install hashdeep -q > /dev/null
cd $LOCAL_ARTIFACTS_STAGING_PATH
{
echo 'ARTIFACT_SHA256SUMS<<EOF'
sha256deep -r -l .
echo EOF
} >> "$GITHUB_OUTPUT"
- uses: actions/cache/save@v4
id: cache
with:
path: ${{ env.LOCAL_ARTIFACTS_STAGING_PATH }}
key: unsigned-${{ env.RUN_ATTEMPT_UID }}
sign:
name: 🔒 Sign
needs: [init, push-release-commit, create-artifacts]
runs-on: ubuntu-latest
env:
KEY_FINGERPRINT: ${{ needs.init.outputs.key_fingerprint }}
steps:
- uses: actions/checkout@v4
with:
path: repo
ref: ${{ needs.push-release-commit.outputs.release_commit_id }}
- uses: actions/cache/restore@v4
with:
path: ${{ env.LOCAL_ARTIFACTS_STAGING_PATH }}
key: unsigned-${{ env.RUN_ATTEMPT_UID }}
fail-on-cache-miss: true
- uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 17
gpg-private-key: ${{ secrets.PGP_PRIVATE_KEY }}
- name: Sign artifacts
run: |
echo "KEY_FINGERPRINT=$KEY_FINGERPRINT"
find $LOCAL_ARTIFACTS_STAGING_PATH -type f -exec gpg -a --local-user "$KEY_FINGERPRINT" --detach-sign {} \;
- name: Push signed tag
env:
RELEASE_TAG: ${{ needs.push-release-commit.outputs.release_tag }}
RELEASE_COMMIT_ID: ${{ needs.push-release-commit.outputs.release_commit_id }}
ARTIFACT_SHA256SUMS: ${{ needs.create-artifacts.outputs.ARTIFACT_SHA256SUMS }}
KEY_EMAIL: ${{ needs.init.outputs.key_email }}
run: |
echo "RELEASE_TAG=$RELEASE_TAG"
echo "RELEASE_COMMIT_ID=$RELEASE_COMMIT_ID"
cd repo
git config user.email "$KEY_EMAIL"
git config user.name "$COMMITTER_NAME"
git config tag.gpgSign true
git config user.signingkey "$KEY_FINGERPRINT"
cat << EndOfFile > tag-message.txt
Release $RELEASE_TAG initiated by $COMMITTER_NAME
$ARTIFACT_SHA256SUMS
EndOfFile
echo "Message is..."
cat tag-message.txt
echo "Creating release tag (including artifact hashes)"
git tag -a -F tag-message.txt $RELEASE_TAG $RELEASE_COMMIT_ID
echo "RELEASE_TAG=$RELEASE_TAG"
echo "Pushing tag $RELEASE_TAG"
git push origin $RELEASE_TAG
- uses: actions/cache/save@v4
with:
path: ${{ env.LOCAL_ARTIFACTS_STAGING_PATH }}
key: signed-${{ env.RUN_ATTEMPT_UID }}
sonatype-release:
name: 🔒 Sonatype Release
needs: sign
runs-on: ubuntu-latest
steps:
- uses: actions/cache/restore@v4
with:
path: ${{ env.LOCAL_ARTIFACTS_STAGING_PATH }}
key: signed-${{ env.RUN_ATTEMPT_UID }}
fail-on-cache-miss: true
- name: Create tiny sbt project to perform Sonatype upload
run: |
cat << EndOfFile > build.sbt
sonatypeBundleDirectory := new File("$LOCAL_ARTIFACTS_STAGING_PATH")
sonatypeProfileName := "${{ inputs.SONATYPE_PROFILE_NAME }}"
sonatypeCredentialHost := "${{ inputs.SONATYPE_CREDENTIAL_HOST }}"
EndOfFile
mkdir project
echo 'addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.21")' > project/plugins.sbt
echo 'sbt.version = 1.9.8' > project/build.properties
ls -lR .
- uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 17
cache: sbt # the issue described in https://github.com/actions/setup-java/pull/564 doesn't affect this step (no version.sbt)
- name: Release
env:
SONATYPE_USERNAME: ${{ inputs.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
run: |
sbt "sonatypeBundleRelease"
github-release:
name: 🔒 Update GitHub
needs: [init, push-release-commit, sign]
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
RELEASE_TAG: ${{ needs.push-release-commit.outputs.release_tag }}
RELEASE_VERSION: ${{ needs.push-release-commit.outputs.release_version }}
GH_REPO: ${{ github.repository }}
GITHUB_REPO_URL: ${{ github.server_url }}/${{ github.repository }}
steps:
- id: generate-github-app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ inputs.GITHUB_APP_ID }}
private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} }
- 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
if: needs.init.outputs.release_type == 'FULL_MAIN_BRANCH'

Check failure on line 392 in .github/workflows/reusable-release.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/reusable-release.yml

Invalid workflow file

You have an error in your yaml syntax on line 392
env: { GH_TOKEN: ${{ steps.generate-github-app-token.outputs.token }} }
run: |
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'
env: { GH_TOKEN: ${{ steps.generate-github-app-token.outputs.token }} }
run: |
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