Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
928bbd3
create-release-pr
marek-saji Oct 7, 2025
f621854
create-release-pr: Pretty white space in CHANGELOG
marek-saji Jul 28, 2025
0edcbd1
create-release: new vision
marek-saji Oct 7, 2025
a546802
feat(create-release): Use semantic-release
marek-saji Oct 2, 2025
c4884eb
chore: Kebab case for inputs
marek-saji Oct 6, 2025
7673a14
create-release: Remove working-dir input, until it’s needed
marek-saji Oct 7, 2025
c81996d
create-release: dry-run
marek-saji Oct 7, 2025
155d04a
create-release: Triggering GH user in git commit
marek-saji Oct 7, 2025
797486b
create-release: Use ::error::
marek-saji Oct 7, 2025
ca4defb
fix(create-release): Piping release notes to step summary
marek-saji Oct 7, 2025
c349fd0
create-release: Notify about success
marek-saji Oct 7, 2025
8a33082
create-release: No notify on dry-run
marek-saji Oct 7, 2025
9d52128
create-release: Use GitHub app token
marek-saji Oct 7, 2025
901e3e3
Remove TODOs
marek-saji Oct 7, 2025
7556e22
doc(create-release)
marek-saji Oct 7, 2025
af58a91
DEBUG(create-release): Use setup@feat/create-release
marek-saji Oct 7, 2025
897a962
create-release: Note about $s
marek-saji Oct 8, 2025
443b82f
create-release: Skip previous_tag_name, if there’s none
marek-saji Oct 8, 2025
f408ce2
create-release: Custom success PR comment
marek-saji Oct 9, 2025
a7e511d
fixup! create-release: Skip previous_tag_name, if there’s none
marek-saji Oct 9, 2025
45890b2
fixup! create-release: Note about $s
marek-saji Oct 9, 2025
5b69386
fixup! create-release: Custom success PR comment
marek-saji Oct 9, 2025
5020218
create-release: unindent shell commands
marek-saji Oct 9, 2025
5058987
fixup! create-release: Custom success PR comment
marek-saji Oct 9, 2025
aae9465
fixup! create-release: Use GitHub app token
marek-saji Oct 9, 2025
d380320
create-release: Improve setup instructions
marek-saji Oct 13, 2025
af8dd51
create-release: docs
marek-saji Oct 14, 2025
b5b898a
fixup! create-release: Triggering GH user in git commit
marek-saji Oct 23, 2025
9f49b22
create-release: Move config to separate file
marek-saji Oct 23, 2025
7a872b0
Merge remote-tracking branch 'origin/v1' into feat/create-release
marek-saji Oct 23, 2025
a6c1d21
create-release: New version and notes in notification
marek-saji Oct 23, 2025
4ee526b
fixup! create-release: New version and notes in notification
marek-saji Oct 23, 2025
a1d8ea0
fixup! create-release: New version and notes in notification
marek-saji Oct 23, 2025
5eb0a9a
create-release: Quote shell env vars
marek-saji Oct 27, 2025
e413b85
setup: Multi–line descriptions
marek-saji Nov 10, 2025
c7a3628
setup: Expand token–related descriptions
marek-saji Nov 10, 2025
f19ddb7
Typo
marek-saji Nov 13, 2025
18085a4
create-release: inputs, not vars
marek-saji Nov 13, 2025
646a51e
create-release: Drop ENV_VARS
marek-saji Nov 13, 2025
a44a7a1
fixup! create-release: New version and notes in notification
marek-saji Nov 17, 2025
f577d46
feat(notify-status): Include text–only value
marek-saji Nov 17, 2025
dcc7879
feat(create-release): Graceful when slackifying fails
marek-saji Nov 17, 2025
41570c3
fixup! feat(notify-status): Include text–only value
marek-saji Nov 17, 2025
48c0298
fixup! fixup! feat(notify-status): Include text–only value
marek-saji Nov 17, 2025
afdab38
feat(create-release): Update package.json if exists only
marek-saji Nov 18, 2025
fb41b25
fix(create-release): Drop type:module import assertion
marek-saji Nov 18, 2025
373c222
fixup! feat(create-release): Update package.json if exists only
marek-saji Nov 18, 2025
50141c4
feat(create-release): Check other workflows before running
marek-saji Nov 18, 2025
4233b53
Merge remote-tracking branch 'origin/v1' into feat/create-release
marek-saji Nov 18, 2025
28ebaa4
fixup! feat(create-release): Check other workflows before running
marek-saji Nov 18, 2025
6d0035c
fix(create-release): Brute force when installing semantic-release plu…
marek-saji Nov 18, 2025
28499b1
feat(create-release): Split Release step
marek-saji Nov 18, 2025
c312664
Merge remote-tracking branch 'origin/v1' into feat/create-release
marek-saji Nov 25, 2025
e08fa8f
chore(create-release): Switch versions from feat branch to v1
marek-saji Nov 25, 2025
a3edfda
chore: prettier -w .
marek-saji Nov 25, 2025
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
263 changes: 263 additions & 0 deletions .github/workflows/create-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
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

