Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ jobs:
- name: Test downstream wait
run: bash downstream/wait.test.bash

version-bump:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Test version-bump
run: bash version-bump/version-bump.test.bash

shopware-version-fallback:
runs-on: ubuntu-latest
steps:
Expand Down
102 changes: 102 additions & 0 deletions .github/workflows/version-bump-notify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Reusable workflow: posts a Slack alert when a plugin's composer.json `version` is bumped
# (an early "a release is being prepared" signal). Only a strict increase notifies — no-op
# edits, downgrades and reverts stay silent. Add a caller to the plugin repo, e.g.:
#
# name: Release prep alert
# on:
# pull_request:
# types: [opened, reopened]
Comment thread
alexdumea marked this conversation as resolved.
Outdated
# branches: [main, master, trunk] # your release branch(es)
# paths: ['composer.json']
# push:
# branches: [main, master, trunk]
# paths: ['composer.json']
# jobs:
# notify:
# uses: shopware/github-actions/.github/workflows/version-bump-notify.yml@main
# secrets: inherit # provides SLACK_WEBHOOK_URL
name: Version Bump Notify
on:
workflow_call:
inputs:
path:
description: "Path to the extension root containing composer.json"
required: false
type: string
default: "."
product-name:
description: "Display name used in the Slack message (defaults to the repository name)"
required: false
type: string
default: ""
secrets:
SLACK_WEBHOOK_URL:
description: "Slack incoming webhook URL to post the release-prep alert to"
required: true

permissions:
contents: read

