diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml index 2ae26f5..cebcfd5 100644 --- a/.github/workflows/reusable-release.yml +++ b/.github/workflows/reusable-release.yml @@ -3,6 +3,13 @@ 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: false # ...but if you're not the Guardian, you'll want to set this explicitly + 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! @@ -28,6 +35,11 @@ on: 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 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'" @@ -143,9 +155,16 @@ jobs: 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 @@ -161,26 +180,52 @@ jobs: env: KEY_FINGERPRINT: ${{ needs.init.outputs.key_fingerprint }} KEY_EMAIL: ${{ needs.init.outputs.key_email }} + GH_TOKEN: ${{ steps.generate-github-app-token.outputs.token }} 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 + + VERSION_FILE_PATH="version.sbt" # TODO, work it out from diff? + VERSION_FILE_INITIAL_SHA=$( git rev-parse $GITHUB_REF:$VERSION_FILE_PATH ) + VERSION_FILE_RELEASE_SHA=$( git rev-parse $RELEASE_TAG:$VERSION_FILE_PATH ) + VERSION_FILE_RELEASE_CONTENT=$( git cat-file blob $RELEASE_TAG:$VERSION_FILE_PATH | base64 ) + VERSION_FILE_POST_RELEASE_CONTENT=$( git cat-file blob unsigned/$GITHUB_REF_NAME:$VERSION_FILE_PATH | base64 ) + + echo "VERSION_FILE_PATH=$VERSION_FILE_PATH" + echo "VERSION_FILE_INITIAL_SHA=$VERSION_FILE_INITIAL_SHA" + echo "VERSION_FILE_RELEASE_SHA=$VERSION_FILE_RELEASE_SHA" + echo "VERSION_FILE_RELEASE_CONTENT=$VERSION_FILE_RELEASE_CONTENT" + echo "VERSION_FILE_POST_RELEASE_CONTENT=$VERSION_FILE_POST_RELEASE_CONTENT" + + branch_for_pushing="preliminary-${{ github.run_id }}" - release_commit_id=$(git rev-parse HEAD^) + gh api --method POST /repos/:owner/:repo/git/refs \ + -f ref="refs/heads/$branch_for_pushing" \ + -f sha="$GITHUB_SHA" + + release_commit_id=$(gh api --method PUT /repos/:owner/:repo/contents/$VERSION_FILE_PATH \ + --field branch="$branch_for_pushing" \ + --field message="$RELEASE_TAG published by @${{github.actor}}: set version for release" \ + --field sha="$VERSION_FILE_INITIAL_SHA" \ + --field content="$VERSION_FILE_RELEASE_CONTENT" --jq '.commit.sha') + + if [ "${{ needs.init.outputs.release_type }}" == "FULL_MAIN_BRANCH" ] + then + echo "Full Main-Branch release, making 2nd update (new snapshot version) on the default branch" + gh api --method PUT /repos/:owner/:repo/contents/$VERSION_FILE_PATH \ + --field branch="$branch_for_pushing" \ + --field message="Put da post release stuff" \ + --field sha="$VERSION_FILE_RELEASE_SHA" \ + --field content="$VERSION_FILE_POST_RELEASE_CONTENT" + fi cat << EndOfFile >> $GITHUB_OUTPUT release_tag=$RELEASE_TAG @@ -188,20 +233,6 @@ jobs: 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 @@ -350,10 +381,14 @@ jobs: 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: + - 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" @@ -367,11 +402,15 @@ jobs: EndOfFile - name: Create Github Release if: needs.init.outputs.release_type == 'FULL_MAIN_BRANCH' + 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 }}: