Skip to content
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

feat: update labels when config changes #25340

Merged
merged 71 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
f20953b
implement update labels logic in github, gitlab, gitea
RahulGautamSingh Aug 17, 2023
1a65f9f
Merge branch 'main' into feat/update-labels
RahulGautamSingh Oct 3, 2023
37de4a4
Merge branch 'main' into feat/update-labels
RahulGautamSingh Oct 22, 2023
33a10d2
skip if pr-labels are modified
RahulGautamSingh Oct 22, 2023
472f4a3
fix tests
RahulGautamSingh Oct 22, 2023
18bca70
fix gitea label update logic
RahulGautamSingh Oct 22, 2023
3af757b
Apply suggestions from code review
RahulGautamSingh Oct 23, 2023
fa29bc8
add tests
RahulGautamSingh Oct 23, 2023
9b18b66
update snap[s
RahulGautamSingh Oct 23, 2023
3a7f427
fix labels order in tests
RahulGautamSingh Oct 24, 2023
ce6777f
revert ordering the labels
RahulGautamSingh Oct 24, 2023
d306847
change gitae logic
RahulGautamSingh Oct 24, 2023
d4bad42
update PrUpdateConfig interface
RahulGautamSingh Oct 24, 2023
068f70f
fix tests
RahulGautamSingh Oct 24, 2023
a84f3f8
Merge branch 'main' into feat/update-labels
RahulGautamSingh Oct 24, 2023
b221ab4
fix coverage
RahulGautamSingh Oct 24, 2023
d90a6ad
Merge branch 'feat/update-labels' of https://github.com/RahulGautamSi…
RahulGautamSingh Oct 24, 2023
3d6f734
refactor getChangedLabels fn
RahulGautamSingh Oct 24, 2023
65138bf
apply suggestions
RahulGautamSingh Oct 24, 2023
e73029f
add docs
RahulGautamSingh Oct 24, 2023
6a51748
Update docs/usage/configuration-options.md
RahulGautamSingh Nov 3, 2023
2365865
Update docs/usage/configuration-options.md
RahulGautamSingh Nov 3, 2023
b9f3cda
store labels in existing debugData
RahulGautamSingh Nov 6, 2023
277f2d6
fix build issues
RahulGautamSingh Nov 6, 2023
3192786
fix coverage
RahulGautamSingh Nov 6, 2023
61fe7d1
fix: logic updatePrdebugData
RahulGautamSingh Nov 7, 2023
b08bba8
Update lib/workers/repository/update/pr/body/index.ts
rarkins Nov 7, 2023
ad64b21
Merge branch 'main' into feat/update-labels
RahulGautamSingh Nov 8, 2023
407223e
fix formatting
RahulGautamSingh Nov 8, 2023
727e013
revert the labels struct changes
RahulGautamSingh Nov 8, 2023
39d8fe0
update snpas
RahulGautamSingh Nov 8, 2023
4c5e802
refactor params of the new fns
RahulGautamSingh Nov 8, 2023
3f09676
fix tests
RahulGautamSingh Nov 8, 2023
9de67bf
Merge branch 'main' into feat/update-labels
RahulGautamSingh Nov 8, 2023
1e5bee8
fix formatting
RahulGautamSingh Nov 8, 2023
d970ece
remove extra logs
RahulGautamSingh Nov 9, 2023
1c85e92
gitea: include labels in getPR result
RahulGautamSingh Nov 9, 2023
fee35a6
Merge branch 'main' into feat/update-labels
RahulGautamSingh Nov 9, 2023
fdeb79f
fix formatting
RahulGautamSingh Nov 9, 2023
71a632e
fix tests
RahulGautamSingh Nov 9, 2023
2a5aae6
refactor
RahulGautamSingh Nov 9, 2023
f198a68
add comments
RahulGautamSingh Nov 10, 2023
dacdb5d
Update docs/usage/configuration-options.md
RahulGautamSingh Nov 10, 2023
0dca273
Apply suggestions from code review
RahulGautamSingh Nov 11, 2023
15ec73a
fix lint issues
RahulGautamSingh Nov 11, 2023
c39e4e4
fix test
RahulGautamSingh Nov 11, 2023
bcc173b
Apply Suggestion
RahulGautamSingh Nov 13, 2023
c2156be
apply suggestions
RahulGautamSingh Nov 14, 2023
b7aebff
Update lib/workers/repository/update/pr/labels.ts
RahulGautamSingh Nov 15, 2023
6e4d3cf
Merge branch 'main' into feat/update-labels
RahulGautamSingh Nov 15, 2023
682469a
remove non-null assertion
RahulGautamSingh Nov 15, 2023
99ba709
merge
RahulGautamSingh Jan 23, 2024
1ec080f
fix gitea tests
RahulGautamSingh Jan 24, 2024
3198053
use pmap
RahulGautamSingh Jan 24, 2024
d8aa7ad
Update lib/modules/platform/gitea/index.ts
RahulGautamSingh Jan 30, 2024
ad91fbf
fix formatting
RahulGautamSingh Jan 30, 2024
ebb1575
Apply suggestions from code review
RahulGautamSingh Feb 3, 2024
4951c89
Update docs/usage/configuration-options.md
RahulGautamSingh Feb 3, 2024
97db32b
Update lib/workers/repository/update/pr/index.ts
RahulGautamSingh Feb 3, 2024
7491f6a
Apply suggestions from code review
RahulGautamSingh Feb 3, 2024
d68c1f5
remove unnecessary comments
RahulGautamSingh Feb 9, 2024
6f68ffa
refactor logic and add logs
RahulGautamSingh Feb 18, 2024
1a10a2c
Apply suggestions from code review
RahulGautamSingh Feb 18, 2024
f24c866
update docs
RahulGautamSingh Feb 18, 2024
670d907
sort in preparelabels
RahulGautamSingh Feb 19, 2024
69e976a
fix docs
RahulGautamSingh Feb 19, 2024
45818d7
fix tests
RahulGautamSingh Feb 19, 2024
921e9f2
Update docs/usage/configuration-options.md
RahulGautamSingh Feb 21, 2024
e0dc474
Merge branch 'main' into feat/update-labels
rarkins Feb 28, 2024
8b92b64
Merge branch 'main' into feat/update-labels
RahulGautamSingh Mar 18, 2024
70126e0
log waring for unavaiable labels
RahulGautamSingh Mar 18, 2024
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: 3 additions & 3 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -2159,10 +2159,10 @@ Consider this example:

With the above config, every PR raised by Renovate will have the label `dependencies` while PRs containing `eslint`-related packages will instead have the label `linting`.

Renovate only adds labels when it creates the PR, which means:
Behaviour details:

- If you remove labels which Renovate added, it won't re-apply them
- If you change your config, the new/changed labels are not applied to any open PRs
- On GitHub, GitLab and Gitea: Renovate will keep PR labels in sync with configured labels, provided that no other user or bot has made changes to the labels after PR creation. If labels are changed by any other account, Renovate will stop making further changes.
- For other platforms, Renovate will add labels only at time of PR creation and not update them after that.

The `labels` array is non-mergeable, meaning if multiple `packageRules` match then Renovate uses the last value for `labels`.
If you want to add/combine labels, use the `addLabels` config option, which is mergeable.
Expand Down
21 changes: 9 additions & 12 deletions lib/modules/platform/gitea/gitea-helper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,7 @@ describe('modules/platform/gitea/gitea-helper', () => {
.patch(`/repos/${mockRepo.full_name}/pulls/${mockPR.number}`)
.reply(200);

const res = await closePR(mockRepo.full_name, mockPR.number);
expect(res).toBeUndefined();
await expect(closePR(mockRepo.full_name, mockPR.number)).toResolve();
});
});

