Repository navigation
ci(release): sync only the version into main at promote #1314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // Prints the release-branch commits that main does not have, version bumps aside. | ||
| // Reads `git cherry -v origin/main origin/release/vX.Y.Z` on stdin; prints nothing | ||
| // when main already holds every fix. | ||
| // | ||
| // promote.yml syncs only the version into main: every fix on a release branch is a | ||
| // cherry-pick of a commit already on main, so the bumps are all main lacks. A fix | ||
| // committed straight to the release branch breaks that contract, and this is what | ||
| // names it instead of leaving it behind. A cherry-pick resolved differently from its | ||
| // original also shows up here: `git cherry` matches on the patch, not the subject. | ||
|
|
||
| import { readFileSync } from "node:fs"; | ||
| import { argv } from "node:process"; | ||
|
|
||
| const VERSION_BUMP = /^chore\(release\): bump to /; | ||
|
|
||
| /** | ||
| * @param {string} cherry Output of `git cherry -v <main> <release>`. | ||
| * @returns {string[]} "<sha> <subject>" for each commit missing from main. | ||
| */ | ||
| export function unsyncedFixes(cherry) { | ||
| return cherry | ||
| .split("\n") | ||
| .filter((line) => line.startsWith("+ ")) | ||
| .map((line) => line.slice(2)) | ||
| .filter((commit) => !VERSION_BUMP.test(commit.slice(commit.indexOf(" ") + 1))); | ||
| } | ||
|
|
||
| // Only run when invoked directly, so the test can import the function. | ||
| if (import.meta.filename === argv[1]) { | ||
| for (const commit of unsyncedFixes(readFileSync(0, "utf8"))) console.log(commit); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
| import { unsyncedFixes } from "./release-unsynced-fixes.mjs"; | ||
|
|
||
| // `git cherry -v origin/main origin/release/v2.1.0-sync` at the v2.1.0 promotion: the | ||
| // fixes were cherry-picks already on main ("-"), only the version bumps were not ("+"). | ||
| const V2_1_0 = [ | ||
| "- 421802f3f fix(export): no Full Camera trail at a cut whose chunk start rounds up", | ||
| "+ 216aed223 chore(release): bump to 2.1.0-rc.1 [skip ci]", | ||
| "- 57686f501 fix(preview): restart the playback clock at the requested time on a held frame", | ||
| "+ 36b3814f0 chore(release): bump to 2.1.0-rc.6 [skip ci]", | ||
| "+ 514105057 chore(release): bump to 2.1.0 [skip ci]", | ||
| "", | ||
| ].join("\n"); | ||
|
|
||
| describe("unsyncedFixes", () => { | ||
| it("finds nothing when main has every fix and lacks only the bumps", () => { | ||
| expect(unsyncedFixes(V2_1_0)).toEqual([]); | ||
| }); | ||
|
|
||
| it("names a fix committed to the release branch alone", () => { | ||
| const cherry = `${V2_1_0}+ 0a1b2c3d4 fix(export): patch made on the release branch only\n`; | ||
| expect(unsyncedFixes(cherry)).toEqual([ | ||
| "0a1b2c3d4 fix(export): patch made on the release branch only", | ||
| ]); | ||
| }); | ||
|
|
||
| it("keeps a commit that only mentions a bump further in its subject", () => { | ||
| const cherry = "+ 0a1b2c3d4 fix(ci): do not chore(release): bump to twice\n"; | ||
| expect(unsyncedFixes(cherry)).toEqual([ | ||
| "0a1b2c3d4 fix(ci): do not chore(release): bump to twice", | ||
| ]); | ||
| }); | ||
|
|
||
| it("finds nothing in empty input", () => { | ||
| expect(unsyncedFixes("")).toEqual([]); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // Exits 0 when the first version is at or past the second, 1 when it is behind. | ||
| // promote.yml asks it whether main already has the stable version: syncing on | ||
| // inequality alone would set main back to 2.0.1 if 2.0.1 were promoted after | ||
| // 2.1.0. A prerelease sits below the release of the same core: 2.1.0-rc.1 < 2.1.0. | ||
|
|
||
| import { argv, exit } from "node:process"; | ||
|
|
||
| const VERSION = /^(\d+)\.(\d+)\.(\d+)(-.+)?$/; | ||
|
|
||
| const parse = (version) => { | ||
| const match = VERSION.exec(version); | ||
| if (!match) throw new Error(`invalid version ${JSON.stringify(version)}`); | ||
| return { core: match.slice(1, 4).map(Number), prerelease: Boolean(match[4]) }; | ||
| }; | ||
|
|
||
| /** | ||
| * @param {string} version e.g. main's package.json version. | ||
| * @param {string} target e.g. the stable version just released. | ||
| */ | ||
| export function versionAtLeast(version, target) { | ||
| const a = parse(version); | ||
| const b = parse(target); | ||
| const order = a.core[0] - b.core[0] || a.core[1] - b.core[1] || a.core[2] - b.core[2]; | ||
| return order > 0 || (order === 0 && (!a.prerelease || b.prerelease)); | ||
| } | ||
|
|
||
| // Only run when invoked directly, so the test can import the function. | ||
| if (import.meta.filename === argv[1]) { | ||
| exit(versionAtLeast(argv[2], argv[3]) ? 0 : 1); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
| import { versionAtLeast } from "./version-at-least.mjs"; | ||
|
|
||
| describe("versionAtLeast", () => { | ||
| it("holds for the same version", () => { | ||
| expect(versionAtLeast("2.1.0", "2.1.0")).toBe(true); | ||
| }); | ||
|
|
||
| it("holds when main is past the release, so promote never sets it back", () => { | ||
| expect(versionAtLeast("2.1.0", "2.0.1")).toBe(true); | ||
| expect(versionAtLeast("3.0.0", "2.10.0")).toBe(true); | ||
| }); | ||
|
|
||
| it("fails when main is behind", () => { | ||
| // v2.1.0's promotion found main at 2.0.0. | ||
| expect(versionAtLeast("2.0.0", "2.1.0")).toBe(false); | ||
| expect(versionAtLeast("2.9.0", "2.10.0")).toBe(false); | ||
| }); | ||
|
|
||
| it("puts a prerelease below the release of the same core", () => { | ||
| expect(versionAtLeast("2.1.0-rc.1", "2.1.0")).toBe(false); | ||
| expect(versionAtLeast("2.2.0-rc.1", "2.1.0")).toBe(true); | ||
| }); | ||
|
|
||
| it("refuses what is not a version", () => { | ||
| expect(() => versionAtLeast("v2.1.0", "2.1.0")).toThrow(/invalid version/); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.