jobs:
run:
name: Notify on version bump
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Resolve refs
id: refs
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "old=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT"
echo "new=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT"
else
echo "old=${{ github.event.before }}" >> "$GITHUB_OUTPUT"
echo "new=${{ github.sha }}" >> "$GITHUB_OUTPUT"
fi
Comment thread
Copilot marked this conversation as resolved.
Outdated
- name: Detect version bump
id: detect
uses: shopware/github-actions/version-bump@main
with:
old-ref: ${{ steps.refs.outputs.old }}
new-ref: ${{ steps.refs.outputs.new }}
path: ${{ inputs.path }}
- name: Notify Slack
if: steps.detect.outputs.bumped == 'true'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
PRODUCT_NAME: ${{ inputs.product-name || github.event.repository.name }}
PREVIOUS_VERSION: ${{ steps.detect.outputs.previous-version }}
CURRENT_VERSION: ${{ steps.detect.outputs.current-version }}
ACTOR: ${{ github.actor }}
LINK_URL: ${{ github.event.pull_request.html_url || github.event.head_commit.url }}
Comment thread
Copilot marked this conversation as resolved.
Outdated
run: |
# Build the payload with jq -n so names/URLs can never break out of the JSON.
payload=$(jq -n \
--arg product "${PRODUCT_NAME}" \
--arg prev "${PREVIOUS_VERSION}" \
--arg cur "${CURRENT_VERSION}" \
--arg actor "${ACTOR}" \
--arg url "${LINK_URL}" \
'
({
type: "section",
text: {
type: "mrkdwn",
text: "*\($product)* is preparing a release\n`composer.json` version bumped *\($prev)* → *\($cur)*"
}
} | if $url != "" then .accessory = {
type: "button",
text: { type: "plain_text", text: "View change" },
url: $url
} else . end) as $section
| {
text: "\($product) is preparing a release: \($prev) → \($cur)",
blocks: [
$section,
{ type: "context", elements: [ { type: "mrkdwn", text: "Triggered by *\($actor)*" } ] }
]
}
')
curl -sS -f -X POST -H 'Content-type: application/json' --data "${payload}" "${SLACK_WEBHOOK_URL}"
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ A collection of reusable GitHub Actions and Workflows for Shopware extensions an
|--------|-------------|------|
| [saas-preview-environment](saas-preview-environment/) | Creates, migrates or archives a SaaS Preview Environment | [README](saas-preview-environment/README.md) |

### Notifications

| Action | Description | Link |
|--------|-------------|------|
| [version-bump](version-bump/) | Detects a `composer.json` version increase between two refs | [README](version-bump/README.md) |

## Usage

All actions follow the standard GitHub Actions format:
Expand Down
44 changes: 44 additions & 0 deletions version-bump/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Version Bump

Detects whether the root `version` field in `composer.json` strictly increased between two git references.

## What it does

1. Reads the `version` field from `composer.json` at `old-ref` and at `new-ref`
2. Reports `bumped: true` only when the version strictly increased (version-aware compare, handles 3- and 4-segment versions)
3. Ignores no-op edits, downgrades/reverts, and cases where the version cannot be read (e.g. a newly created branch)

## Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `old-ref` | The git ref/sha for the previous state (e.g. the PR base sha) | Yes | - |
| `new-ref` | The git ref/sha for the new state (e.g. the PR head sha) | Yes | - |
| `path` | Path to the extension root containing `composer.json` | No | `.` |

## Outputs

| Output | Description |
|--------|-------------|
| `bumped` | `'true'` if the version strictly increased, otherwise `'false'` |
| `previous-version` | The version at `old-ref` (empty if not found) |
| `current-version` | The version at `new-ref` (empty if not found) |

> **Note:** the caller must check out the repository with `fetch-depth: 0` so both refs are available to `git show`.
Comment thread
Copilot marked this conversation as resolved.

## Usage

```yaml
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: shopware/github-actions/version-bump@main
id: detect
with:
old-ref: ${{ github.event.pull_request.base.sha }}
new-ref: ${{ github.event.pull_request.head.sha }}
- if: steps.detect.outputs.bumped == 'true'
run: echo "Version bumped ${{ steps.detect.outputs.previous-version }} -> ${{ steps.detect.outputs.current-version }}"
```

For the ready-made Slack notification, use the [`version-bump-notify`](../.github/workflows/version-bump-notify.yml) reusable workflow instead of wiring this action up yourself.
41 changes: 41 additions & 0 deletions version-bump/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: version-bump
description: "Detects whether the root version field in composer.json strictly increased between two git refs."
author: "shopware AG"
branding:
color: "yellow"
icon: "bell"

inputs:
old-ref:
description: The git ref/sha for the previous state (e.g. the PR base sha)
required: true
new-ref:
description: The git ref/sha for the new state (e.g. the PR head sha)
required: true
path:
description: Path to the extension root containing composer.json
required: false
default: "."

outputs:
bumped:
description: "'true' if the composer.json version strictly increased, otherwise 'false'"
value: ${{ steps.detect.outputs.bumped }}
previous-version:
description: The version at old-ref (empty if not found)
value: ${{ steps.detect.outputs.previous-version }}
current-version:
description: The version at new-ref (empty if not found)
value: ${{ steps.detect.outputs.current-version }}

runs:
using: "composite"
steps:
- name: Detect version bump
id: detect
shell: bash
env:
OLD_REF: "${{ inputs.old-ref }}"
NEW_REF: "${{ inputs.new-ref }}"
EXT_PATH: "${{ inputs.path }}"
run: ${GITHUB_ACTION_PATH}/version-bump.bash
47 changes: 47 additions & 0 deletions version-bump/version-bump.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash

# Detects whether the root `version` field in composer.json strictly increased
# between two git references.
#
# Global environment variables required:
# OLD_REF - git ref/sha for the previous state (e.g. the PR base sha)
# NEW_REF - git ref/sha for the new state (e.g. the PR head sha)
# EXT_PATH - path to the extension root containing composer.json (default: .)

set -euo pipefail

EXT_PATH="${EXT_PATH:-.}"
if [[ "${EXT_PATH}" == "." || -z "${EXT_PATH}" ]]; then
COMPOSER_PATH="composer.json"
else
COMPOSER_PATH="${EXT_PATH%/}/composer.json"
fi

read_version() {
# Prints the composer.json version at a ref, or nothing if the ref/file/field is absent.
git show "${1}:${COMPOSER_PATH}" 2>/dev/null | jq -r '.version // empty' 2>/dev/null || true
}
Comment thread
alexdumea marked this conversation as resolved.

OLD_VERSION=$(read_version "${OLD_REF}")
NEW_VERSION=$(read_version "${NEW_REF}")

bumped=false
if [[ -n "${OLD_VERSION}" && -n "${NEW_VERSION}" && "${OLD_VERSION}" != "${NEW_VERSION}" ]]; then
# Compare on a v-stripped value so a leading "v" never skews the ordering.
old_cmp="${OLD_VERSION#v}"
new_cmp="${NEW_VERSION#v}"
highest=$(printf '%s\n%s\n' "${old_cmp}" "${new_cmp}" | sort -V | tail -n1)
if [[ "${highest}" == "${new_cmp}" ]]; then
bumped=true
fi
fi
Comment thread
alexdumea marked this conversation as resolved.
Outdated

echo "Previous version: '${OLD_VERSION:-<none>}'"
echo "Current version: '${NEW_VERSION:-<none>}'"
echo "Bumped: ${bumped}"

{
echo "bumped=${bumped}"
echo "previous-version=${OLD_VERSION}"
echo "current-version=${NEW_VERSION}"
} >>"${GITHUB_OUTPUT}"
Comment thread
alexdumea marked this conversation as resolved.
Outdated
68 changes: 68 additions & 0 deletions version-bump/version-bump.test.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
TMP_DIR=$(mktemp -d)

trap 'rm -rf "${TMP_DIR}"' EXIT

# Stub `git`: `git show <ref>:<path>` returns the composer.json fixture for that ref
# (STUB_OLD / STUB_NEW). An empty fixture simulates a missing ref/file (git exits non-zero).
cat > "${TMP_DIR}/git" <<'EOF'
#!/usr/bin/env bash
if [[ "${1}" == "show" ]]; then
ref="${2%%:*}"
case "${ref}" in
old) content="${STUB_OLD-}" ;;
new) content="${STUB_NEW-}" ;;
*) content="" ;;
esac
if [[ -z "${content}" ]]; then
exit 128
fi
printf '%s' "${content}"
exit 0
fi
exit 1
EOF
chmod +x "${TMP_DIR}/git"

