Skip to content

Commit 8d1fdf4

Browse files
jairmyreeCopilotalzimmermsft
authored
Updating Patch Release Process (#50712)
* Update patch release merge-back automation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Enhance patch release process by removing unused external dependencies and adding tests * Update eng/pipelines/templates/stages/archetype-java-release-patch.yml Co-authored-by: Alan Zimmer <48699787+alzimmermsft@users.noreply.github.com> * Update eng/pipelines/templates/stages/archetype-java-release-patch.yml Co-authored-by: Alan Zimmer <48699787+alzimmermsft@users.noreply.github.com> * Update to the PR based on feedback --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Alan Zimmer <48699787+alzimmermsft@users.noreply.github.com>
1 parent f9c2949 commit 8d1fdf4

18 files changed

Lines changed: 1345 additions & 353 deletions

‎.github/skills/azsdk-java-patch-mergeback/SKILL.md‎

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ compatibility: "Requires a checked-out azure-sdk-for-java repo with git access t
1010

1111
# Patch Release Merge-back
1212

13-
Prepare a PR that merges the version, CHANGELOG, and downstream `pom.xml`
14-
updates produced by a patch release (on a `release/patch/YYYYMMDD` branch) back
15-
into `main`. Patches revert `CHANGELOG.md` and version files to the last stable
16-
release, so a naive merge creates many conflicts. This skill encodes how to
17-
resolve each file type correctly.
13+
Patch releases automatically prepare a PR that brings the released dependency
14+
versions, exact patch CHANGELOG entries, and downstream `pom.xml` updates from a
15+
`release/patch/YYYYMMDD` branch back into `main`. Use this skill to understand,
16+
validate, or recover that merge-back when automation fails.
1817

1918
## Triggers
2019

@@ -36,46 +35,49 @@ If either value is ambiguous, ask the user to confirm before proceeding.
3635

3736
## Critical Rules (read first)
3837

39-
- **Only the last two commits** of `RELEASE_BRANCH` carry the updates to bring
40-
back. Diff against `RELEASE_BRANCH~2` to scope the change set.
38+
- `patch-changelog.md` on the release branch is the authoritative list of
39+
patched artifacts and exact CHANGELOG blocks to bring back.
4140
- **Never edit `pom.xml` by hand.** It is regenerated by
4241
`eng/versioning/update_versions.py` **after** `version_client.txt` is correct.
4342
- **Do not touch `README.md` files.** Run the version script with `--skip-readme`
4443
so READMEs are left unchanged (README updates are handled separately).
45-
- **`version_client.txt`:** update only the `dependency-version` of SDK
46-
libraries that changed on the release branch; **always keep the
47-
`current-version` from `main`.** Never reset beta versions to `beta.1`.
44+
- **`version_client.txt`:** promote the patch version recorded in the manifest
45+
into `dependency-version`; **always keep the `current-version` from `main`.**
46+
If `main` already has a newer dependency version, keep it. Never reset beta
47+
versions to `beta.1`.
4848
- **`CHANGELOG.md`:** keep the `PATCH_DATE` entry from the release branch; every
4949
other line must match `main`. Do not invent or edit any other CHANGELOG
5050
content.
5151
- Base the merge-back branch on **`main`**, not on the release branch.
52+
- Never include `patch-changelog.md`, source resets, README changes, or any
53+
release-branch-only files in the merge-back.
5254

5355
## Workflow
5456

5557
1. **Confirm inputs** — Establish `RELEASE_BRANCH` and `PATCH_DATE` (see table
56-
above). Fetch the branch: `git fetch origin RELEASE_BRANCH`.
57-
2. **Create the working branch from `main`:**
58-
`git checkout main && git pull` then
59-
`git checkout -b copilot/merge-back-release-patch-YYYYMMDD`.
60-
3. **Scope the changes** — List files touched by the last two commits:
61-
`git diff --name-only origin/RELEASE_BRANCH~2 origin/RELEASE_BRANCH`.
62-
Expect three kinds: `eng/versioning/version_client.txt`, many `CHANGELOG.md`,
63-
and many `pom.xml` (+ possibly `README.md`).
64-
4. **Reconcile `version_client.txt`** — Follow
58+
above). Fetch the branch and verify it contains `patch-changelog.md`.
59+
2. **Run the merge-back helper from a clean clone:**
60+
`pwsh eng/scripts/Create-Patch-Mergeback.ps1 -ReleaseBranch RELEASE_REF`.
61+
Prefer the immutable release commit SHA used by the build; a branch name is
62+
supported for manual recovery.
63+
The helper checks out `origin/main`, applies the manifest, regenerates POMs,
64+
and rejects unsupported file changes.
65+
3. **Reconcile `version_client.txt` if recovery is required** — Follow
6566
[references/version-client-resolution.md](references/version-client-resolution.md).
66-
5. **Reconcile each `CHANGELOG.md`** — Follow
67+
4. **Reconcile each `CHANGELOG.md` if recovery is required** — Follow
6768
[references/changelog-resolution.md](references/changelog-resolution.md).
68-
6. **Regenerate `pom.xml`** — From the repo root run the version script with the
69+
5. **Regenerate `pom.xml`** — From the repo root run the version script with the
6970
`--skip-readme` (`--sr`) flag so `README.md` files are left untouched:
7071
```bash
7172
python eng/versioning/update_versions.py --skip-readme
7273
```
7374
Do not stage any manual `pom.xml` edits; only the generated output. Confirm no
7475
`README.md` files appear in the resulting diff.
75-
7. **Review & sanity-check** — Verify no v2 (`*-v2`) or unrelated libraries were
76-
touched, no `current-version` values were altered, and no beta version was
77-
reset to `beta.1`.
78-
8. **Commit and open the PR against `main`** — Title it like
76+
6. **Review & sanity-check** — Verify the diff contains only
77+
`eng/versioning/version_client.txt`, manifest-listed `CHANGELOG.md` files,
78+
and generated `pom.xml` files. Confirm no current versions changed and no
79+
dependency versions were downgraded.
80+
7. **Commit and open the PR against `main`** — Title it like
7981
`<Month> <Year> Patches Merge-back`. Summarize: bumped dependency versions,
8082
inserted `PATCH_DATE` CHANGELOG entries, and auto-generated pom.xml updates
8183
(READMEs intentionally left unchanged via `--skip-readme`).

