create a single DefaultJenkinsProvider

Signed-off-by: Andrew Shirley <andrew.shirley@sainsburys.co.uk>
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
Andrew Shirley
2021-06-01 19:01:07 +01:00
committed by blam
parent 449b995261
commit e3675685a2
2 changed files with 175 additions and 250 deletions
+93 -49
View File
@@ -19,32 +19,39 @@ Typically, this means creating a `src/plugins/jenkins.ts` file and adding a refe
```typescript
import {
createRouter,
SingleJenkinsInfoProvider,
DefaultJenkinsInfoProvider,
} from '@backstage/plugin-jenkins-backend';
import { CatalogClient } from '@backstage/catalog-client';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin({
logger,
config,
discovery,
}: PluginEnvironment): Promise<Router> {
const catalogClient = new CatalogClient({ discoveryApi: discovery });
return await createRouter({
logger,
jenkinsInfoProvider: new SingleJenkinsInfoProvider(),
jenkinsInfoProvider: new DefaultJenkinsInfoProvider(catalogClient, config),
});
}
```
This plugin must be provided with a JenkinsInfoProvider, this is a strategy object for finding the jenkins instance and job for an entity.
There is a selection of standard ones provided, but the Integrator is free to build their own.
There is a standard one provided, but the Integrator is free to build their own.
### SingleJenkinsInfoProvider
### DefaultJenkinsInfoProvider
Allows configuration of a single global jenkins instance and annotating entities with the job name on that instance.
Allows configuration of either a single or multiple global jenkins instances and annotating entities with the job name on that instance (and optionally the name of the instance).
#### Example - Single global instance
The following will look for jobs for this entity at `https://jenkins.example.com/job/teamA/job/artistLookup-build`
#### Config
Config
```yaml
jenkins:
@@ -53,7 +60,7 @@ jenkins:
apikey: 123456789abcdef0123456789abcedf012
```
#### Catalog
Catalog
```yaml
apiVersion: backstage.io/v1alpha1
@@ -61,16 +68,16 @@ kind: Component
metadata:
name: artist-lookup
annotations:
'jenkins.io/github-folder': teamA/artistLookup-build
'jenkins.io/job-slug': teamA/artistLookup-build
```
### PrefixedJenkinsInfoProvider
The old annotation name of `jenkins.io/github-folder` is equivalent to `jenkins.io/job-slug`
Allows configuration of multiple global jenkins instance and annotating entities with the name of the instance and job name on that instance.
#### Example - Multiple global instances
The following will look for jobs for this entity at `https://jenkins-foo.example.com/job/teamA/job/artistLookup-build`
#### Config
Config
```yaml
jenkins:
@@ -85,7 +92,7 @@ jenkins:
apikey: 123456789abcdef0123456789abcedf012
```
#### Catalog
Catalog
```yaml
apiVersion: backstage.io/v1alpha1
@@ -93,53 +100,92 @@ kind: Component
metadata:
name: artist-lookup
annotations:
'jenkins.io/github-folder': departmentFoo#teamA/artistLookup-build
'jenkins.io/job-slug': departmentFoo:teamA/artistLookup-build
```
If the `departmentFoo#` part is omitted, the default instance will be assumed.
If the `departmentFoo:` part is omitted, the default instance will be assumed.
### DefaultJenkinsInfoProvider
The default jenkins info provider makes it clear it is replaceable in the config but is otherwise the same as PrefixedJenkinsInfoProvider
The following will look for jobs for this entity at `https://jenkins-foo.example.com/job/teamA/job/artistLookup-build`
#### Config
The following config is an equivalent (but less clear) version of the above:
```yaml
jenkins:
DefaultJenkinsInfoProvider:
instances:
- name: default
baseUrl: https://jenkins.example.com
username: backstage-bot
apikey: 123456789abcdef0123456789abcedf012
- name: departmentFoo
baseUrl: https://jenkins-foo.example.com
username: backstage-bot
apikey: 123456789abcdef0123456789abcedf012
baseUrl: https://jenkins.example.com
username: backstage-bot
apikey: 123456789abcdef0123456789abcedf012
instances:
- name: departmentFoo
baseUrl: https://jenkins-foo.example.com
username: backstage-bot
apikey: 123456789abcdef0123456789abcedf012
```
#### Catalog
### Custom JenkinsInfoProvider
```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-lookup
annotations:
'jenkins.io/github-folder': departmentFoo#teamA/artistLookup-build
An example of a bespoke JenkinsInfoProvider which uses an organisation specific annotation to look up the jenkins info (including jobName):
```typescript
class AcmeJenkinsInfoProvider implements JenkinsInfoProvider {
constructor(private readonly catalog: CatalogClient) {}
async getInstance(opt: {
entityRef: EntityName;
jobName?: string;
}): Promise<JenkinsInfo> {
const PAAS_ANNOTATION = 'acme.example.com/paas-project-name';
// lookup pass-project-name from entity annotation
const entity = await this.catalog.getEntityByName(opt.entityRef);
if (!entity) {
throw new Error(
`Couldn't find entity with name: ${stringifyEntityRef(opt.entityRef)}`,
);
}
const paasProjectName = entity.metadata.annotations?.[PAAS_ANNOTATION];
if (!paasProjectName) {
throw new Error(
`Couldn't find paas annotation (${PAAS_ANNOTATION}) on entity with name: ${stringifyEntityRef(
opt.entityRef,
)}`,
);
}
// lookup department and team for paas project name
const { team, dept } = this.lookupPaasInfo(paasProjectName);
const baseUrl = `https://jenkins-${dept}.example.com/`;
const jobName = `${team}/${paasProjectName}`;
const username = 'backstage-bot';
const apiKey = this.getJenkinsApiKey(paasProjectName);
const creds = btoa(`${username}:${apiKey}`);
return {
baseUrl,
headers: {
Authorization: `Basic ${creds}`,
},
jobName,
};
}
private lookupPaasInfo(_: string): { team: string; dept: string } {
// Mock implementation, this would get info from the paas system somehow in reality.
return {
team: 'teamA',
dept: 'DepartmentFoo',
};
}
private getJenkinsApiKey(_: string): string {
// Mock implementation, this would get info from the paas system somehow in reality.
return '123456789abcdef0123456789abcedf012';
}
}
```
### AcmeJenkinsInfoProvider
No config would be needed if using this JenkinsInfoProvider
An example of a bespoke JenkinsInfoProvider which uses an organisation specific annotation to look up the jenkins info (including jobName)
#### Config
None needed
#### Catalog
A Catalog entity of the following will look for jobs for this entity at `https://jenkins-departmentFoo.example.com/job/teamA/job/artistLookupService`
```yaml
apiVersion: backstage.io/v1alpha1
@@ -150,8 +196,6 @@ metadata:
'acme.example.com/paas-project-name': artistLookupService
```
The following will look for jobs for this entity at `https://jenkins-departmentFoo.example.com/job/teamA/job/artistLookupService`
## Jenkins' terminology notes
The domain model for Jenkins is not particularly clear but for the purposes of this plugin the following model has been assumed: