Skip to content

Commit ac4edb7

Browse files
committed
chore: prepare release workflow for codegen 3.0
1 parent 6ed13b7 commit ac4edb7

4 files changed

Lines changed: 486 additions & 0 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: Prepare Release 3.0
2+
3+
# Manual pre-release workflow for creating the prepare PR on branch 3.0.0.
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
codegen_version:
8+
description: 'Release version, for example 3.0.80. Leave empty to derive from current SNAPSHOT.'
9+
required: false
10+
type: string
11+
next_codegen_snapshot_version:
12+
description: 'Next development version, for example 3.0.81-SNAPSHOT. Leave empty to increment codegen_version.'
13+
required: false
14+
type: string
15+
release_generators:
16+
description: 'Prepare for releasing swagger-codegen-generators with codegen'
17+
required: true
18+
default: 'false'
19+
type: choice
20+
options:
21+
- 'false'
22+
- 'true'
23+
generators_version:
24+
description: 'Generator release version when release_generators=true, for example 1.0.61'
25+
required: false
26+
type: string
27+
previous_generators_version:
28+
description: 'Optional bootstrap generator version for circular dependency validation'
29+
required: false
30+
type: string
31+
permissions:
32+
contents: write
33+
pull-requests: write
34+
35+
jobs:
36+
prepare:
37+
# Resolves release versions, applies file updates, validates build, then opens PR.
38+
runs-on: ubuntu-latest
39+
env:
40+
CODEGEN_VERSION: ${{ inputs.codegen_version }}
41+
NEXT_CODEGEN_SNAPSHOT_VERSION: ${{ inputs.next_codegen_snapshot_version }}
42+
RELEASE_GENERATORS: ${{ inputs.release_generators }}
43+
GENERATORS_VERSION: ${{ inputs.generators_version }}
44+
PREVIOUS_GENERATORS_VERSION: ${{ inputs.previous_generators_version }}
45+
steps:
46+
- name: Checkout swagger-codegen 3.0.0
47+
uses: actions/checkout@v6
48+
with:
49+
ref: 3.0.0
50+
fetch-depth: 0
51+
52+
- uses: actions/create-github-app-token@v3
53+
id: generate-token
54+
with:
55+
app-id: ${{ secrets.APP_ID }}
56+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
57+
58+
- name: Set up Java and Maven
59+
uses: actions/setup-java@v5
60+
with:
61+
java-version: '17'
62+
distribution: temurin
63+
cache: maven
64+
65+
- name: Add Central Portal snapshot repository
66+
uses: s4u/maven-settings-action@v4.0.0
67+
with:
68+
repositories: '[{"id":"central-portal-snapshots","name":"Sonatype Central Portal snapshots","url":"https://central.sonatype.com/repository/maven-snapshots/","releases":{"enabled":false},"snapshots":{"enabled":true}}]'
69+
servers: '[{"id":"central","username":"${{ secrets.MAVEN_CENTRAL_USERNAME }}","password":"${{ secrets.MAVEN_CENTRAL_PASSWORD }}"}]'
70+
71+
- name: Validate bootstrap generator snapshot
72+
if: inputs.previous_generators_version != ''
73+
run: |
74+
# Optional safeguard for circular dependency bootstrap inputs.
75+
source CI/release/common.sh
76+
require_release_or_snapshot_version "previous_generators_version" "${PREVIOUS_GENERATORS_VERSION}"
77+
if [[ "${PREVIOUS_GENERATORS_VERSION}" =~ SNAPSHOT$ ]]; then
78+
assert_snapshot_metadata_exists "${GENERATORS_ARTIFACT}" "${PREVIOUS_GENERATORS_VERSION}"
79+
elif ! release_artifact_exists "${GENERATORS_ARTIFACT}" "${PREVIOUS_GENERATORS_VERSION}"; then
80+
fail "previous_generators_version ${PREVIOUS_GENERATORS_VERSION} does not exist in Maven Central"
81+
fi
82+
83+
- name: Prepare release file changes
84+
id: prepare-release
85+
# Performs version bump to release and updates docs/poms/openapi.
86+
run: bash CI/release/prepare-codegen-release.sh
87+
88+
- name: Build release candidate
89+
# Build with the resolved generators version to catch dependency issues early.
90+
run: |
91+
mvn -B -U clean install -Pdocker \
92+
-Dswagger-codegen-generators-version="${BUILD_GENERATORS_VERSION}" \
93+
-DJETTY_TEST_HTTP_PORT=8090 \
94+
-DJETTY_TEST_STOP_PORT=8089
95+
96+
- name: Print generator repo follow-up
97+
if: inputs.release_generators == 'true'
98+
run: |
99+
# Generators repo changes are intentionally handled in a separate repository PR.
100+
echo "::notice::Open a separate PR in swagger-api/swagger-codegen-generators master setting version ${GENERATORS_VERSION} and a usable swagger-codegen-version. This repository workflow does not push cross-repository generator changes."
101+
102+
- name: Create prepare release pull request
103+
# Opens PR with all prepare-release changes targeting 3.0.0.
104+
uses: peter-evans/create-pull-request@v8
105+
with:
106+
token: ${{ steps.generate-token.outputs.token }}
107+
commit-message: prepare release ${{ steps.prepare-release.outputs.codegen_version }}
108+
title: prepare release ${{ steps.prepare-release.outputs.codegen_version }}
109+
branch: prepare-release-${{ steps.prepare-release.outputs.codegen_version }}
110+
base: 3.0.0
111+
body: |
112+
Prepare Swagger Codegen ${{ steps.prepare-release.outputs.codegen_version }}.
113+
114+
release_generators: ${{ inputs.release_generators }}
115+
swagger-codegen-generators version: ${{ steps.prepare-release.outputs.generators_version }}
116+
next codegen snapshot: ${{ steps.prepare-release.outputs.next_codegen_snapshot_version }}

