Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-dashboard
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Logger } from 'winston';
|
||||
import { pickBy } from 'lodash';
|
||||
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { Config } from '@backstage/config';
|
||||
@@ -64,16 +65,20 @@ export class KeyStores {
|
||||
if (provider === 'firestore') {
|
||||
const settings = ks?.getConfig(provider);
|
||||
|
||||
const keyStore = await FirestoreKeyStore.create({
|
||||
projectId: settings?.getOptionalString('projectId'),
|
||||
keyFilename: settings?.getOptionalString('keyFilename'),
|
||||
host: settings?.getOptionalString('host'),
|
||||
port: settings?.getOptionalNumber('port'),
|
||||
ssl: settings?.getOptionalBoolean('ssl'),
|
||||
path: settings?.getOptionalString('path'),
|
||||
timeout: settings?.getOptionalNumber('timeout'),
|
||||
});
|
||||
|
||||
const keyStore = await FirestoreKeyStore.create(
|
||||
pickBy(
|
||||
{
|
||||
projectId: settings?.getOptionalString('projectId'),
|
||||
keyFilename: settings?.getOptionalString('keyFilename'),
|
||||
host: settings?.getOptionalString('host'),
|
||||
port: settings?.getOptionalNumber('port'),
|
||||
ssl: settings?.getOptionalBoolean('ssl'),
|
||||
path: settings?.getOptionalString('path'),
|
||||
timeout: settings?.getOptionalNumber('timeout'),
|
||||
},
|
||||
value => value !== undefined,
|
||||
),
|
||||
);
|
||||
await FirestoreKeyStore.verifyConnection(keyStore, logger);
|
||||
|
||||
return keyStore;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
```ts
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { BuildResult } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { BuildStatus } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { PullRequestStatus } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { PullRequest } from '@backstage/plugin-azure-devops-common';
|
||||
import { PullRequestOptions } from '@backstage/plugin-azure-devops-common';
|
||||
import { RepoBuild } from '@backstage/plugin-azure-devops-common';
|
||||
import { WebApi } from 'azure-devops-node-api';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AzureDevOpsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
@@ -29,8 +29,6 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
): Promise<GitRepository>;
|
||||
// Warning: (ae-forgotten-export) The symbol "PullRequestOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
@@ -45,48 +43,11 @@ export class AzureDevOpsApi {
|
||||
): Promise<RepoBuild[]>;
|
||||
}
|
||||
|
||||
export { BuildResult };
|
||||
|
||||
export { BuildStatus };
|
||||
|
||||
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuild" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
startTime?: Date;
|
||||
finishTime?: Date;
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.9.8",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/plugin-azure-devops-common": "^0.0.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"azure-devops-node-api": "^11.0.1",
|
||||
"express": "^4.17.1",
|
||||
|
||||
@@ -16,17 +16,21 @@
|
||||
|
||||
import {
|
||||
Build,
|
||||
DefinitionReference,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
GitPullRequest,
|
||||
GitRepository,
|
||||
PullRequest,
|
||||
PullRequestStatus,
|
||||
RepoBuild,
|
||||
} from './types';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitRepository,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { mappedPullRequest, mappedRepoBuild } from './AzureDevOpsApi';
|
||||
|
||||
import { DefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
|
||||
|
||||
describe('AzureDevOpsApi', () => {
|
||||
|
||||
@@ -15,17 +15,19 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
PullRequest,
|
||||
PullRequestOptions,
|
||||
RepoBuild,
|
||||
} from './types';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { Logger } from 'winston';
|
||||
import { WebApi } from 'azure-devops-node-api';
|
||||
|
||||
|
||||
@@ -15,5 +15,3 @@
|
||||
*/
|
||||
|
||||
export { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
export { BuildResult, BuildStatus } from './types';
|
||||
export type { RepoBuild, PullRequest } from './types';
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
PullRequestStatus,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
|
||||
export { BuildResult, BuildStatus, PullRequestStatus };
|
||||
export type {
|
||||
Build,
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
};
|
||||
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
startTime?: Date;
|
||||
finishTime?: Date;
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
@@ -13,6 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { AzureDevOpsApi, BuildResult, BuildStatus } from './api';
|
||||
export type { RepoBuild, PullRequest } from './api';
|
||||
export { AzureDevOpsApi } from './api';
|
||||
export * from './service/router';
|
||||
|
||||
@@ -14,22 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
import { createRouter } from './router';
|
||||
import { PullRequest, RepoBuild } from '../api/types';
|
||||
import {
|
||||
GitRepository,
|
||||
PullRequestStatus,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
PullRequest,
|
||||
PullRequestStatus,
|
||||
RepoBuild,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { createRouter } from './router';
|
||||
import express from 'express';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import request from 'supertest';
|
||||
|
||||
describe('createRouter', () => {
|
||||
let azureDevOpsApi: jest.Mocked<AzureDevOpsApi>;
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PullRequestOptions, PullRequestStatus } from '../api/types';
|
||||
import {
|
||||
PullRequestOptions,
|
||||
PullRequestStatus,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api';
|
||||
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
|
||||
@@ -27,6 +27,42 @@ export enum BuildStatus {
|
||||
Postponed = 8,
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequestOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequestStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export enum PullRequestStatus {
|
||||
Abandoned = 2,
|
||||
Active = 1,
|
||||
All = 4,
|
||||
Completed = 3,
|
||||
NotSet = 0,
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuild" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -43,5 +79,12 @@ export type RepoBuild = {
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuildOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -80,3 +80,49 @@ export type RepoBuild = {
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
|
||||
export enum PullRequestStatus {
|
||||
/**
|
||||
* Status not set. Default state.
|
||||
*/
|
||||
NotSet = 0,
|
||||
/**
|
||||
* Pull request is active.
|
||||
*/
|
||||
Active = 1,
|
||||
/**
|
||||
* Pull request is abandoned.
|
||||
*/
|
||||
Abandoned = 2,
|
||||
/**
|
||||
* Pull request is completed.
|
||||
*/
|
||||
Completed = 3,
|
||||
/**
|
||||
* Used in pull request search criteria to include all statuses.
|
||||
*/
|
||||
All = 4,
|
||||
}
|
||||
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"azure-devops-node-api": "^11.0.1",
|
||||
"luxon": "^2.0.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RepoBuild, RepoBuildOptions } from './types';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const azureDevOpsApiRef = createApiRef<AzureDevOpsApi>({
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { RepoBuild, RepoBuildOptions } from './types';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
|
||||
export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import { getBuildResultComponent, getBuildStateComponent } from './BuildTable';
|
||||
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
@@ -18,7 +18,8 @@ import { Box, Typography } from '@material-ui/core';
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
RepoBuild,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
Link,
|
||||
ResponseErrorPanel,
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
|
||||
import { DateTime } from 'luxon';
|
||||
import React from 'react';
|
||||
import { RepoBuild } from '../../api/types';
|
||||
|
||||
export const getBuildResultComponent = (result: number | undefined) => {
|
||||
switch (result) {
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RepoBuild, RepoBuildOptions } from '../api/types';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
@@ -158,7 +158,11 @@ export const CoverageHistoryChart = () => {
|
||||
margin={{ right: 48, top: 32 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="timestamp" tickFormatter={formatDateToHuman} />
|
||||
<XAxis
|
||||
dataKey="timestamp"
|
||||
tickFormatter={formatDateToHuman}
|
||||
reversed
|
||||
/>
|
||||
<YAxis dataKey="line.percentage" />
|
||||
<YAxis dataKey="branch.percentage" />
|
||||
<Tooltip labelFormatter={formatDateToHuman} />
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { getVoidLogger, loadBackendConfig } from '@backstage/backend-common';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { Config, ConfigReader } from '@backstage/config';
|
||||
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
import {
|
||||
ClusterDetails,
|
||||
FetchResponseWrapper,
|
||||
@@ -27,8 +27,8 @@ import {
|
||||
KubernetesServiceLocator,
|
||||
ObjectFetchParams,
|
||||
} from '../types/types';
|
||||
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
|
||||
import { KubernetesBuilder } from './KubernetesBuilder';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
|
||||
describe('KubernetesBuilder', () => {
|
||||
let app: express.Express;
|
||||
@@ -37,7 +37,12 @@ describe('KubernetesBuilder', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
const logger = getVoidLogger();
|
||||
config = await loadBackendConfig({ logger, argv: [] });
|
||||
config = new ConfigReader({
|
||||
kubernetes: {
|
||||
serviceLocatorMethod: { type: 'multiTenant' },
|
||||
clusterLocatorMethods: [{ type: 'config', clusters: [] }],
|
||||
},
|
||||
});
|
||||
|
||||
const clusters: ClusterDetails[] = [
|
||||
{
|
||||
|
||||
@@ -14,11 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
getVoidLogger,
|
||||
loadBackendConfig,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import { getVoidLogger, SingleHostDiscovery } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { Request, Response } from 'express';
|
||||
import * as http from 'http';
|
||||
import { createProxyMiddleware, Options } from 'http-proxy-middleware';
|
||||
@@ -35,7 +32,14 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction<
|
||||
describe('createRouter', () => {
|
||||
it('works', async () => {
|
||||
const logger = getVoidLogger();
|
||||
const config = await loadBackendConfig({ logger, argv: [] });
|
||||
const config = new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'https://example.com:7000',
|
||||
listen: {
|
||||
port: 7000,
|
||||
},
|
||||
},
|
||||
});
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const router = await createRouter({
|
||||
config,
|
||||
|
||||
+74
-6
@@ -254,7 +254,7 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with executable file', () => {
|
||||
describe('with executable file mode 755', () => {
|
||||
let input: GithubPullRequestActionInput;
|
||||
let ctx: ActionContext<GithubPullRequestActionInput>;
|
||||
|
||||
@@ -268,9 +268,9 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
|
||||
mockFs({
|
||||
[workspacePath]: {
|
||||
'file.txt': mockFs.file({
|
||||
content: 'Hello there!',
|
||||
mode: 33277, // File mode: 100755
|
||||
'hello.sh': mockFs.file({
|
||||
content: 'echo Hello there!',
|
||||
mode: 0o100755,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -297,8 +297,76 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
{
|
||||
commit: 'Create my new app',
|
||||
files: {
|
||||
'file.txt': {
|
||||
content: Buffer.from('Hello there!').toString('base64'),
|
||||
'hello.sh': {
|
||||
content: Buffer.from('echo Hello there!').toString('base64'),
|
||||
encoding: 'base64',
|
||||
mode: '100755',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('creates outputs for the url', async () => {
|
||||
await instance.handler(ctx);
|
||||
|
||||
expect(ctx.output).toHaveBeenCalledWith(
|
||||
'remoteUrl',
|
||||
'https://github.com/myorg/myrepo/pull/123',
|
||||
);
|
||||
});
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with executable file mode 775', () => {
|
||||
let input: GithubPullRequestActionInput;
|
||||
let ctx: ActionContext<GithubPullRequestActionInput>;
|
||||
|
||||
beforeEach(() => {
|
||||
input = {
|
||||
repoUrl: 'github.com?owner=myorg&repo=myrepo',
|
||||
title: 'Create my new app',
|
||||
branchName: 'new-app',
|
||||
description: 'This PR is really good',
|
||||
};
|
||||
|
||||
mockFs({
|
||||
[workspacePath]: {
|
||||
'hello.sh': mockFs.file({
|
||||
content: 'echo Hello there!',
|
||||
mode: 0o100775,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
ctx = {
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
output: jest.fn(),
|
||||
logger: getRootLogger(),
|
||||
logStream: new Writable(),
|
||||
input,
|
||||
workspacePath,
|
||||
};
|
||||
});
|
||||
it('creates a pull request', async () => {
|
||||
await instance.handler(ctx);
|
||||
|
||||
expect(fakeClient.createPullRequest).toHaveBeenCalledWith({
|
||||
owner: 'myorg',
|
||||
repo: 'myrepo',
|
||||
title: 'Create my new app',
|
||||
head: 'new-app',
|
||||
body: 'This PR is really good',
|
||||
changes: [
|
||||
{
|
||||
commit: 'Create my new app',
|
||||
files: {
|
||||
'hello.sh': {
|
||||
content: Buffer.from('echo Hello there!').toString('base64'),
|
||||
encoding: 'base64',
|
||||
mode: '100755',
|
||||
},
|
||||
|
||||
+4
-3
@@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { parseRepoUrl } from './util';
|
||||
import { parseRepoUrl, isExecutable } from './util';
|
||||
|
||||
import {
|
||||
GithubCredentialsProvider,
|
||||
@@ -202,10 +202,11 @@ export const createPublishGithubPullRequestAction = ({
|
||||
.readFileSync(absPath)
|
||||
.toString('base64');
|
||||
const fileStat = fs.statSync(absPath);
|
||||
const isExecutable = fileStat.mode === 33277; // aka. 100755
|
||||
// See the properties of tree items
|
||||
// in https://docs.github.com/en/rest/reference/git#trees
|
||||
const githubTreeItemMode = isExecutable ? '100755' : '100644';
|
||||
const githubTreeItemMode = isExecutable(fileStat.mode)
|
||||
? '100755'
|
||||
: '100644';
|
||||
// Always use base64 encoding to avoid doubling a binary file in size
|
||||
// due to interpreting a binary file as utf-8 and sending github
|
||||
// the utf-8 encoded content.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { getRepoSourceDirectory } from './util';
|
||||
import { getRepoSourceDirectory, isExecutable } from './util';
|
||||
|
||||
describe('getRepoSourceDirectory', () => {
|
||||
it('should return workspace root if no sub folder is given', () => {
|
||||
@@ -55,3 +55,33 @@ describe('getRepoSourceDirectory', () => {
|
||||
).toEqual(path.join('/', 'var', 'workspace', 'absolute', 'secret'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('isExecutable', () => {
|
||||
it('should return true for file mode 777', () => {
|
||||
expect(isExecutable(0o100777)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 775', () => {
|
||||
expect(isExecutable(0o100775)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 755', () => {
|
||||
expect(isExecutable(0o100755)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 700', () => {
|
||||
expect(isExecutable(0o100700)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 770', () => {
|
||||
expect(isExecutable(0o100770)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 670', () => {
|
||||
expect(isExecutable(0o100670)).toBe(true);
|
||||
});
|
||||
it('should return false for file mode 644', () => {
|
||||
expect(isExecutable(0o100644)).toBe(false);
|
||||
});
|
||||
it('should return false for file mode 600', () => {
|
||||
expect(isExecutable(0o100600)).toBe(false);
|
||||
});
|
||||
it('should return false for file mode 640', () => {
|
||||
expect(isExecutable(0o100640)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -101,3 +101,8 @@ export const parseRepoUrl = (
|
||||
|
||||
return { host, owner, repo, organization, workspace, project };
|
||||
};
|
||||
export const isExecutable = (fileMode: number) => {
|
||||
const executeBitMask = 0o000111;
|
||||
const res = fileMode & executeBitMask;
|
||||
return res > 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user