run_case() {
local name="${1}"
local old_json="${2}"
local new_json="${3}"
local expected_bumped="${4}"
local out
out=$(mktemp)

PATH="${TMP_DIR}:${PATH}" \
STUB_OLD="${old_json}" \
STUB_NEW="${new_json}" \
OLD_REF=old NEW_REF=new EXT_PATH=. \
GITHUB_OUTPUT="${out}" \
bash "${SCRIPT_DIR}/version-bump.bash" >/dev/null 2>&1

local got
got=$(grep '^bumped=' "${out}" | cut -d= -f2)
Comment thread
alexdumea marked this conversation as resolved.
Outdated
if [[ "${got}" != "${expected_bumped}" ]]; then
echo "FAIL ${name}: expected bumped=${expected_bumped}, got '${got}'"
cat "${out}"
rm -f "${out}"
exit 1
fi

echo "ok - ${name} (bumped=${got})"
rm -f "${out}"
}

run_case "minor bump" '{"version":"5.3.0"}' '{"version":"5.4.0"}' true
run_case "patch bump" '{"version":"5.3.0"}' '{"version":"5.3.1"}' true
run_case "no change" '{"version":"5.3.0"}' '{"version":"5.3.0"}' false
run_case "downgrade" '{"version":"5.4.0"}' '{"version":"5.3.0"}' false
run_case "four-segment bump" '{"version":"6.6.10.0"}' '{"version":"6.6.10.1"}' true
run_case "version field removed" '{"version":"5.3.0"}' '{"name":"swag/foo"}' false
run_case "version field added" '{"name":"swag/foo"}' '{"version":"5.3.0"}' false
run_case "missing old ref" '' '{"version":"5.3.0"}' false
run_case "leading v prefix" '{"version":"v1.0.0"}' '{"version":"v1.1.0"}' true

Comment thread
alexdumea marked this conversation as resolved.
echo "All version-bump tests passed."