Skip to content
Merged
9 changes: 4 additions & 5 deletions .github/workflows/gptchangelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
- name: Get changed paths (monorepo)
if: (steps.check-tag.outputs.is_stable == 'true' || inputs.stable_releases_only == false) && inputs.filter_paths != ''
id: changed-paths
uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0

Check warning on line 149 in .github/workflows/gptchangelog.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0
with:
filter-paths: ${{ inputs.filter_paths }}
shared-paths: ${{ inputs.shared_paths }}
Expand Down Expand Up @@ -255,7 +255,7 @@
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3
id: app-token
with:
app-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
client-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
private-key: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_PRIVATE_KEY }}

- name: Checkout repository
Expand Down Expand Up @@ -732,8 +732,10 @@
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Send Slack notification for sync PR
uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"blocks": [
Expand Down Expand Up @@ -770,6 +772,3 @@
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
32 changes: 26 additions & 6 deletions .github/workflows/helm-update-chart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:
type: string
required: true
base_branch:
description: 'Target branch for the PR (default: develop)'
description: 'Target branch for the PR. Allowed: main, develop, master, staging (default: main)'
type: string
default: 'main'
scripts_path:
Expand Down Expand Up @@ -93,16 +93,33 @@ on:
description: 'Slack bot user ID for Severino (@severino)'
required: false

permissions:
contents: read

jobs:
update-chart:
name: Update Chart
runs-on: ${{ inputs.runner_type }}
steps:
- name: Validate base_branch
env:
BASE_BRANCH: ${{ inputs.base_branch }}
run: |
case "${BASE_BRANCH}" in
main|develop|master|staging)
echo "✅ base_branch '${BASE_BRANCH}' is allowed"
;;
*)
echo "::error::Invalid base_branch '${BASE_BRANCH}'. Allowed: main, develop, master, staging"
exit 1
;;
esac
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ secrets.APP_ID }}
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Extract payload
Expand Down Expand Up @@ -149,16 +166,19 @@ jobs:
# Save components array to file for processing
jq -c '.components' /tmp/payload.json > /tmp/components.json
# CodeQL: untrusted-checkout — false positive. This is a workflow_call
# triggered by internal dispatch, not a PR event. The ref is a controlled
# branch name (develop/main), not an untrusted PR head.
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ steps.app-token.outputs.token }}
ref: ${{ inputs.base_branch }}
fetch-depth: 0

- name: Switch to base branch
env:
BASE_BRANCH: ${{ inputs.base_branch }}
run: |
git fetch --no-tags origin "${BASE_BRANCH}"
git checkout -B "${BASE_BRANCH}" "origin/${BASE_BRANCH}"
- name: Import GPG key
if: ${{ inputs.gpg_sign_commits }}
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release-notification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@
type: boolean
default: false

permissions:
contents: read

jobs:
notify:
name: Release Notification
Expand All @@ -117,7 +120,7 @@
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- name: Checkout
Expand Down Expand Up @@ -162,7 +165,7 @@

- name: Discord notification
if: ${{ env.DISCORD_WEBHOOK_URL != '' }}
uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@v1.18.0

Check warning on line 168 in .github/workflows/release-notification.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@v1.18.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
release-tag: ${{ steps.release.outputs.tag }}
Expand All @@ -174,7 +177,7 @@

- name: Slack notification
if: ${{ env.SLACK_WEBHOOK_URL != '' && inputs.slack_channel != '' }}
uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@v1.18.0

Check warning on line 180 in .github/workflows/release-notification.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/notify/slack-release@v1.18.0
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: ${{ inputs.slack_channel }}
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
type: string
default: '2'

permissions:
contents: read

jobs:
prepare:
runs-on: ${{ inputs.runner_type }}
Expand Down Expand Up @@ -60,7 +63,7 @@
- name: Get changed paths (monorepo)
if: inputs.filter_paths != ''
id: changed-paths
uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0

Check warning on line 66 in .github/workflows/release.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0
with:
filter-paths: ${{ inputs.filter_paths }}
shared-paths: ${{ inputs.shared_paths }}
Expand Down Expand Up @@ -106,7 +109,7 @@
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
app-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
client-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
private-key: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_PRIVATE_KEY }}

- name: Checkout repository
Expand Down Expand Up @@ -150,7 +153,7 @@
# ----------------- Snapshot tags before release -----------------
- name: Snapshot tags before release
id: pre-tags
uses: LerianStudio/github-actions-shared-workflows/src/config/release-tag-snapshot@v1.22.0

