Skip to content
This repository was archived by the owner on Aug 29, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b10cc2d
Revert "include cross-package coverage in codecov"
galargh Dec 10, 2021
8d7b557
Merge pull request #245 from protocol/revert-210-codecov-cross-package
galargh Dec 10, 2021
af39fc8
Revert "Revert "include cross-package coverage in codecov""
galargh Dec 10, 2021
3d5f0d1
Merge pull request #246 from protocol/revert-245-revert-210-codecov-c…
galargh Dec 10, 2021
6f5cf40
Make automerge a reusable workflow (#260)
galargh Jan 7, 2022
3543681
Merge remote-tracking branch 'origin/master' into next
galargh Jan 11, 2022
0454bfc
check github actions yamls (#272)
galargh Jan 11, 2022
c9b7c51
use validate-yaml-schema action from mainline (#277)
galargh Jan 12, 2022
816b8a7
upgrade lewagon/wait-on-check-action to v1.1.1 (#278)
galargh Jan 13, 2022
1a2b29c
always add a version.json file if it doesn't exist (#281)
galargh Jan 14, 2022
97688fd
fix go-test runner string
galargh Jan 14, 2022
9d885d4
check if tag already exists in release-check (#287)
galargh Jan 28, 2022
a199227
allow specifying custom PATH for 386 arch (#289)
galargh Feb 1, 2022
1814d3c
use pull_request_target event for release-check workflow
galargh Feb 22, 2022
16a1f3d
create draft github release during release check
galargh Feb 24, 2022
3dfc692
publish github release in releaser workflow
galargh Feb 24, 2022
7eb44ac
add names and comments to release related workflows
galargh Feb 25, 2022
11c6e00
add info about github releases to versioning.md
galargh Feb 25, 2022
4911f21
move version check in release check
galargh Feb 25, 2022
dc5ecc8
clean up the release check comment
galargh Feb 25, 2022
5f45689
add comment on missing version.json
galargh Mar 16, 2022
09e1b32
Merge branch 'pr-target-release-check' into github-release
galargh May 13, 2022
b08430a
Merge branch 'next' into pr-target-release-check
galargh Nov 14, 2022
b070412
Merge branch 'pr-target-release-check' into github-release
galargh Nov 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 127 additions & 105 deletions .github/workflows/release-check.yml
Original file line number Diff line number Diff line change
@@ -1,144 +1,166 @@
# This workflow cannot post sticky comments on PRs from forked repositories.
# Instead, it outputs the message it would have posted as a workflow notice.
# See https://github.com/protocol/.github/issues/254 for details.

name: Release Checker
on: [ workflow_call ]

jobs:
releaser:
prepare:
runs-on: ubuntu-latest
env:
TAG_EXISTS: "true"
VERSION: "" # the version number read from version.json
COMPARETO: "" # the version number to compare this version to
GORELEASE: ""
GOCOMPAT: ""
GOMODDIFF: ""
RELEASE_BRANCH_NOTE: ""
GITHUB_TOKEN: ${{ github.token }}
outputs:
version: ${{ steps.version.outputs.this }}
tag_exists: ${{ steps.tag_exists.outputs.this }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "1.19.x"
- name: Determine version
if: hashFiles('version.json')
run: echo "VERSION=$(jq -r .version version.json)" >> $GITHUB_ENV
- name: Check if the tag already exists
# Check if a git tag for the version (as read from version.json) exists
# If that is the case, we don't need to run the rest of the workflow.
if: env.VERSION != ''
- id: version
name: Retrieve new version from version.json
run: |
git fetch origin --tags
status=0
git rev-list $VERSION &> /dev/null || status=$?
if [[ $status != 0 ]]; then
echo "TAG_EXISTS=false" >> $GITHUB_ENV
fi
- name: Install semver (node command line tool)
if: env.TAG_EXISTS == 'false'
run: npm install -g "https://github.com/npm/node-semver#e79ac3a450e8bb504e78b8159e3efc7089569" # v7.3.5
# https://docs.github.com/en/rest/reference/repos#get-repository-content
version="$(gh api -X GET 'repos/${{ github.event.pull_request.head.repo.full_name }}/contents/version.json' -f ref='${{ github.event.pull_request.head.sha }}' --jq '.content' | base64 -d | jq -r '.version // ""')"
status=$? && ([[ $status == 0 ]] || exit $status)
echo "version=$version"
echo "::set-output name=this::$version"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- id: tag_exists
name: Check if version tag already exists
if: steps.version.outputs.this != ''
run: |
# https://docs.github.com/en/rest/reference/git#get-a-reference
gh api '/repos/${{ github.repository }}/git/ref/tags/${{ steps.version.outputs.this }}' && tag_exists='true' || tag_exists='false'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're using string interpolation at the yml level here, is it possible a malformed value in steps.version.outputs.this turns into a string injection?

Should we use something like:

env:
    TAG_URL: /repos/${{ github.repository }}/git/ref/tags/${{ steps.version.outputs.this }}
run:
    gh api "${TAG_URL}" # using shell's expansion here

?

ref: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable


echo "tag_exists=$tag_exists"
echo "::set-output name=this::$tag_exists"
check:
needs: [prepare]
if: needs.prepare.outputs.tag_exists != 'true'
runs-on: ubuntu-latest
env:
COMMENT: "Suggested version: `${{ needs.prepare.outputs.version }}`"
GITHUB_TOKEN: ${{ github.token }}
steps:
- name: Check version
if: env.TAG_EXISTS == 'false'
run: semver ${{ env.VERSION }} # fails if the version is not a valid semver version (e.g. v0.1 would fail)
- name: Determine version number to compare to
if: env.TAG_EXISTS == 'false'
run: |
npm install -g 'https://github.com/npm/node-semver#e79ac3a450e8bb504e78b8159e3efc7089569' # v7.3.5

semver '${{ needs.prepare.outputs.version }}' # fails if the version is not a valid semver version (e.g. v0.1 would fail)
- id: release
name: Create draft GitHub Release (if it doesn't exist yet)
run: |
# using GraphQL because https://docs.github.com/en/rest/reference/releases#list-releases does not return draft releases
# https://docs.github.com/en/graphql/reference/objects#release
release="$(gh api graphql -f query='query { repository(owner: "${{ github.event.repository.owner.login }}", name: "${{ github.event.repository.name }}") { release(tagName: "${{ needs.prepare.outputs.version }}") { url } } }' --jq '.data.repository.release.url // ""')"
status=$? && ([[ $status == 0 ]] || exit $status)

if [[ -z "$release" ]]; then
# https://docs.github.com/en/rest/reference/releases#create-a-release
# creating a draft release does not create a tag, only publishing does
release="$(gh api '/repos/${{ github.repository }}/releases' -F 'draft=true' -f 'tag_name=${{ needs.prepare.outputs.version }}' -F 'generate_release_notes=true' --jq '.html_url')"
status=$? && ([[ $status == 0 ]] || exit $status)
fi

echo "COMMENT<<EOF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$COMMENT

Draft GitHub Release: [\`${{ needs.prepare.outputs.version }}\`](https://github.com/${{ github.repository }}/releases?q=draft%3Atrue+tag%3A${{ needs.prepare.outputs.version }})
Merging the PR will publish the release. All modifications to the draft will be preserved. In particular, deleting the draft will prevent the release from getting published.
EOF" >> $GITHUB_ENV
- uses: actions/setup-go@v2
with:
go-version: "1.17.x"
- id: prev_version
name: Determine version number to compare to
# We need to determine the version number we want to compare to,
# taking into account that this might be a (patch) release on a release branch.
# Example:
# Imagine a module that has releases for v0.1.0, v0.2.0 and v0.3.0.
# When trying to cut a release v0.2.1, we need to base our comparisons on v0.2.0.
# When trying to cut a release v0.3.1 or v0.4.0, we need to base our comparisons on v0.3.0.
run: |
git fetch origin --tags
go install github.com/marten-seemann/semver-highest@fcdc98f8820ff0e6613c1bee071c096febd98dbf
v=$(semver-highest -target ${{ env.VERSION }} -versions $(git tag | paste -sd , -))
status=$?
if [[ $status != 0 ]]; then
echo $v
exit $status

versions="$(gh api --paginate '/repos/${{ github.repository }}/tags' --jq 'map(.name)' | jq -nr '[inputs] | add | join(",")')"
status=$? && ([[ $status == 0 ]] || exit $status)

prev_version="$(semver-highest -target '${{ needs.prepare.outputs.version }}' -versions "$versions")"

echo "prev_version=$prev_version"
echo "::set-output name=this::$prev_version"

if [[ -z "$prev_version" ]]; then
output="This is the first release of this module."
else
output="Comparing to: [\`$prev_version\`](${{ github.event.pull_request.base.repo.html_url }}/releases/tag/$prev_version) ([diff](${{ github.event.pull_request.base.repo.html_url }}/compare/$prev_version..${{ github.event.pull_request.head.label }}))"
fi
echo "COMPARETO=$v" >> $GITHUB_ENV
- name: Post output
if: env.TAG_EXISTS == 'false' && env.COMPARETO == ''
uses: marocchino/sticky-pull-request-comment@82e7a0d3c51217201b3fedc4ddde6632e969a477 # v2.1.1
with:
header: release-check
recreate: true
message: |
Suggested version: `${{ env.VERSION }}`

This is the first release of this module.
- name: run git diff on go.mod file(s)
if: env.TAG_EXISTS == 'false' && env.COMPARETO != ''
echo "COMMENT<<EOF
$COMMENT

$output
EOF" >> $GITHUB_ENV
- uses: actions/checkout@v2
if: steps.prev_version.outputs.this != ''
- if: steps.prev_version.outputs.this != ''
run: git fetch origin --tags
- name: Run git diff on go.mod file(s)
if: steps.prev_version.outputs.this != ''
run: |
# First get the diff for the go.mod file in the root directory...
output=$(git diff ${{ env.COMPARETO }}..HEAD -- './go.mod')
output="$(git diff ${{ steps.prev_version.outputs.this }}..HEAD -- './go.mod')"

# ... then get the diff for all go.mod files in subdirectories.
# Note that this command also finds go.mod files more than one level deep in the directory structure.
output+=$(git diff ${{ env.COMPARETO }}..HEAD -- '*/go.mod')
if [[ -z "$output" ]]; then
output="(empty)"
fi
printf "GOMODDIFF<<EOF\n%s\nEOF" "$output" >> $GITHUB_ENV
output+="$(git diff ${{ steps.prev_version.outputs.this }}..HEAD -- '*/go.mod')"

echo "COMMENT<<EOF
$COMMENT

Changes in \`go.mod\` file(s):
\`\`\`diff
$output
\`\`\`
EOF" >> $GITHUB_ENV
- name: Run gorelease
if: env.TAG_EXISTS == 'false' && env.COMPARETO != ''
if: steps.prev_version.outputs.this != ''
# see https://github.com/golang/exp/commits/master/cmd/gorelease
run: |
go install golang.org/x/exp/cmd/gorelease@b4e88ed8e8aab63a9aa9a52276782ebbc547adef
output=$((gorelease -base ${{ env.COMPARETO }}) 2>&1 || true)
printf "GORELEASE<<EOF\n%s\nEOF" "$output" >> $GITHUB_ENV
- name: Check Compatibility
if: env.TAG_EXISTS == 'false' && env.COMPARETO != ''

output="$((gorelease -base ${{ steps.prev_version.outputs.this }}) 2>&1 || true)"

echo "COMMENT<<EOF
$COMMENT

\`gorelease\` says:
\`\`\`diff
$output
\`\`\`
EOF" >> $GITHUB_ENV
- name: Check compatibility
if: steps.prev_version.outputs.this != ''
run: |
go install github.com/smola/gocompat/cmd/gocompat@8498b97a44792a3a6063c47014726baa63e2e669 # v0.3.0
output=$(gocompat compare --go1compat --git-refs="${{ env.COMPARETO }}..HEAD" ./... || true)
if [[ -z "$output" ]]; then
output="(empty)"
fi
printf "GOCOMPAT<<EOF\n%s\nEOF" "$output" >> $GITHUB_ENV
- run: |
echo "RELEASE_BRANCH_NOTE<<EOF
---

output="$(gocompat compare --go1compat --git-refs='${{ steps.prev_version.outputs.this }}..HEAD' ./... || true)"

echo "COMMENT<<EOF
$COMMENT

\`gocompat\` says:
\`\`\`diff
$output
\`\`\`
EOF" >> $GITHUB_ENV
- name: Add a note for PRs targeting release branches
if: github.base_ref != github.event.repository.default_branch
run: |
echo "COMMENT<<EOF
$COMMENT

## Cutting a Release (when not on \`${{ github.event.repository.default_branch }}\`)

This PR is targeting \`${{ github.base_ref }}\`, which is not the default branch.
If you wish to cut a release once this PR is merged, please add the \`release\` label to this PR.
EOF" >> $GITHUB_ENV
if: github.base_ref != github.event.repository.default_branch
- run: |
echo 'MESSAGE<<EOF
Suggested version: `${{ env.VERSION }}`
Comparing to: [`${{ env.COMPARETO }}`](${{ github.event.pull_request.base.repo.html_url }}/releases/tag/${{ env.COMPARETO }}) ([diff](${{ github.event.pull_request.base.repo.html_url }}/compare/${{ env.COMPARETO }}..${{ github.event.pull_request.head.label }}))

Changes in `go.mod` file(s):
```diff
${{ env.GOMODDIFF }}
```

`gorelease` says:
```
${{ env.GORELEASE }}
```

`gocompat` says:
```
${{ env.GOCOMPAT }}
```
${{ env.RELEASE_BRANCH_NOTE }}
EOF' >> $GITHUB_ENV
if: env.TAG_EXISTS == 'false' && env.COMPARETO != ''
- name: Post message on PR
uses: marocchino/sticky-pull-request-comment@82e7a0d3c51217201b3fedc4ddde6632e969a477 # v2.1.1
if: env.TAG_EXISTS == 'false' && env.COMPARETO != '' && github.event.pull_request.head.repo.full_name == github.repository
with:
header: release-check
recreate: true
message: ${{ env.MESSAGE }}
- name: Set a notice message on run
run: |
message="${MESSAGE//'%'/'%25'}"
message="${message//$'\n'/'%0A'}"
message="${message//$'\r'/'%0D'}"
echo "::notice ::$message"
if: env.TAG_EXISTS == 'false' && env.COMPARETO != '' && github.event.pull_request.head.repo.full_name != github.repository
message: ${{ env.COMMENT }}
64 changes: 33 additions & 31 deletions .github/workflows/releaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,40 @@ jobs:
releaser:
runs-on: ubuntu-latest
env:
VERSION: ""
CREATETAG: "false"
DEFAULT_BRANCH: ""
GITHUB_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v3
- name: Determine version
run: echo "VERSION=$(jq -r .version version.json)" >> $GITHUB_ENV
- name: Determine branch
run: echo "DEFAULT_BRANCH=refs/heads/${{ github.event.repository.default_branch }}" >> $GITHUB_ENV
- name: Create a release, if we're on the default branch
run: echo "CREATETAG=true" >> $GITHUB_ENV
if: env.DEFAULT_BRANCH == github.ref
- name: Determine if this commit is a merged PR (if we're not on a default branch)
if: env.DEFAULT_BRANCH != github.ref
id: getmergedpr
uses: actions-ecosystem/action-get-merged-pull-request@59afe90821bb0b555082ce8ff1e36b03f91553d9
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Check if the "release" label was set on the PR
if: steps.getmergedpr.outputs.number != '' && env.DEFAULT_BRANCH != github.ref
- id: version
name: Retrieve new version from version.json
run: |
while IFS= read -r label; do
if [[ "$label" == "release" ]]; then
echo "CREATETAG=true" >> $GITHUB_ENV
break
fi
done <<< "${{ steps.getmergedpr.outputs.labels }}"
- name: Create release
if: env.CREATETAG == 'true'
# https://docs.github.com/en/rest/reference/repos#get-repository-content
version="$(gh api -X GET '/repos/${{ github.repository }}/contents/version.json' -f ref='${{ github.ref }}' --jq '.content' | base64 -d | jq -r '.version // ""')"
status=$? && ([[ $status == 0 ]] || exit $status)

echo "version=$version"
echo "::set-output name=this::$version"
- id: label_exists
name: Check if the related PR is merged and has release label
if: github.ref_name != github.event.repository.default_branch
run: |
# https://docs.github.com/en/rest/reference/search#search-issues-and-pull-requests
label_exists="$(gh api -X GET '/search/issues' -f 'q=repository:${{ github.repository }} is:pr is:merged ${{ github.sha }}' -F 'per_page=1' --jq '.items[0].labels // [] | map(select(.name == "release")) | map("true") | .[0] // "false"')"
status=$? && ([[ $status == 0 ]] || exit $status)

echo "label_exists=$label_exists"
echo "::set-output name=this::$label_exists"
- if: github.ref_name == github.event.repository.default_branch || steps.label_exists.outputs.this == 'true'
name: Publish GitHub Release and/or lightweight git tag
run: |
git fetch origin --tags
if ! $(git rev-list ${{ env.VERSION}}.. &> /dev/null); then
git tag ${{ env.VERSION }}
git push --tags
# using GraphQL because https://docs.github.com/en/rest/reference/releases#list-releases does not return draft releases
# https://docs.github.com/en/graphql/reference/objects#release
release="$(gh api graphql -f query='query { repository(owner: "${{ github.event.repository.owner.name }}", name: "${{ github.event.repository.name }}") { release(tagName: "${{ steps.version.outputs.this }}") { databaseId } } }' --jq '.data.repository.release.databaseId // ""')"
status=$? && ([[ $status == 0 ]] || exit $status)

echo "release=$release"
if [[ -z "$release" ]]; then
# https://docs.github.com/en/rest/reference/git#create-a-reference
gh api '/repos/${{ github.repository }}/git/refs' -f 'ref=refs/tags/${{ steps.version.outputs.this }}' -f 'sha=${{ github.sha }}'
else
# https://docs.github.com/en/rest/reference/releases#update-a-release
gh api -X PATCH "/repos/${{ github.repository }}/releases/$release" -f 'target_commitish=${{ github.sha }}' -F 'draft=false'
fi
10 changes: 8 additions & 2 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ Every Go repository contains a `version.json` file in the root directory:
This version file defines the currently released version.

When cutting a new release, open a Pull Request that bumps the version number and have it review by your team mates.
The [release check workflow](.github/workflows/release-check.yml) will comment on the PR and post useful information (the output of `gorelease`, `gocompat` and a diff of the `go.mod` files(s)).
The [release check workflow](.github/workflows/release-check.yml) will comment on the PR and post useful information (the output of `gorelease`, `gocompat` and a diff of the `go.mod` files(s)). It will also post a link to a draft GitHub Release.

As soon as the PR is merged into the default branch, the [releaser workflow](.github/workflows/releaser.yml) is run. This workflow cuts a new release on CI and pushes the tag.
As soon as the PR is merged into the default branch, the [releaser workflow](.github/workflows/releaser.yml) is run. This workflow cuts a new release on CI, publishes the GitHub Release and the tag.

### Modifying GitHub Release

All modification you make to the draft GitHub Release created by the release check workflow will be preserved. You can change its' name and body to describe the release in more detail.

If you do not wish for a GitHub Release to be published after a merge, you can delete the draft. If you do so, only a tag will be published after a merge.

### Using a Release Branch

Expand Down
4 changes: 2 additions & 2 deletions templates/.github/workflows/release-check.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Release Checker
on:
pull_request:
paths: [ 'version.json' ]
pull_request_target:
paths-ignore: [ '!version.json' ]

jobs:
release-check:
Expand Down