Merge branch 'master' of github.com:backstage/backstage into update-docs
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
"fs-extra": "^9.0.1",
|
||||
"git-url-parse": "^11.4.3",
|
||||
"helmet": "^4.0.0",
|
||||
"isomorphic-git": "^1.8.0",
|
||||
"knex": "^0.21.6",
|
||||
"lodash": "^4.17.15",
|
||||
"logform": "^2.1.1",
|
||||
|
||||
@@ -24,3 +24,4 @@ export * from './reading';
|
||||
export * from './service';
|
||||
export * from './paths';
|
||||
export * from './hot';
|
||||
export * from './scm';
|
||||
|
||||
@@ -17,19 +17,23 @@ import * as winston from 'winston';
|
||||
import { TransformableInfo } from 'logform';
|
||||
|
||||
const coloredTemplate = (info: TransformableInfo) => {
|
||||
const { timestamp, level, message, plugin, service } = info;
|
||||
const { timestamp, level, message, plugin, service, ...fields } = info;
|
||||
const colorizer = winston.format.colorize();
|
||||
const prefix = plugin || service;
|
||||
const timestampColor = colorizer.colorize('timestamp', timestamp);
|
||||
const prefixColor = colorizer.colorize('prefix', prefix);
|
||||
|
||||
return `${timestampColor} ${prefixColor} ${level} ${message}`;
|
||||
const extraFields = Object.entries(fields)
|
||||
.map(([key, value]) => `${colorizer.colorize('field', `${key}`)}=${value}`)
|
||||
.join(' ');
|
||||
|
||||
return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`;
|
||||
};
|
||||
|
||||
export const coloredFormat = winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.colorize({
|
||||
colors: { timestamp: 'dim', prefix: 'blue' },
|
||||
colors: { timestamp: 'dim', prefix: 'blue', field: 'cyan' },
|
||||
}),
|
||||
winston.format.printf(coloredTemplate),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
jest.mock('isomorphic-git');
|
||||
jest.mock('isomorphic-git/http/node');
|
||||
jest.mock('fs-extra');
|
||||
|
||||
import * as isomorphic from 'isomorphic-git';
|
||||
import { Git } from './git';
|
||||
import http from 'isomorphic-git/http/node';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
describe('Git', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
describe('add', () => {
|
||||
it('should call isomorphic-git add with the correct arguments', async () => {
|
||||
const git = Git.fromAuth({});
|
||||
const dir = 'mockdirectory';
|
||||
const filepath = 'mockfile/path';
|
||||
|
||||
await git.add({ dir, filepath });
|
||||
|
||||
expect(isomorphic.add).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
filepath,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addRemote', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const git = Git.fromAuth({});
|
||||
const dir = 'mockdirectory';
|
||||
const remote = 'origin';
|
||||
const url = 'git@github.com/something/sads';
|
||||
|
||||
await git.addRemote({ dir, remote, url });
|
||||
|
||||
expect(isomorphic.addRemote).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
remote,
|
||||
url,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('commit', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const git = Git.fromAuth({});
|
||||
const dir = 'mockdirectory';
|
||||
const message = 'Inital Commit';
|
||||
const author = {
|
||||
name: 'author',
|
||||
email: 'test@backstage.io',
|
||||
};
|
||||
const committer = {
|
||||
name: 'comitter',
|
||||
email: 'test@backstage.io',
|
||||
};
|
||||
|
||||
await git.commit({ dir, message, author, committer });
|
||||
|
||||
expect(isomorphic.commit).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
message,
|
||||
author,
|
||||
committer,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('clone', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const url = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.clone({ url, dir });
|
||||
|
||||
expect(isomorphic.clone).toHaveBeenCalledWith({
|
||||
fs,
|
||||
http,
|
||||
url,
|
||||
dir,
|
||||
singleBranch: true,
|
||||
depth: 1,
|
||||
onProgress: expect.any(Function),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
onAuth: expect.any(Function),
|
||||
});
|
||||
});
|
||||
it('should pass a function that returns the authorization as the onAuth handler', async () => {
|
||||
const url = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.clone({ url, dir });
|
||||
|
||||
const { onAuth } = ((isomorphic.clone as unknown) as jest.Mock<
|
||||
typeof isomorphic['clone']
|
||||
>).mock.calls[0][0]!;
|
||||
|
||||
expect(onAuth()).toEqual(auth);
|
||||
});
|
||||
});
|
||||
|
||||
describe('currentBranch', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
const fullName = true;
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.currentBranch({ dir, fullName });
|
||||
|
||||
expect(isomorphic.currentBranch).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
fullname: true,
|
||||
});
|
||||
|
||||
await git.currentBranch({ dir });
|
||||
|
||||
expect(isomorphic.currentBranch).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
fullname: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetch', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const remote = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.fetch({ remote, dir });
|
||||
|
||||
expect(isomorphic.fetch).toHaveBeenCalledWith({
|
||||
fs,
|
||||
http,
|
||||
remote,
|
||||
dir,
|
||||
onProgress: expect.any(Function),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
onAuth: expect.any(Function),
|
||||
});
|
||||
});
|
||||
it('should pass a function that returns the authorization as the onAuth handler', async () => {
|
||||
const remote = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.fetch({ remote, dir });
|
||||
|
||||
const { onAuth } = ((isomorphic.fetch as unknown) as jest.Mock<
|
||||
typeof isomorphic['fetch']
|
||||
>).mock.calls[0][0]!;
|
||||
|
||||
expect(onAuth()).toEqual(auth);
|
||||
});
|
||||
});
|
||||
|
||||
describe('init', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.init({ dir });
|
||||
|
||||
expect(isomorphic.init).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('merge', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
const author = {
|
||||
name: 'author',
|
||||
email: 'test@backstage.io',
|
||||
};
|
||||
const committer = {
|
||||
name: 'comitter',
|
||||
email: 'test@backstage.io',
|
||||
};
|
||||
const theirs = 'master';
|
||||
const ours = 'production';
|
||||
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.merge({ dir, theirs, ours, author, committer });
|
||||
|
||||
expect(isomorphic.merge).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
ours,
|
||||
theirs,
|
||||
author,
|
||||
committer,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('push', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const remote = 'origin';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.push({ dir, remote });
|
||||
|
||||
expect(isomorphic.push).toHaveBeenCalledWith({
|
||||
fs,
|
||||
http,
|
||||
remote,
|
||||
dir,
|
||||
onProgress: expect.any(Function),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
onAuth: expect.any(Function),
|
||||
});
|
||||
});
|
||||
it('should pass a function that returns the authorization as the onAuth handler', async () => {
|
||||
const remote = 'origin';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'blob',
|
||||
password: 'hunter2',
|
||||
};
|
||||
const git = Git.fromAuth(auth);
|
||||
|
||||
await git.push({ remote, dir });
|
||||
|
||||
const { onAuth } = ((isomorphic.push as unknown) as jest.Mock<
|
||||
typeof isomorphic['push']
|
||||
>).mock.calls[0][0]!;
|
||||
|
||||
expect(onAuth()).toEqual(auth);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readCommit', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
const sha = 'as43bd7';
|
||||
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.readCommit({ dir, sha });
|
||||
|
||||
expect(isomorphic.readCommit).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
oid: sha,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRef', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
const ref = 'as43bd7';
|
||||
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.resolveRef({ dir, ref });
|
||||
|
||||
expect(isomorphic.resolveRef).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
ref,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 git, {
|
||||
ProgressCallback,
|
||||
MergeResult,
|
||||
ReadCommitResult,
|
||||
} from 'isomorphic-git';
|
||||
import http from 'isomorphic-git/http/node';
|
||||
import fs from 'fs-extra';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
/*
|
||||
provider username password
|
||||
GitHub token 'x-oauth-basic'
|
||||
GitHub App token 'x-access-token'
|
||||
BitBucket 'x-token-auth' token
|
||||
GitLab 'oauth2' token
|
||||
From : https://isomorphic-git.org/docs/en/onAuth
|
||||
|
||||
Azure 'notempty' token
|
||||
*/
|
||||
export class Git {
|
||||
private constructor(
|
||||
private readonly config: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
logger?: Logger;
|
||||
},
|
||||
) {}
|
||||
|
||||
async add({
|
||||
dir,
|
||||
filepath,
|
||||
}: {
|
||||
dir: string;
|
||||
filepath: string;
|
||||
}): Promise<void> {
|
||||
this.config.logger?.info(`Adding file {dir=${dir},filepath=${filepath}}`);
|
||||
|
||||
return git.add({ fs, dir, filepath });
|
||||
}
|
||||
|
||||
async addRemote({
|
||||
dir,
|
||||
url,
|
||||
remote,
|
||||
}: {
|
||||
dir: string;
|
||||
remote: string;
|
||||
url: string;
|
||||
}): Promise<void> {
|
||||
this.config.logger?.info(
|
||||
`Creating new remote {dir=${dir},remote=${remote},url=${url}}`,
|
||||
);
|
||||
return git.addRemote({ fs, dir, remote, url });
|
||||
}
|
||||
|
||||
async commit({
|
||||
dir,
|
||||
message,
|
||||
author,
|
||||
committer,
|
||||
}: {
|
||||
dir: string;
|
||||
message: string;
|
||||
author: { name: string; email: string };
|
||||
committer: { name: string; email: string };
|
||||
}): Promise<string> {
|
||||
this.config.logger?.info(
|
||||
`Committing file to repo {dir=${dir},message=${message}}`,
|
||||
);
|
||||
|
||||
return git.commit({ fs, dir, message, author, committer });
|
||||
}
|
||||
|
||||
async clone({ url, dir }: { url: string; dir: string }): Promise<void> {
|
||||
this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`);
|
||||
return git.clone({
|
||||
fs,
|
||||
http,
|
||||
url,
|
||||
dir,
|
||||
singleBranch: true,
|
||||
depth: 1,
|
||||
onProgress: this.onProgressHandler(),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
onAuth: this.onAuth,
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/currentBranch
|
||||
async currentBranch({
|
||||
dir,
|
||||
fullName,
|
||||
}: {
|
||||
dir: string;
|
||||
fullName?: boolean;
|
||||
}): Promise<string | undefined> {
|
||||
const fullname = fullName ?? false;
|
||||
return git.currentBranch({ fs, dir, fullname }) as Promise<
|
||||
string | undefined
|
||||
>;
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/fetch
|
||||
async fetch({
|
||||
dir,
|
||||
remote,
|
||||
}: {
|
||||
dir: string;
|
||||
remote?: string;
|
||||
}): Promise<void> {
|
||||
const remoteValue = remote ?? 'origin';
|
||||
this.config.logger?.info(
|
||||
`Fetching remote=${remoteValue} for repository {dir=${dir}}`,
|
||||
);
|
||||
await git.fetch({
|
||||
fs,
|
||||
http,
|
||||
dir,
|
||||
remote: remoteValue,
|
||||
onProgress: this.onProgressHandler(),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
onAuth: this.onAuth,
|
||||
});
|
||||
}
|
||||
|
||||
async init({ dir }: { dir: string }): Promise<void> {
|
||||
this.config.logger?.info(`Init git repository {dir=${dir}}`);
|
||||
|
||||
return git.init({
|
||||
fs,
|
||||
dir,
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/merge
|
||||
async merge({
|
||||
dir,
|
||||
theirs,
|
||||
ours,
|
||||
author,
|
||||
committer,
|
||||
}: {
|
||||
dir: string;
|
||||
theirs: string;
|
||||
ours?: string;
|
||||
author: { name: string; email: string };
|
||||
committer: { name: string; email: string };
|
||||
}): Promise<MergeResult> {
|
||||
this.config.logger?.info(
|
||||
`Merging branch '${theirs}' into '${ours}' for repository {dir=${dir}}`,
|
||||
);
|
||||
|
||||
// If ours is undefined, current branch is used.
|
||||
return git.merge({
|
||||
fs,
|
||||
dir,
|
||||
ours,
|
||||
theirs,
|
||||
author,
|
||||
committer,
|
||||
});
|
||||
}
|
||||
|
||||
async push({ dir, remote }: { dir: string; remote: string }) {
|
||||
this.config.logger?.info(
|
||||
`Pushing directory to remote {dir=${dir},remote=${remote}}`,
|
||||
);
|
||||
return git.push({
|
||||
fs,
|
||||
dir,
|
||||
http,
|
||||
onProgress: this.onProgressHandler(),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
},
|
||||
remote: remote,
|
||||
onAuth: this.onAuth,
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/readCommit
|
||||
async readCommit({
|
||||
dir,
|
||||
sha,
|
||||
}: {
|
||||
dir: string;
|
||||
sha: string;
|
||||
}): Promise<ReadCommitResult> {
|
||||
return git.readCommit({ fs, dir, oid: sha });
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/resolveRef
|
||||
async resolveRef({
|
||||
dir,
|
||||
ref,
|
||||
}: {
|
||||
dir: string;
|
||||
ref: string;
|
||||
}): Promise<string> {
|
||||
return git.resolveRef({ fs, dir, ref });
|
||||
}
|
||||
|
||||
private onAuth = () => ({
|
||||
username: this.config.username,
|
||||
password: this.config.password,
|
||||
});
|
||||
|
||||
private onProgressHandler = (): ProgressCallback => {
|
||||
let currentPhase = '';
|
||||
|
||||
return event => {
|
||||
if (currentPhase !== event.phase) {
|
||||
currentPhase = event.phase;
|
||||
this.config.logger?.info(event.phase);
|
||||
}
|
||||
const total = event.total
|
||||
? `${Math.round((event.loaded / event.total) * 100)}%`
|
||||
: event.loaded;
|
||||
this.config.logger?.debug(`status={${event.phase},total={${total}}}`);
|
||||
};
|
||||
};
|
||||
|
||||
static fromAuth = ({
|
||||
username,
|
||||
password,
|
||||
logger,
|
||||
}: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
logger?: Logger;
|
||||
}) => new Git({ username, password, logger });
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { Git } from './git';
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d45efbc9b: Fix typo in .app.listen.port config schema
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.4.3",
|
||||
"version": "0.4.4",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -113,8 +113,8 @@
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.4.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.4.2",
|
||||
"@backstage/dev-utils": "^0.1.6",
|
||||
"@backstage/core": "^0.4.3",
|
||||
"@backstage/dev-utils": "^0.1.7",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@types/diff": "^4.0.2",
|
||||
@@ -182,7 +182,7 @@
|
||||
"visibility": "frontend",
|
||||
"description": "The host that the frontend should be bound to. Only used for local development."
|
||||
},
|
||||
"post": {
|
||||
"port": {
|
||||
"type": "number",
|
||||
"visibility": "frontend",
|
||||
"description": "The port that the frontend should be bound to. Only used for local development."
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/core-api
|
||||
|
||||
## 0.2.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a08c32ced: Add `FlatRoutes` component to replace the top-level `Routes` component from `react-router` within apps, removing the need for manually appending `/*` to paths or sorting routes.
|
||||
- 86c3c652a: Deprecate `RouteRef` path parameter and member, and remove deprecated `routeRef.createSubRouteRef`.
|
||||
- 27f2af935: Delay auth loginPopup close to avoid race condition with callers of authFlowHelpers.
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-api",
|
||||
"description": "Internal Core API used by Backstage plugins and apps",
|
||||
"version": "0.2.7",
|
||||
"version": "0.2.8",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -43,7 +43,7 @@
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.3",
|
||||
"@backstage/cli": "^0.4.4",
|
||||
"@backstage/test-utils-core": "^0.1.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/core
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a08c32ced: Add `FlatRoutes` component to replace the top-level `Routes` component from `react-router` within apps, removing the need for manually appending `/*` to paths or sorting routes.
|
||||
- Updated dependencies [a08c32ced]
|
||||
- Updated dependencies [86c3c652a]
|
||||
- Updated dependencies [27f2af935]
|
||||
- @backstage/core-api@0.2.8
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core",
|
||||
"description": "Core API used by Backstage plugins and apps",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.3",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core-api": "^0.2.7",
|
||||
"@backstage/core-api": "^0.2.8",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -65,7 +65,7 @@
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.3",
|
||||
"@backstage/cli": "^0.4.4",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @backstage/create-app
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4e0e3b1bf: Add missing `yarn clean` for app.
|
||||
|
||||
For users with existing Backstage installations, add the following under the `scripts` section in `packages/app/package.json`, after the "lint" entry:
|
||||
|
||||
```json
|
||||
"clean": "backstage-cli clean",
|
||||
```
|
||||
|
||||
This will add the missing `yarn clean` for the generated frontend.
|
||||
|
||||
- 352a6581f: Added `"start-backend"` script to root `package.json`.
|
||||
|
||||
To apply this change to an existing app, add the following script to the root `package.json`:
|
||||
|
||||
```json
|
||||
"start-backend": "yarn workspace backend start"
|
||||
```
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -24,6 +24,8 @@ const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
|
||||
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
|
||||
require('..');
|
||||
} else {
|
||||
// Only used for development, so should be a devDependency
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
require('ts-node').register({
|
||||
transpileOnly: true,
|
||||
project: path.resolve(__dirname, '../../../tsconfig.json'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/create-app",
|
||||
"description": "Create app package for Backstage",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -39,27 +39,27 @@
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.4.1",
|
||||
"@backstage/catalog-model": "^0.6.0",
|
||||
"@backstage/cli": "^0.4.3",
|
||||
"@backstage/cli": "^0.4.4",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.4.2",
|
||||
"@backstage/plugin-api-docs": "^0.4.1",
|
||||
"@backstage/core": "^0.4.3",
|
||||
"@backstage/plugin-api-docs": "^0.4.2",
|
||||
"@backstage/plugin-app-backend": "^0.3.3",
|
||||
"@backstage/plugin-auth-backend": "^0.2.7",
|
||||
"@backstage/plugin-catalog": "^0.2.8",
|
||||
"@backstage/plugin-auth-backend": "^0.2.8",
|
||||
"@backstage/plugin-catalog": "^0.2.9",
|
||||
"@backstage/plugin-catalog-backend": "^0.5.1",
|
||||
"@backstage/plugin-circleci": "^0.2.5",
|
||||
"@backstage/plugin-explore": "^0.2.2",
|
||||
"@backstage/plugin-github-actions": "^0.2.6",
|
||||
"@backstage/plugin-lighthouse": "^0.2.6",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.3",
|
||||
"@backstage/plugin-register-component": "^0.2.5",
|
||||
"@backstage/plugin-register-component": "^0.2.6",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.5",
|
||||
"@backstage/plugin-scaffolder": "^0.3.5",
|
||||
"@backstage/plugin-search": "^0.2.4",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.6",
|
||||
"@backstage/plugin-tech-radar": "^0.3.1",
|
||||
"@backstage/plugin-techdocs": "^0.5.1",
|
||||
"@backstage/plugin-techdocs-backend": "^0.5.0",
|
||||
"@backstage/plugin-techdocs": "^0.5.2",
|
||||
"@backstage/plugin-techdocs-backend": "^0.5.1",
|
||||
"@backstage/plugin-user-settings": "^0.2.3",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
@@ -70,6 +70,11 @@
|
||||
"@types/recursive-readdir": "^2.2.0",
|
||||
"ts-node": "^8.6.2"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"watch": "./src",
|
||||
"exec": "bin/backstage-create-app",
|
||||
"ext": "ts"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "yarn workspace app start",
|
||||
"start-backend": "yarn workspace backend start",
|
||||
"build": "lerna run build",
|
||||
"build-image": "yarn workspace backend build-image",
|
||||
"tsc": "tsc",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"build": "backstage-cli app:build",
|
||||
"test": "backstage-cli test",
|
||||
"lint": "backstage-cli lint",
|
||||
"clean": "backstage-cli clean",
|
||||
"test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev",
|
||||
"test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run",
|
||||
"cy:dev": "cypress open",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/dev-utils
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 696b8ce74: Add new `addPage` method for use with extensions, as well as an `EntityGridItem` to easily create different test cases for entity overview cards.
|
||||
- Updated dependencies [a08c32ced]
|
||||
- Updated dependencies [7e0b8cac5]
|
||||
- Updated dependencies [87c0c53c2]
|
||||
- @backstage/core@0.4.3
|
||||
- @backstage/plugin-catalog@0.2.9
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/dev-utils",
|
||||
"description": "Utilities for developing Backstage plugins.",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.7",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -29,9 +29,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.4.0",
|
||||
"@backstage/core": "^0.4.3",
|
||||
"@backstage/catalog-model": "^0.6.0",
|
||||
"@backstage/plugin-catalog": "^0.2.8",
|
||||
"@backstage/plugin-catalog": "^0.2.9",
|
||||
"@backstage/test-utils": "^0.1.5",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
@@ -47,7 +47,7 @@
|
||||
"react-router-dom": "6.0.0-beta.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.1",
|
||||
"@backstage/cli": "^0.4.4",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^12.0.0"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @backstage/techdocs-common
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8804e8981: Using @backstage/integration package for GitHub/GitLab/Azure tokens and request options.
|
||||
|
||||
Most probably you do not have to make any changes in the app because of this change.
|
||||
However, if you are using the `DirectoryPreparer` or `CommonGitPreparer` exported by
|
||||
`@backstage/techdocs-common` package, you now need to add pass in a `config` (from `@backstage/config`)
|
||||
instance as argument.
|
||||
|
||||
```
|
||||
<!-- Before -->
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
const commonGitPreparer = new CommonGitPreparer(logger);
|
||||
<!-- Now -->
|
||||
const directoryPreparer = new DirectoryPreparer(config, logger);
|
||||
const commonGitPreparer = new CommonGitPreparer(config, logger);
|
||||
```
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/techdocs-common",
|
||||
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -51,18 +51,16 @@
|
||||
"js-yaml": "^3.14.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"mock-fs": "^4.13.0",
|
||||
"nodegit": "^0.27.0",
|
||||
"recursive-readdir": "^2.2.2",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.3",
|
||||
"@backstage/cli": "^0.4.4",
|
||||
"@types/fs-extra": "^9.0.5",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
"@types/js-yaml": "^3.12.5",
|
||||
"@types/mime-types": "^2.1.0",
|
||||
"@types/mock-fs": "^4.13.0",
|
||||
"@types/nodegit": "^0.26.12",
|
||||
"@types/recursive-readdir": "^2.2.0"
|
||||
},
|
||||
"jest": {
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import NodeGit, { Clone, Repository } from 'nodegit';
|
||||
import fs from 'fs-extra';
|
||||
import { InputError, UrlReader } from '@backstage/backend-common';
|
||||
import { InputError, UrlReader, Git } from '@backstage/backend-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
import { getDefaultBranch } from './default-branch';
|
||||
@@ -27,10 +26,6 @@ import { getGitRepoType, getTokenForGitRepo } from './git-auth';
|
||||
import { RemoteProtocol } from './stages/prepare/types';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
// Enables core.longpaths on windows to prevent crashing when checking out repos with long foldernames and/or deep nesting
|
||||
// @ts-ignore
|
||||
NodeGit.Libgit2.opts(28, 1);
|
||||
|
||||
export type ParsedLocationAnnotation = {
|
||||
type: RemoteProtocol;
|
||||
target: string;
|
||||
@@ -128,17 +123,61 @@ export const checkoutGitRepository = async (
|
||||
const repositoryTmpPath = await getGitRepositoryTempFolder(repoUrl, config);
|
||||
const token = await getTokenForGitRepo(repoUrl, config);
|
||||
|
||||
// Initialize a git client
|
||||
let git = Git.fromAuth({ logger });
|
||||
|
||||
// Docs about why username and password are set to these specific values.
|
||||
// https://isomorphic-git.org/docs/en/onAuth#oauth2-tokens
|
||||
if (token) {
|
||||
const type = getGitRepoType(repoUrl);
|
||||
switch (type) {
|
||||
case 'github':
|
||||
git = Git.fromAuth({
|
||||
username: token,
|
||||
password: 'x-oauth-basic',
|
||||
logger,
|
||||
});
|
||||
parsedGitLocation.token = `${token}:x-oauth-basic`;
|
||||
break;
|
||||
case 'gitlab':
|
||||
git = Git.fromAuth({
|
||||
username: 'oauth2',
|
||||
password: token,
|
||||
logger,
|
||||
});
|
||||
parsedGitLocation.token = `dummyUsername:${token}`;
|
||||
parsedGitLocation.git_suffix = true;
|
||||
break;
|
||||
case 'azure/api':
|
||||
git = Git.fromAuth({
|
||||
username: 'notempty',
|
||||
password: token,
|
||||
logger: logger,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
parsedGitLocation.token = `:${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Pull from repository if it has already been cloned.
|
||||
if (fs.existsSync(repositoryTmpPath)) {
|
||||
try {
|
||||
const repository = await Repository.open(repositoryTmpPath);
|
||||
const currentBranchName = (
|
||||
await repository.getCurrentBranch()
|
||||
).shorthand();
|
||||
await repository.fetch('origin');
|
||||
await repository.mergeBranches(
|
||||
currentBranchName,
|
||||
`origin/${currentBranchName}`,
|
||||
);
|
||||
const currentBranchName = await git.currentBranch({
|
||||
dir: repositoryTmpPath,
|
||||
});
|
||||
|
||||
await git.fetch({ dir: repositoryTmpPath, remote: 'origin' });
|
||||
await git.merge({
|
||||
dir: repositoryTmpPath,
|
||||
theirs: `origin/${currentBranchName}`,
|
||||
ours: currentBranchName || undefined,
|
||||
author: { name: 'Backstage TechDocs', email: 'techdocs@backstage.io' },
|
||||
committer: {
|
||||
name: 'Backstage TechDocs',
|
||||
email: 'techdocs@backstage.io',
|
||||
},
|
||||
});
|
||||
return repositoryTmpPath;
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
@@ -148,26 +187,10 @@ export const checkoutGitRepository = async (
|
||||
}
|
||||
}
|
||||
|
||||
if (token) {
|
||||
const type = getGitRepoType(repoUrl);
|
||||
switch (type) {
|
||||
case 'gitlab':
|
||||
// Personal Access Token
|
||||
parsedGitLocation.token = `dummyUsername:${token}`;
|
||||
parsedGitLocation.git_suffix = true;
|
||||
break;
|
||||
case 'github':
|
||||
parsedGitLocation.token = `${token}:x-oauth-basic`;
|
||||
break;
|
||||
default:
|
||||
parsedGitLocation.token = `:${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
const repositoryCheckoutUrl = parsedGitLocation.toString('https');
|
||||
|
||||
fs.mkdirSync(repositoryTmpPath, { recursive: true });
|
||||
await Clone.clone(repositoryCheckoutUrl, repositoryTmpPath);
|
||||
await git.clone({ url: repositoryCheckoutUrl, dir: repositoryTmpPath });
|
||||
|
||||
return repositoryTmpPath;
|
||||
};
|
||||
@@ -183,10 +206,11 @@ export const getLastCommitTimestamp = async (
|
||||
logger,
|
||||
);
|
||||
|
||||
const repository = await Repository.open(repositoryLocation);
|
||||
const commit = await repository.getReferenceCommit('HEAD');
|
||||
const git = Git.fromAuth({ logger });
|
||||
const sha = await git.resolveRef({ dir: repositoryLocation, ref: 'HEAD' });
|
||||
const commit = await git.readCommit({ dir: repositoryLocation, sha });
|
||||
|
||||
return commit.date().getTime();
|
||||
return commit.commit.committer.timestamp;
|
||||
};
|
||||
|
||||
export const getDocFilesFromRepository = async (
|
||||
|
||||
Reference in New Issue
Block a user