Check warning on line 156 in .github/workflows/release.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/release-tag-snapshot@v1.22.0

- name: Semantic Release
uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 # v6
Expand All @@ -174,7 +177,7 @@
- name: Detect if release was published
if: always() && steps.semantic.outcome == 'failure'
id: detect-release
uses: LerianStudio/github-actions-shared-workflows/src/config/release-tag-check@v1.21.0

Check warning on line 180 in .github/workflows/release.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/release-tag-check@v1.21.0
with:
previous-tag: ${{ steps.pre-tags.outputs.latest-tag }}

Expand All @@ -185,7 +188,7 @@
steps.semantic.outputs.new_release_published == 'true' ||
steps.detect-release.outputs.release-published == 'true'
)
uses: LerianStudio/github-actions-shared-workflows/src/config/backmerge-pr@v1.21.0

Check warning on line 191 in .github/workflows/release.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/backmerge-pr@v1.21.0
with:
github-token: ${{ steps.app-token.outputs.token }}
source-branch: ${{ github.ref_name }}
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/self-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,39 @@ jobs:
runner_type: ubuntu-latest
stable_releases_only: true
secrets: inherit

# Force-update the floating major version tag (e.g. v1) to point at the
# latest stable release. Enables downstream composites to pin to @v1 and
# always resolve to the latest stable v1.x.x release. Stable-only: gated to
# main so beta/rc releases from develop/release-candidate don't move v1.
update-major-tag:
needs: publish-release
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
client-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
private-key: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_PRIVATE_KEY }}

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}

- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7
with:
gpg_private_key: ${{ secrets.LERIAN_CI_CD_USER_GPG_KEY }}
passphrase: ${{ secrets.LERIAN_CI_CD_USER_GPG_KEY_PASSWORD }}
git_committer_name: ${{ secrets.LERIAN_CI_CD_USER_NAME }}
git_committer_email: ${{ secrets.LERIAN_CI_CD_USER_EMAIL }}
git_config_global: true
git_user_signingkey: true
git_tag_gpgsign: true

- name: Update floating major version tag
uses: ./src/config/update-major-tag
2 changes: 1 addition & 1 deletion .github/workflows/typescript-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
- name: Get changed paths (monorepo)
if: inputs.filter_paths != ''
id: changed-paths
uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0

Check warning on line 72 in .github/workflows/typescript-release.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Internal composite must use floating major tag (e.g. @v1) or develop/main for testing: uses: LerianStudio/github-actions-shared-workflows/src/config/changed-paths@v1.18.0
with:
filter-paths: ${{ inputs.filter_paths }}
shared-paths: ${{ inputs.shared_paths }}
Expand Down Expand Up @@ -117,7 +117,7 @@
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
app-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
client-id: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID }}
private-key: ${{ secrets.LERIAN_STUDIO_MIDAZ_PUSH_BOT_PRIVATE_KEY }}

- name: Checkout repository
Expand Down
75 changes: 75 additions & 0 deletions src/config/update-major-tag/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><img src="https://github.com/LerianStudio.png" width="72" alt="Lerian" /></td>
<td><h1>update-major-tag</h1></td>
</tr>
</table>

Force-update the floating major version tag (e.g. `v1`) to point at the latest stable `vX.Y.Z` tag in the repository. Intended to run after a successful stable release so callers can pin composite actions to `@v1` and always resolve to the latest stable release.

### Behavior

1. Fetches all tags from the remote.
2. Finds the greatest stable tag matching `^v[0-9]+\.[0-9]+\.[0-9]+$` (pre-release tags like `-beta.N` / `-rc.N` are ignored).
3. Derives the major prefix (`v1.26.0 → v1`).
4. If the major tag already points at the resolved commit, exits with a notice — idempotent.
5. Otherwise, creates/moves the major tag as an annotated tag and force-pushes it.

### Assumptions

- The caller has already checked out the repository with `fetch-depth: 0` (so all tags are reachable).
- The checkout was authenticated with a token that has permission to push tags (typically via `actions/checkout@... with.token:`).
- For signed tags, the caller has imported a GPG key and enabled `git_tag_gpgsign` (`git tag -a` will auto-sign when `tag.gpgSign=true` is set globally).

## Inputs

