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
6 changes: 5 additions & 1 deletion .github/tools/tag-selector/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ inputs:
description: "Number of latest stable patches to return"
required: false
default: "2"
rc_count:
description: "Number of latest RC versions to return"
required: false
default: "2"
rc_identifier:
description: "RC prerelease identifier"
required: false
default: "rc"
outputs:
matrix_json:
description: "Output matrix"
description: "Output matrix"
50 changes: 8 additions & 42 deletions .github/tools/tag-selector/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25431,12 +25431,10 @@ function stripPrefix(tag, prefix) {
return tag;
return tag.startsWith(prefix) ? tag.slice(prefix.length) : tag;
}
function versionKey(major, minor) {
return `${major}.${minor}`;
}
function computeFromTags(input) {
const tagPrefix = input.tagPrefix ?? "";
const stableCount = input.stableCount ?? 2;
const rcCount = input.rcCount ?? 1;
const rcIdent = input.rcIdent ?? "rc";
const versions = [];
for (const t of input.tags) {
Expand All @@ -25461,47 +25459,13 @@ function computeFromTags(input) {
stableMinor = `${sMajor}.${sMinor}`;
stablePatches = stableSorted.filter((v) => import_semver.default.major(v) === sMajor && import_semver.default.minor(v) === sMinor).slice(0, stableCount);
}
const minorMap = /* @__PURE__ */ new Map();
for (const v of stable) {
const key = versionKey(import_semver.default.major(v), import_semver.default.minor(v));
const entry = minorMap.get(key) || {
hasStable: false,
rcVersions: [],
major: import_semver.default.major(v),
minor: import_semver.default.minor(v)
};
entry.hasStable = true;
minorMap.set(key, entry);
}
for (const v of prerelease) {
const rcVersions = prerelease.filter((v) => {
const pr = import_semver.default.prerelease(v) || [];
if (pr[0] === rcIdent) {
const key = versionKey(import_semver.default.major(v), import_semver.default.minor(v));
const entry = minorMap.get(key) || {
hasStable: false,
rcVersions: [],
major: import_semver.default.major(v),
minor: import_semver.default.minor(v)
};
entry.rcVersions.push(v);
minorMap.set(key, entry);
}
}
let rcMinor = "";
let latestRc = "";
const candidates = Array.from(minorMap.values()).filter(
(m) => !m.hasStable && m.rcVersions.length > 0
);
if (candidates.length > 0) {
candidates.sort(
(a, b) => a.major === b.major ? b.minor - a.minor : b.major - a.major
);
const newest = candidates[0];
rcMinor = `${newest.major}.${newest.minor}`;
latestRc = newest.rcVersions.sort(import_semver.default.rcompare)[0];
}
return pr[0] === rcIdent;
});
const latestRcs = rcCount > 0 ? [...rcVersions].sort(import_semver.default.rcompare).slice(0, rcCount) : [];
const matrix = [
...latestRc ? [{ version: latestRc, channel: "rc" }] : [],
...latestRcs.map((v) => ({ version: v, channel: "rc" })),
...stablePatches.map((v) => ({ version: v, channel: "stable" }))
];
return {
Expand All @@ -25515,6 +25479,7 @@ async function run() {
const token = getInput("github_token", { required: true });
const tagPrefix = getInput("tag_prefix") || "";
const stableCount = parseInt(getInput("stable_count") || "1", 10);
const rcCount = parseInt(getInput("rc_count") || "1", 10);
const rcIdent = getInput("rc_identifier") || "rc";
const owner = getInput("owner") || "dapr";
const repo = getInput("repo") || "dapr";
Expand All @@ -25529,6 +25494,7 @@ async function run() {
tags: tagNames,
tagPrefix,
stableCount,
rcCount,
rcIdent
});
setOutput("matrix_json", JSON.stringify(result.matrix_json));
Expand Down
12 changes: 7 additions & 5 deletions .github/tools/tag-selector/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,27 @@ async function run() {
const token = core.getInput("github_token", { required: true});
const tagPrefix = core.getInput("tag_prefix") || "";
const stableCount = parseInt(core.getInput("stable_count") || "1", 10);
const rcCount = parseInt(core.getInput("rc_count") || "1", 10);
const rcIdent = core.getInput("rc_identifier") || "rc";

const owner = core.getInput("owner") || "dapr";
const repo = core.getInput("repo") || "dapr";

const octokit = github.getOctokit(token);

// Paginate all tags
const tags: Tag[] = await octokit.paginate(octokit.rest.repos.listTags, {
owner,
repo,
per_page: 100
});

const tagNames = tags.map((t: { name: string }) => t.name);
const result = computeFromTags({
tags: tagNames,
tagPrefix,
stableCount,
rcCount,
rcIdent,
});

Expand All @@ -35,4 +37,4 @@ async function run() {
}
}

run();
run();
64 changes: 10 additions & 54 deletions .github/tools/tag-selector/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type ComputeInput = {
tags: string[]; // raw tag names e.g., ["v1.16.8", "1.17.0-rc.3"]
tagPrefix?: string; // e.g., "v"
stableCount?: number; // default: 2
rcCount?: number; // default: 1
rcIdent?: string; // default: "rc"
}

Expand All @@ -14,18 +15,15 @@ export type ComputeOutput = {
export function stripPrefix(tag: string, prefix?: string): string {
if (!prefix)
return tag;

return tag.startsWith(prefix) ? tag.slice(prefix.length) : tag;
}

function versionKey(major: number, minor: number) {
return `${major}.${minor}`;
return tag.startsWith(prefix) ? tag.slice(prefix.length) : tag;
}

/** Compute outputs from a set of tag names */
export function computeFromTags(input: ComputeInput): ComputeOutput {
const tagPrefix = input.tagPrefix ?? "";
const stableCount = input.stableCount ?? 2;
const rcCount = input.rcCount ?? 1;
const rcIdent = input.rcIdent ?? "rc";

// Normalize tags -> semver.valid versions
Expand Down Expand Up @@ -59,58 +57,16 @@ export function computeFromTags(input: ComputeInput): ComputeOutput {
.slice(0, stableCount);
}

// Build minor map for RC-only minors
const minorMap = new Map<
string,
{ hasStable: boolean; rcVersions: string[]; major: number; minor: number }
>();

for (const v of stable) {
const key = versionKey(semver.major(v), semver.minor(v));
const entry =
minorMap.get(key) || {
hasStable: false,
rcVersions: [],
major: semver.major(v),
minor: semver.minor(v),
};
entry.hasStable = true;
minorMap.set(key, entry);
}

for (const v of prerelease) {
// Pick latest RC versions across all minors
const rcVersions = prerelease.filter((v) => {
const pr = semver.prerelease(v) || [];
if (pr[0] === rcIdent) {
const key = versionKey(semver.major(v), semver.minor(v));
const entry =
minorMap.get(key) || {
hasStable: false,
rcVersions: [],
major: semver.major(v),
minor: semver.minor(v),
};
entry.rcVersions.push(v);
minorMap.set(key, entry);
}
}

// Find newest (major.minor) with only RCs
let rcMinor = "";
let latestRc = "";
const candidates = Array.from(minorMap.values()).filter(
(m) => !m.hasStable && m.rcVersions.length > 0
);
if (candidates.length > 0) {
candidates.sort((a, b) =>
a.major === b.major ? b.minor - a.minor : b.major - a.major
);
const newest = candidates[0];
rcMinor = `${newest.major}.${newest.minor}`;
latestRc = newest.rcVersions.sort(semver.rcompare)[0];
}
return pr[0] === rcIdent;
});
const latestRcs =
rcCount > 0 ? [...rcVersions].sort(semver.rcompare).slice(0, rcCount) : [];

const matrix = [
...(latestRc ? [{ version: latestRc, channel: "rc" as const }] : []),
...latestRcs.map((v) => ({ version: v, channel: "rc" as const })),
...stablePatches.map((v) => ({ version: v, channel: "stable" as const })),
];

Expand Down
66 changes: 65 additions & 1 deletion .github/tools/tag-selector/test/lib.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,70 @@ describe("computeFromTags - core scenarios", () => {
]);
});

test("rc_count returns latest N RCs from newest RC minor", () => {
const tags = [
"v1.16.7",
"v1.16.8",
"v1.17.0-rc.1",
"v1.17.0-rc.2",
"v1.17.0-rc.3",
];
const out = computeFromTags({
tags,
tagPrefix: "v",
stableCount: 2,
rcCount: 2,
rcIdent: "rc",
});

expect(out.matrix_json).toEqual([
{ version: "1.17.0-rc.3", channel: "rc" },
{ version: "1.17.0-rc.2", channel: "rc" },
{ version: "1.16.8", channel: "stable" },
{ version: "1.16.7", channel: "stable" },
]);
});

test("rc_count returns available RCs when fewer exist", () => {
const tags = [
"v1.16.8",
"v1.17.0-rc.1",
];
const out = computeFromTags({
tags,
tagPrefix: "v",
stableCount: 1,
rcCount: 2,
rcIdent: "rc",
});

expect(out.matrix_json).toEqual([
{ version: "1.17.0-rc.1", channel: "rc" },
{ version: "1.16.8", channel: "stable" },
]);
});

test("rc_count returns latest RCs regardless of stable availability", () => {
const tags = [
"1.18.0",
"1.18.1-rc.1",
"1.17.0-rc.2",
"1.17.0-rc.1",
];
const out = computeFromTags({
tags,
stableCount: 1,
rcCount: 2,
rcIdent: "rc",
});

expect(out.matrix_json).toEqual([
{ version: "1.18.1-rc.1", channel: "rc" },
{ version: "1.17.0-rc.2", channel: "rc" },
{ version: "1.18.0", channel: "stable" },
]);
});

test("no RC-only newest minor -> only stable outputs", () => {
const tags = ["1.16.7", "1.16.8", "1.17.0"]; // 1.17 has a stable, so not RC-only
const out = computeFromTags({ tags, stableCount: 2 });
Expand All @@ -58,4 +122,4 @@ describe("computeFromTags - core scenarios", () => {
matrix_json: [],
});
});
});
});
1 change: 1 addition & 0 deletions .github/workflows/sdk_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
INPUT_TAG_PREFIX: "v"
INPUT_STABLE_COUNT: "2"
INPUT_RC_IDENTIFIER: "rc"
INPUT_RC_COUNT: "2"
run: |
node .github/tools/tag-selector/dist/index.js
- name: Show outputs
Expand Down
Loading