Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
42 changes: 38 additions & 4 deletions .github/workflows/chart-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ on:
description: Space-separated paths that never count as a chart change (default <charts-dir>/README.md)
type: string
default: ""
helm-docs-version:
description: Version of the jnorwood/helm-docs image to regenerate the charts' README.md with, e.g. v1.14.2 (default none, no regeneration)
type: string
default: ""

jobs:
semver-label:
Expand Down Expand Up @@ -92,17 +96,47 @@ jobs:
EXCLUDE: ${{ inputs.exclude }}
run: ../chart-workflows/scripts/bump-chart-versions.sh

# after the bump, so that the documentation shows the new versions. Only the charts the pull
# request changes: documentation another chart left stale would change that chart without a new
# version, which chart-release.yml refuses.
- name: Regenerate the chart documentation
id: docs
if: inputs.helm-docs-version != '' && steps.bump.outputs.changed != ''
working-directory: pr
env:
HELM_DOCS_VERSION: ${{ inputs.helm-docs-version }}
CHARTS_DIR: ${{ inputs.charts-dir }}
CHANGED: ${{ steps.bump.outputs.changed }}
run: |
for chart in $CHANGED; do
docker run --rm --volume "$PWD:/helm-docs" --user "$(id -u)" "jnorwood/helm-docs:$HELM_DOCS_VERSION" \
--chart-search-root "$CHARTS_DIR/$chart"
done
if git diff --quiet; then
echo "The chart documentation is up to date"
echo "committed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git add --update
bot_name="github-actions[bot]"
bot_email="41898282+github-actions[bot]@users.noreply.github.com"
GIT_AUTHOR_NAME="$bot_name" GIT_AUTHOR_EMAIL="$bot_email" \
GIT_COMMITTER_NAME="$bot_name" GIT_COMMITTER_EMAIL="$bot_email" \
git commit --quiet -m "Update helm documentation"
git show --stat --format='%s' HEAD
echo "committed=true" >> "$GITHUB_OUTPUT"

# the workflow token cannot push to a fork
- name: Versions to set in a pull request from a fork
if: steps.bump.outputs.committed == 'true' && github.event.pull_request.head.repo.full_name != github.repository
if: (steps.bump.outputs.committed == 'true' || steps.docs.outputs.committed == 'true') && github.event.pull_request.head.repo.full_name != github.repository
working-directory: pr
run: |
echo "::error::This pull request comes from a fork, so the chart versions cannot be updated automatically. Set them in the pull request:"
git show --format= HEAD
echo "::error::This pull request comes from a fork, so the chart versions and documentation cannot be updated automatically. Set them in the pull request:"
git diff "origin/$GITHUB_HEAD_REF" HEAD
exit 1