Expand All @@ -389,10 +388,11 @@ describe('modules/platform/gitea/gitea-helper', () => {
.post(`/repos/${mockRepo.full_name}/pulls/${mockPR.number}/merge`)
.reply(200);

const res = await mergePR(mockRepo.full_name, mockPR.number, {
Do: 'rebase',
});
expect(res).toBeUndefined();
await expect(
mergePR(mockRepo.full_name, mockPR.number, {
Do: 'rebase',
}),
).toResolve();
});
});

Expand Down Expand Up @@ -569,12 +569,9 @@ describe('modules/platform/gitea/gitea-helper', () => {
)
.reply(200);

const res = await unassignLabel(
mockRepo.full_name,
mockIssue.number,
mockLabel.id,
);
expect(res).toBeUndefined();
await expect(
unassignLabel(mockRepo.full_name, mockIssue.number, mockLabel.id),
).toResolve();
});
});

Expand Down
45 changes: 45 additions & 0 deletions lib/modules/platform/gitea/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ describe('modules/platform/gitea/index', () => {
sha: 'other-head-sha' as LongCommitSha,
repo: partial<Repo>({ full_name: mockRepo.full_name }),
},
labels: [
{
id: 1,
name: 'bug',
},
],
}),
partial<MockPr>({
number: 3,
Expand Down Expand Up @@ -1830,6 +1836,45 @@ describe('modules/platform/gitea/index', () => {
}),
).toResolve();
});