CI/release/common.sh

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
RELEASED_MAVEN_BASE="${RELEASED_MAVEN_BASE:-https://repo1.maven.org/maven2}"
6+
SNAPSHOT_MAVEN_BASE="${SNAPSHOT_MAVEN_BASE:-https://central.sonatype.com/repository/maven-snapshots}"
7+
CODEGEN_GROUP_PATH="io/swagger/codegen/v3"
8+
GENERATORS_ARTIFACT="swagger-codegen-generators"
9+
10+
fail() {
11+
echo "::error::$*"
12+
exit 1
13+
}
14+
15+
require_release_version() {
16+
local name="$1"
17+
local version="$2"
18+
19+
[[ -n "${version}" ]] || fail "${name} is required"
20+
[[ ! "${version}" =~ SNAPSHOT$ ]] || fail "${name} must be a release version, got ${version}"
21+
[[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "${name} must match X.Y.Z, got ${version}"
22+
}
23+
24+
require_release_or_snapshot_version() {
25+
local name="$1"
26+
local version="$2"
27+
28+
[[ -n "${version}" ]] || fail "${name} is required"
29+
[[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-SNAPSHOT)?$ ]] || fail "${name} must match X.Y.Z or X.Y.Z-SNAPSHOT, got ${version}"
30+
}
31+
32+
require_snapshot_version() {
33+
local name="$1"
34+
local version="$2"
35+
36+
[[ -n "${version}" ]] || fail "${name} is required"
37+
[[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-SNAPSHOT$ ]] || fail "${name} must match X.Y.Z-SNAPSHOT, got ${version}"
38+
}
39+
40+
release_from_snapshot_version() {
41+
local version="$1"
42+
43+
[[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-SNAPSHOT$ ]] || fail "Cannot derive release version from non-SNAPSHOT version ${version}"
44+
printf '%s\n' "${version%-SNAPSHOT}"
45+
}
46+
47+
next_snapshot_from_release_version() {
48+
local version="$1"
49+
local major minor patch
50+
51+
require_release_version "version" "${version}"
52+
IFS=. read -r major minor patch <<< "${version}"
53+
printf '%s.%s.%s-SNAPSHOT\n' "${major}" "${minor}" "$((patch + 1))"
54+
}
55+
56+
## Thin Maven helpers for reading project-level values from pom.xml.
57+
maven_project_version() {
58+
mvn -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec
59+
}
60+
61+
## Shared curl wrapper for metadata fetch with retries and hard timeouts.
62+
curl_metadata() {
63+
local url="$1"
64+
curl --fail --silent --show-error --location --retry 5 --retry-delay 2 --connect-timeout 20 --max-time 90 "${url}"
65+
}
66+
67+
## Parse <version> entries from Maven metadata.xml.
68+
versions_from_metadata() {
69+
awk -F'[<>]' '/<version>/{print $3}'
70+
}
71+
72+
## Resolve the newest version matching a regex pattern from metadata.
73+
latest_matching_version() {
74+
local metadata_url="$1"
75+
local pattern="$2"
76+
local version
77+
78+
version="$(curl_metadata "${metadata_url}" | versions_from_metadata | grep -E "${pattern}" | sort -V | tail -n 1 || true)"
79+
[[ -n "${version}" ]] || fail "No version matching '${pattern}' found in ${metadata_url}"
80+
printf '%s\n' "${version}"
81+
}
82+
83+
latest_released_generators_version() {
84+
latest_matching_version "${RELEASED_MAVEN_BASE}/${CODEGEN_GROUP_PATH}/${GENERATORS_ARTIFACT}/maven-metadata.xml" '^1\.[0-9]+\.[0-9]+$'
85+
}
86+
87+
latest_snapshot_generators_version() {
88+
latest_matching_version "${SNAPSHOT_MAVEN_BASE}/${CODEGEN_GROUP_PATH}/${GENERATORS_ARTIFACT}/maven-metadata.xml" '^1\.[0-9]+\.[0-9]+-SNAPSHOT$'
89+
}
90+
91+
## Build canonical artifact URLs and probe existence without downloading payloads.
92+
release_artifact_url() {
93+
local artifact="$1"
94+
local version="$2"
95+
96+
printf '%s/%s/%s/%s/%s-%s.pom\n' "${RELEASED_MAVEN_BASE}" "${CODEGEN_GROUP_PATH}" "${artifact}" "${version}" "${artifact}" "${version}"
97+
}
98+
99+
release_artifact_exists() {
100+
local artifact="$1"
101+
local version="$2"
102+
local url
103+
104+
url="$(release_artifact_url "${artifact}" "${version}")"
105+
curl --fail --silent --show-error --head --location --retry 3 --connect-timeout 20 --max-time 60 "${url}" >/dev/null 2>&1
106+
}
107+
108+
## SNAPSHOT coordinates resolve via maven-metadata.xml, not fixed file names.
109+
snapshot_metadata_url() {
110+
local artifact="$1"
111+
local version="$2"
112+
113+
printf '%s/%s/%s/%s/maven-metadata.xml\n' "${SNAPSHOT_MAVEN_BASE}" "${CODEGEN_GROUP_PATH}" "${artifact}" "${version}"
114+
}
115+
116+
assert_snapshot_metadata_exists() {
117+
local artifact="$1"
118+
local version="$2"
119+
local metadata_url
120+
121+
metadata_url="$(snapshot_metadata_url "${artifact}" "${version}")"
122+
if ! curl_metadata "${metadata_url}" >/dev/null; then
123+
fail "Required SNAPSHOT ${CODEGEN_GROUP_PATH}:${artifact}:${version} cannot be resolved from ${metadata_url}. Sonatype snapshots can expire. Recovery: publish that exact snapshot version, then rerun this workflow."
124+
fi
125+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
source "${SCRIPT_DIR}/common.sh"
7+
8+
codegen_version="${CODEGEN_VERSION:-}"
9+
next_codegen_snapshot_version="${NEXT_CODEGEN_SNAPSHOT_VERSION:-}"
10+
release_generators="${RELEASE_GENERATORS:-false}"
11+
generators_version="${GENERATORS_VERSION:-}"
12+
previous_generators_version="${PREVIOUS_GENERATORS_VERSION:-}"
13+
build_generators_version=""
14+
15+
# Prepare flow must start from a SNAPSHOT on branch 3.0.0.
16+
current_version="$(maven_project_version)"
17+
[[ "${current_version}" =~ SNAPSHOT$ ]] || fail "Prepare release must start from a SNAPSHOT codegen version, got ${current_version}"
18+
19+
## Resolve target release + next snapshot versions when not provided explicitly.
20+
if [[ -z "${codegen_version}" ]]; then
21+
codegen_version="$(release_from_snapshot_version "${current_version}")"
22+
fi
23+
require_release_version "CODEGEN_VERSION" "${codegen_version}"
24+
25+
if [[ -z "${next_codegen_snapshot_version}" ]]; then
26+
next_codegen_snapshot_version="$(next_snapshot_from_release_version "${codegen_version}")"
27+
fi
28+
require_snapshot_version "NEXT_CODEGEN_SNAPSHOT_VERSION" "${next_codegen_snapshot_version}"
29+
30+
if [[ "${release_generators}" == "true" ]]; then
31+
# Releasing generators: release version is explicit, build can bootstrap from previous snapshot/release.
32+
require_release_version "GENERATORS_VERSION" "${generators_version}"
33+
if [[ -n "${previous_generators_version}" ]]; then
34+
require_release_or_snapshot_version "PREVIOUS_GENERATORS_VERSION" "${previous_generators_version}"
35+
build_generators_version="${previous_generators_version}"
36+
else
37+
build_generators_version="$(latest_snapshot_generators_version)"
38+
fi
39+
else
40+
# Not releasing generators: pin codegen to an already released generators artifact.
41+
if [[ -z "${generators_version}" ]]; then
42+
generators_version="$(latest_released_generators_version)"
43+
fi
44+
require_release_version "resolved generators version" "${generators_version}"
45+
build_generators_version="${generators_version}"
46+
fi
47+
48+
## Validate the exact generators coordinate used for the candidate build.
49+
if [[ "${build_generators_version}" =~ SNAPSHOT$ ]]; then
50+
assert_snapshot_metadata_exists "${GENERATORS_ARTIFACT}" "${build_generators_version}"
51+
else
52+
release_artifact_exists "${GENERATORS_ARTIFACT}" "${build_generators_version}" || fail "Generator release ${build_generators_version} does not exist in Maven Central"
53+
fi
54+
55+
echo "Preparing codegen ${codegen_version} from ${current_version}"
56+
echo "Using swagger-codegen-generators ${generators_version}"
57+
echo "Building release candidate with swagger-codegen-generators ${build_generators_version}"
58+
59+
## Expose resolved values to later workflow steps and PR metadata.
60+
if [[ -n "${GITHUB_ENV:-}" ]]; then
61+
echo "GENERATORS_VERSION=${generators_version}" >> "${GITHUB_ENV}"
62+
echo "BUILD_GENERATORS_VERSION=${build_generators_version}" >> "${GITHUB_ENV}"
63+
echo "CODEGEN_VERSION=${codegen_version}" >> "${GITHUB_ENV}"
64+
echo "NEXT_CODEGEN_SNAPSHOT_VERSION=${next_codegen_snapshot_version}" >> "${GITHUB_ENV}"
65+
fi
66+
67+
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
68+
echo "generators_version=${generators_version}" >> "${GITHUB_OUTPUT}"
69+
echo "build_generators_version=${build_generators_version}" >> "${GITHUB_OUTPUT}"
70+
echo "codegen_version=${codegen_version}" >> "${GITHUB_OUTPUT}"
71+
echo "next_codegen_snapshot_version=${next_codegen_snapshot_version}" >> "${GITHUB_OUTPUT}"
72+
fi
73+
74+
## Move project from snapshot to release version before file-level content updates.
75+
mvn -B versions:set -DnewVersion="${codegen_version}"
76+
mvn -B versions:commit
77+
78+
# Generate a minimal release-notes draft aligned with current GitHub release style.
79+
mkdir -p docs/release-notes
80+
previous_tag="$(git tag --merged HEAD --list 'v3.*' | sort -V | tail -n 1 || true)"
81+
release_notes_file="docs/release-notes/v${codegen_version}.md"
82+
{
83+
echo "# Swagger Codegen v${codegen_version}"
84+
echo
85+
echo "## What's Changed"
86+
echo
87+
if [[ -n "${previous_tag}" ]]; then
88+
git log --first-parent --pretty=format:'* %s' "${previous_tag}..HEAD"
89+
echo
90+
echo
91+
echo "Full Changelog: ${previous_tag}...v${codegen_version}"
92+
else
93+
git log --first-parent --pretty=format:'* %s' HEAD
94+
echo
95+
echo
96+
echo "Full Changelog: initial...v${codegen_version}"
97+
echo
98+
fi
99+
} > "${release_notes_file}"
100+
101+
update_codegen_release_files_script="CI/release/update-codegen-release-files.py"
102+
[[ -f "${update_codegen_release_files_script}" ]] || fail "Missing ${update_codegen_release_files_script}"
103+
104+
## Keep docs/poms/openapi in sync with the release state.
105+
python3 "${update_codegen_release_files_script}" prepare \
106+
"${codegen_version}" \
107+
"${next_codegen_snapshot_version}" \
108+
"${generators_version}"
109+
110+
echo "Prepared release file updates for ${codegen_version}"

0 commit comments

Comments
 (0)