on:
workflow_call:
secrets:
GITHUB_APP_PRIVATE_KEY:
description: >
GitHub App private key.
See `github-app-id` input for more details.
required: true
GH_NPM_REGISTRY_PERSONAL_ACCESS_TOKEN:
description: >
Access token with `read:packages` scope to access GitHub npm registry.
You probably do not need this. See inputs for `setup` action for more details.
required: false
SLACK_BOT_TOKEN:
description: >
Slack bot token.
Required if `slack-channel-id` input is set.
required: false
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
env-vars:
description: >
Environment variables to set
(as multiline string, e.g., `VAR1=value1\nVAR2=value2`)
type: string
default: ''
github-app-id:
description: >
GitHub App ID to use for obtaining a git token capable of pushing to the main branch:
Actions: Read
Contents: Read & Write,
Issues: Read & Write,
Pull requests: Read & Write.
type: string
required: true
slack-channel-id:
description: >
Slack channel ID to send the notification about the release to.
Leave empty to disable.
type: string
required: 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

- name: 'GitHub App token: Token'
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ inputs.github-app-id }}
private-key: ${{ secrets.GITHUB_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: 'Checkout'
uses: actions/checkout@v5
with:
fetch-depth: 1
ref: ${{ github.event.pull_request.head.ref || github.ref }}
token: ${{ steps.app-token.outputs.token }}

- name: Check other workflows
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REQUIRED_WORKFLOWS: |
.github/workflows/ci.yaml
.github/workflows/docker-build-push.yaml
run: |
for workflow_path in $REQUIRED_WORKFLOWS
do
if [ -f "$workflow_path" ]
then
printf "%s: " "$workflow_path"
workflow_id="$(
gh api "repos/${{ github.repository }}/actions/workflows" \
| jq -r \
--arg path "$workflow_path" \
'.workflows[] | select(.path == $path) | .id'
)"

conclusion="$(
gh api "repos/${{ github.repository }}/actions/workflows/$workflow_id/runs" \
| jq -r \
--arg sha "${{ github.sha }}" \
'.workflow_runs[] | select(.head_sha == $sha ) | .conclusion'
)"
printf "%s\n" "$conclusion"

if [ "$conclusion" != "success" ]
then
echo "::error::Required workflow '$workflow_path' has not succeeded for commit ${{ github.sha }}: $conclusion"
exit 65 # EX_DATAERR
fi
fi
done

- 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="v1"
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: 'Install semantic-release plugins'
env:
RELEASE_CONFIG_MJS: '${{ steps.release-config.outputs.path }}'
run: |
# shellcheck disable=SC2046
set -- $(
node --input-type=module --eval "
const { default: config } = await import(process.argv[1]);
process.stdout.write(config.plugins.map(p => p[0]).join('\\n'));
" "$RELEASE_CONFIG_MJS"
)