- name: Push the versions
if: steps.bump.outputs.committed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
if: (steps.bump.outputs.committed == 'true' || steps.docs.outputs.committed == 'true') && github.event.pull_request.head.repo.full_name == github.repository
working-directory: pr
env:
HEAD_REF: ${{ github.head_ref }}
Expand Down
113 changes: 113 additions & 0 deletions .github/workflows/semver-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Reusable workflow that works out the version a pull request releases from its semver label (major,
# minor or patch): on a pull request, the pre-release X.Y.Z-PRE-<number>, asking for the label when
# it is missing; on a push to the main branch, X.Y.Z from the label of the merged pull request. See
# README.md for how to call it.
name: Semver version

on:
workflow_call:
inputs:
tag-prefix:
description: Text the release tags start with (default v); empty for tags like 1.2.3
type: string
default: v
outputs:
version:
description: X.Y.Z on a push, X.Y.Z-PRE-<pull request number> on a pull request
value: ${{ jobs.version.outputs.version }}
bump:
description: major, minor or patch, from the label
value: ${{ jobs.version.outputs.bump }}

jobs:
version:
name: Semver version
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
outputs:
version: ${{ steps.version.outputs.version }}
bump: ${{ steps.label.outputs.bump }}
steps:
# all the tags, to find the latest release
- name: Check out the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
path: repo
persist-credentials: false

# the script from the same commit as this workflow, not from the caller's repository
- name: Locate this workflow
env:
WORKFLOW_REPOSITORY: ${{ job.workflow_repository }}
WORKFLOW_SHA: ${{ job.workflow_sha }}
run: |
if [ -z "$WORKFLOW_REPOSITORY" ] || [ -z "$WORKFLOW_SHA" ]; then
echo "::error::job.workflow_repository and job.workflow_sha are empty: this workflow has to run as a reusable workflow on github.com"
exit 1
fi
echo "Using $WORKFLOW_REPOSITORY@$WORKFLOW_SHA"

- name: Check out the version script
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
path: semver-workflows
persist-credentials: false

# on a push, the labels of the pull request the pushed commit was merged from
- name: Read the semver label
id: label
env:
GH_TOKEN: ${{ github.token }}
EVENT: ${{ github.event_name }}
PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }}
SHA: ${{ github.sha }}
run: |
if [ "$EVENT" = pull_request ]; then
labels="$PR_LABELS"
else
pr=$(gh api "repos/$GITHUB_REPOSITORY/commits/$SHA/pulls" \
--jq '[.[] | select(.merged_at != null)][0] // empty | {number, labels: [.labels[].name]}')
if [ -z "$pr" ]; then
echo "::error::No merged pull request contains $SHA, so there is no semver label to release it with"
exit 1
fi
echo "Releasing pull request #$(jq -r .number <<< "$pr")"
labels=$(jq -c .labels <<< "$pr")
fi
bumps=$(jq -r '[.[] | select(. == "major" or . == "minor" or . == "patch")] | join(" ")' <<< "$labels")
if [ "$(wc -w <<< "$bumps")" -ne 1 ]; then
echo "::error::The pull request needs exactly one of the labels major, minor or patch (found: ${bumps:-none})"
exit 1
fi
echo "bump=$bumps" >> "$GITHUB_OUTPUT"

- name: Ask for the label
if: failure() && steps.label.outcome == 'failure' && github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
run: |
gh pr comment "$PR" --repo "$GITHUB_REPOSITORY" \
--body "Please apply exactly one of the following labels to the PR: 'patch', 'minor', 'major'." \
|| echo "::warning::Could not comment on the pull request"

- name: Work out the version
id: version
working-directory: repo
env:
BUMP: ${{ steps.label.outputs.bump }}
TAG_PREFIX: ${{ inputs.tag-prefix }}
EVENT: ${{ github.event_name }}
PR: ${{ github.event.pull_request.number }}
run: |
version=$(../semver-workflows/scripts/next-version.sh)
if [ "$EVENT" = pull_request ]; then
version="$version-PRE-$PR"
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Version: $version"
10 changes: 10 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,13 @@ jobs:
permissions:
contents: write
pull-requests: write

# Exercises semver-version.yml before it is released: the version this pull request would release,
# as a pre-release. Only once semver-label passed, so a missing label is reported once.
semver-version:
if: github.event_name == 'pull_request'
needs: semver-label
uses: ./.github/workflows/semver-version.yml
permissions:
contents: read
pull-requests: write
55 changes: 47 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

Reusable GitHub Actions workflows shared by FIWARE repositories, so that a fix is made in one place.

The repository lives in the SEAMWARE organization until it moves to FIWARE; callers then change the owner in `uses:`.