it('should update labels', async () => {
const updatedMockPR = partial<PR>({
...mockPRs[0],
number: 1,
title: 'New Title',
body: 'New Body',
state: 'open',
labels: [
{
id: 1,
name: 'some-label',
},
],
});
const scope = httpMock
.scope('https://gitea.com/api/v1')
.get('/repos/some/repo/pulls')
.query({ state: 'all', sort: 'recentupdate' })
.reply(200, mockPRs)
.get('/repos/some/repo/labels')
.reply(200, mockRepoLabels)
.get('/orgs/some/labels')
.reply(200, mockOrgLabels)
.patch('/repos/some/repo/pulls/1')
.reply(200, updatedMockPR);

await initFakePlatform(scope);
await initFakeRepo(scope);
await expect(
gitea.updatePr({
number: 1,
prTitle: 'New Title',
prBody: 'New Body',
state: 'open',
labels: ['some-label'],
}),
).toResolve();
});
});

describe('mergePr', () => {
Expand Down
16 changes: 15 additions & 1 deletion lib/modules/platform/gitea/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ const platform: Platform = {
logger.debug(`Creating pull request: ${title} (${head} => ${base})`);
try {
const labels = Array.isArray(labelNames)
? await Promise.all(labelNames.map(lookupLabelByName))
? await map(labelNames, lookupLabelByName)
: [];
const gpr = await helper.createPR(config.repository, {
base,
Expand Down Expand Up @@ -583,6 +583,7 @@ const platform: Platform = {
number,
prTitle,
prBody: body,
labels,
state,
targetBranch,
}: UpdatePrConfig): Promise<void> {
Expand All @@ -600,6 +601,19 @@ const platform: Platform = {
prUpdateParams.base = targetBranch;
}

/**
* Update PR labels.
* In the Gitea API, labels are replaced on each update if the field is present.
* If the field is not present (i.e., undefined), labels aren't updated.
* However, the labels array must contain label IDs instead of names,
* so a lookup is performed to fetch the details (including the ID) of each label.
*/
if (Array.isArray(labels)) {
prUpdateParams.labels = (await map(labels, lookupLabelByName)).filter(
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
is.number,
);
}

const gpr = await helper.updatePR(
config.repository,
number,
Expand Down
8 changes: 8 additions & 0 deletions lib/modules/platform/gitea/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export type CommitStatusType =
| 'unknown';
export type PRMergeMethod = 'merge' | 'rebase' | 'rebase-merge' | 'squash';

export interface GiteaLabel {
id: number;
name: string;
}
export interface PR {
number: number;
state: PRState;
Expand All @@ -40,6 +44,10 @@ export interface PR {
};
assignees?: any[];
user?: { username?: string };

// labels returned from the Gitea API are represented as an array of objects
// ref: https://docs.gitea.com/api/1.20/#tag/repository/operation/repoGetPullRequest
labels?: GiteaLabel[];
}

export interface Issue {
Expand Down
2 changes: 2 additions & 0 deletions lib/modules/platform/gitea/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ export function toRenovatePR(data: PR, author: string | null): Pr | null {
title = title.substring(DRAFT_PREFIX.length);
isDraft = true;
}
const labels = (data?.labels ?? []).map((l) => l.name);

return {
labels,
number: data.number,
state: data.state,
title,
Expand Down
37 changes: 37 additions & 0 deletions lib/modules/platform/github/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3328,6 +3328,43 @@ describe('modules/platform/github/index', () => {

await expect(github.updatePr(pr)).toResolve();
});

it('should add and remove labels', async () => {
const pr: UpdatePrConfig = {
number: 1234,
prTitle: 'The New Title',
prBody: 'Hello world again',
state: 'closed',
targetBranch: 'new_base',
addLabels: ['new_label'],
removeLabels: ['old_label'],
};
const scope = httpMock.scope(githubApiHost);
initRepoMock(scope, 'some/repo');
await github.initRepo({ repository: 'some/repo' });
scope
.patch('/repos/some/repo/pulls/1234')
.reply(200, {
number: 91,
base: { sha: '1234' },
head: { ref: 'somebranch', repo: { full_name: 'some/repo' } },
state: 'open',
title: 'old title',
updated_at: '01-09-2022',
})
.post('/repos/some/repo/issues/1234/labels')
.reply(200, pr)
.delete('/repos/some/repo/issues/1234/labels/old_label')
.reply(200, pr);

await expect(github.updatePr(pr)).toResolve();
expect(logger.logger.debug).toHaveBeenCalledWith(
`Adding labels 'new_label' to #1234`,
);
expect(logger.logger.debug).toHaveBeenCalledWith(
`Deleting label old_label from #1234`,
);
});
});

describe('mergePr(prNo)', () => {
Expand Down
14 changes: 14 additions & 0 deletions lib/modules/platform/github/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,8 @@ export async function updatePr({
number: prNo,
prTitle: title,
prBody: rawBody,
addLabels: labelsToAdd,
removeLabels,
state,
targetBranch,
}: UpdatePrConfig): Promise<void> {
Expand All @@ -1778,7 +1780,19 @@ export async function updatePr({
if (config.forkToken) {
options.token = config.forkToken;
}

// Update PR labels
try {
if (labelsToAdd) {
await addLabels(prNo, labelsToAdd);
}

if (removeLabels) {
for (const label of removeLabels) {
await deleteLabel(prNo, label);
}
}

const { body: ghPr } = await githubApi.patchJson<GhRestPr>(
`repos/${config.parentRepo ?? config.repository}/pulls/${prNo}`,
options,
Expand Down
29 changes: 29 additions & 0 deletions lib/modules/platform/gitlab/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2874,6 +2874,35 @@ describe('modules/platform/gitlab/index', () => {
}),
).toResolve();
});
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved

it('adds and removes labels', async () => {
await initPlatform('13.3.6-ee');
httpMock
.scope(gitlabApiHost)
.get(
'/api/v4/projects/undefined/merge_requests?per_page=100&scope=created_by_me',
)
.reply(200, [
{
iid: 1,
source_branch: 'branch-a',
title: 'branch a pr',
state: 'open',
},
])
.put('/api/v4/projects/undefined/merge_requests/1')
.reply(200);
await expect(
gitlab.updatePr({
number: 1,
prTitle: 'title',
prBody: 'body',
state: 'closed',
addLabels: ['new_label'],
removeLabels: ['old_label'],
}),
).toResolve();
});
});

describe('mergePr(pr)', () => {
Expand Down
10 changes: 10 additions & 0 deletions lib/modules/platform/gitlab/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,8 @@ export async function updatePr({
number: iid,
prTitle,
prBody: description,
addLabels,
removeLabels,
state,
platformOptions,
targetBranch,
Expand All @@ -840,6 +842,14 @@ export async function updatePr({
body.target_branch = targetBranch;
}

if (addLabels) {
body.add_labels = addLabels;
}

if (removeLabels) {
body.remove_labels = removeLabels;
}

await gitlabApi.putJson(
`projects/${config.repository}/merge_requests/${iid}`,
{ body },
Expand Down
24 changes: 24 additions & 0 deletions lib/modules/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface PrDebugData {
createdInVer: string;
updatedInVer: string;
targetBranch: string;
labels?: string[];
}

export interface PrBodyStruct {
Expand Down Expand Up @@ -122,6 +123,28 @@ export interface UpdatePrConfig {
prBody?: string;
state?: 'open' | 'closed';
targetBranch?: string;

/**
* This field allows for label management and is designed to
* accommodate the different label update methods on various platforms.
*
* - For Gitea, labels are updated by replacing the entire labels array.
* - In the case of GitHub and GitLab, specific endpoints exist
* for adding and removing labels.
*/
labels?: string[] | null;

/**
* Specifies an array of labels to be added.
* @see {@link labels}
*/
addLabels?: string[] | null;

/**
* Specifies an array of labels to be removed.
* @see {@link labels}
*/
removeLabels?: string[] | null;
}
export interface EnsureIssueConfig {
title: string;
Expand Down Expand Up @@ -211,6 +234,7 @@ export interface Platform {
getRepos(config?: AutodiscoverConfig): Promise<string[]>;
getBranchForceRebase?(branchName: string): Promise<boolean>;
deleteLabel(number: number, label: string): Promise<void>;
addLabel?(number: number, label: string): Promise<void>;
setBranchStatus(branchStatusConfig: BranchStatusConfig): Promise<void>;
getBranchStatusCheck(
branchName: string,
Expand Down
2 changes: 1 addition & 1 deletion lib/workers/repository/config-migration/pr/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ describe('workers/repository/config-migration/pr/index', () => {
);
expect(platform.createPr).toHaveBeenCalledTimes(1);
expect(platform.createPr.mock.calls[0][0].labels).toEqual([
'label',
'additional-label',
'label',
]);
});

Expand Down
2 changes: 1 addition & 1 deletion lib/workers/repository/onboarding/pr/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ describe('workers/repository/onboarding/pr/index', () => {
);
expect(platform.createPr).toHaveBeenCalledTimes(1);
expect(platform.createPr.mock.calls[0][0].labels).toEqual([
'label',
'additional-label',
'label',
]);
});

Expand Down
Loading