Skip to content
Open
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
91 changes: 91 additions & 0 deletions .github/actions/release-prep-only/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Release-prep-only changes
description: >-
Detects whether this PR or push contains only release-preparation changes:
the top-level LICENSE.txt file, and/or pure akka-http version bumps in
sample build files (samples/**/build.sbt, samples/**/pom.xml,
samples/**/build.gradle). Sets release_prep_only="true" only when every
changed file matches the whitelist AND, for sample build files, the only
diff is the akka-http version literal. Any other change (a different
dependency, a non-version edit, a README, a sample source file) results
in "false" so the regular CI runs. Requires the repository to be checked
out with sufficient history to diff the base and head shas (typically
fetch-depth: 0).
outputs:
release_prep_only:
description: '"true" if change is limited to LICENSE.txt and/or akka-http version bumps in sample build files'
value: ${{ steps.filter.outputs.release_prep_only }}
runs:
using: composite
steps:
- name: Detect release-prep-only changes
id: filter
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
set -euo pipefail
if [ -z "${BASE_SHA:-}" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
echo "No usable base sha; assuming non release-prep-only"
echo "release_prep_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi

changed=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
echo "Changed files between $BASE_SHA and $HEAD_SHA:"
echo "$changed"

if [ -z "$changed" ]; then
echo "No changed files; treating as non release-prep"
echo "release_prep_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi

# For each sample build file, normalize the akka-http version pattern out
# and compare base vs head. If the normalized contents differ, the change
# is not a pure version bump and full CI should run.
result=true
while IFS= read -r f; do
[ -z "$f" ] && continue

if [ "$f" = "LICENSE.txt" ]; then
continue
fi

if [[ "$f" =~ ^samples/.+/build\.sbt$ ]]; then
# Sample build.sbt uses the override-aware
# 'lazy val akkaHttpVersion = sys.props.getOrElse("akka-http.version", "...")'
sed_args=(
-e 's/^lazy val akkaHttpVersion = sys\.props\.getOrElse\("akka-http\.version", "[^"]*"\)$/lazy val akkaHttpVersion = sys.props.getOrElse("akka-http.version", "X")/'
)
elif [[ "$f" =~ ^samples/.+/pom\.xml$ ]]; then
sed_args=(-e 's|^([[:space:]]*)<akka-http\.version>[^<]*</akka-http\.version>$|\1<akka-http.version>X</akka-http.version>|')
elif [[ "$f" =~ ^samples/.+/build\.gradle$ ]]; then
sed_args=(-e "s|('com\\.typesafe\\.akka:[^:']+:)[^']*'|\\1X'|g")
else
echo "Non-release-prep file changed: $f"
result=false
break
fi

if ! base=$(git show "$BASE_SHA:$f" 2>/dev/null); then
echo "$f did not exist at base; treating as non release-prep"
result=false
break
fi
if ! head=$(git show "$HEAD_SHA:$f" 2>/dev/null); then
echo "$f deleted at head; treating as non release-prep"
result=false
break
fi

base_norm=$(echo "$base" | sed -E "${sed_args[@]}")
head_norm=$(echo "$head" | sed -E "${sed_args[@]}")
if [ "$base_norm" != "$head_norm" ]; then
echo "Change in $f is not limited to akka-http version bump"
result=false
break
fi
done <<< "$changed"

echo "release_prep_only=$result" >> "$GITHUB_OUTPUT"
16 changes: 16 additions & 0 deletions .github/workflows/check-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@ permissions:
contents: read

jobs:
changes:
name: Detect changes
runs-on: Akka-Default
outputs:
release_prep_only: ${{ steps.filter.outputs.release_prep_only }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect release-prep-only changes
id: filter
uses: ./.github/actions/release-prep-only

check-samples:
name: Check Sample Projects
needs: changes
if: needs.changes.outputs.release_prep_only != 'true'
runs-on: Akka-Default
steps:
- name: Checkout Global Scripts
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/publish-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,27 @@ permissions:
contents: read

jobs:
changes:
name: Detect changes
runs-on: Akka-Default
outputs:
release_prep_only: ${{ steps.filter.outputs.release_prep_only }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect release-prep-only changes
id: filter
uses: ./.github/actions/release-prep-only

documentation:
name: Documentation
needs: changes
runs-on: Akka-Default
if: github.repository == 'akka/akka-http'
if: |
github.repository == 'akka/akka-http' &&
needs.changes.outputs.release_prep_only != 'true'
steps:
- name: Checkout Global Scripts
uses: actions/checkout@v6
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,27 @@ permissions:
contents: read

jobs:
changes:
name: Detect changes
runs-on: Akka-Default
outputs:
release_prep_only: ${{ steps.filter.outputs.release_prep_only }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect release-prep-only changes
id: filter
uses: ./.github/actions/release-prep-only

publish-artifacts:
name: Publish artifacts
needs: changes
runs-on: Akka-Default
if: github.event.repository.fork == false
if: |
github.event.repository.fork == false &&
needs.changes.outputs.release_prep_only != 'true'
steps:
- name: Checkout Global Scripts
uses: actions/checkout@v6
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/validate-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@ concurrency:
cancel-in-progress: true

jobs:
changes:
name: Detect changes
runs-on: Akka-Default
outputs:
release_prep_only: ${{ steps.filter.outputs.release_prep_only }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect release-prep-only changes
id: filter
uses: ./.github/actions/release-prep-only

formatting-check:
name: Checks
needs: changes
if: needs.changes.outputs.release_prep_only != 'true'
runs-on: Akka-Default
steps:
- name: Checkout Global Scripts
Expand Down Expand Up @@ -59,6 +75,8 @@ jobs:

compile-and-test:
name: Compile and test
needs: changes
if: needs.changes.outputs.release_prep_only != 'true'
runs-on: Akka-Default
strategy:
fail-fast: false
Expand Down
10 changes: 6 additions & 4 deletions docs/release-train-issue-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ Key links:

### Cutting the release

- [ ] Check that open PRs and issues assigned to the milestone are reasonable
- [ ] Check that [open PRs](https://github.com/akka/akka-http/pulls) and [issues assigned to the milestone](https://github.com/akka/akka-http/issues?q=milestone%3A%22$VERSION$%22) are reasonable
- [ ] If PRs were merged after EU midnight, trigger the [native-image tests](https://github.com/akka/akka-http/actions/workflows/native-image-tests.yml) and see that they are gr
- [ ] Update the Change date in the LICENSE file.
- [ ] Update the Akka HTTP version in the samples to $VERSION$, otherwise the published zip files of the samples will have the old version.
- [ ] Run the release-prep script to update LICENSE.txt (version, copyright year, change date + 3y) and bump the akka-http version in every sample build file. With `--commit-and-pr` it pushes a `wip-release-prep-$VERSION$` branch and opens a PR:
```
./scripts/release-prep.sh --commit-and-pr $VERSION$
```
- [ ] For minor or major versions, add a release notes entry in `docs/src/main/paradox/release-notes/`.
- [ ] Create a new milestone for the [next version](https://github.com/akka/akka-http/milestones)
- [ ] Close the [$VERSION$ milestone](https://github.com/akka/akka-http/milestones?direction=asc&sort=due_date)
- [ ] Make sure all important PRs have been merged
- [ ] For recent dependency updates or changes on a minor release branch the Fossa validation can be triggered from the GitHub actions "Dependency License Scanning" (Manually choosing the release branch)
- [ ] Update the revision in Fossa in the Akka Group for the Akka umbrella version, e.g. `22.10`. Note that the revisions for the release is udpated by Akka Group > Projects > Edit. For recent dependency updates the Fossa validation can be triggered from the GitHub actions "Dependency License Scanning".
- [ ] Wait until [main build finished](https://github.com/akka/akka-http/actions) after merging the latest PR
- [ ] Update the [draft release](https://github.com/akka/akka-http/releases) with the next tag version `v$VERSION$`, title and release description. Use the `Publish release` button, which will create the tag.
- [ ] Create the [draft release](https://github.com/akka/akka-http/releases/new?tag=v$VERSION$), click `Generate release notes` to get a title and release description. Use the `Publish release` button, which will create the tag.
- [ ] Check that GitHub Actions release build has executed successfully (GitHub Actions will start a [CI build](https://github.com/akka/akka-http/actions) for the new tag and publish artifacts to https://repo.akka.io/TOKEN/secure)

### Check availability
Expand Down
134 changes: 134 additions & 0 deletions scripts/release-prep.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
#
# release-prep.sh [--commit-and-pr] <akka-http-version>
#
# Prepares the repository for a release by:
# - Updating the LICENSE.txt file:
# * "Licensed Work: Akka HTTP X.Y.Z" -> the given akka-http version
# * "(c) YYYY Lightbend Inc." -> the current year
# * "Change Date: YYYY-MM-DD" -> today + 3 years
# - Bumping the akka-http version in every sample build file:
# * samples/**/build.sbt (sys.props.getOrElse("akka-http.version", ...))
# * samples/**/pom.xml (<akka-http.version>...)
# * samples/**/build.gradle ('com.typesafe.akka:<artifact>:<version>')
#
# By default the script only updates the files; review with `git diff` and
# commit yourself. With --commit-and-pr it creates a wip-release-prep-X.Y.Z
# branch off of the currently checked-out branch, applies the changes,
# commits, pushes, and opens a pull request via the gh CLI.

set -euo pipefail

usage() {
echo "Usage: $0 [--commit-and-pr] <akka-http-version>" >&2
echo "Example: $0 10.7.5" >&2
echo " $0 --commit-and-pr 10.7.5" >&2
}

COMMIT_AND_PR=false
POSITIONAL=()
while [ $# -gt 0 ]; do
case "$1" in
--commit-and-pr) COMMIT_AND_PR=true; shift ;;
-h|--help) usage; exit 0 ;;
--) shift; POSITIONAL+=("$@"); break ;;
-*) echo "Unknown flag: $1" >&2; usage; exit 1 ;;
*) POSITIONAL+=("$1"); shift ;;
esac
done
if [ ${#POSITIONAL[@]} -ne 1 ]; then
usage
exit 1
fi

AKKA_HTTP_VERSION="${POSITIONAL[0]}"
COMMIT_MSG="chore: License change date and sample bump for $AKKA_HTTP_VERSION"

# Cross-platform date arithmetic: BSD (macOS) and GNU (Linux) take different flags.
if date -v+0d >/dev/null 2>&1; then
CHANGE_DATE=$(date -v+3y +%Y-%m-%d)
else
CHANGE_DATE=$(date -d '+3 years' +%Y-%m-%d)
fi
CURRENT_YEAR=$(date +%Y)

# Cross-platform in-place sed: BSD requires an explicit backup-extension argument
# (empty = no backup), GNU does not accept the empty argument. Stored as an
# array so it composes with both direct calls and `find -exec`.
if sed --version >/dev/null 2>&1; then
SED_INPLACE=(sed -i)
else
SED_INPLACE=(sed -i '')
fi

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_ROOT"

# When opening a PR we need a clean tree, the gh CLI, and a free branch name.
if [ "$COMMIT_AND_PR" = true ]; then
command -v gh >/dev/null 2>&1 || {
echo "gh CLI not found; install from https://cli.github.com" >&2
exit 1
}
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Working tree is not clean; commit or stash changes first." >&2
exit 1
fi
TARGET_BASE=$(git rev-parse --abbrev-ref HEAD)
if [ "$TARGET_BASE" = "HEAD" ]; then
echo "Detached HEAD; check out the target branch (e.g. main or release-X.Y) first." >&2
exit 1
fi
NEW_BRANCH="wip-release-prep-$AKKA_HTTP_VERSION"
if git rev-parse --verify "$NEW_BRANCH" >/dev/null 2>&1; then
echo "Branch $NEW_BRANCH already exists; aborting." >&2
exit 1
fi
echo "Creating branch $NEW_BRANCH (PR will target $TARGET_BASE)"
git checkout -b "$NEW_BRANCH"
echo
fi

echo "Preparing release of Akka HTTP $AKKA_HTTP_VERSION"
echo " Copyright year: $CURRENT_YEAR"
echo " Change Date: $CHANGE_DATE (today + 3 years)"
echo

echo "Updating LICENSE.txt..."
"${SED_INPLACE[@]}" -E \
-e "s/^(Licensed Work:[[:space:]]+Akka HTTP )[^[:space:]]+/\\1$AKKA_HTTP_VERSION/" \
-e "s/(The Licensed Work is \\(c\\) )[0-9]{4}( Lightbend Inc\\.)/\\1$CURRENT_YEAR\\2/" \
-e "s/^(Change Date:[[:space:]]+)[0-9-]+/\\1$CHANGE_DATE/" \
LICENSE.txt

echo "Bumping samples to $AKKA_HTTP_VERSION..."
# build.sbt: sys.props-aware `lazy val akkaHttpVersion = sys.props.getOrElse("akka-http.version", "...")` form.
find samples -name build.sbt -exec "${SED_INPLACE[@]}" -E \
-e "s/^lazy val akkaHttpVersion = sys\\.props\\.getOrElse\\(\"akka-http\\.version\", \"[^\"]*\"\\)/lazy val akkaHttpVersion = sys.props.getOrElse(\"akka-http.version\", \"$AKKA_HTTP_VERSION\")/" \
{} +

# pom.xml: the <akka-http.version> property.
find samples -name pom.xml -exec "${SED_INPLACE[@]}" -E \
-e "s|<akka-http\\.version>[^<]*</akka-http\\.version>|<akka-http.version>$AKKA_HTTP_VERSION</akka-http.version>|" \
{} +

# build.gradle: every 'com.typesafe.akka:<artifact>:<version>' coordinate.
find samples -name build.gradle -exec "${SED_INPLACE[@]}" -E \
-e "s|('com\\.typesafe\\.akka:[^:']+:)[^']*'|\\1$AKKA_HTTP_VERSION'|g" \
{} +

if [ "$COMMIT_AND_PR" = true ]; then
echo
echo "Committing..."
git add LICENSE.txt samples
git commit -m "$COMMIT_MSG"
echo "Pushing $NEW_BRANCH..."
git push -u origin "$NEW_BRANCH"
echo "Opening pull request..."
gh pr create --base "$TARGET_BASE" --title "$COMMIT_MSG" --body "$COMMIT_MSG"
echo "Done."
else
echo
echo "Done. Review the changes with 'git diff' and commit when ready."
echo "(Re-run with --commit-and-pr to commit, push, and open a PR automatically.)"
fi
Loading