diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..9decf16 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,113 @@ +name: tag and release +on: push +env: + check_only: true + commits: ${{ github.event.commits }} +jobs: + tag-release: + runs-on: self-hosted + defaults: + run: + shell: bash + steps: + - name: identify execution context + id: context + run: | + # search for key words in commit messages + echo "${commits}" | jq '.[].message' > messages.txt + if [[ $( grep -i '\[major\]' messages.txt ) ]]; then + type=major + elif [[ $( grep -i '\[minor\]' messages.txt ) ]]; then + type=minor + else + type=patch + fi + echo "type=${type:-patch}" >> $GITHUB_OUTPUT + + - name: checkout + uses: actions/checkout@v4 + + - name: fetch current tag + id: oldver + run: | + echo '>>>> searching current release tag' + + elem_pattern='\.(0|[0-9]+)' + + # by default, find the latest released tag without a suffix + pattern='^v'${elem_pattern:2}${elem_pattern}${elem_pattern}'$' + + # list tags in the remote + git ls-remote --tags --refs --sort=-v:refname origin refs/tags/v[0-9]* | sed 's/.*\///' > tags.txt + + # get the appropriate tag and fetch it + echo ">>>> searching last tag matching '${pattern}'" + last_tag=$( grep -m 1 -E "${pattern}" tags.txt ) + git fetch --no-tags origin "+refs/tags/${last_tag}:refs/tags/${last_tag}" &>/dev/null + + echo ">>>> identified current version: ${last_tag}" + echo "tag=${last_tag:-v0.0.0}" >> $GITHUB_OUTPUT + + - name: calculate new tag + id: newver + run: | + # split the latest tag into major/minor/patch values + last_tag='${{ steps.oldver.outputs.tag }}' + IFS='.' read -r v_major v_minor v_patch <<< "${last_tag:1}" + + type='${{ steps.context.outputs.type }}' + case ${type} in + major) + v_major=$((v_major+1)) + v_minor=0 + v_patch=0 + ;; + minor) + v_minor=$((v_minor+1)) + v_patch=0 + ;; + *) + v_patch=$((v_patch+1)) + ;; + esac + + new_tag="v${v_major}.${v_minor}.${v_patch}" + echo ">>>> new version calculated: ${new_tag}" + + echo "tag=${new_tag}" >> $GITHUB_OUTPUT + + - name: push tag + if: ${{ ! env.check_only }} + run: | + new_tag='${{ steps.newver.outputs.tag }}' + git tag -f ${new_tag} ${{ github.sha }} + git push -f origin ${new_tag} + + - name: publish release + if: ${{ ! env.check_only }} + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const oldTag = '${{ steps.oldver.outputs.tag }}'; + const newTag = '${{ steps.newver.outputs.tag }}'; + + // generate release notes + const { data: notes } = await github.rest.repos.generateReleaseNotes({ + ...context.repo, + tag_name: newTag, + target_commitish: context.sha, + previous_tag_name: oldTag + }); + + // build request body + const request = { + ...context.repo, + tag_name: newTag, + name: newTag, + target_commitish: context.sha, + body: notes.body + }; + + console.debug('>>>> creating a new release'); + await github.rest.repos.createRelease(request); \ No newline at end of file