_None._ All behavior is derived from the repository's tag list.

## Outputs

| Output | Description |
|---|---|
| `skip` | `true` when no tag update was performed — either no stable tag was found, or the major tag already pointed at the latest stable commit |
| `tag-updated` | `true` when the floating major tag was force-pushed to a new commit |
| `major-tag` | The major tag name that was considered (e.g. `v1`). Empty when no stable tag was found |
| `latest-tag` | The latest stable tag the major tag was aligned with (e.g. `v1.26.0`). Empty when no stable tag was found |

## Usage

```yaml
jobs:
update-major-tag:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/create-github-app-token@<sha> # v3.1.1
id: app-token
with:
client-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

- uses: actions/checkout@<sha> # v6
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}

- uses: crazy-max/ghaction-import-gpg@<sha> # v7
with:
gpg_private_key: ${{ secrets.GPG_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_committer_name: ${{ secrets.CI_USER_NAME }}
git_committer_email: ${{ secrets.CI_USER_EMAIL }}
git_config_global: true
git_user_signingkey: true
git_tag_gpgsign: true

- uses: LerianStudio/github-actions-shared-workflows/src/config/update-major-tag@v1
```

## Required permissions

```yaml
permissions:
contents: write
```
83 changes: 83 additions & 0 deletions src/config/update-major-tag/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Update Major Version Tag
description: Force-update the floating major version tag (e.g. v1) to point at the latest stable semver tag (vX.Y.Z) found in the repository.

outputs:
skip:
description: 'true when no tag update was performed (no stable tag found, or major already points at the latest stable commit)'
value: ${{ steps.update.outputs.skip }}
tag-updated:
description: 'true when the floating major tag was force-pushed to a new commit'
value: ${{ steps.update.outputs.tag-updated }}
major-tag:
description: 'The major tag name that was considered (e.g. v1). Empty when no stable tag was found.'
value: ${{ steps.update.outputs.major-tag }}
latest-tag:
description: 'The latest stable tag the major tag was aligned with (e.g. v1.26.0). Empty when no stable tag was found.'
value: ${{ steps.update.outputs.latest-tag }}

runs:
using: composite
steps:
- id: update
name: Resolve and push major version tag
shell: bash
run: |
set -euo pipefail

git fetch --tags --force --prune

LATEST=$(git tag --list \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V \
| tail -n1 || true)

if [ -z "$LATEST" ]; then
echo "::notice::No stable release tag found — skipping major tag update."
{
echo "skip=true"
echo "tag-updated=false"
echo "major-tag="
echo "latest-tag="
} >> "$GITHUB_OUTPUT"
exit 0
fi

VERSION="${LATEST#v}"
MAJOR="v${VERSION%%.*}"
SHA=$(git rev-list -n1 "refs/tags/$LATEST")

CURRENT_SHA=""
# Ref snapshot taken right after the initial fetch: using this as the
# lease ensures the push aborts if another run advances $MAJOR between
# our fetch and our push (re-reading the remote later would defeat the
# lease, since it would reflect the other run's update).
CURRENT_MAJOR_REF=""
if git rev-parse --verify --quiet "refs/tags/$MAJOR" >/dev/null; then
CURRENT_SHA=$(git rev-list -n1 "refs/tags/$MAJOR")
CURRENT_MAJOR_REF=$(git rev-parse "refs/tags/$MAJOR")
fi

if [ "$CURRENT_SHA" = "$SHA" ]; then
echo "::notice::$MAJOR already points at $LATEST ($SHA) — nothing to do."
{
echo "skip=true"
echo "tag-updated=false"
echo "major-tag=$MAJOR"
echo "latest-tag=$LATEST"
} >> "$GITHUB_OUTPUT"
exit 0
fi

echo "Moving $MAJOR → $LATEST ($SHA)"
git tag -f -a "$MAJOR" "$SHA" -m "Release $MAJOR ($LATEST)"

LEASE_SHA="${CURRENT_MAJOR_REF:-0000000000000000000000000000000000000000}"
git push origin "refs/tags/$MAJOR:refs/tags/$MAJOR" \
--force-with-lease="refs/tags/$MAJOR:$LEASE_SHA"

{
echo "skip=false"
echo "tag-updated=true"
echo "major-tag=$MAJOR"
echo "latest-tag=$LATEST"
} >> "$GITHUB_OUTPUT"
Loading
Loading