Skip to content
Open
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: 6 additions & 0 deletions .changeset/jolly-islands-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@secustor/backstage-plugin-renovate-backend': patch
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'@secustor/backstage-plugin-renovate-backend': patch
'@secustor/backstage-plugin-renovate-backend': minor

Also split up these changesets please

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, not too familiar with changesets. Yeah, I can break them up into one for each package.

'@secustor/backstage-plugin-renovate-common': patch
---

Modifies getTargetRepo to accept ADO's odd org/\_git/repo form and adds support for ADO as a config option
5 changes: 5 additions & 0 deletions plugins/renovate-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Supported platforms:

- Github
- Gitlab
- AzureDevOps

## Getting started

Expand Down Expand Up @@ -45,6 +46,9 @@ integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
azure:
- host: dev.azure.com
token: ${AZURE_PAT_TOKEN}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

@GigiaJ GigiaJ Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, it is a deprecated method though still currently working. The way listed in the docs is the updated way though I wasn't sure if more changes would've been needed if I did the one listed in their docs. I can test and find out though. If it isn't a huge hassle, I'll update it to use the documented version shortly.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, please update to the upstream documented style


backend:
cache:
Expand Down Expand Up @@ -97,6 +101,7 @@ renovate:
queue:
type: local-fastq

# Can pass any Renovate config through here.
config:
# only do a lookup and create reports with updates and do not open PRs
dryRun: lookup
Expand Down
59 changes: 57 additions & 2 deletions plugins/renovate-backend/src/wrapper/platforms/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { getPlatformEnvs } from './index';
import { mockDeep } from 'jest-mock-extended';
import { DefaultGithubCredentialsProvider } from '@backstage/integration';
import { DefaultGithubCredentialsProvider, DefaultAzureDevOpsCredentialsProvider } from '@backstage/integration';
import { mockServices } from '@backstage/backend-test-utils';

const githubCredentialProvider = mockDeep<DefaultGithubCredentialsProvider>();
DefaultGithubCredentialsProvider.fromIntegrations = jest
.fn()
.mockReturnValue(githubCredentialProvider);

const azureCredentialProvider = mockDeep<DefaultAzureDevOpsCredentialsProvider>();
DefaultAzureDevOpsCredentialsProvider.fromIntegrations = jest
.fn()
.mockReturnValue(azureCredentialProvider);

describe('wrapper/platforms', () => {
beforeEach(() => {
githubCredentialProvider.getCredentials.mockReset();
azureCredentialProvider.getCredentials.mockReset();
});

it('throw if platform could not be identified', async () => {
Expand Down Expand Up @@ -153,4 +159,53 @@ describe('wrapper/platforms', () => {
RENOVATE_TOKEN: 'bbbbbbbbbb',
});
});
});

it('return env for azure devops with token', async () => {
const rootConfig = mockServices.rootConfig({
data: {
integrations: {
github: [
{
host: 'github.com',
token: 'aaaaaa',
},
],
azure: [
{
host: 'dev.azure.com',
token: 'cccccccc',
},
],
},
},
});
azureCredentialProvider.getCredentials.mockResolvedValue({
headers: { Authorization: 'Basic cccccccc' },
token: 'cccccccc',
type: 'pat',
});
azureCredentialProvider.getCredentials.mockResolvedValue({
headers: { Authorization: 'Basic cccccccc' },
token: 'cccccccc',
type: 'pat',
});
await expect(
getPlatformEnvs(
{
host: 'dev.azure.com',
repository: 'myOrg/myRepo',
},
{
rootConfig,
logger: mockServices.logger.mock(),
},
),
).resolves.toEqual({
RENOVATE_ENDPOINT: 'https://dev.azure.com',
GITHUB_COM_TOKEN: 'aaaaaa',
RENOVATE_PLATFORM: 'azure',
RENOVATE_REPOSITORIES: 'myOrg/myRepo',
RENOVATE_TOKEN: 'cccccccc',
});
});
});
12 changes: 12 additions & 0 deletions plugins/renovate-backend/src/wrapper/platforms/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
DefaultGitlabCredentialsProvider,
ScmIntegrations,
DefaultAzureDevOpsCredentialsProvider,
} from '@backstage/integration';
import is from '@sindresorhus/is';
import { PlatformEnvsOptions } from './types';
Expand Down Expand Up @@ -52,6 +53,17 @@ export async function getPlatformEnvs(
env.RENOVATE_REPOSITORIES = target.repository;
}
break;
case 'azure':
{
const cred = await DefaultAzureDevOpsCredentialsProvider.fromIntegrations(
integrations,
).getCredentials({ url });
env.RENOVATE_PLATFORM = 'azure';
env.RENOVATE_ENDPOINT = `https://${target.host}`;
env.RENOVATE_TOKEN = requireConfigVariable(cred?.token, errMsg);
env.RENOVATE_REPOSITORIES = target.repository;
}
break;
default:
throw new Error(`Unsupported platform type ${integration.type}`);
}
Expand Down
9 changes: 9 additions & 0 deletions plugins/renovate-common/src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ describe('utils', () => {
});
});

it('should extract ADO repo format', () => {
const result = getTargetRepo('dev.azure.com/project/_git/repo');

expect(result).toMatchObject({
host: 'dev.azure.com',
repository: 'project/repo',
});
});

it('should extract repo from Entity with source location annotation', () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
Expand Down
14 changes: 13 additions & 1 deletion plugins/renovate-common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,21 @@ export function getTargetRepo(
return target;
}
const url = getTargetURL(target);

let repository = url.full_name;

if (repository.includes('/_git/')) {
const parts = repository.split('/_git/');
const leftSide = parts[0].split('/');
const repoName = parts[1];
const projectName = leftSide[leftSide.length - 1];

repository = `${projectName}/${repoName}`;
}

return {
host: url.resource,
repository: url.full_name,
repository: repository,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
repository: repository,
repository: `${url.owner}/${url.repo}`,

Rather than doing this manually this seems more stable
https://github.com/IonicaBizau/git-url-parse/blob/master/test/index.js

};
}

Expand Down