‎.github/skills/azsdk-java-patch-mergeback/references/changelog-resolution.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ Produce, from top to bottom:
1111
1. **The `## X.Y.Z (Unreleased)` section exactly as it is on `main`** — including
1212
any unreleased entries already present there. Do not add to, edit, or remove
1313
unreleased content.
14-
2. **The patch entry from `RELEASE_BRANCH`**, i.e. the `## X.Y.Z (PATCH_DATE)`
15-
section (e.g. `## 12.33.3 (2026-07-01)`). This is the *only* content taken
16-
from the release branch.
14+
2. **The exact patch entry from `patch-changelog.md`**, i.e. the
15+
`## X.Y.Z (PATCH_DATE)` section (e.g. `## 12.33.3 (2026-07-01)`). This is the
16+
only release-branch content inserted into the target changelog.
1717
3. **The remainder of the file exactly as it is on `main`** (all previously
1818
released entries, unchanged).
1919

‎.github/skills/azsdk-java-patch-mergeback/references/version-client-resolution.md‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,53 @@ for the authoritative explanation. Key points:
1212
- **`current-version`** — the in-development version of the library on `main`.
1313
This must **not** change during a merge-back.
1414

15+
Patch changelog and merge-back scripts parse this file through
16+
`eng/scripts/Convert-VersionClientToJson.ps1`. The generated JSON is temporary
17+
and must not be committed. It is keyed by artifact coordinate:
18+
19+
```json
20+
{
21+
"com.azure:azure-example": {
22+
"dependency": "1.0.0",
23+
"current": "1.1.0-beta.1"
24+
}
25+
}
26+
```
27+
28+
Two-column external and unreleased entries have a `null` `current` value.
29+
`version_client.txt` remains the canonical file and the merge-back writes its
30+
updated dependency versions back to that file.
31+
1532
## Resolution algorithm
1633

1734
Compare the file on `main` against the file on `RELEASE_BRANCH`, line by line
1835
(match by `groupId:artifactId`):
1936

20-
1. If the release branch line has a **different `dependency-version`** than
21-
`main`, take the release branch `dependency-version`.
22-
2. **Always keep the `current-version` from `main`**, regardless of what the
37+
1. Read the released patch version from the artifact's entry in
38+
`patch-changelog.md`. During preparation this is also the release branch's
39+
`current-version`.
40+
2. If that patch version is newer than `main`'s **`dependency-version`**, use
41+
the patch version. If `main` already has an equal or newer dependency
42+
version, keep the value from `main`.
43+
3. **Always keep the `current-version` from `main`**, regardless of what the
2344
release branch shows (patches revert `current-version` to the stable value).
24-
3. Leave every other line exactly as it is on `main`.
45+
4. Leave every other line exactly as it is on `main`.
2546

26-
Resulting line = `groupId:artifactId;<release-branch dependency-version>;<main current-version>`.
47+
Resulting line = `groupId:artifactId;<newer of patch version or main dependency-version>;<main current-version>`.
2748

2849
## Guardrails
2950