printf "Installing semantic-release plugins:\n%s\n\n" "$*"

rm -rf package.json package-lock.json yarn.lock

npm init --yes >/dev/null
npm install --save-dev "$@"

git clean -f
git restore .

- name: 'Setup git to commit as GitHub App bot'
run: |
{
# Use our GitHub app bot as author of the release commit
echo GIT_AUTHOR_NAME='${{ steps.app-token.outputs.app-slug }}[bot]'
echo GIT_AUTHOR_EMAIL='${{ steps.app-token-data.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com'

# 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
echo GIT_COMMITTER_NAME="$GITHUB_ACTOR"
echo GIT_COMMITTER_EMAIL="$GITHUB_ACTOR_ID+$GITHUB_ACTOR@users.noreply.github.com"
} | tee -a "$GITHUB_ENV"

- name: Release
id: release
run: |
export GITHUB_TOKEN="${{ steps.app-token.outputs.token }}"
export RELEASE_TYPE="${{ inputs.release-type }}"
export RELEASE_CONFIG_MJS="${{ steps.release-config.outputs.path }}"
export GITHUB_STEP_SUMMARY
export GITHUB_OUTPUT # Note: It will add some outputs

if [ "${{ inputs.dry-run }}" = "true" ]
then
set -- "$@" --dry-run
fi

npx --yes semantic-release --extends "$RELEASE_CONFIG_MJS" "$@"

- name: Convert release notes to Slack’s markdown–like markup
id: slack-release-notes
env:
RAW_TEXT: ${{ steps.release.outputs.release-notes }}
run: |
TEXT="$RAW_TEXT"

if [ -n "$TEXT" ]
then
mkdir -p "$RUNNER_TEMP/slackify-markdown"
cd "$RUNNER_TEMP/slackify-markdown"
echo '{}' > package.json
npm install slackify-markdown@^5.0.0
TEXT=$(
node \
-e '
import { slackifyMarkdown } from "slackify-markdown";
process.stdout.write(slackifyMarkdown(process.argv[1]));
' \
"$TEXT"
)
# shellcheck disable=SC2181
if [ $? -ne 0 ]
then
echo "::error::Failed to convert release notes to Slack format, falling back to using original markdown."
TEXT="$RAW_TEXT"
fi
fi

{
echo 'text<<TEXT_EOL'
echo "$TEXT"
echo 'TEXT_EOL'
} | tee -a "$GITHUB_OUTPUT"

- name: Notify
if: inputs.dry-run != true && inputs.slack-channel-id
uses: verkstedt/actions/notify-status@v1
with:
status: success
slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
slack-channel-id: ${{ inputs.slack-channel-id }}
text: ${{ steps.slack-release-notes.outputs.text }}
4 changes: 2 additions & 2 deletions .github/workflows/deploy-cloudfunction.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
source-dir:
description: 'Directory containing the function source code'
type: string
default: "."
default: '.'
entry-point:
description: 'Name of the function entry point (function name in code)'
required: true
Expand All @@ -26,7 +26,7 @@ on:
memory:
description: 'Amount of memory allocated to the function'
type: string
default: "256Mi"
default: '256Mi'
service-timeout:
description: 'Maximum execution time for the function in seconds'
type: number
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-cloudrun.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ jobs:
${CONTAINER_FLAG} \
--image "$IMAGE" \
${EXTRA_FLAGS}
fi
fi
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ Template:

When a GH commit URL is included in commit message, link the commit from said comment.

### Create Release

Template:
<https://github.com/verkstedt/.github/tree/main/workflow-templates/create-release.yaml>

See [create-release.yaml](./.github/workflows/create-release.yaml) for details.

### Cloud Run Deployment

Deploy images to Google Cloud Run services or jobs.
Expand Down
1 change: 1 addition & 0 deletions create-release/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Files used by [`create-release` workflow](../.github/workflows/create-release.yaml).
Loading