| Workflow | What it does | Typical trigger |
|---|---|---|
| [`chart-lint.yml`](#chart-lint-chart-lintyml) | Lints the Helm charts and validates what they render | Pull requests |
| [`chart-pr.yml`](#chart-version-chart-pryml) | Requires a semver label and bumps the versions of the changed charts | Pull requests |
| [`chart-release.yml`](#chart-release-chart-releaseyml) | Publishes the charts, failing when a changed chart has no new version | Push to the main branch |
| [`chart-dependencies.yml`](#chart-dependencies-chart-dependenciesyml) | Opens pull requests for newer chart dependencies | Schedule |
| [`semver-version.yml`](#semver-version-semver-versionyml) | Works out the version to release from the semver label of the pull request | Pull requests and push to the main branch |
| [`stale.yml`](#stale-issues-staleyml) | Marks and closes issues and pull requests without activity | Schedule |

Together, the chart workflows cover the life of a chart: a pull request is linted and gets its new version, and merging it publishes that version.
Expand All @@ -21,7 +20,7 @@ Lints every chart under `charts/` (the directories with a `Chart.yaml`) with `he
```yaml
jobs:
chart-lint:
uses: SEAMWARE/github-workflows/.github/workflows/chart-lint.yml@v1
uses: FIWARE/github-workflows/.github/workflows/chart-lint.yml@v1
```

| Input | Default | Description |
Expand Down Expand Up @@ -59,7 +58,7 @@ jobs:

chart-version:
needs: [lint] # whatever has to pass first
uses: SEAMWARE/github-workflows/.github/workflows/chart-pr.yml@v1
uses: FIWARE/github-workflows/.github/workflows/chart-pr.yml@v1
permissions:
contents: write # push the new versions to the pull request branch
pull-requests: write # comment when the label is missing
Expand All @@ -71,6 +70,7 @@ Inputs, both optional:
|---|---|---|
| `charts-dir` | `charts` | Directory that holds one directory per chart |
| `exclude` | `<charts-dir>/README.md` | Space-separated paths that never count as a chart change |
| `helm-docs-version` | (none) | Version of the [`jnorwood/helm-docs`](https://github.com/norwoodj/helm-docs) image, e.g. `v1.14.2`. When set, the `README.md` of every chart the pull request changes is regenerated after the bump and pushed with it. Other charts are left alone: regenerating a stale one would change it without a new version |

Pushes made with the workflow token do not trigger workflows, so the checks of the pull request keep running on the commit before the version bump.

Expand All @@ -80,7 +80,7 @@ Publishes the charts when the main branch changes:

1. **checks the versions first**: a chart that the push changed without changing its version fails the workflow, naming it, before anything is published. Such a change would otherwise never be released, since the version is already published;
2. publishes every chart version that is not released yet as a GitHub release, and updates the Helm repository index on GitHub Pages, with [chart-releaser](https://github.com/helm/chart-releaser-action);
3. optionally, pushes them to an OCI registry, each version once.
3. optionally, pushes them to an OCI registry, each version once, retrying a push that fails.

The repositories the charts' dependencies come from are added from their `Chart.yaml`.

Expand All @@ -91,7 +91,7 @@ on:

jobs:
chart-release:
uses: SEAMWARE/github-workflows/.github/workflows/chart-release.yml@v1
uses: FIWARE/github-workflows/.github/workflows/chart-release.yml@v1
permissions:
contents: write
with:
Expand Down Expand Up @@ -121,7 +121,7 @@ on:

jobs:
chart-dependencies:
uses: SEAMWARE/github-workflows/.github/workflows/chart-dependencies.yml@v1
uses: FIWARE/github-workflows/.github/workflows/chart-dependencies.yml@v1
permissions:
contents: write
pull-requests: write
Expand All @@ -137,6 +137,45 @@ jobs:

The chart version is bumped in the pull request itself because pull requests opened with the workflow token do not run their checks, `chart-pr.yml` included. To have the checks run, pass a GitHub App or personal token as the `token` secret.

## Semver version (`semver-version.yml`)

For repositories that release an application, not charts, with the version driven by the semver label of the pull request. It works out the version and leaves the build and the release to the caller:

- on a pull request, it requires exactly one of the labels `major`, `minor` or `patch`, commenting on the pull request when it is missing, and returns `X.Y.Z-PRE-<pull request number>`;
- on a push to the main branch, it reads the label of the pull request the pushed commit was merged from, and returns `X.Y.Z`. A commit that no merged pull request contains, or one merged without a label, fails.

`X.Y.Z` is the highest release tag bumped by the label. Release tags are `<tag-prefix>X.Y.Z`; other tags, such as pre-releases (`1.2.3-PRE-4`), are ignored.

```yaml
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]

jobs:
generate-version:
uses: FIWARE/github-workflows/.github/workflows/semver-version.yml@v1
permissions:
contents: read
pull-requests: write # comment when the label is missing
with:
tag-prefix: "" # tags like 1.2.3

build-and-push:
needs: generate-version
runs-on: ubuntu-latest
steps:
- run: echo "Building ${{ needs.generate-version.outputs.version }}"
```

| Input | Default | Description |
|---|---|---|
| `tag-prefix` | `v` | Text the release tags start with; empty for tags like `1.2.3` |

| Output | Description |
|---|---|
| `version` | `X.Y.Z` on a push, `X.Y.Z-PRE-<pull request number>` on a pull request |
| `bump` | `major`, `minor` or `patch`, from the label |

## Stale issues (`stale.yml`)

Marks issues and pull requests without activity as stale, and closes them when they stay so, with [actions/stale](https://github.com/actions/stale).
Expand All @@ -149,7 +188,7 @@ on:

jobs:
stale:
uses: SEAMWARE/github-workflows/.github/workflows/stale.yml@v1
uses: FIWARE/github-workflows/.github/workflows/stale.yml@v1
permissions:
issues: write
pull-requests: write
Expand Down
8 changes: 6 additions & 2 deletions scripts/bump-chart-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
# CHARTS_DIR directory that holds one directory per chart (default: charts)
# EXCLUDE space-separated paths that never count as a chart change
# (default: $CHARTS_DIR/README.md)
# GITHUB_OUTPUT when set, receives committed=true|false and the bumped charts
# GITHUB_OUTPUT when set, receives committed=true|false, the bumped charts and the changed
# charts (changed=, also the ones whose version was already right)
#
# Requires git and yq (mikefarah, v4).

Expand Down Expand Up @@ -53,8 +54,11 @@ while IFS= read -r file; do
esac
done < <(git diff --name-only "$base...HEAD")

changed=$(printf '%s\n' "${!charts[@]}" | sort | xargs)
output "changed=$changed"

bumped=()
for chart in $(printf '%s\n' "${!charts[@]}" | sort); do
for chart in $changed; do
chart_file="$CHARTS_DIR/$chart/Chart.yaml"
if [ ! -f "$chart_file" ]; then
echo "$chart has no Chart.yaml on the branch, skipping"
Expand Down
18 changes: 13 additions & 5 deletions scripts/next-version.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
#!/usr/bin/env bash
# Prints the next release version (X.Y.Z, without the v) of the repository in the current
# directory: its highest vX.Y.Z tag bumped by BUMP, or 0.0.0 bumped when there is none. Tags that
# are not plain vX.Y.Z, such as the moving major tags (v1) or pre-releases, are ignored.
# Prints the next release version (X.Y.Z, without the prefix) of the repository in the current
# directory: its highest <prefix>X.Y.Z tag bumped by BUMP, or 0.0.0 bumped when there is none. Tags
# that are not plain <prefix>X.Y.Z, such as the moving major tags (v1) or pre-releases, are ignored.
#
# Environment:
# BUMP major, minor or patch (required)
# BUMP major, minor or patch (required)
# TAG_PREFIX text the release tags start with (default: v); empty for tags like 1.2.3

set -euo pipefail

: "${BUMP:?BUMP must be major, minor or patch}"

latest=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' | sort -t. -k1,1n -k2,2n -k3,3n | tail -n 1 || true)
TAG_PREFIX="${TAG_PREFIX-v}"

latest=$(git tag --list "$TAG_PREFIX*" | while IFS= read -r tag; do
version="${tag#"$TAG_PREFIX"}"
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "$version"
fi
done | sort -t. -k1,1n -k2,2n -k3,3n | tail -n 1 || true)
IFS=. read -r major minor patch <<< "${latest:-0.0.0}"

case "$BUMP" in
Expand Down
Loading
Loading