3051
- **Do not reset beta versions to `beta.1`.** If a `current-version` on `main`
3152
is e.g. `1.2.0-beta.4`, it stays `1.2.0-beta.4`.
32-
- Only touch SDK library lines whose `dependency-version` actually changed on
33-
the release branch. Do not modify parent/BOM lines or unrelated libraries.
53+
- Only touch SDK library lines listed in `patch-changelog.md`. Do not modify
54+
parent/BOM lines or unrelated libraries.
3455
- Never alter `current-version` values — a changed `current-version` is the most
3556
common merge-back bug and surfaces later as a pom.xml mismatch.
3657

3758
## Example
3859

3960
- `main`: `com.azure:azure-storage-blob;12.33.2;12.34.0-beta.1`
40-
- `RELEASE_BRANCH`: `com.azure:azure-storage-blob;12.33.3;12.33.3`
61+
- `RELEASE_BRANCH`: `com.azure:azure-storage-blob;12.33.2;12.33.3`
4162
- **Result:** `com.azure:azure-storage-blob;12.33.3;12.34.0-beta.1`
4263

4364
Here the dependency-version moves `12.33.2` → `12.33.3` (the patch), while the

‎eng/pipelines/Patch-Release-README.md‎

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Path Release Pipeline
1+
# Patch Release Pipeline
22

33
The patch release pipeline is a pipeline designed to release a patch of updated azure-sdk-for-java Artifacts in preparation for release of the Azure Java SDK BOM (Bill of Materials).
44

55
## Prerequisites
66

7-
The patch release pipeline differs from service directory pipelines in that the Artifacts list should change, every time, prior to this pipeline being run. The list of what Artifacts and external dependencies that needs updated, built, and released, to enable the BOM release, is computed by other Java scripts. The last part of this computation feeds in the computed artifacts list to the [Update-Artifacts-List-For-Patch-Release.ps1][update_for_release_script] script which, in turn, updates the [patch-release.yml][patch_release_yml] file's Artifacts and AdditionalModules lists. The updated patch-release.yml should be checked in along with the version_client.txt, pom, CHANGELOG and README updates when prepping for the patch release.
7+
The patch release pipeline differs from service directory pipelines in that the Artifacts list should change, every time, prior to this pipeline being run. The list of what Artifacts and external dependencies that needs updated, built, and released, to enable the BOM release, is computed by other Java scripts. The last part of this computation feeds in the computed artifacts list to the [Update-Artifacts-List-For-Patch-Release.ps1][update_for_release_script] script which, in turn, updates the [patch-release.yml][patch_release_yml] file's Artifacts and AdditionalModules lists. The prepare pipeline also removes entries from `external_dependencies.txt` that are not referenced by version-update markers in any POM file. The updated patch-release.yml should be checked in along with the version_client.txt, external_dependencies.txt, pom, CHANGELOG, README, and generated `patch-changelog.md` updates when prepping for the patch release.
88

99
### [Update-Artifacts-List-For-Patch-Release.ps1][update_for_release_script]
1010

