Merge pull request #12099 from planeiii-te/jenkins-branches

feat(jenkins-backend): add multiple branch support to the JenkinsApi
This commit is contained in:
Fredrik Adelöw
2022-07-01 09:41:04 +02:00
committed by GitHub
7 changed files with 70 additions and 18 deletions
+1
View File
@@ -37,6 +37,7 @@
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"jenkins": "^0.28.1",
"promise-any-polyfill": "^1.0.1",
"winston": "^3.2.1",
"yn": "^4.0.0"
},
@@ -118,10 +118,9 @@ describe('JenkinsApi', () => {
it('standard github layout', async () => {
mockedJenkinsClient.job.get.mockResolvedValueOnce(project);
const result = await jenkinsApi.getProjects(
jenkinsInfo,
const result = await jenkinsApi.getProjects(jenkinsInfo, [
'testBranchName',
);
]);
expect(mockedJenkins).toHaveBeenCalledWith({
baseUrl: jenkinsInfo.baseUrl,
@@ -134,6 +133,35 @@ describe('JenkinsApi', () => {
});
expect(result).toHaveLength(1);
});
it('supports multiple branches', async () => {
mockedJenkinsClient.job.get.mockResolvedValue(project);
const result = await jenkinsApi.getProjects(jenkinsInfo, [
'foo',
'bar',
'catpants',
]);
expect(mockedJenkins).toHaveBeenCalledWith({
baseUrl: jenkinsInfo.baseUrl,
headers: jenkinsInfo.headers,
promisify: true,
});
expect(mockedJenkinsClient.job.get).toBeCalledWith({
name: `${jenkinsInfo.jobFullName}/foo`,
tree: expect.anything(),
});
expect(mockedJenkinsClient.job.get).toBeCalledWith({
name: `${jenkinsInfo.jobFullName}/bar`,
tree: expect.anything(),
});
expect(mockedJenkinsClient.job.get).toBeCalledWith({
name: `${jenkinsInfo.jobFullName}/catpants`,
tree: expect.anything(),
});
expect(result).toHaveLength(1);
});
});
describe('augmented', () => {
const projectWithScmActions: JenkinsProject = {
@@ -30,6 +30,12 @@ import {
import { jenkinsExecutePermission } from '@backstage/plugin-jenkins-common';
import { NotAllowedError } from '@backstage/errors';
if (!Promise.any) {
(async () => {
await import('promise-any-polyfill');
})();
}
export class JenkinsApiImpl {
private static readonly lastBuildTreeSpec = `lastBuild[
number,
@@ -70,18 +76,21 @@ export class JenkinsApiImpl {
* Get a list of projects for the given JenkinsInfo.
* @see ../../../jenkins/src/api/JenkinsApi.ts#getProjects
*/
async getProjects(jenkinsInfo: JenkinsInfo, branch?: string) {
async getProjects(jenkinsInfo: JenkinsInfo, branches?: string[]) {
const client = await JenkinsApiImpl.getClient(jenkinsInfo);
const projects: BackstageProject[] = [];
if (branch) {
// we have been asked to filter to a single branch.
if (branches) {
// Assume jenkinsInfo.jobFullName is a folder which contains one job per branch.
// TODO: extract a strategy interface for this
const job = await client.job.get({
name: `${jenkinsInfo.jobFullName}/${branch}`,
tree: JenkinsApiImpl.jobTreeSpec.replace(/\s/g, ''),
});
const job = await Promise.any(
branches.map(branch =>
client.job.get({
name: `${jenkinsInfo.jobFullName}/${branch}`,
tree: JenkinsApiImpl.jobTreeSpec.replace(/\s/g, ''),
}),
),
);
projects.push(this.augmentProject(job));
} else {
// We aren't filtering
@@ -64,12 +64,12 @@ export async function createRouter(
request.header('authorization'),
);
const branch = request.query.branch;
let branchStr: string | undefined;
let branches: string[] | undefined;
if (branch === undefined) {
branchStr = undefined;
branches = undefined;
} else if (typeof branch === 'string') {
branchStr = branch;
branches = branch.split(/,/g);
} else {
// this was passed in as something weird -> 400
// https://evanhahn.com/gotchas-with-express-query-parsing-and-how-to-avoid-them/
@@ -88,7 +88,7 @@ export async function createRouter(
},
backstageToken: token,
});
const projects = await jenkinsApi.getProjects(jenkinsInfo, branchStr);
const projects = await jenkinsApi.getProjects(jenkinsInfo, branches);
response.json({
projects: projects,
+5 -2
View File
@@ -19,7 +19,7 @@ yarn add --cwd packages/app @backstage/plugin-jenkins
3. Add the `EntityJenkinsContent` extension to the `CI/CD` page and `EntityLatestJenkinsRunCard` to the `overview` page in the app (or wherever you'd prefer):
Note that if you configured a custom JenkinsInfoProvider in step 2, you may need a custom isJenkinsAvailable.
Note that if you configured a custom JenkinsInfoProvider in step 2, you may need a custom isJenkinsAvailable. Also if you're transitioning to a new default branch name, you can pass multiple branch names as a comma-separated list and it will check for each branch name.
```tsx
// In packages/app/src/components/catalog/EntityPage.tsx
@@ -38,7 +38,10 @@ const serviceEntityPage = (
<EntitySwitch>
<EntitySwitch.Case if={isJenkinsAvailable}>
<Grid item sm={6}>
<EntityLatestJenkinsRunCard branch="master" variant="gridItem" />
<EntityLatestJenkinsRunCard
branch="main,master"
variant="gridItem"
/>
</Grid>
</EntitySwitch.Case>
{/* ... */}