-
Notifications
You must be signed in to change notification settings - Fork 1
feat: create-release
#25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 34 commits
928bbd3
f621854
0edcbd1
a546802
c4884eb
7673a14
c81996d
155d04a
797486b
ca4defb
c349fd0
8a33082
9d52128
901e3e3
7556e22
af58a91
897a962
443b82f
f408ce2
a7e511d
45890b2
5b69386
5020218
5058987
aae9465
d380320
af8dd51
b5b898a
9f49b22
7a872b0
a6c1d21
4ee526b
a1d8ea0
5eb0a9a
e413b85
c7a3628
f19ddb7
18085a4
646a51e
a44a7a1
f577d46
dcc7879
41570c3
48c0298
afdab38
fb41b25
373c222
50141c4
4233b53
28ebaa4
6d0035c
28499b1
c312664
e08fa8f
a3edfda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,208 @@ | ||||||||||||||||||||||||||
| name: Create Release | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Uses `semantic-release` under the hood, but we did not want to force | ||||||||||||||||||||||||||
| # devs to be pedantic with commit messages, so instead we take GitHub | ||||||||||||||||||||||||||
| # approach and list only merged PRs in the release notes and allow | ||||||||||||||||||||||||||
| # releaser to decide if it’s major, minor or patch release. | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # - Push a commit bumping up a version: | ||||||||||||||||||||||||||
| # - Version in `package.json` and — if it exists — `version.txt` | ||||||||||||||||||||||||||
| # - Release notes in `CHANGELOG.md` | ||||||||||||||||||||||||||
| # - Create git version tag | ||||||||||||||||||||||||||
| # - Create GitHub release | ||||||||||||||||||||||||||
| # - Send slack notification | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # # Authentication | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # This workflow needs higher permissions to be able to push to main | ||||||||||||||||||||||||||
| # branch etc. We obtain it using a GitHub app. App needs to have these | ||||||||||||||||||||||||||
| # permissions: | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # - Contents: Read & Write | ||||||||||||||||||||||||||
| # - Issues: Read & Write | ||||||||||||||||||||||||||
| # - Pull requests: Read & Write | ||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||
| # Install it and and set `CREATE_RELEASE_APP_ID` and | ||||||||||||||||||||||||||
| # `CREATE_RELEASE_APP_PRIVATE_KEY` secrets. Convinent to do so on the | ||||||||||||||||||||||||||
| # organisation level. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||
| workflow_call: | ||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||
| release-type: | ||||||||||||||||||||||||||
| description: 'Type of release (major, minor, patch, or prerelease)' | ||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||
| default: 'patch' | ||||||||||||||||||||||||||
| dry-run: | ||||||||||||||||||||||||||
| description: 'Dry–run' | ||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||
| default: false | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||
| name: 'Create Release' | ||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||
| contents: write | ||||||||||||||||||||||||||
| pull-requests: write | ||||||||||||||||||||||||||
| issues: write | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||
| - name: Verify inputs | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| if ! echo "${{ inputs.release-type }}" | grep -qE '^(major|minor|patch|prerelease)$' | ||||||||||||||||||||||||||
| then | ||||||||||||||||||||||||||
| echo "::error::Invalid release-type: ${{ inputs.release-type }}. Must be one of: major, minor, patch, prerelease." | ||||||||||||||||||||||||||
| exit 64 # EX_USAGE | ||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if [ "${{ inputs.release-type }}" = "prerelease" ] | ||||||||||||||||||||||||||
| then | ||||||||||||||||||||||||||
| echo "::error::Prerelease not supported (yet)." | ||||||||||||||||||||||||||
| exit 64 # EX_USAGE | ||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||
|
marek-saji marked this conversation as resolved.
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Set environment variables | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| ENV_VARS: ${{ secrets.env_vars }} | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| echo "$ENV_VARS" >> "$GITHUB_ENV" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Guard ENV_VARS append to avoid malformed GITHUB_ENV. If the secret is empty or misformatted, it can corrupt the environment for later steps. Add a simple guard. - echo "$ENV_VARS" >> "$GITHUB_ENV"
+ if [ -n "$ENV_VARS" ]; then
+ printf '%s\n' "$ENV_VARS" >> "$GITHUB_ENV"
+ fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| - name: 'GitHub App token: Token' | ||||||||||||||||||||||||||
| id: app-token | ||||||||||||||||||||||||||
| uses: actions/create-github-app-token@v2 | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| app-id: ${{ vars.CREATE_RELEASE_APP_ID }} | ||||||||||||||||||||||||||
| private-key: ${{ secrets.CREATE_RELEASE_APP_PRIVATE_KEY }} | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: 'GitHub App token: App Data' | ||||||||||||||||||||||||||
| id: app-token-data | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| user_id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id) | ||||||||||||||||||||||||||
| echo "user-id=$user_id" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Setup | ||||||||||||||||||||||||||
| id: setup | ||||||||||||||||||||||||||
| uses: verkstedt/actions/setup@feat/create-release | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| token: ${{ steps.app-token.outputs.token }} | ||||||||||||||||||||||||||
| github-npm-registry-personal-access-token: ${{ secrets.GH_NPM_REGISTRY_PERSONAL_ACCESS_TOKEN }} | ||||||||||||||||||||||||||
|
marek-saji marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Download semantic-release config | ||||||||||||||||||||||||||
| id: release-config | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||||||||||||||||||||||||||
| # Unfortunatelly when using reusable workflows, GitHub doesn’t | ||||||||||||||||||||||||||
| # expose paths to these workflows in any way, so we need to | ||||||||||||||||||||||||||
| # hardcode repo and reference and fetch the file manually 🙄 | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| config_repo="verkstedt/actions" | ||||||||||||||||||||||||||
| config_ref="feat/create-release" # TODO DEBUG Change to v1 before merging | ||||||||||||||||||||||||||
| config_path="create-release/semantic-release.config.mjs" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| release_config_mjs="$RUNNER_TEMP/$( basename "$config_path" )" | ||||||||||||||||||||||||||
| echo "path=$release_config_mjs" | tee -a "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| gh api \ | ||||||||||||||||||||||||||
| -H 'Accept: application/vnd.github.raw' \ | ||||||||||||||||||||||||||
| "/repos/${config_repo}/contents/${config_path}?ref=${config_ref}" \ | ||||||||||||||||||||||||||
| > "$release_config_mjs" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Release | ||||||||||||||||||||||||||
| id: release | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| # Note: This script doesn’t access steps.*.outputs and | ||||||||||||||||||||||||||
| # inputs.* directly to make it easier to copy it to separate | ||||||||||||||||||||||||||
| # file for testing | ||||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | ||||||||||||||||||||||||||
| PACKAGE_MANAGER: ${{ steps.setup.outputs.package-manager }} | ||||||||||||||||||||||||||
| RELEASE_TYPE: ${{ inputs.release-type }} | ||||||||||||||||||||||||||
| RELEASE_CONFIG_MJS: ${{ steps.release-config.outputs.path }} | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
|
marek-saji marked this conversation as resolved.
|
||||||||||||||||||||||||||
| echo "::group::Install semantic-release plugins" | ||||||||||||||||||||||||||
| install-plugin-pkgs () { | ||||||||||||||||||||||||||
| # shellcheck disable=SC2046 | ||||||||||||||||||||||||||
| set -- $( | ||||||||||||||||||||||||||
| node --input-type=module --eval " | ||||||||||||||||||||||||||
| const { default: config } = await import(process.argv[1], { assert: { type: 'module' } }); | ||||||||||||||||||||||||||
| process.stdout.write(config.plugins.map(p => p[0]).join('\\n')); | ||||||||||||||||||||||||||
| " "$RELEASE_CONFIG_MJS" | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| case "$PACKAGE_MANAGER" in | ||||||||||||||||||||||||||
| yarn) | ||||||||||||||||||||||||||
| yarn add -D "$@" | ||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||
| npm) | ||||||||||||||||||||||||||
| npm install -D "$@" | ||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||||
| echo "::error::Unsupported package manager: $PACKAGE_MANAGER" | ||||||||||||||||||||||||||
| exit 69 # EX_UNAVAILABLE | ||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| git restore package.json || : | ||||||||||||||||||||||||||
| git restore package-lock.json || : | ||||||||||||||||||||||||||
| git restore yarn.lock || : | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| install-plugin-pkgs | ||||||||||||||||||||||||||
|
marek-saji marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||
| echo "::endgroup::" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| echo "::group::Setup git" | ||||||||||||||||||||||||||
| # Use our GitHub app bot as author of the release commit | ||||||||||||||||||||||||||
| GIT_AUTHOR_NAME='${{ steps.app-token.outputs.app-slug }}[bot]' | ||||||||||||||||||||||||||
| GIT_AUTHOR_EMAIL='${{ steps.app-token-data.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com' | ||||||||||||||||||||||||||
| export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Not really semantically true, because semantic-release is | ||||||||||||||||||||||||||
| # both the author and commiter, but with this we’ll have a | ||||||||||||||||||||||||||
| # nice info in git of who triggered the release | ||||||||||||||||||||||||||
| GIT_COMMITTER_NAME="$GITHUB_ACTOR" | ||||||||||||||||||||||||||
| GIT_COMMITTER_EMAIL="$GITHUB_ACTOR_ID+$GITHUB_ACTOR@users.noreply.github.com" | ||||||||||||||||||||||||||
| export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL | ||||||||||||||||||||||||||
| echo "::endgroup::" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| echo "::group::Run semantic-release" | ||||||||||||||||||||||||||
| if [ "${{ inputs.dry-run }}" = "true" ] | ||||||||||||||||||||||||||
| then | ||||||||||||||||||||||||||
| set -- "$@" --dry-run | ||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||
| export RELEASE_TYPE | ||||||||||||||||||||||||||
| export GITHUB_STEP_SUMMARY | ||||||||||||||||||||||||||
| export GITHUB_OUTPUT # Note: It will add some outputs | ||||||||||||||||||||||||||
| npx --yes semantic-release --extends "$RELEASE_CONFIG_MJS" "$@" | ||||||||||||||||||||||||||
| echo "::endgroup::" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Convert release notes to Slack’s markdown–like markup | ||||||||||||||||||||||||||
| id: slack-release-notes | ||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||
| TEXT: ${{ steps.release.outputs.release-notes }} | ||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||
| if [ -n "$TEXT" ] | ||||||||||||||||||||||||||
| then | ||||||||||||||||||||||||||
| mkdir -p "$RUNNER_TEMP/slackify-markdown" | ||||||||||||||||||||||||||
| cd "$RUNNER_TEMP/slackify-markdown" | ||||||||||||||||||||||||||
| echo '{}' > package.json | ||||||||||||||||||||||||||
| npm install slackify-markdown | ||||||||||||||||||||||||||
| TEXT=$( node -e 'process.stdout.write(require("slackify-markdown")(process.argv[1]))' "$TEXT" ) | ||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| echo 'text<<TEXT_EOL' | ||||||||||||||||||||||||||
| echo "$TEXT" | ||||||||||||||||||||||||||
| echo 'TEXT_EOL' | ||||||||||||||||||||||||||
| } | tee -a "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - name: Notify | ||||||||||||||||||||||||||
| if: inputs.dry-run != true | ||||||||||||||||||||||||||
| uses: verkstedt/actions/notify-status@feat/create-release | ||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||
| status: success | ||||||||||||||||||||||||||
| slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }} | ||||||||||||||||||||||||||
| slack-channel-id: ${{ vars.SLACK_CHANNEL_ID }} | ||||||||||||||||||||||||||
| text: ${{ steps.slack-release-notes.outputs.text }} | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Files used by [`create-release` workflow](../.github/workflows/create-release.yaml). | ||
|
marek-saji marked this conversation as resolved.
|
||
Uh oh!
There was an error while loading. Please reload this page.