@@ -26,6 +26,30 @@ This is the yml file that belongs to the [java - patch-release][java_patch_relea
2626

2727
The [java - patch-release][java_patch_release] pipeline is manual only. There is no purpose to running this pipeline other than than to release a patch build. The pipeline will build, analyze, verify and release the set of Artifacts that are in the patch-release.yml.
2828

29+
After package publication succeeds, the pipeline creates a merge-back PR against
30+
`main`. It does not merge the patch release branch. The PR contains only:
31+
32+
- released dependency versions promoted into `eng/versioning/version_client.txt`,
33+
while keeping `main`'s current versions;
34+
- the exact patch entries recorded in `patch-changelog.md`; and
35+
- `pom.xml` updates generated by
36+
`python eng/versioning/update_versions.py --skip-readme`.
37+
38+
If `main` already contains a newer dependency version, the merge-back keeps the
39+
newer value. Source resets, README changes, `patch-changelog.md`, and all other
40+
patch-branch changes are intentionally excluded.
41+
42+
### `patch-changelog.md`
43+
44+
The prepare pipeline generates `patch-changelog.md` at the repository root after
45+
all patch artifacts have been prepared. Each entry records the artifact
46+
coordinate, repository-relative changelog path, released patch version, and the
47+
exact markdown block generated for that release.
48+
49+
The file is committed to the patch release branch so the release pipeline can
50+
consume deterministic changelog content. It is a transient release artifact and
51+
must not be copied or merged into `main`.
52+
2953
### How build works in the patch build pipeline
3054

3155
Normal service directory pipelines are only concerned with the set of Artifacts that live within that service directory. Any interdependencies within that service directory use current versions of each other and any dependencies outside of that service directory use the dependency versions. When a artifacts from a service directory are released, the released version becomes the new dependency version and everything that depends on it gets the updated version. This is why monthly releases have a release order. The From Source runs, which are part of every test matrix, is how we know this process works.
@@ -36,12 +60,15 @@ The patch-release pipeline utilizes the same tools that the From Source runs use
3660

3761
**Release verifications are done in the AnalyzeAndVerify Job.** In the patch-release pipeline, verifications normally done as part of the release task in service directories pipelines are now being done as part of the AnalyzeAndVerify job. This can be done since there's no ambiguity as to whether or not the artifacts are going to be released.
3862

39-
**Testing is not done in the patch-release pipeline.** Unlike service directory pipelines, there are no tests being run. We have a highly customizable test matrix which many service directories have made changes to. Because of this, it's nearly impossible to rectify a test matrix for a set of artifacts that spans the entire repository. There is a mitigation for this; as part of the preparation for patch release versions, poms, CHANGELOG and README files all need to be updated. These updates will cause each individual service directory pipeline to get run as part of the process for the update PR. In between the update PR and kicking off the patch-release pipeline, there should be no outside changes that aren't related to the aforementioned update. The matrix of FromSource and non-FromSource runs should provide enough verification. We already make the same assumptions when we release service directory, update the dependency version and then release a service directory that depends on what was previously released.
63+
**Testing is not done in the patch-release pipeline.** Unlike service directory pipelines, there are no tests being run. We have a highly customizable test matrix which many service directories have made changes to. Because of this, it's nearly impossible to rectify a test matrix for a set of artifacts that spans the entire repository. There is a mitigation for this; as part of the preparation for patch release versions, POM, CHANGELOG, README, and patch changelog manifest files all need to be updated. These updates will cause each individual service directory pipeline to get run as part of the process for the update PR. In between the update PR and kicking off the patch-release pipeline, there should be no outside changes that aren't related to the aforementioned update. The matrix of FromSource and non-FromSource runs should provide enough verification. We already make the same assumptions when we release service directory, update the dependency version and then release a service directory that depends on what was previously released.
4064

4165
## Testing changes/updates to the patch-release pipeline
4266

43-
The easiest way to test the patch release pipeline is to use the example above which sets the Artifacts list to the
44-
list of template libraries. After running, add the following parameter **TestPipeline**: **true**. This will allow the release of the template libraries without any version preparation, just run and release. The parameter will cause the test pipeline version code, which sets template libraries to a new beta version, based upon the buildId, for release and then auto closes the version increment PR.
67+
The merge-back path requires a prepared patch branch containing
68+
`patch-changelog.md`. Run the prepare pipeline with the intended test artifact
69+
set, then run the patch release pipeline from that branch with
70+
**TestPipeline** set to **true**. The test parameter keeps the existing
71+
test-package behavior and automatically closes the generated merge-back PR.
4572

4673
<!-- LINKS -->
4774
[java_patch_release]: https://dev.azure.com/azure-sdk/internal/_build?definitionId=5015&_a=summary

‎eng/pipelines/patch-release-prepare.yml‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extends:
1919
- stage: PreparePatchRelease
2020
displayName: Prepare Patch Release
2121
variables:
22+
- template: /eng/pipelines/templates/variables/globals.yml
2223
- template: /eng/pipelines/templates/variables/image.yml
2324
jobs:
2425
- job: PreparePatchRelease
@@ -68,6 +69,23 @@ extends:
6869
env:
6970
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
7071

72+
- task: UsePythonVersion@0
73+
displayName: 'Use Python $(PythonVersion)'
74+
inputs:
75+
versionSpec: $(PythonVersion)
76+
77+
- task: PythonScript@0
78+
displayName: 'Remove unused external dependencies'
79+
inputs:
80+
scriptPath: eng/versioning/find_unused_dependencies.py
81+
arguments: --remove-unused-external-dependencies
82+
83+
- task: PowerShell@2
84+
displayName: 'Generate patch changelog manifest'
85+
inputs:
86+
pwsh: true
87+
filePath: eng/scripts/New-PatchChangelog.ps1
88+
7189
# Create a PR with the patches prepared
7290
- template: /eng/common/pipelines/templates/steps/create-pull-request.yml
7391
parameters:

‎eng/pipelines/patch-release.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extends:
1111
template: /eng/pipelines/templates/stages/archetype-sdk-client-patch.yml
1212
parameters:
1313
TestPipeline: ${{ parameters.TestPipeline }}
14+
PatchMergeBack: true
1415
artifacts:
1516
- name: azure-sdk-template
1617
groupId: com.azure
@@ -42,4 +43,3 @@ extends:
4243
safeName: azuresdktemplatethree
4344
skipPublishDocMs: true
4445
ServiceDirectory: template-v2
45-

0 commit comments

Comments
 (0)