Merge pull request #21595 from awanlin/topic/use-host-org-everywhere
Added multi-org support
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-azure-devops-backend': patch
|
||||
'@backstage/plugin-azure-devops-common': patch
|
||||
'@backstage/plugin-azure-devops': patch
|
||||
---
|
||||
|
||||
Added multi-org support
|
||||
@@ -8,7 +8,7 @@ The following sections will help you get the Azure DevOps Backend plugin setup a
|
||||
|
||||
### Configuration
|
||||
|
||||
The Azure DevOps plugin requires the following YAML to be added to your app-config.yaml:
|
||||
The Azure DevOps plugin requires the following YAML to be added to your `app-config.yaml`:
|
||||
|
||||
```yaml
|
||||
azureDevOps:
|
||||
@@ -23,6 +23,12 @@ Configuration Details:
|
||||
- `AZURE_TOKEN` environment variable must be set to a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page) with read access to both Code and Build
|
||||
- `organization` is your Azure DevOps Services (cloud) Organization name or for Azure DevOps Server (on-premise) this will be your Collection name
|
||||
|
||||
#### Multi Organization
|
||||
|
||||
To support cases where you have multiple Azure DevOps organizations you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation.
|
||||
|
||||
**Note:** You will still need to define the [configuration above](#configuration).
|
||||
|
||||
### Up and Running
|
||||
|
||||
Here's how to get the backend up and running:
|
||||
@@ -112,6 +118,39 @@ The Azure DevOps backend plugin includes the `AzureDevOpsAnnotatorProcessor` whi
|
||||
}
|
||||
```
|
||||
|
||||
To use this with the New Backend System you'll want to create a [backend module extension for the Catalog](https://backstage.io/docs/backend-system/building-backends/migrating#other-catalog-extensions) if you haven't already. Here's a basic example of this assuming you are only adding the `AzureDevOpsAnnotatorProcessor`, this would go in your `packages/backend/index.ts`:
|
||||
|
||||
```diff
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
+ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
|
||||
+ import { coreServices, createBackendModule } from '@backstage/backend-plugin-api';
|
||||
+ import { AzureDevOpsAnnotatorProcessor } from '@backstage/plugin-azure-devops-backend';
|
||||
|
||||
+ const catalogModuleCustomExtensions = createBackendModule({
|
||||
+ pluginId: 'catalog', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'custom-extensions',
|
||||
+ register(env) {
|
||||
+ env.registerInit({
|
||||
+ deps: {
|
||||
+ catalog: catalogProcessingExtensionPoint,
|
||||
+ config: coreServices.rootConfig,
|
||||
+ },
|
||||
+ async init({ catalog, config }) {
|
||||
+ catalog.addProcessor(AzureDevOpsAnnotatorProcessor.fromConfig(config));
|
||||
+ },
|
||||
+ });
|
||||
+ },
|
||||
+ });
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
// ... other feature additions
|
||||
|
||||
+ backend.add(catalogModuleCustomExtensions());
|
||||
|
||||
backend.start();
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/azure-devops)
|
||||
|
||||
@@ -60,12 +60,16 @@ export class AzureDevOpsApi {
|
||||
getBuildDefinitions(
|
||||
projectName: string,
|
||||
definitionName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<BuildDefinitionReference[]>;
|
||||
// (undocumented)
|
||||
getBuildList(
|
||||
projectName: string,
|
||||
repoId: string,
|
||||
top: number,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<Build[]>;
|
||||
// (undocumented)
|
||||
getBuildRuns(
|
||||
@@ -73,6 +77,8 @@ export class AzureDevOpsApi {
|
||||
top: number,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<BuildRun[]>;
|
||||
// (undocumented)
|
||||
getBuilds(
|
||||
@@ -80,6 +86,8 @@ export class AzureDevOpsApi {
|
||||
top: number,
|
||||
repoId?: string,
|
||||
definitions?: number[],
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<Build[]>;
|
||||
// (undocumented)
|
||||
getDashboardPullRequests(
|
||||
@@ -90,16 +98,25 @@ export class AzureDevOpsApi {
|
||||
getGitRepository(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<GitRepository>;
|
||||
// (undocumented)
|
||||
getGitTags(projectName: string, repoName: string): Promise<GitTag[]>;
|
||||
getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<GitTag[]>;
|
||||
// (undocumented)
|
||||
getProjects(): Promise<Project[]>;
|
||||
getProjects(host?: string, org?: string): Promise<Project[]>;
|
||||
// (undocumented)
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
options: PullRequestOptions,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<PullRequest[]>;
|
||||
// (undocumented)
|
||||
getReadme(
|
||||
@@ -116,6 +133,8 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
top: number,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<RepoBuild[]>;
|
||||
// (undocumented)
|
||||
getTeamMembers(options: {
|
||||
|
||||
@@ -130,8 +130,8 @@ export class AzureDevOpsApi {
|
||||
return webApi;
|
||||
}
|
||||
|
||||
public async getProjects(): Promise<Project[]> {
|
||||
const webApi = await this.getWebApi();
|
||||
public async getProjects(host?: string, org?: string): Promise<Project[]> {
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getCoreApi();
|
||||
const projectList: TeamProjectReference[] = await client.getProjects();
|
||||
|
||||
@@ -149,12 +149,14 @@ export class AzureDevOpsApi {
|
||||
public async getGitRepository(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<GitRepository> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting Repository ${repoName} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const webApi = await this.getWebApi();
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getGitApi();
|
||||
return client.getRepository(repoName, projectName);
|
||||
}
|
||||
@@ -163,12 +165,14 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoId: string,
|
||||
top: number,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<Build[]> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const webApi = await this.getWebApi();
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getBuildApi();
|
||||
return client.getBuilds(
|
||||
projectName,
|
||||
@@ -199,16 +203,25 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
top: number,
|
||||
host?: string,
|
||||
org?: string,
|
||||
) {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting up to ${top} Builds for Repository ${repoName} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const gitRepository = await this.getGitRepository(projectName, repoName);
|
||||
const gitRepository = await this.getGitRepository(
|
||||
projectName,
|
||||
repoName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
const buildList = await this.getBuildList(
|
||||
projectName,
|
||||
gitRepository.id as string,
|
||||
top,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
|
||||
const repoBuilds: RepoBuild[] = buildList.map(build => {
|
||||
@@ -221,13 +234,20 @@ export class AzureDevOpsApi {
|
||||
public async getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<GitTag[]> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting Git Tags for Repository ${repoName} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const gitRepository = await this.getGitRepository(projectName, repoName);
|
||||
const webApi = await this.getWebApi();
|
||||
const gitRepository = await this.getGitRepository(
|
||||
projectName,
|
||||
repoName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getGitApi();
|
||||
const tagRefs: GitRef[] = await client.getRefs(
|
||||
gitRepository.id as string,
|
||||
@@ -256,13 +276,20 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
options: PullRequestOptions,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<PullRequest[]> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting up to ${options.top} Pull Requests for Repository ${repoName} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const gitRepository = await this.getGitRepository(projectName, repoName);
|
||||
const webApi = await this.getWebApi();
|
||||
const gitRepository = await this.getGitRepository(
|
||||
projectName,
|
||||
repoName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getGitApi();
|
||||
const searchCriteria: GitPullRequestSearchCriteria = {
|
||||
status: options.status,
|
||||
@@ -397,12 +424,14 @@ export class AzureDevOpsApi {
|
||||
public async getBuildDefinitions(
|
||||
projectName: string,
|
||||
definitionName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<BuildDefinitionReference[]> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting Build Definitions for ${definitionName} in Project ${projectName}`,
|
||||
);
|
||||
|
||||
const webApi = await this.getWebApi();
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getBuildApi();
|
||||
return client.getDefinitions(projectName, definitionName);
|
||||
}
|
||||
@@ -412,12 +441,14 @@ export class AzureDevOpsApi {
|
||||
top: number,
|
||||
repoId?: string,
|
||||
definitions?: number[],
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<Build[]> {
|
||||
this.logger?.debug(
|
||||
`Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`,
|
||||
);
|
||||
|
||||
const webApi = await this.getWebApi();
|
||||
const webApi = await this.getWebApi(host, org);
|
||||
const client = await webApi.getBuildApi();
|
||||
return client.getBuilds(
|
||||
projectName,
|
||||
@@ -449,12 +480,19 @@ export class AzureDevOpsApi {
|
||||
top: number,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
) {
|
||||
let repoId: string | undefined;
|
||||
let definitions: number[] | undefined;
|
||||
|
||||
if (repoName) {
|
||||
const gitRepository = await this.getGitRepository(projectName, repoName);
|
||||
const gitRepository = await this.getGitRepository(
|
||||
projectName,
|
||||
repoName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
repoId = gitRepository.id;
|
||||
}
|
||||
|
||||
@@ -462,13 +500,22 @@ export class AzureDevOpsApi {
|
||||
const buildDefinitions = await this.getBuildDefinitions(
|
||||
projectName,
|
||||
definitionName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
definitions = buildDefinitions
|
||||
.map(bd => bd.id)
|
||||
.filter((bd): bd is number => Boolean(bd));
|
||||
}
|
||||
|
||||
const builds = await this.getBuilds(projectName, top, repoId, definitions);
|
||||
const builds = await this.getBuilds(
|
||||
projectName,
|
||||
top,
|
||||
repoId,
|
||||
definitions,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
|
||||
const buildRuns: BuildRun[] = builds.map(mappedBuildRun);
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ describe('createRouter', () => {
|
||||
'myProject',
|
||||
'af4ae3af-e747-4129-9bbc-d1329f6b0998',
|
||||
40,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(builds);
|
||||
@@ -215,6 +217,8 @@ describe('createRouter', () => {
|
||||
'myProject',
|
||||
'myRepo',
|
||||
50,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(repoBuilds);
|
||||
@@ -252,6 +256,8 @@ describe('createRouter', () => {
|
||||
expect(azureDevOpsApi.getGitTags).toHaveBeenCalledWith(
|
||||
'myProject',
|
||||
'myRepo',
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(gitTags);
|
||||
@@ -315,6 +321,8 @@ describe('createRouter', () => {
|
||||
'myProject',
|
||||
'myRepo',
|
||||
{ status: 1, top: 50 },
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(pullRequests);
|
||||
@@ -341,6 +349,8 @@ describe('createRouter', () => {
|
||||
expect(azureDevOpsApi.getBuildDefinitions).toHaveBeenCalledWith(
|
||||
'myProject',
|
||||
'myBuildDefinition',
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(inputDefinitions);
|
||||
@@ -397,6 +407,8 @@ describe('createRouter', () => {
|
||||
50,
|
||||
'myRepo',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(buildRuns);
|
||||
@@ -452,6 +464,8 @@ describe('createRouter', () => {
|
||||
50,
|
||||
undefined,
|
||||
'myDefinition',
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual(buildRuns);
|
||||
|
||||
@@ -75,10 +75,14 @@ export async function createRouter(
|
||||
router.get('/builds/:projectName/:repoId', async (req, res) => {
|
||||
const { projectName, repoId } = req.params;
|
||||
const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP;
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const buildList = await azureDevOpsApi.getBuildList(
|
||||
projectName,
|
||||
repoId,
|
||||
top,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
res.status(200).json(buildList);
|
||||
});
|
||||
@@ -87,11 +91,14 @@ export async function createRouter(
|
||||
const { projectName, repoName } = req.params;
|
||||
|
||||
const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP;
|
||||
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const gitRepository = await azureDevOpsApi.getRepoBuilds(
|
||||
projectName,
|
||||
repoName,
|
||||
top,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
|
||||
res.status(200).json(gitRepository);
|
||||
@@ -99,7 +106,14 @@ export async function createRouter(
|
||||
|
||||
router.get('/git-tags/:projectName/:repoName', async (req, res) => {
|
||||
const { projectName, repoName } = req.params;
|
||||
const gitTags = await azureDevOpsApi.getGitTags(projectName, repoName);
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const gitTags = await azureDevOpsApi.getGitTags(
|
||||
projectName,
|
||||
repoName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
res.status(200).json(gitTags);
|
||||
});
|
||||
|
||||
@@ -107,7 +121,8 @@ export async function createRouter(
|
||||
const { projectName, repoName } = req.params;
|
||||
|
||||
const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP;
|
||||
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const status = req.query.status
|
||||
? Number(req.query.status)
|
||||
: PullRequestStatus.Active;
|
||||
@@ -121,6 +136,8 @@ export async function createRouter(
|
||||
projectName,
|
||||
repoName,
|
||||
pullRequestOptions,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
|
||||
res.status(200).json(gitPullRequest);
|
||||
@@ -158,9 +175,13 @@ export async function createRouter(
|
||||
'/build-definitions/:projectName/:definitionName',
|
||||
async (req, res) => {
|
||||
const { projectName, definitionName } = req.params;
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const buildDefinitionList = await azureDevOpsApi.getBuildDefinitions(
|
||||
projectName,
|
||||
definitionName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
res.status(200).json(buildDefinitionList);
|
||||
},
|
||||
@@ -171,11 +192,15 @@ export async function createRouter(
|
||||
const repoName = req.query.repoName?.toString();
|
||||
const definitionName = req.query.definitionName?.toString();
|
||||
const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP;
|
||||
const host = req.query.host?.toString();
|
||||
const org = req.query.org?.toString();
|
||||
const builds = await azureDevOpsApi.getBuildRuns(
|
||||
projectName,
|
||||
top,
|
||||
repoName,
|
||||
definitionName,
|
||||
host,
|
||||
org,
|
||||
);
|
||||
res.status(200).json(builds);
|
||||
});
|
||||
@@ -187,12 +212,14 @@ export async function createRouter(
|
||||
});
|
||||
|
||||
router.get('/readme/:projectName/:repoName', async (req, res) => {
|
||||
const host = config.getString('azureDevOps.host');
|
||||
const organization = config.getString('azureDevOps.organization');
|
||||
const host =
|
||||
req.query.host?.toString() ?? config.getString('azureDevOps.host');
|
||||
const org =
|
||||
req.query.org?.toString() ?? config.getString('azureDevOps.organization');
|
||||
const { projectName, repoName } = req.params;
|
||||
const readme = await azureDevOpsApi.getReadme(
|
||||
host,
|
||||
organization,
|
||||
org,
|
||||
projectName,
|
||||
repoName,
|
||||
);
|
||||
|
||||
@@ -223,6 +223,10 @@ export interface Readme {
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ReadmeConfig {
|
||||
// (undocumented)
|
||||
host?: string;
|
||||
// (undocumented)
|
||||
org?: string;
|
||||
// (undocumented)
|
||||
project: string;
|
||||
// (undocumented)
|
||||
|
||||
@@ -210,6 +210,8 @@ export interface Team {
|
||||
export interface ReadmeConfig {
|
||||
project: string;
|
||||
repo: string;
|
||||
host?: string;
|
||||
org?: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -72,6 +72,53 @@ dev.azure.com/build-definition: <build-definition-name>
|
||||
|
||||
In this case `<project-name>` will be the name of your Team Project and `<build-definition-name>` will be the name of the Build Definition you would like to see Builds for, and it's possible to add more Builds separated by a comma. If the Build Definition name has spaces in it make sure to put quotes around it.
|
||||
|
||||
#### Multiple Organizations
|
||||
|
||||
If you have multiple organizations you'll need to also add this annotation:
|
||||
|
||||
```yaml
|
||||
dev.azure.com/host-org: <host>/<organization>
|
||||
```
|
||||
|
||||
For this annotation `<host>` will match the `host` value in the `integrations.azure` section in your `app-config.yaml` and `<organization>` will be the name of the Organization that is part of the `host`. Let's break this down with an example:
|
||||
|
||||
Say we have the following `integrations.azure` section:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
credentials:
|
||||
- organizations:
|
||||
- my-org
|
||||
- my-other-org
|
||||
clientId: ${AZURE_CLIENT_ID}
|
||||
clientSecret: ${AZURE_CLIENT_SECRET}
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
- organizations:
|
||||
- another-org
|
||||
clientId: ${AZURE_CLIENT_ID}
|
||||
- host: server.company.com
|
||||
credentials:
|
||||
- organizations:
|
||||
- yet-another-org
|
||||
personalAccessToken: ${PERSONAL_ACCESS_TOKEN}
|
||||
```
|
||||
|
||||
If the entity we are viewing lives in the `my-other-org` organization then the `dev.azure.com/host-org` annotation would look like this:
|
||||
|
||||
```yaml
|
||||
dev.azure.com/host-org: dev.azure.com/my-other-org
|
||||
```
|
||||
|
||||
And if the entity was from `yet-another-org` it would look like this:
|
||||
|
||||
```yaml
|
||||
dev.azure.com/host-org: server.company.com/yet-another-org
|
||||
```
|
||||
|
||||
**Note:** To save you time, effort, and confusion setting up these annotations manually you can use the `AzureDevOpsAnnotatorProcessor` processor which will add the `dev.azure.com/host-org` and `dev.azure.com/project-repo` annotations for you with the correct values. The Azure DevOps backend plugin has details on how to [add this processor](https://github.com/backstage/backstage/tree/master/plugins/azure-devops-backend#processor).
|
||||
|
||||
### Azure Pipelines Component
|
||||
|
||||
To get the Azure Pipelines component working you'll need to do the following two steps:
|
||||
@@ -247,8 +294,3 @@ To get the README component working you'll need to do the following two steps:
|
||||
- You'll need to add the `EntitySwitch.Case` above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
|
||||
- The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
|
||||
- The `maxHeight` property on the `EntityAzureReadmeCard` will set the maximum screen size you would like to see, if not set it will default to 100%
|
||||
|
||||
## Limitations
|
||||
|
||||
- Currently multiple organizations are not supported
|
||||
- Mixing Azure DevOps Services (cloud) and Azure DevOps Server (on-premise) is not supported
|
||||
|
||||
@@ -71,6 +71,8 @@ export interface AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: BuildRunOptions,
|
||||
): Promise<{
|
||||
items: BuildRun[];
|
||||
@@ -83,6 +85,8 @@ export interface AzureDevOpsApi {
|
||||
getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<{
|
||||
items: GitTag[];
|
||||
}>;
|
||||
@@ -90,6 +94,8 @@ export interface AzureDevOpsApi {
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: PullRequestOptions,
|
||||
): Promise<{
|
||||
items: PullRequest[];
|
||||
@@ -100,6 +106,8 @@ export interface AzureDevOpsApi {
|
||||
getRepoBuilds(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: RepoBuildOptions,
|
||||
): Promise<{
|
||||
items: RepoBuild[];
|
||||
@@ -124,6 +132,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: BuildRunOptions,
|
||||
): Promise<{
|
||||
items: BuildRun[];
|
||||
@@ -136,6 +146,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<{
|
||||
items: GitTag[];
|
||||
}>;
|
||||
@@ -143,6 +155,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: PullRequestOptions,
|
||||
): Promise<{
|
||||
items: PullRequest[];
|
||||
@@ -153,6 +167,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
getRepoBuilds(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: RepoBuildOptions,
|
||||
): Promise<{
|
||||
items: RepoBuild[];
|
||||
|
||||
@@ -40,17 +40,23 @@ export interface AzureDevOpsApi {
|
||||
getRepoBuilds(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: RepoBuildOptions,
|
||||
): Promise<{ items: RepoBuild[] }>;
|
||||
|
||||
getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<{ items: GitTag[] }>;
|
||||
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: PullRequestOptions,
|
||||
): Promise<{ items: PullRequest[] }>;
|
||||
|
||||
@@ -66,6 +72,8 @@ export interface AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: BuildRunOptions,
|
||||
): Promise<{ items: BuildRun[] }>;
|
||||
|
||||
|
||||
@@ -47,12 +47,20 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
public async getRepoBuilds(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: RepoBuildOptions,
|
||||
): Promise<{ items: RepoBuild[] }> {
|
||||
const queryString = new URLSearchParams();
|
||||
if (options?.top) {
|
||||
queryString.append('top', options.top.toString());
|
||||
}
|
||||
if (host) {
|
||||
queryString.append('host', host);
|
||||
}
|
||||
if (org) {
|
||||
queryString.append('org', org);
|
||||
}
|
||||
const urlSegment = `repo-builds/${encodeURIComponent(
|
||||
projectName,
|
||||
)}/${encodeURIComponent(repoName)}?${queryString}`;
|
||||
@@ -64,10 +72,19 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
public async getGitTags(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
): Promise<{ items: GitTag[] }> {
|
||||
const queryString = new URLSearchParams();
|
||||
if (host) {
|
||||
queryString.append('host', host);
|
||||
}
|
||||
if (org) {
|
||||
queryString.append('org', org);
|
||||
}
|
||||
const urlSegment = `git-tags/${encodeURIComponent(
|
||||
projectName,
|
||||
)}/${encodeURIComponent(repoName)}`;
|
||||
)}/${encodeURIComponent(repoName)}?${queryString}`;
|
||||
|
||||
const items = await this.get<GitTag[]>(urlSegment);
|
||||
return { items };
|
||||
@@ -76,6 +93,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
public async getPullRequests(
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: PullRequestOptions,
|
||||
): Promise<{ items: PullRequest[] }> {
|
||||
const queryString = new URLSearchParams();
|
||||
@@ -85,6 +104,12 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
if (options?.status) {
|
||||
queryString.append('status', options.status.toString());
|
||||
}
|
||||
if (host) {
|
||||
queryString.append('host', host);
|
||||
}
|
||||
if (org) {
|
||||
queryString.append('org', org);
|
||||
}
|
||||
const urlSegment = `pull-requests/${encodeURIComponent(
|
||||
projectName,
|
||||
)}/${encodeURIComponent(repoName)}?${queryString}`;
|
||||
@@ -113,12 +138,20 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName?: string,
|
||||
definitionName?: string,
|
||||
host?: string,
|
||||
org?: string,
|
||||
options?: BuildRunOptions,
|
||||
): Promise<{ items: BuildRun[] }> {
|
||||
const queryString = new URLSearchParams();
|
||||
if (repoName) {
|
||||
queryString.append('repoName', repoName);
|
||||
}
|
||||
if (host) {
|
||||
queryString.append('host', host);
|
||||
}
|
||||
if (org) {
|
||||
queryString.append('org', org);
|
||||
}
|
||||
if (definitionName) {
|
||||
const definitionNames = definitionName.split(',');
|
||||
if (definitionNames.length > 1) {
|
||||
@@ -149,10 +182,17 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
}
|
||||
|
||||
public async getReadme(opts: ReadmeConfig): Promise<Readme> {
|
||||
const queryString = new URLSearchParams();
|
||||
if (opts.host) {
|
||||
queryString.append('host', opts.host);
|
||||
}
|
||||
if (opts.org) {
|
||||
queryString.append('org', opts.org);
|
||||
}
|
||||
return await this.get(
|
||||
`readme/${encodeURIComponent(opts.project)}/${encodeURIComponent(
|
||||
opts.repo,
|
||||
)}`,
|
||||
)}?${queryString}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ export function useBuildRuns(
|
||||
const api = useApi(azureDevOpsApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
const { project, repo, definition } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getBuildRuns(project, repo, definition, options);
|
||||
const { project, repo, definition, host, org } =
|
||||
getAnnotationValuesFromEntity(entity);
|
||||
return api.getBuildRuns(project, repo, definition, host, org, options);
|
||||
}, [api]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -30,8 +30,8 @@ export function useGitTags(entity: Entity): {
|
||||
const api = useApi(azureDevOpsApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
const { project, repo } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getGitTags(project, repo as string);
|
||||
const { project, repo, host, org } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getGitTags(project, repo as string, host, org);
|
||||
}, [api]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -46,8 +46,8 @@ export function usePullRequests(
|
||||
const api = useApi(azureDevOpsApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
const { project, repo } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getPullRequests(project, repo as string, options);
|
||||
const { project, repo, host, org } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getPullRequests(project, repo as string, host, org, options);
|
||||
}, [api, top, status]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -30,8 +30,8 @@ export function useReadme(entity: Entity): {
|
||||
const api = useApi(azureDevOpsApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
const { project, repo } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getReadme({ project, repo: repo as string });
|
||||
const { project, repo, host, org } = getAnnotationValuesFromEntity(entity);
|
||||
return api.getReadme({ project, repo: repo as string, host, org });
|
||||
}, [api]);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user