Merge branch 'master' of github.com:backstage/backstage into update-docs

This commit is contained in:
Adam Harvey
2020-12-29 11:48:31 -05:00
99 changed files with 1387 additions and 875 deletions
+1
View File
@@ -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",
+1
View File
@@ -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),
);
+321
View File
@@ -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,
});
});
});
});
+251
View File
@@ -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 });
}
+17
View File
@@ -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';
+6
View File
@@ -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
+4 -4
View File
@@ -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."
+8
View File
@@ -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
+2 -2
View File
@@ -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",
+10
View File
@@ -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
+3 -3
View File
@@ -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",
+22
View File
@@ -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'),
+14 -9
View File
@@ -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",
+11
View File
@@ -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
+4 -4
View File
@@ -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"
},
+20
View File
@@ -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
+2 -4
View File
@@ -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": {
+59 -35
View File
@@ -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 (