Skip to content

Commit 130d29c

Browse files
committed
feat(ng-dev): update target labels in renovate config
This commit enhances the release tool to dynamically adjust Renovate labels based on the current version. Example: angular/angular#61894
1 parent d8615e0 commit 130d29c

File tree

3 files changed

+109
-6
lines changed

3 files changed

+109
-6
lines changed

ng-dev/release/publish/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ts_library(
88
visibility = ["//ng-dev:__subpackages__"],
99
deps = [
1010
"//ng-dev/commit-message",
11+
"//ng-dev/pr/common/labels",
1112
"//ng-dev/pr/merge",
1213
"//ng-dev/release/build",
1314
"//ng-dev/release/config",

ng-dev/release/publish/actions.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import {Prompt} from '../../utils/prompt.js';
4444
import {glob} from 'fast-glob';
4545
import {PnpmVersioning} from './pnpm-versioning.js';
4646
import {Commit} from '../../utils/git/octokit-types.js';
47+
import {updateRenovateConfigTargetLabels} from './actions/renovate-config-updates.js';
48+
import {targetLabels} from '../../pr/common/labels/target.js';
4749

4850
/** Interface describing a Github repository. */
4951
export interface GithubRepo {
@@ -217,13 +219,27 @@ export abstract class ReleaseAction {
217219
}
218220

219221
// Commit message for the release point.
220-
const commitMessage = getCommitMessageForRelease(newVersion);
221222
const filesToCommit = [
222223
workspaceRelativePackageJsonPath,
223224
workspaceRelativeChangelogPath,
224225
...this.getAspectLockFiles(),
225226
];
226227

228+
if (newVersion.patch === 0 && !newVersion.prerelease) {
229+
// Switch the renovate labels for `target: rc` to `target: patch`
230+
const renovateConfigPath = await updateRenovateConfigTargetLabels(
231+
this.projectDir,
232+
targetLabels['TARGET_RC'].name,
233+
targetLabels['TARGET_PATCH'].name,
234+
);
235+
236+
if (renovateConfigPath) {
237+
filesToCommit.push(renovateConfigPath);
238+
}
239+
}
240+
241+
const commitMessage = getCommitMessageForRelease(newVersion);
242+
227243
// Create a release staging commit including changelog and version bump.
228244
await this.createCommit(commitMessage, filesToCommit);
229245

ng-dev/release/publish/actions/renovate-config-updates.ts

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import {existsSync} from 'node:fs';
22
import {green, Log} from '../../../utils/logging.js';
33
import {join} from 'node:path';
44
import {writeFile, readFile} from 'node:fs/promises';
5+
import {targetLabels} from '../../../pr/common/labels/target.js';
56

67
/**
78
* Updates the `renovate.json` configuration file to include a new base branch.
9+
* It also updates specific target labels within the package rules.
810
*
9-
* @param projectDir - The project directory path.
11+
* @param projectDir - The path to the project directory.
1012
* @param newBranchName - The name of the new branch to add to the base branches list.
11-
* @returns A promise that resolves to an string containing the path to the modified `renovate.json` file,
12-
* or null if config updating is disabled.
13+
* @returns A promise that resolves to the path of the modified `renovate.json` file if updated,
14+
* or `null` if the file was not found or the `baseBranches` array has an unexpected format.
1315
*/
1416
export async function updateRenovateConfig(
1517
projectDir: string,
@@ -18,13 +20,13 @@ export async function updateRenovateConfig(
1820
const renovateConfigPath = join(projectDir, 'renovate.json');
1921
if (!existsSync(renovateConfigPath)) {
2022
Log.warn(` ✘ Skipped updating Renovate config as it was not found.`);
21-
2223
return null;
2324
}
2425

2526
const config = await readFile(renovateConfigPath, 'utf-8');
2627
const configJson = JSON.parse(config) as Record<string, unknown>;
2728
const baseBranches = configJson.baseBranches;
29+
2830
if (!Array.isArray(baseBranches) || baseBranches.length !== 2) {
2931
Log.warn(
3032
` ✘ Skipped updating Renovate config: "baseBranches" must contain exactly 2 branches.`,
@@ -34,8 +36,92 @@ export async function updateRenovateConfig(
3436
}
3537

3638
configJson.baseBranches = ['main', newBranchName];
39+
40+
updateRenovateTargetLabel(
41+
configJson,
42+
targetLabels['TARGET_PATCH'].name,
43+
targetLabels['TARGET_RC'].name,
44+
);
3745
await writeFile(renovateConfigPath, JSON.stringify(configJson, undefined, 2));
38-
Log.info(green(` ✓ Updated Renovate config.`));
3946

47+
Log.info(green(` ✓ Updated Renovate config.`));
4048
return renovateConfigPath;
4149
}
50+
51+
/**
52+
* Updates a specific target label in the `renovate.json` configuration file.
53+
* This function specifically targets and replaces one label with another within the `packageRules`.
54+
*
55+
* @param projectDir - The path to the project directory.
56+
* @param fromLabel - The label name to be replaced.
57+
* @param toLabel - The new label name to replace `fromLabel` with.
58+
* @returns A promise that resolves to `true` if a label was updated and the file was written `false` otherwise.
59+
*/
60+
export async function updateRenovateConfigTargetLabels(
61+
projectDir: string,
62+
fromLabel: string,
63+
toLabel: string,
64+
): Promise<string | null> {
65+
const renovateConfigPath = join(projectDir, 'renovate.json');
66+
if (!existsSync(renovateConfigPath)) {
67+
Log.warn(` ✘ Skipped updating Renovate config as it was not found.`);
68+
69+
return null;
70+
}
71+
72+
const config = await readFile(renovateConfigPath, 'utf-8');
73+
const configJson = JSON.parse(config) as Record<string, unknown>;
74+
75+
// Check baseBranches just in case, though this function's primary focus is labels
76+
const baseBranches = configJson.baseBranches;
77+
if (!Array.isArray(baseBranches) || baseBranches.length !== 2) {
78+
Log.warn(
79+
` ✘ Skipped updating Renovate config: "baseBranches" must contain exactly 2 branches.`,
80+
);
81+
82+
return null;
83+
}
84+
85+
if (updateRenovateTargetLabel(configJson, fromLabel, toLabel)) {
86+
await writeFile(renovateConfigPath, JSON.stringify(configJson, undefined, 2));
87+
Log.info(green(` ✓ Updated target label in Renovate config.`));
88+
89+
return renovateConfigPath;
90+
} else {
91+
Log.info(green(` ✓ No changes to target labels in Renovate config.`));
92+
return null;
93+
}
94+
}
95+
96+
/**
97+
* Updates a specific target label within the `packageRules` of a Renovate configuration.
98+
*
99+
* @param configJson - The parsed JSON object of the Renovate configuration.
100+
* @param fromLabel - The label name to be replaced.
101+
* @param toLabel - The new label name to replace `fromLabel` with.
102+
* @returns `true` is the label has been updated, otherwise `false`.
103+
*/
104+
function updateRenovateTargetLabel(
105+
configJson: Record<string, unknown>,
106+
fromLabel: string,
107+
toLabel: string,
108+
): boolean {
109+
if (!Array.isArray(configJson.packageRules)) {
110+
return false;
111+
}
112+
113+
let updated = false;
114+
for (const rule of configJson.packageRules) {
115+
if (!Array.isArray(rule.addLabels)) {
116+
continue;
117+
}
118+
119+
const idx = (rule.addLabels as string[]).findIndex((x) => x === fromLabel);
120+
if (idx >= 0) {
121+
rule.addLabels[idx] = toLabel;
122+
updated = true;
123+
}
124+
}
125+
126+
return updated;
127+
}

0 commit comments

Comments
 (0)