From 86cec8dff4868b042d56e9ca8e40bc60ae4b87e5 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 13:49:00 +1200 Subject: [PATCH 01/13] NEW Create action --- README.md | 4 +- action.yml | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 action.yml diff --git a/README.md b/README.md index a3705ef..84da2be 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# gha-tag-release \ No newline at end of file +# GitHub Actions - Tag release + +Create a tag and an optional release diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..2cf86f5 --- /dev/null +++ b/action.yml @@ -0,0 +1,111 @@ +name: Tag and release +description: GitHub Action to create a tag and an optional release +inputs: + sha: + type: string + required: true + tag: + type: string + required: true + delete_existing: + type: boolean + required: false + default: false + release: + type: boolean + required: false + default: false + body: + type: string + required: false + default: '' +runs: + using: composite + steps: + - name: Delete existing tag if one exists + if: ${{ inputs.delete_existing }} + shell: bash + # Add string inputs to memory instead of using string substitution in shell script + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + env: + TAG: ${{ inputs.tag }} + run: | + echo "Deleting old $TAG tag if it exists" + # Delete tag via GitHub API + # https://docs.github.com/en/rest/reference/git#delete-a-reference + curl -s \ + -X DELETE https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$TAG \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ github.token }}" + + - name: Create tag + shell: bash + env: + SHA: ${{ inputs.branch }} + TAG: ${{ inputs.tag }} + run: | + SHA=${{ github.sha }} + # Create new tag via GitHub API + # https://docs.github.com/en/rest/reference/git#create-a-reference + curl -s \ + -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ github.token }}" \ + -d @- << EOF + { + "sha": "$SHA", + "ref": "refs/tags/$TAG" + } + EOF + echo "New tag $TAG created with sha $SHA" + +# Note: untestested below this line: + +# - name: Delete existing release if one exists +# if: ${{ inputs.release && inputs.delete_existing }} +# shell: bash +# env: +# SHA: ${{ inputs.branch }} +# TAG: ${{ inputs.tag }} +# BODY: ${{ inputs.body }} +# run: | +# echo "Deleting old release for $TAG if it exists" +# # Get id for an existing release matching $TAG +# curl -s \ +# -X GET https://api.github.com/repos/silverstripe/silverstripe-framework/releases/tags/$TAG \ +# -H "Accept: application/vnd.github.v3+json" > __.json +# RELEASE_ID=$(jq .id __.json) +# if [ "$RELEASE_ID" != "null" ]; then +# curl -s \ +# -X DELETE https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID \ +# -H "Accept: application/vnd.github.v3+json" \ +# -H "Authorization: token ${{ github.token }}" +# echo "Deleted existing release $RELEASE_ID for tag $TAG" +# else +# echo "Could not find an existing release for tag $TAG" +# fi + +# - name: Create release +# if: ${{ inputs.release }} +# shell: bash +# env: +# SHA: ${{ inputs.branch }} +# TAG: ${{ inputs.tag }} +# BODY: ${{ inputs.body }} +# run: | +# # Run git commit, push and create pull-request as 'github-actions' user + +# # Create new pull-request via GitHub API +# # https://docs.github.com/en/rest/reference/releases#create-a-release +# curl -s \ +# -X POST https://api.github.com/repos/${{ github.repository }}/releases \ +# -H "Accept: application/vnd.github.v3+json" \ +# -H "Authorization: token ${{ github.token }}" \ +# -d @- << EOF +# { +# "tag_name": "$TAG", +# "name": "$TAG", +# "body": "$BODY", +# } +# EOF +# echo "New pull-request created" From e79a1d6fa0490bcbd2bce4d67afc04ebd977143d Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 16:23:17 +1200 Subject: [PATCH 02/13] MNT Add auto-tag workflow --- .github/workflows/auto-tag.yml | 14 ++++ README.md | 2 + action.yml | 113 +++++++++++++++++---------------- 3 files changed, 76 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/auto-tag.yml diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml new file mode 100644 index 0000000..982c17a --- /dev/null +++ b/.github/workflows/auto-tag.yml @@ -0,0 +1,14 @@ +on: + push: + tags: + - '*.*.*' +jobs: + auto-tag: + name: Auto-tag + runs-on: ubuntu-latest + steps: + - name: Auto-tag + uses: silverstripe/gha-auto-tag@main + with: + ref: ${{ github.ref }} + sha: ${{ github.sha }} diff --git a/README.md b/README.md index 84da2be..d26c6a9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # GitHub Actions - Tag release Create a tag and an optional release + +Note: this ctions seems to have issues creating tags and releases on forked repos, though it's fine on non-forked repos diff --git a/action.yml b/action.yml index 2cf86f5..cb018c2 100644 --- a/action.yml +++ b/action.yml @@ -22,8 +22,31 @@ inputs: runs: using: composite steps: + + - name: Delete existing release if one exists + if: ${{ inputs.release == 'true' && inputs.delete_existing == 'true' }} + shell: bash + env: + TAG: ${{ inputs.tag }} + run: | + echo "Deleting old release for $TAG if it exists" + # Get id for an existing release matching $TAG + curl -s \ + -X GET https://api.github.com/repos/${{ github.repository }}/releases/tags/$TAG \ + -H "Accept: application/vnd.github.v3+json" > __.json + RELEASE_ID=$(jq .id __.json) + if [ "$RELEASE_ID" != "null" ]; then + curl -s \ + -X DELETE https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ github.token }}" + echo "Deleted existing release $RELEASE_ID for tag $TAG" + else + echo "Could not find an existing release for tag $TAG" + fi + - name: Delete existing tag if one exists - if: ${{ inputs.delete_existing }} + if: ${{ inputs.delete_existing == 'true' }} shell: bash # Add string inputs to memory instead of using string substitution in shell script # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable @@ -39,12 +62,17 @@ runs: -H "Authorization: token ${{ github.token }}" - name: Create tag + if: ${{ inputs.release == 'false' }} shell: bash env: - SHA: ${{ inputs.branch }} + SHA: ${{ inputs.sha }} TAG: ${{ inputs.tag }} run: | + # TODO: remove SHA=${{ github.sha }} + echo "SHA is $SHA" + echo "TAG is $TAG" + echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" # Create new tag via GitHub API # https://docs.github.com/en/rest/reference/git#create-a-reference curl -s \ @@ -57,55 +85,34 @@ runs: "ref": "refs/tags/$TAG" } EOF - echo "New tag $TAG created with sha $SHA" - -# Note: untestested below this line: + echo "New tag $TAG created for sha $SHA" -# - name: Delete existing release if one exists -# if: ${{ inputs.release && inputs.delete_existing }} -# shell: bash -# env: -# SHA: ${{ inputs.branch }} -# TAG: ${{ inputs.tag }} -# BODY: ${{ inputs.body }} -# run: | -# echo "Deleting old release for $TAG if it exists" -# # Get id for an existing release matching $TAG -# curl -s \ -# -X GET https://api.github.com/repos/silverstripe/silverstripe-framework/releases/tags/$TAG \ -# -H "Accept: application/vnd.github.v3+json" > __.json -# RELEASE_ID=$(jq .id __.json) -# if [ "$RELEASE_ID" != "null" ]; then -# curl -s \ -# -X DELETE https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID \ -# -H "Accept: application/vnd.github.v3+json" \ -# -H "Authorization: token ${{ github.token }}" -# echo "Deleted existing release $RELEASE_ID for tag $TAG" -# else -# echo "Could not find an existing release for tag $TAG" -# fi - -# - name: Create release -# if: ${{ inputs.release }} -# shell: bash -# env: -# SHA: ${{ inputs.branch }} -# TAG: ${{ inputs.tag }} -# BODY: ${{ inputs.body }} -# run: | -# # Run git commit, push and create pull-request as 'github-actions' user - -# # Create new pull-request via GitHub API -# # https://docs.github.com/en/rest/reference/releases#create-a-release -# curl -s \ -# -X POST https://api.github.com/repos/${{ github.repository }}/releases \ -# -H "Accept: application/vnd.github.v3+json" \ -# -H "Authorization: token ${{ github.token }}" \ -# -d @- << EOF -# { -# "tag_name": "$TAG", -# "name": "$TAG", -# "body": "$BODY", -# } -# EOF -# echo "New pull-request created" + # Creating a release will also create a tag + - name: Create release + if: ${{ inputs.release == 'true' }} + shell: bash + env: + SHA: ${{ inputs.sha }} + TAG: ${{ inputs.tag }} + BODY: ${{ inputs.body }} + run: | + # Create new release via GitHub API + # https://docs.github.com/en/rest/reference/releases#create-a-release + # Escape double quotes '"' => '\"' + BODY=${BODY//\"/\\\"} + curl -s \ + -X POST https://api.github.com/repos/${{ github.repository }}/releases \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ github.token }}" \ + -d @- << EOF + { + "tag_name": "$TAG", + "target_commitish": "$SHA", + "name": "$TAG", + "body": "$BODY", + "draft": false, + "prerelease": false + } + EOF + echo "New release $TAG created" +# ^ todo: test inputs.body with a single double quote in it \ No newline at end of file From c5def80ccf9f162807d66c26b32a42c4b6843cbf Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:04:56 +1200 Subject: [PATCH 03/13] NEW Create action --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index cb018c2..2e556cd 100644 --- a/action.yml +++ b/action.yml @@ -69,7 +69,7 @@ runs: TAG: ${{ inputs.tag }} run: | # TODO: remove - SHA=${{ github.sha }} + # SHA=${{ github.sha }} echo "SHA is $SHA" echo "TAG is $TAG" echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" From 74bfe712d110839e1128809b0d1b6c360d4456f7 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:16:21 +1200 Subject: [PATCH 04/13] NEW Create action --- action.yml | 58 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/action.yml b/action.yml index 2e556cd..93d9957 100644 --- a/action.yml +++ b/action.yml @@ -63,29 +63,41 @@ runs: - name: Create tag if: ${{ inputs.release == 'false' }} - shell: bash - env: - SHA: ${{ inputs.sha }} - TAG: ${{ inputs.tag }} - run: | - # TODO: remove - # SHA=${{ github.sha }} - echo "SHA is $SHA" - echo "TAG is $TAG" - echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" - # Create new tag via GitHub API - # https://docs.github.com/en/rest/reference/git#create-a-reference - curl -s \ - -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ github.token }}" \ - -d @- << EOF - { - "sha": "$SHA", - "ref": "refs/tags/$TAG" - } - EOF - echo "New tag $TAG created for sha $SHA" + uses: actions/github-script@v5 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ inputs.tag }}', + sha: ${{ inputs.sha }} + }) + + # - name: Create tag + # if: ${{ inputs.release == 'false' }} + # shell: bash + # env: + # SHA: ${{ inputs.sha }} + # TAG: ${{ inputs.tag }} + # run: | + # # TODO: remove + # # SHA=${{ github.sha }} + # echo "SHA is $SHA" + # echo "TAG is $TAG" + # echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" + # # Create new tag via GitHub API + # # https://docs.github.com/en/rest/reference/git#create-a-reference + # curl -s \ + # -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ + # -H "Accept: application/vnd.github.v3+json" \ + # -H "Authorization: token ${{ github.token }}" \ + # -d @- << EOF + # { + # "sha": "$SHA", + # "ref": "refs/tags/$TAG" + # } + # EOF + # echo "New tag $TAG created for sha $SHA" # Creating a release will also create a tag - name: Create release From fdb4c35ae004db5d78838f2ff95e62b8893ddd72 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:21:39 +1200 Subject: [PATCH 05/13] NEW Create action --- action.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 93d9957..d980c70 100644 --- a/action.yml +++ b/action.yml @@ -61,6 +61,22 @@ runs: -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${{ github.token }}" + # - name: Delete existing tag if one exists + # if: ${{ inputs.delete_existing == 'true' }} + # shell: bash + # # Add string inputs to memory instead of using string substitution in shell script + # # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + # env: + # TAG: ${{ inputs.tag }} + # run: | + # echo "Deleting old $TAG tag if it exists" + # # Delete tag via GitHub API + # # https://docs.github.com/en/rest/reference/git#delete-a-reference + # curl -s \ + # -X DELETE https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$TAG \ + # -H "Accept: application/vnd.github.v3+json" \ + # -H "Authorization: token ${{ github.token }}" + - name: Create tag if: ${{ inputs.release == 'false' }} uses: actions/github-script@v5 @@ -70,7 +86,7 @@ runs: owner: context.repo.owner, repo: context.repo.repo, ref: 'refs/tags/${{ inputs.tag }}', - sha: ${{ inputs.sha }} + sha: '${{ inputs.sha }}' }) # - name: Create tag From 9de6939dae686e13ec236d196c6920b42c3f5577 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:34:47 +1200 Subject: [PATCH 06/13] NEW Create action --- action.yml | 57 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/action.yml b/action.yml index d980c70..1e1f145 100644 --- a/action.yml +++ b/action.yml @@ -23,6 +23,22 @@ runs: using: composite steps: + - name: Validate inputs + shell: bash + env: + SHA: ${{ inputs.sha }} + TAG: ${{ inputs.tag }} + BODY: ${{ inputs.body }} + run: | + if ! [[ "$SHA" =~ [^0-9a-f]{40} ]]; then + echo "Invalid sha" + exit 1 + fi + if [[ "$TAG" =~ [^a-z0-9\.\-] ]]; then + echo "Invalid tag" + exit 1 + fi + - name: Delete existing release if one exists if: ${{ inputs.release == 'true' && inputs.delete_existing == 'true' }} shell: bash @@ -61,33 +77,24 @@ runs: -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${{ github.token }}" - # - name: Delete existing tag if one exists - # if: ${{ inputs.delete_existing == 'true' }} - # shell: bash - # # Add string inputs to memory instead of using string substitution in shell script - # # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable - # env: - # TAG: ${{ inputs.tag }} - # run: | - # echo "Deleting old $TAG tag if it exists" - # # Delete tag via GitHub API - # # https://docs.github.com/en/rest/reference/git#delete-a-reference - # curl -s \ - # -X DELETE https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$TAG \ - # -H "Accept: application/vnd.github.v3+json" \ - # -H "Authorization: token ${{ github.token }}" - - name: Create tag if: ${{ inputs.release == 'false' }} - uses: actions/github-script@v5 - with: - script: | - github.rest.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: 'refs/tags/${{ inputs.tag }}', - sha: '${{ inputs.sha }}' - }) + shell: bash + env: + SHA: ${{ inputs.sha }} + TAG: ${{ inputs.tag }} + run: | + # Use raw git commands, otherwise we get "Resource not accessible by integration" + # and the tag is not created, even if parent job is run with permission: write-all + # This is despite the fact we can create a release via the API which generates a tag + RES=$(git checkout "$SHA") + if [[ $RES =~ error ]]; then + echo "SHA does not exist, did not create tag" + exit 1 + fi + git tag "$TAG" + git push origin "$TAG" + echo "New tag $TAG created for sha $SHA" # - name: Create tag # if: ${{ inputs.release == 'false' }} From d9ea084d733d3b1971e9e0f6642da9cdb93c38a7 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:36:12 +1200 Subject: [PATCH 07/13] NEW Create action --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 1e1f145..5774fbe 100644 --- a/action.yml +++ b/action.yml @@ -30,7 +30,7 @@ runs: TAG: ${{ inputs.tag }} BODY: ${{ inputs.body }} run: | - if ! [[ "$SHA" =~ [^0-9a-f]{40} ]]; then + if ! [[ "$SHA" =~ ^[0-9a-f]{40}$ ]]; then echo "Invalid sha" exit 1 fi From 5fe87bfa1a302666631bea4d51dfc3f467d4f583 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:38:06 +1200 Subject: [PATCH 08/13] NEW Create action --- action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/action.yml b/action.yml index 5774fbe..d503ccc 100644 --- a/action.yml +++ b/action.yml @@ -77,6 +77,10 @@ runs: -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${{ github.token }}" + - name: Checkout code + if: ${{ inputs.release == 'false' }} + uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # @v2 + - name: Create tag if: ${{ inputs.release == 'false' }} shell: bash From bb9bcb89962d580654b668403618c2313c6a3dd8 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:40:59 +1200 Subject: [PATCH 09/13] NEW Create action --- action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/action.yml b/action.yml index d503ccc..4a2bbd4 100644 --- a/action.yml +++ b/action.yml @@ -88,6 +88,8 @@ runs: SHA: ${{ inputs.sha }} TAG: ${{ inputs.tag }} run: | + # debug + git log # Use raw git commands, otherwise we get "Resource not accessible by integration" # and the tag is not created, even if parent job is run with permission: write-all # This is despite the fact we can create a release via the API which generates a tag From b5aad7e1e6f0eb4ecbfd7db4fd16e411030de8d9 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:43:59 +1200 Subject: [PATCH 10/13] NEW Create action --- action.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 4a2bbd4..1cc0ce7 100644 --- a/action.yml +++ b/action.yml @@ -80,6 +80,8 @@ runs: - name: Checkout code if: ${{ inputs.release == 'false' }} uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # @v2 + with: + fetch-depth: 50 - name: Create tag if: ${{ inputs.release == 'false' }} @@ -93,11 +95,7 @@ runs: # Use raw git commands, otherwise we get "Resource not accessible by integration" # and the tag is not created, even if parent job is run with permission: write-all # This is despite the fact we can create a release via the API which generates a tag - RES=$(git checkout "$SHA") - if [[ $RES =~ error ]]; then - echo "SHA does not exist, did not create tag" - exit 1 - fi + git checkout "$SHA" git tag "$TAG" git push origin "$TAG" echo "New tag $TAG created for sha $SHA" From 0c2284d226ed64ed4f1d41c2d199cd4d410202d8 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:54:13 +1200 Subject: [PATCH 11/13] NEW Create action --- action.yml | 87 +++++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/action.yml b/action.yml index 1cc0ce7..31c36c7 100644 --- a/action.yml +++ b/action.yml @@ -19,6 +19,9 @@ inputs: type: string required: false default: '' + github_token: + description: "GitHub secret token" + required: true runs: using: composite steps: @@ -61,6 +64,7 @@ runs: echo "Could not find an existing release for tag $TAG" fi + # Note the use of ${{ inputs.github_token }} instead of ${{ github.token }} - name: Delete existing tag if one exists if: ${{ inputs.delete_existing == 'true' }} shell: bash @@ -75,31 +79,16 @@ runs: curl -s \ -X DELETE https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$TAG \ -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ github.token }}" - - - name: Checkout code - if: ${{ inputs.release == 'false' }} - uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # @v2 - with: - fetch-depth: 50 + -H "Authorization: token ${{ inputs.github_token }}" - - name: Create tag - if: ${{ inputs.release == 'false' }} - shell: bash - env: - SHA: ${{ inputs.sha }} - TAG: ${{ inputs.tag }} - run: | - # debug - git log - # Use raw git commands, otherwise we get "Resource not accessible by integration" - # and the tag is not created, even if parent job is run with permission: write-all - # This is despite the fact we can create a release via the API which generates a tag - git checkout "$SHA" - git tag "$TAG" - git push origin "$TAG" - echo "New tag $TAG created for sha $SHA" + # - name: Checkout code + # if: ${{ inputs.release == 'false' }} + # uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # @v2 + # with: + # fetch-depth: 50 + # This fails + # ! [remote rejected] mytag -> mytag (refusing to allow a GitHub App to create or update workflow `.github/workflows/test.yml` without `workflows` permission) # - name: Create tag # if: ${{ inputs.release == 'false' }} # shell: bash @@ -107,25 +96,43 @@ runs: # SHA: ${{ inputs.sha }} # TAG: ${{ inputs.tag }} # run: | - # # TODO: remove - # # SHA=${{ github.sha }} - # echo "SHA is $SHA" - # echo "TAG is $TAG" - # echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" - # # Create new tag via GitHub API - # # https://docs.github.com/en/rest/reference/git#create-a-reference - # curl -s \ - # -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ - # -H "Accept: application/vnd.github.v3+json" \ - # -H "Authorization: token ${{ github.token }}" \ - # -d @- << EOF - # { - # "sha": "$SHA", - # "ref": "refs/tags/$TAG" - # } - # EOF + # # debug + # git log + # # Use raw git commands, otherwise we get "Resource not accessible by integration" + # # and the tag is not created, even if parent job is run with permission: write-all + # # This is despite the fact we can create a release via the API which generates a tag + # git checkout "$SHA" + # git tag "$TAG" + # git push origin "$TAG" # echo "New tag $TAG created for sha $SHA" + # Note the use of ${{ inputs.github_token }} instead of ${{ github.token }} + - name: Create tag + if: ${{ inputs.release == 'false' }} + shell: bash + env: + SHA: ${{ inputs.sha }} + TAG: ${{ inputs.tag }} + run: | + # TODO: remove + # SHA=${{ github.sha }} + echo "SHA is $SHA" + echo "TAG is $TAG" + echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" + # Create new tag via GitHub API + # https://docs.github.com/en/rest/reference/git#create-a-reference + curl -s \ + -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ inputs.github_token }}" \ + -d @- << EOF + { + "sha": "$SHA", + "ref": "refs/tags/$TAG" + } + EOF + echo "New tag $TAG created for sha $SHA" + # Creating a release will also create a tag - name: Create release if: ${{ inputs.release == 'true' }} From da6ec187df03a30296e8caedb1e1bbf5ed6d5b3e Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 20:56:37 +1200 Subject: [PATCH 12/13] NEW Create action --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 31c36c7..58f0ef2 100644 --- a/action.yml +++ b/action.yml @@ -64,6 +64,7 @@ runs: echo "Could not find an existing release for tag $TAG" fi + # This fails "Resource not accessible by integration" - even with token passed in # Note the use of ${{ inputs.github_token }} instead of ${{ github.token }} - name: Delete existing tag if one exists if: ${{ inputs.delete_existing == 'true' }} From 84daf1727474304a0fb15b4b1680ff56c0670055 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 31 May 2022 21:00:26 +1200 Subject: [PATCH 13/13] NEW Create action --- .github/workflows/auto-tag.yml | 4 +- README.md | 29 +++++- action.yml | 168 +++++++++++++++++---------------- 3 files changed, 115 insertions(+), 86 deletions(-) diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml index 982c17a..33446ca 100644 --- a/.github/workflows/auto-tag.yml +++ b/.github/workflows/auto-tag.yml @@ -1,3 +1,4 @@ +name: Auto-tag on: push: tags: @@ -9,6 +10,3 @@ jobs: steps: - name: Auto-tag uses: silverstripe/gha-auto-tag@main - with: - ref: ${{ github.ref }} - sha: ${{ github.sha }} diff --git a/README.md b/README.md index d26c6a9..7aea143 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,31 @@ Create a tag and an optional release -Note: this ctions seems to have issues creating tags and releases on forked repos, though it's fine on non-forked repos +## Usage + +**workflow.yml** +```yml +steps: + - name: Create tag and release + uses: silverstripe/gha-pull-request@main + with: + tag: 1.2.3 + release: true +``` + +Read more information about the inputs available for [silverstripe/gha-pull-request](https://github.com/silverstripe/gha-pull-request). + +## Why there is no SHA input paramater + +Creating a tag for a particular SHA, either via the GitHub API or via CLI (i.e. git tag) in an action is strangely blocked. The error is "Resource not accessible by integration" which is a permissions error. + +However, tags can be created with the following methods: +- Using `${{ github.sha }}` which is the latest sha in a context instead of historic sha +- Creating a release via GitHub API, which will also create a tag. While it's tempting to just use this and then delete the release, it's seems possible that this may stop working in the future + +The following methods have been attempted: +- Using third party actions to create tags +- Passing in `permissions: write-all` from the calling workflow +- Passing in a github token from the calling workflow + +It's likely that `${{ github.sha }}` will be good enough though - the intention is that this action will be used to tag the _most recent commit_ on a given branch, e.g. after a pull request is merged. diff --git a/action.yml b/action.yml index 58f0ef2..ad7f774 100644 --- a/action.yml +++ b/action.yml @@ -1,9 +1,8 @@ name: Tag and release description: GitHub Action to create a tag and an optional release + inputs: - sha: - type: string - required: true + # Note: there is an explicit reason why there is no sha input parameter - see the readme tag: type: string required: true @@ -15,13 +14,11 @@ inputs: type: boolean required: false default: false - body: + release_description: type: string required: false default: '' - github_token: - description: "GitHub secret token" - required: true + runs: using: composite steps: @@ -29,15 +26,10 @@ runs: - name: Validate inputs shell: bash env: - SHA: ${{ inputs.sha }} TAG: ${{ inputs.tag }} - BODY: ${{ inputs.body }} run: | - if ! [[ "$SHA" =~ ^[0-9a-f]{40}$ ]]; then - echo "Invalid sha" - exit 1 - fi - if [[ "$TAG" =~ [^a-z0-9\.\-] ]]; then + git check-ref-format "tags/$TAG" > /dev/null + if [[ $? != "0" ]]; then echo "Invalid tag" exit 1 fi @@ -47,119 +39,131 @@ runs: shell: bash env: TAG: ${{ inputs.tag }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | - echo "Deleting old release for $TAG if it exists" # Get id for an existing release matching $TAG - curl -s \ - -X GET https://api.github.com/repos/${{ github.repository }}/releases/tags/$TAG \ - -H "Accept: application/vnd.github.v3+json" > __.json - RELEASE_ID=$(jq .id __.json) - if [ "$RELEASE_ID" != "null" ]; then - curl -s \ - -X DELETE https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID \ + # https://docs.github.com/en/rest/releases/releases#get-a-release-by-tag-name + RESP_CODE=$(curl -w %{http_code} -s -o __response.json \ + -X GET https://api.github.com/repos/$GITHUB_REPOSITORY/releases/tags/$TAG \ + -H "Accept: application/vnd.github.v3+json") + if [[ $RESP_CODE != "200" ]]; + echo "Unable to check tag status for $TAG - HTTP response code was $RESP_CODE" + exit 1 + fi + RELEASE_ID=$https://docs.github.com/en/rest/git/refs#get-a-reference(jq .id __response.json) + if [[ $RELEASE_ID == "null" ]]; then + echo "Did not find an existing release for tag $TAG" + else + # https://docs.github.com/en/rest/releases/releases#delete-a-release + RESP_CODE=$(curl -w %{http_code} -s -o /dev/null \ + -X DELETE https://api.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${{ github.token }}" + if [[ $RESP_CODE != "204" ]]; + echo "Unable to delete release $RELEASE_ID for tag $TAG - HTTP response code was $RESP_CODE" + exit 1 + fi echo "Deleted existing release $RELEASE_ID for tag $TAG" - else - echo "Could not find an existing release for tag $TAG" fi - # This fails "Resource not accessible by integration" - even with token passed in - # Note the use of ${{ inputs.github_token }} instead of ${{ github.token }} - name: Delete existing tag if one exists if: ${{ inputs.delete_existing == 'true' }} shell: bash - # Add string inputs to memory instead of using string substitution in shell script - # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable env: TAG: ${{ inputs.tag }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | - echo "Deleting old $TAG tag if it exists" - # Delete tag via GitHub API - # https://docs.github.com/en/rest/reference/git#delete-a-reference - curl -s \ - -X DELETE https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$TAG \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ inputs.github_token }}" - - # - name: Checkout code - # if: ${{ inputs.release == 'false' }} - # uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # @v2 - # with: - # fetch-depth: 50 - - # This fails - # ! [remote rejected] mytag -> mytag (refusing to allow a GitHub App to create or update workflow `.github/workflows/test.yml` without `workflows` permission) - # - name: Create tag - # if: ${{ inputs.release == 'false' }} - # shell: bash - # env: - # SHA: ${{ inputs.sha }} - # TAG: ${{ inputs.tag }} - # run: | - # # debug - # git log - # # Use raw git commands, otherwise we get "Resource not accessible by integration" - # # and the tag is not created, even if parent job is run with permission: write-all - # # This is despite the fact we can create a release via the API which generates a tag - # git checkout "$SHA" - # git tag "$TAG" - # git push origin "$TAG" - # echo "New tag $TAG created for sha $SHA" + # Check if tag currently exists + # Note: not using https://api.github.com/repos/$GITHUB_REPOSITORY/git/refs/tags/ + # because that uses a "starts-with" filter, so it will also match -beta1 and -rc1 tags + # https://docs.github.com/en/rest/git/refs#get-a-reference + RESP_CODE=$(curl -w %{http_code} -s -o __response.json \ + -X GET https://api.github.com/repos/$GITHUB_REPOSITORY/git/refs/tags \ + -H "Accept: application/vnd.github.v3+json") + if [[ $RESP_CODE != "200" ]]; + echo "Unable to check tag status - HTTP response code was $RESP_CODE" + exit 1 + fi + FOUND="true" + # Check there are any tags so we can use jq array selector later + if [[ $(jq 'map(type)' __response.json) =~ object ]]; then + if [[ $(jq '.[] | select(.ref == "refs/tags/$TAG")' __response.json) == "" ]]; then + FOUND="false" + fi + fi + if [[ $FOUND == "false" ]]; then + echo "Did not find an existing tag for $TAG" + else + # Delete tag via GitHub API + # https://docs.github.com/en/rest/reference/git#delete-a-reference + RESP_CODE=$(curl -w %{http_code} -s -o /dev/null \ + curl -s \ + -X DELETE https://api.github.com/repos/$GITHUB_REPOSITORY/git/refs/tags/$TAG \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token ${{ github.token }}") + if [[ $RESP_CODE != "204" ]]; + echo "Unable to delete existing TAG $TAG - HTTP response code was $RESP_CODE" + exit 1 + fi + echo "Deleted existing tag $TAG" + fi - # Note the use of ${{ inputs.github_token }} instead of ${{ github.token }} - name: Create tag + # Creating a release will also create a tag, so only create explicitly create tag if not creating release if: ${{ inputs.release == 'false' }} shell: bash env: - SHA: ${{ inputs.sha }} TAG: ${{ inputs.tag }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | - # TODO: remove - # SHA=${{ github.sha }} - echo "SHA is $SHA" - echo "TAG is $TAG" - echo "url is https://api.github.com/repos/${{ github.repository }}/git/refs" # Create new tag via GitHub API # https://docs.github.com/en/rest/reference/git#create-a-reference - curl -s \ - -X POST https://api.github.com/repos/${{ github.repository }}/git/refs \ + RESP_CODE=$(curl -w %{http_code} -s -o /dev/null \ + -X POST https://api.github.com/repos/$GITHUB_REPOSITORY/git/refs \ -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ inputs.github_token }}" \ + -H "Authorization: token ${{ github.token }}" \ -d @- << EOF { - "sha": "$SHA", + "sha": "${{ github.sha }}", "ref": "refs/tags/$TAG" } EOF - echo "New tag $TAG created for sha $SHA" + ) + if [[ $RESP_CODE != "201" ]]; + echo "Unable to create tag $TAG for sha ${{ github.sha }} - HTTP response code was $RESP_CODE" + exit 1 + fi + echo "New tag $TAG created for sha ${{ github.sha }}" - # Creating a release will also create a tag - name: Create release if: ${{ inputs.release == 'true' }} shell: bash env: - SHA: ${{ inputs.sha }} TAG: ${{ inputs.tag }} - BODY: ${{ inputs.body }} + RELEASE_DESCRIPTION: ${{ inputs.release_description }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | # Create new release via GitHub API - # https://docs.github.com/en/rest/reference/releases#create-a-release + # https://docs.github.com/en/rest/releases/releases#create-a-release # Escape double quotes '"' => '\"' - BODY=${BODY//\"/\\\"} - curl -s \ - -X POST https://api.github.com/repos/${{ github.repository }}/releases \ + RELEASE_DESCRIPTION=${RELEASE_DESCRIPTION//\"/\\\"} + RESP_CODE=$(curl -w %{http_code} -s -o /dev/null \ + -X POST https://api.github.com/repos/$GITHUB_REPOSITORY/releases \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${{ github.token }}" \ -d @- << EOF { "tag_name": "$TAG", - "target_commitish": "$SHA", + "target_commitish": "${{ github.sha }}", "name": "$TAG", - "body": "$BODY", + "body": "$RELEASE_DESCRIPTION", "draft": false, "prerelease": false } EOF + ) + if [[ $RESP_CODE != "201" ]]; + echo "Unable to create release for tag $TAG - HTTP response code was $RESP_CODE" + exit 1 + fi echo "New release $TAG created" -# ^ todo: test inputs.body with a single double quote in it \ No newline at end of file