Skip to content

Commit

Permalink
NEW Create action
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Jun 13, 2022
1 parent da6ec18 commit 84daf17
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 86 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/auto-tag.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
name: Auto-tag
on:
push:
tags:
Expand All @@ -9,6 +10,3 @@ jobs:
steps:
- name: Auto-tag
uses: silverstripe/gha-auto-tag@main
with:
ref: ${{ github.ref }}
sha: ${{ github.sha }}
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
168 changes: 86 additions & 82 deletions action.yml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -15,29 +14,22 @@ 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:

- 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
Expand All @@ -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/<tag>
# 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

0 comments on commit 84daf17

Please sign in to comment.