diff --git a/.changeset/dull-seals-march.md b/.changeset/dull-seals-march.md deleted file mode 100644 index 714c5c5cad..0000000000 --- a/.changeset/dull-seals-march.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-api': patch -'@backstage/core': patch ---- - -Add `BackstageRoutes` component to replace the top-level `Routes` component from `react-router` within apps, removing the need for manually appending `/*` to paths or sorting routes. diff --git a/.changeset/famous-eagles-swim.md b/.changeset/famous-eagles-swim.md deleted file mode 100644 index 49f2724b5b..0000000000 --- a/.changeset/famous-eagles-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-register-component': patch ---- - -Register component plugin is deprecated in favor of @backstage/plugin-catalog-import diff --git a/.changeset/friendly-shoes-compare.md b/.changeset/friendly-shoes-compare.md deleted file mode 100644 index 0b242511c0..0000000000 --- a/.changeset/friendly-shoes-compare.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Add `CatalogIndexPage` and `CatalogEntityPage`, two new extensions that replace the existing `Router` component. - -Add `EntityLayout` to replace `EntityPageLayout`, using children instead of an element property, and allowing for collection of all `RouteRef` mount points used within tabs. - -Add `EntitySwitch` to be used to select components based on entity data, along with accompanying `isKind`, `isNamespace`, and `isComponentType` filters. diff --git a/.changeset/gentle-dragons-marry.md b/.changeset/gentle-dragons-marry.md deleted file mode 100644 index d9ef443932..0000000000 --- a/.changeset/gentle-dragons-marry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Link register API to catalog-import plugin diff --git a/.changeset/kind-buses-change.md b/.changeset/kind-buses-change.md new file mode 100644 index 0000000000..1d93e27dff --- /dev/null +++ b/.changeset/kind-buses-change.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-common': patch +'@backstage/techdocs-common': patch +'@backstage/plugin-scaffolder-backend': patch +--- + +Moving the Git actions to isomorphic-git instead of the node binding version of nodegit diff --git a/.changeset/mighty-plums-wave.md b/.changeset/mighty-plums-wave.md new file mode 100644 index 0000000000..ac84b68e04 --- /dev/null +++ b/.changeset/mighty-plums-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Tweaked development log formatter to include extra fields at the end of each log line diff --git a/.changeset/neat-maps-return.md b/.changeset/neat-maps-return.md deleted file mode 100644 index 9ff2ebe845..0000000000 --- a/.changeset/neat-maps-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-fossa': patch ---- - -Bump dependency versions of @backstage/core, cli and test-utils diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 0f8dd87ff1..7dd6305ea4 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -135,6 +135,7 @@ neuro newrelic nginx Niklas +nodegit nohoist nonces npm diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2fafd3756d..92660b9ca4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -11,6 +11,11 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [master] + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#scanning-pull-requests + paths-ignore: + - '**/*.md' + - '**/*.yml' + - '**/*.yaml' schedule: - cron: '0 8 * * 6' @@ -36,11 +41,6 @@ jobs: # a pull request then we can checkout the head. fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index ca63e627e9..4de1ed060a 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -81,7 +81,7 @@ jobs: - uses: Klemensas/action-autotag@1.2.3 if: matrix.node-version == '12.x' with: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: '${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}' package_root: 'packages/core' tag_prefix: 'v' diff --git a/microsite/data/plugins/aws-lambda.yaml b/microsite/data/plugins/aws-lambda.yaml index f325c0df8b..cc3d59d188 100644 --- a/microsite/data/plugins/aws-lambda.yaml +++ b/microsite/data/plugins/aws-lambda.yaml @@ -2,7 +2,7 @@ title: AWS Lambda author: roadie.io authorUrl: https://roadie.io -category: Monitoring +category: Infrastructure description: View AWS Lambda functions for your components in Backstage. documentation: https://roadie.io/backstage/plugins/aws-lambda iconUrl: https://roadie.io/images/logos/lambda.png diff --git a/microsite/data/plugins/firebase-functions.yaml b/microsite/data/plugins/firebase-functions.yaml index 8c1ea0be0a..9a1777754a 100644 --- a/microsite/data/plugins/firebase-functions.yaml +++ b/microsite/data/plugins/firebase-functions.yaml @@ -2,7 +2,7 @@ title: Firebase Functions author: roadie.io authorUrl: https://roadie.io/ -category: Monitoring +category: Infrastructure description: View Firebase Functions details for your service in Backstage. documentation: https://roadie.io/backstage/plugins/firebase-functions iconUrl: https://roadie.io/images/logos/firebase.png diff --git a/microsite/pages/en/demos.js b/microsite/pages/en/demos.js index 63c15ab698..c26fc9a8e8 100644 --- a/microsite/pages/en/demos.js +++ b/microsite/pages/en/demos.js @@ -17,22 +17,18 @@ const Background = props => { - See us in action. + See us in action - To illustrate the potential of Backstage, we’re showing you{' '} - - how we use it here at Spotify + To explore the UI and basic features of Backstage firsthand, go + to: demo.backstage.io. + + + Watch the videos below to get an introduction to Backstage and to + see how we use different plugins to customize{' '} + + our internal version of Backstage at Spotify - . The videos below feature the custom plugins and templates that - we built for our internal version of Backstage. You can use - Backstage to build the developer portal you want — integrating the - tools that you use in your own infrastructure ecosystem. (Or get - started by building an open source plugin for Backstage that - everyone can use, like our{' '} - - Lighthouse Plugin - - .) + . diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index e65edba0a5..a6b47bd7b4 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -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", diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index e968edef69..3f04f32b34 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -24,3 +24,4 @@ export * from './reading'; export * from './service'; export * from './paths'; export * from './hot'; +export * from './scm'; diff --git a/packages/backend-common/src/logging/formats.ts b/packages/backend-common/src/logging/formats.ts index 5f00448744..4f7949f115 100644 --- a/packages/backend-common/src/logging/formats.ts +++ b/packages/backend-common/src/logging/formats.ts @@ -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), ); diff --git a/packages/backend-common/src/scm/git.test.ts b/packages/backend-common/src/scm/git.test.ts new file mode 100644 index 0000000000..9af080a782 --- /dev/null +++ b/packages/backend-common/src/scm/git.test.ts @@ -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, + }); + }); + }); +}); diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts new file mode 100644 index 0000000000..b0a1df6541 --- /dev/null +++ b/packages/backend-common/src/scm/git.ts @@ -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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + return git.readCommit({ fs, dir, oid: sha }); + } + + // https://isomorphic-git.org/docs/en/resolveRef + async resolveRef({ + dir, + ref, + }: { + dir: string; + ref: string; + }): Promise { + 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 }); +} diff --git a/packages/backend-common/src/scm/index.ts b/packages/backend-common/src/scm/index.ts new file mode 100644 index 0000000000..e967fffb44 --- /dev/null +++ b/packages/backend-common/src/scm/index.ts @@ -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'; diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 256480bf70..d88220cc23 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -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 diff --git a/packages/cli/package.json b/packages/cli/package.json index 90d2fe24f1..6da871e74c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -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." diff --git a/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.test.ts b/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.test.ts index 53512567eb..b4580ea281 100644 --- a/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.test.ts +++ b/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.test.ts @@ -14,20 +14,27 @@ * limitations under the License. */ +import * as os from 'os'; +import * as path from 'path'; import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin'; describe('LinkedPackageResolvePlugin', () => { + const root = os.platform() === 'win32' ? 'C:\\root' : '/root'; + it('should re-write paths for external packages', () => { - const plugin = new LinkedPackageResolvePlugin('/root/repo/node_modules', [ - { - name: 'a', - location: '/root/external-a', - }, - { - name: '@s/b', - location: '/root/external-b', - }, - ]); + const plugin = new LinkedPackageResolvePlugin( + path.resolve(root, 'repo/node_modules'), + [ + { + name: 'a', + location: path.resolve(root, 'external-a'), + }, + { + name: '@s/b', + location: path.resolve(root, 'external-b'), + }, + ], + ); const tapAsync = jest.fn(); const doResolve = jest.fn(); @@ -50,10 +57,10 @@ describe('LinkedPackageResolvePlugin', () => { const callbackX = jest.fn(); tap( { - request: '/root/repo/package/x/src/module.ts', - path: '/root/repo/package/x/src', + request: path.resolve(root, 'repo/package/x/src/module.ts'), + path: path.resolve(root, 'repo/package/x/src'), context: { - issuer: '/root/repo/package/x/src/index.ts', + issuer: path.resolve(root, 'repo/package/x/src/index.ts'), }, }, 'some-context', @@ -81,10 +88,10 @@ describe('LinkedPackageResolvePlugin', () => { const callbackA = jest.fn(); tap( { - request: '/root/external-a/src/module.ts', - path: '/root/external-a/src', + request: path.resolve(root, 'external-a/src/module.ts'), + path: path.resolve(root, 'external-a/src'), context: { - issuer: '/root/external-a/src/index.ts', + issuer: path.resolve(root, 'external-a/src/index.ts'), }, }, 'some-context', @@ -95,13 +102,16 @@ describe('LinkedPackageResolvePlugin', () => { expect(doResolve).toHaveBeenCalledWith( resolver.hooks.resolve, { - request: '/root/external-a/src/module.ts', - path: '/root/repo/node_modules/a/src', + request: path.resolve(root, 'external-a/src/module.ts'), + path: path.resolve(root, 'repo/node_modules/a/src'), context: { - issuer: '/root/repo/node_modules/a/src/index.ts', + issuer: path.resolve(root, 'repo/node_modules/a/src/index.ts'), }, }, - 'resolve /root/external-a/src/module.ts in /root/repo/node_modules/a', + `resolve ${path.resolve( + root, + 'external-a/src/module.ts', + )} in ${path.resolve(root, 'repo/node_modules/a')}`, 'some-context', callbackA, ); @@ -110,8 +120,8 @@ describe('LinkedPackageResolvePlugin', () => { const callbackB = jest.fn(); tap( { - request: '/root/external-b/src/module.ts', - path: '/root/external-b/src', + request: path.resolve(root, 'external-b/src/module.ts'), + path: path.resolve(root, 'external-b/src'), context: { issuer: false, }, @@ -124,13 +134,16 @@ describe('LinkedPackageResolvePlugin', () => { expect(doResolve).toHaveBeenLastCalledWith( resolver.hooks.resolve, { - request: '/root/external-b/src/module.ts', - path: '/root/repo/node_modules/@s/b/src', + request: path.resolve(root, 'external-b/src/module.ts'), + path: path.resolve(root, 'repo/node_modules/@s/b/src'), context: { issuer: false, }, }, - 'resolve /root/external-b/src/module.ts in /root/repo/node_modules/@s/b', + `resolve ${path.resolve( + root, + 'external-b/src/module.ts', + )} in ${path.resolve(root, 'repo/node_modules/@s/b')}`, 'some-context', callbackB, ); diff --git a/packages/core-api/CHANGELOG.md b/packages/core-api/CHANGELOG.md index 2d8915e7f1..3f412f3e17 100644 --- a/packages/core-api/CHANGELOG.md +++ b/packages/core-api/CHANGELOG.md @@ -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 diff --git a/packages/core-api/package.json b/packages/core-api/package.json index f02520d170..a818d38143 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -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", diff --git a/packages/core-api/src/routing/BackstageRoutes.tsx b/packages/core-api/src/routing/FlatRoutes.tsx similarity index 94% rename from packages/core-api/src/routing/BackstageRoutes.tsx rename to packages/core-api/src/routing/FlatRoutes.tsx index 6c042af27d..a6783964a7 100644 --- a/packages/core-api/src/routing/BackstageRoutes.tsx +++ b/packages/core-api/src/routing/FlatRoutes.tsx @@ -66,13 +66,11 @@ function createRoutesFromChildren(children: ReactNode): RouteObject[] { }); } -type BackstageRoutesProps = { +type FlatRoutesProps = { children: ReactNode; }; -export const BackstageRoutes = ( - props: BackstageRoutesProps, -): JSX.Element | null => { +export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => { const routes = createRoutesFromChildren(props.children); return useRoutes(routes); }; diff --git a/packages/core-api/src/routing/RouteRef.ts b/packages/core-api/src/routing/RouteRef.ts index f89634e0ec..4c2da34098 100644 --- a/packages/core-api/src/routing/RouteRef.ts +++ b/packages/core-api/src/routing/RouteRef.ts @@ -25,25 +25,15 @@ export class AbsoluteRouteRef { // TODO(Rugvip): Remove this, routes are looked up via the registry instead get path() { - return this.config.path; + return this.config.path ?? ''; } get title() { return this.config.title; } - /** - * This function should not be used, create a separate RouteRef instead - * @deprecated - */ - createSubRoute(): any { - throw new Error( - 'This method should not be called, create a separate RouteRef instead', - ); - } - toString() { - return `routeRef{path=${this.path}}`; + return `routeRef{title=${this.title}}`; } } @@ -54,13 +44,7 @@ export function createRouteRef< return new AbsoluteRouteRef(config); } -const create = Symbol('create-external-route-ref'); - export class ExternalRouteRef { - static [create]() { - return new ExternalRouteRef(); - } - private constructor() {} toString() { @@ -69,5 +53,5 @@ export class ExternalRouteRef { } export function createExternalRouteRef(): ExternalRouteRef { - return ExternalRouteRef[create](); + return new ((ExternalRouteRef as unknown) as { new (): ExternalRouteRef })(); } diff --git a/packages/core-api/src/routing/index.ts b/packages/core-api/src/routing/index.ts index 2bdf0aa5e8..9564b3b225 100644 --- a/packages/core-api/src/routing/index.ts +++ b/packages/core-api/src/routing/index.ts @@ -21,6 +21,6 @@ export type { ConcreteRoute, MutableRouteRef, } from './types'; -export { BackstageRoutes } from './BackstageRoutes'; +export { FlatRoutes } from './FlatRoutes'; export { createRouteRef } from './RouteRef'; export { useRouteRef } from './hooks'; diff --git a/packages/core-api/src/routing/types.ts b/packages/core-api/src/routing/types.ts index c6d79fd991..99a20c31e9 100644 --- a/packages/core-api/src/routing/types.ts +++ b/packages/core-api/src/routing/types.ts @@ -19,14 +19,10 @@ import { IconComponent } from '../icons'; // @ts-ignore, we're just embedding the Params type for usage in other places export type RouteRef = { // TODO(Rugvip): Remove path, look up via registry instead + /** @deprecated paths are no longer accessed directly from RouteRefs, use useRouteRef instead */ path: string; icon?: IconComponent; title: string; - /** - * This function should not be used, create a separate RouteRef instead - * @deprecated - */ - createSubRoute(): any; }; export type AnyRouteRef = RouteRef; @@ -51,7 +47,8 @@ export type MutableRouteRef = RouteRef<{}>; export type RouteRefConfig = { params?: Array; - path: string; + /** @deprecated Route refs no longer decide their own path */ + path?: string; icon?: IconComponent; title: string; }; diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 6b59bb7fbb..bb13447f94 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -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 diff --git a/packages/core/package.json b/packages/core/package.json index 71f2daceb8..b84eb4ff7b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -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", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index e589cab0ae..94260dcec9 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -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 diff --git a/packages/create-app/bin/backstage-create-app b/packages/create-app/bin/backstage-create-app index 467a0cae8f..902f341bfb 100755 --- a/packages/create-app/bin/backstage-create-app +++ b/packages/create-app/bin/backstage-create-app @@ -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'), diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 23a0b1a584..ac29dc1431 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.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", diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index 975a5a2ed2..1353e33072 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -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", diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 1746f171c9..919ca678a0 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -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", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index e634a09c20..1938754169 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -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 diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 1e0304a5a9..785607c6d3 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -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" }, diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index f15a4c4078..f1a6d30b4c 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -30,7 +30,7 @@ import { OAuthRequestDialog, AnyApiFactory, IconComponent, - BackstageRoutes, + FlatRoutes, attachComponentData, } from '@backstage/core'; import SentimentDissatisfiedIcon from '@material-ui/icons/SentimentDissatisfied'; @@ -133,10 +133,10 @@ class DevAppBuilder { {sidebar} - + {this.routes} {deprecatedAppRoutes} - + diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md index 40bac7ce7f..1672e5a61b 100644 --- a/packages/techdocs-common/CHANGELOG.md +++ b/packages/techdocs-common/CHANGELOG.md @@ -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. + + ``` + + const directoryPreparer = new DirectoryPreparer(logger); + const commonGitPreparer = new CommonGitPreparer(logger); + + const directoryPreparer = new DirectoryPreparer(config, logger); + const commonGitPreparer = new CommonGitPreparer(config, logger); + ``` + ## 0.3.0 ### Minor Changes diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index 68debc2448..7fc88a5238 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -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, @@ -39,6 +39,7 @@ "@backstage/backend-common": "^0.4.1", "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", + "@backstage/integration": "^0.1.4", "@google-cloud/storage": "^5.6.0", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", @@ -50,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": { diff --git a/packages/techdocs-common/src/default-branch.ts b/packages/techdocs-common/src/default-branch.ts index 1090fcb3d3..7dd460a9fe 100644 --- a/packages/techdocs-common/src/default-branch.ts +++ b/packages/techdocs-common/src/default-branch.ts @@ -16,13 +16,17 @@ import fetch from 'cross-fetch'; import parseGitUrl from 'git-url-parse'; import { Config } from '@backstage/config'; -import { getRootLogger, loadBackendConfig } from '@backstage/backend-common'; import { - getAzureHostToken, + getGitHubRequestOptions, + getGitLabRequestOptions, + getAzureRequestOptions, +} from '@backstage/integration'; +import { getGitHost, - getGithubHostToken, - getGitlabHostToken, getGitRepoType, + getGitHubIntegrationConfig, + getGitLabIntegrationConfig, + getAzureIntegrationConfig, } from './git-auth'; interface IGitlabBranch { @@ -86,62 +90,15 @@ function getAzureApiUrl(url: string): URL { ); } -function getGithubRequestOptions(config: Config, host: string): RequestInit { - const headers: HeadersInit = { - Accept: 'application/vnd.github.v3.raw', - }; - - const token = getGithubHostToken(config, host); - - if (token) { - headers.Authorization = `token ${token}`; - } - - return { - headers, - }; -} - -function getGitlabRequestOptions(config: Config, host: string): RequestInit { - const headers: HeadersInit = { - 'PRIVATE-TOKEN': '', - }; - - const token = getGitlabHostToken(config, host); - if (token) { - headers['PRIVATE-TOKEN'] = token; - } - - return { - headers, - }; -} - -function getAzureRequestOptions(config: Config, host: string): RequestInit { - const headers: HeadersInit = {}; - - const token = getAzureHostToken(config, host); - - if (token !== '') { - headers.Authorization = `Basic ${Buffer.from(`:${token}`, 'utf8').toString( - 'base64', - )}`; - } - - const requestOptions: RequestInit = { - headers, - }; - - return requestOptions; -} - async function getGithubDefaultBranch( repositoryUrl: string, config: Config, ): Promise { const path = getGithubApiUrl(config, repositoryUrl).toString(); const host = getGitHost(repositoryUrl); - const options = getGithubRequestOptions(config, host); + + const integrationConfig = getGitHubIntegrationConfig(config, host); + const options = getGitHubRequestOptions(integrationConfig); try { const raw = await fetch(path, options); @@ -169,9 +126,10 @@ async function getGitlabDefaultBranch( config: Config, ): Promise { const path = getGitlabApiUrl(repositoryUrl).toString(); + const host = getGitHost(repositoryUrl); - const gitlabHost = getGitHost(repositoryUrl); - const options = getGitlabRequestOptions(config, gitlabHost); + const integrationConfig = getGitLabIntegrationConfig(config, host); + const options = getGitLabRequestOptions(integrationConfig); try { const raw = await fetch(path, options); @@ -203,7 +161,9 @@ async function getAzureDefaultBranch( ): Promise { const path = getAzureApiUrl(repositoryUrl).toString(); const host = getGitHost(repositoryUrl); - const options = getAzureRequestOptions(config, host); + + const integrationConfig = getAzureIntegrationConfig(config, host); + const options = getAzureRequestOptions(integrationConfig); try { const urlResponse = await fetch(path, options); @@ -235,12 +195,8 @@ async function getAzureDefaultBranch( export const getDefaultBranch = async ( repositoryUrl: string, + config: Config, ): Promise => { - // TODO(Rugvip): Config should not be loaded here, pass it in instead - const config = await loadBackendConfig({ - logger: getRootLogger(), - argv: process.argv, - }); const type = getGitRepoType(repositoryUrl); try { diff --git a/packages/techdocs-common/src/git-auth.ts b/packages/techdocs-common/src/git-auth.ts index b580a6f05b..b58afae490 100644 --- a/packages/techdocs-common/src/git-auth.ts +++ b/packages/techdocs-common/src/git-auth.ts @@ -15,7 +15,14 @@ */ import parseGitUrl from 'git-url-parse'; import { Config } from '@backstage/config'; -import { getRootLogger, loadBackendConfig } from '@backstage/backend-common'; +import { + readGitHubIntegrationConfigs, + readGitLabIntegrationConfigs, + readAzureIntegrationConfigs, + GitHubIntegrationConfig, + GitLabIntegrationConfig, + AzureIntegrationConfig, +} from '@backstage/integration'; export function getGitHost(url: string): string { const { resource } = parseGitUrl(url); @@ -34,83 +41,65 @@ export function getGitRepoType(url: string): string { return type; } -export function getGithubHostToken( +export const getGitHubIntegrationConfig = ( config: Config, host: string, -): string | undefined { - const providerConfigs = - config.getOptionalConfigArray('integrations.github') ?? []; - - const hostConfig = providerConfigs.filter( - providerConfig => providerConfig.getOptionalString('host') === host, +): GitHubIntegrationConfig => { + const allGitHubConfigs = readGitHubIntegrationConfigs( + config.getOptionalConfigArray('integrations.github') ?? [], ); - const token = - hostConfig[0]?.getOptionalString('token') ?? - config.getOptionalString('catalog.processors.github.privateToken') ?? - config.getOptionalString('catalog.processors.githubApi.privateToken') ?? - process.env.GITHUB_TOKEN; + const gitHubIntegrationConfig = allGitHubConfigs.find(v => v.host === host); + if (!gitHubIntegrationConfig) { + throw new Error(`Unable to locate GitHub integration for the host ${host}`); + } + return gitHubIntegrationConfig; +}; - return token; -} - -export function getGitlabHostToken( +export const getGitLabIntegrationConfig = ( config: Config, host: string, -): string | undefined { - const providerConfigs = - config.getOptionalConfigArray('integrations.gitlab') ?? []; - - const hostConfig = providerConfigs.filter( - providerConfig => providerConfig.getOptionalString('host') === host, +): GitLabIntegrationConfig => { + const allGitLabConfigs = readGitLabIntegrationConfigs( + config.getOptionalConfigArray('integrations.gitlab') ?? [], ); - const token = - hostConfig[0]?.getOptionalString('token') ?? - config.getOptionalString('catalog.processors.gitlab.privateToken') ?? - config.getOptionalString('catalog.processors.gitlabApi.privateToken') ?? - process.env.GITLAB_TOKEN; + const gitLabIntegrationConfig = allGitLabConfigs.find(v => v.host === host); + if (!gitLabIntegrationConfig) { + throw new Error(`Unable to locate GitLab integration for the host ${host}`); + } + return gitLabIntegrationConfig; +}; - return token; -} - -export function getAzureHostToken( +export const getAzureIntegrationConfig = ( config: Config, host: string, -): string | undefined { - const providerConfigs = - config.getOptionalConfigArray('integrations.azure') ?? []; - - const hostConfig = providerConfigs.filter( - providerConfig => providerConfig.getOptionalString('host') === host, +): AzureIntegrationConfig => { + const allAzureIntegrationConfig = readAzureIntegrationConfigs( + config.getOptionalConfigArray('integrations.azure') ?? [], ); - const token = - hostConfig[0]?.getOptionalString('token') ?? - config.getOptionalString('catalog.processors.azureApi.privateToken') ?? - process.env.AZURE_TOKEN; - - return token; -} + const azureIntegrationConfig = allAzureIntegrationConfig.find( + v => v.host === host, + ); + if (!azureIntegrationConfig) { + throw new Error(`Unable to locate Azure integration for the host ${host}`); + } + return azureIntegrationConfig; +}; export const getTokenForGitRepo = async ( repositoryUrl: string, + config: Config, ): Promise => { - // TODO(Rugvip): Config should not be loaded here, pass it in instead - const config = await loadBackendConfig({ - logger: getRootLogger(), - argv: process.argv, - }); - const host = getGitHost(repositoryUrl); const type = getGitRepoType(repositoryUrl); try { switch (type) { case 'github': - return getGithubHostToken(config, host); + return getGitHubIntegrationConfig(config, host).token; case 'gitlab': - return getGitlabHostToken(config, host); + return getGitLabIntegrationConfig(config, host).token; case 'azure/api': - return getAzureHostToken(config, host); - + return getAzureIntegrationConfig(config, host).token; default: throw new Error('Failed to get repository type'); } diff --git a/packages/techdocs-common/src/helpers.ts b/packages/techdocs-common/src/helpers.ts index e08d58d58e..f70b0f3840 100644 --- a/packages/techdocs-common/src/helpers.ts +++ b/packages/techdocs-common/src/helpers.ts @@ -17,19 +17,15 @@ 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, Git } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import { getDefaultBranch } from './default-branch'; import { getGitRepoType, getTokenForGitRepo } from './git-auth'; -import { Entity } from '@backstage/catalog-model'; -import { InputError, UrlReader } from '@backstage/backend-common'; 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; @@ -94,6 +90,7 @@ export const getLocationForEntity = ( export const getGitRepositoryTempFolder = async ( repositoryUrl: string, + config: Config, ): Promise => { const parsedGitLocation = parseGitUrl(repositoryUrl); // removes .git from git location path @@ -102,6 +99,7 @@ export const getGitRepositoryTempFolder = async ( if (!parsedGitLocation.ref) { parsedGitLocation.ref = await getDefaultBranch( parsedGitLocation.toString('https'), + config, ); } @@ -118,23 +116,68 @@ export const getGitRepositoryTempFolder = async ( export const checkoutGitRepository = async ( repoUrl: string, + config: Config, logger: Logger, ): Promise => { const parsedGitLocation = parseGitUrl(repoUrl); - const repositoryTmpPath = await getGitRepositoryTempFolder(repoUrl); - const token = await getTokenForGitRepo(repoUrl); + 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( @@ -144,40 +187,30 @@ 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; }; export const getLastCommitTimestamp = async ( repositoryUrl: string, + config: Config, logger: Logger, ): Promise => { - const repositoryLocation = await checkoutGitRepository(repositoryUrl, logger); + const repositoryLocation = await checkoutGitRepository( + repositoryUrl, + config, + 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 ( diff --git a/packages/techdocs-common/src/stages/prepare/commonGit.test.ts b/packages/techdocs-common/src/stages/prepare/commonGit.test.ts index a4240514b5..704cd23daa 100644 --- a/packages/techdocs-common/src/stages/prepare/commonGit.test.ts +++ b/packages/techdocs-common/src/stages/prepare/commonGit.test.ts @@ -15,6 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; import { CommonGitPreparer } from './commonGit'; import { checkoutGitRepository } from '../../helpers'; @@ -43,11 +44,13 @@ const createMockEntity = (annotations = {}) => { }; }; +const mockConfig = new ConfigReader({}); + const logger = getVoidLogger(); describe('commonGit preparer', () => { it('should prepare temp docs path from github repo', async () => { - const preparer = new CommonGitPreparer(logger); + const preparer = new CommonGitPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/techdocs-ref': @@ -62,7 +65,7 @@ describe('commonGit preparer', () => { }); it('should prepare temp docs path from gitlab repo', async () => { - const preparer = new CommonGitPreparer(logger); + const preparer = new CommonGitPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/techdocs-ref': @@ -77,7 +80,7 @@ describe('commonGit preparer', () => { }); it('should prepare temp docs path from azure repo', async () => { - const preparer = new CommonGitPreparer(logger); + const preparer = new CommonGitPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/techdocs-ref': diff --git a/packages/techdocs-common/src/stages/prepare/commonGit.ts b/packages/techdocs-common/src/stages/prepare/commonGit.ts index d79373fba3..7eac07d76f 100644 --- a/packages/techdocs-common/src/stages/prepare/commonGit.ts +++ b/packages/techdocs-common/src/stages/prepare/commonGit.ts @@ -14,17 +14,20 @@ * limitations under the License. */ import path from 'path'; -import { Entity } from '@backstage/catalog-model'; -import { PreparerBase } from './types'; import parseGitUrl from 'git-url-parse'; +import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { PreparerBase } from './types'; import { parseReferenceAnnotation, checkoutGitRepository } from '../../helpers'; import { Logger } from 'winston'; export class CommonGitPreparer implements PreparerBase { + private readonly config: Config; private readonly logger: Logger; - constructor(logger: Logger) { + constructor(config: Config, logger: Logger) { + this.config = config; this.logger = logger; } @@ -35,7 +38,11 @@ export class CommonGitPreparer implements PreparerBase { ); try { - const repoPath = await checkoutGitRepository(target, this.logger); + const repoPath = await checkoutGitRepository( + target, + this.config, + this.logger, + ); const parsedGitLocation = parseGitUrl(target); return path.join(repoPath, parsedGitLocation.filepath); diff --git a/packages/techdocs-common/src/stages/prepare/dir.test.ts b/packages/techdocs-common/src/stages/prepare/dir.test.ts index 5b51f1f46d..d082b1367b 100644 --- a/packages/techdocs-common/src/stages/prepare/dir.test.ts +++ b/packages/techdocs-common/src/stages/prepare/dir.test.ts @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DirectoryPreparer } from './dir'; import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { DirectoryPreparer } from './dir'; import { checkoutGitRepository } from '../../helpers'; function normalizePath(path: string) { @@ -44,9 +45,11 @@ const createMockEntity = (annotations: {}) => { }; }; +const mockConfig = new ConfigReader({}); + describe('directory preparer', () => { it('should merge managed-by-location and techdocs-ref when techdocs-ref is relative', async () => { - const directoryPreparer = new DirectoryPreparer(logger); + const directoryPreparer = new DirectoryPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/managed-by-location': @@ -60,7 +63,7 @@ describe('directory preparer', () => { }); it('should merge managed-by-location and techdocs-ref when techdocs-ref is absolute', async () => { - const directoryPreparer = new DirectoryPreparer(logger); + const directoryPreparer = new DirectoryPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/managed-by-location': @@ -74,7 +77,7 @@ describe('directory preparer', () => { }); it('should merge managed-by-location and techdocs-ref when managed-by-location is a git repository', async () => { - const directoryPreparer = new DirectoryPreparer(logger); + const directoryPreparer = new DirectoryPreparer(mockConfig, logger); const mockEntity = createMockEntity({ 'backstage.io/managed-by-location': diff --git a/packages/techdocs-common/src/stages/prepare/dir.ts b/packages/techdocs-common/src/stages/prepare/dir.ts index 3485ecb5dd..537f670edc 100644 --- a/packages/techdocs-common/src/stages/prepare/dir.ts +++ b/packages/techdocs-common/src/stages/prepare/dir.ts @@ -15,6 +15,7 @@ */ import { PreparerBase } from './types'; import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import path from 'path'; import { parseReferenceAnnotation, checkoutGitRepository } from '../../helpers'; import { InputError } from '@backstage/backend-common'; @@ -22,9 +23,11 @@ import parseGitUrl from 'git-url-parse'; import { Logger } from 'winston'; export class DirectoryPreparer implements PreparerBase { + private readonly config: Config; private readonly logger: Logger; - constructor(logger: Logger) { + constructor(config: Config, logger: Logger) { + this.config = config; this.logger = logger; } @@ -43,7 +46,11 @@ export class DirectoryPreparer implements PreparerBase { case 'url': case 'azure/api': { const parsedGitLocation = parseGitUrl(target); - const repoLocation = await checkoutGitRepository(target, this.logger); + const repoLocation = await checkoutGitRepository( + target, + this.config, + this.logger, + ); return path.dirname( path.join(repoLocation, parsedGitLocation.filepath), diff --git a/packages/techdocs-common/src/stages/prepare/preparers.ts b/packages/techdocs-common/src/stages/prepare/preparers.ts index 4a2d60eb31..4625d7b0e4 100644 --- a/packages/techdocs-common/src/stages/prepare/preparers.ts +++ b/packages/techdocs-common/src/stages/prepare/preparers.ts @@ -30,18 +30,15 @@ export class Preparers implements PreparerBuilder { private preparerMap = new Map(); static async fromConfig( - // @ts-ignore - // Config not used now, but will be used in urlPreparer when it starts using - // @backstage/integration to get the tokens for providers. config: Config, { logger, reader }: factoryOptions, ): Promise { const preparers = new Preparers(); - const directoryPreparer = new DirectoryPreparer(logger); + const directoryPreparer = new DirectoryPreparer(config, logger); preparers.register('dir', directoryPreparer); - const commonGitPreparer = new CommonGitPreparer(logger); + const commonGitPreparer = new CommonGitPreparer(config, logger); preparers.register('github', commonGitPreparer); preparers.register('gitlab', commonGitPreparer); preparers.register('azure/api', commonGitPreparer); diff --git a/packages/techdocs-common/src/stages/prepare/url.ts b/packages/techdocs-common/src/stages/prepare/url.ts index 3407684837..b938c6b5bc 100644 --- a/packages/techdocs-common/src/stages/prepare/url.ts +++ b/packages/techdocs-common/src/stages/prepare/url.ts @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Logger } from 'winston'; import { Entity } from '@backstage/catalog-model'; +import { UrlReader } from '@backstage/backend-common'; import { PreparerBase } from './types'; import { getDocFilesFromRepository } from '../../helpers'; -import { Logger } from 'winston'; -import { UrlReader } from '@backstage/backend-common'; export class UrlPreparer implements PreparerBase { private readonly logger: Logger; diff --git a/packages/techdocs-common/src/stages/publish/helpers.test.ts b/packages/techdocs-common/src/stages/publish/helpers.test.ts index 3b01f5ac43..1fae66f3d2 100644 --- a/packages/techdocs-common/src/stages/publish/helpers.test.ts +++ b/packages/techdocs-common/src/stages/publish/helpers.test.ts @@ -14,6 +14,8 @@ * limitations under the License. */ import mockFs from 'mock-fs'; +import * as os from 'os'; +import * as path from 'path'; import { getFileTreeRecursively, getHeadersForFileExtension } from './helpers'; describe('getHeadersForFileExtension', () => { @@ -39,9 +41,11 @@ describe('getHeadersForFileExtension', () => { }); describe('getFileTreeRecursively', () => { + const root = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir'; + beforeEach(() => { mockFs({ - '/rootDir': { + [root]: { file1: '', subDirA: { file2: '', @@ -57,9 +61,9 @@ describe('getFileTreeRecursively', () => { }); it('returns complete file tree of a path', async () => { - const fileList = await getFileTreeRecursively('/rootDir'); + const fileList = await getFileTreeRecursively(root); expect(fileList.length).toBe(2); - expect(fileList).toContain('/rootDir/file1'); - expect(fileList).toContain('/rootDir/subDirA/file2'); + expect(fileList).toContain(path.resolve(root, 'file1')); + expect(fileList).toContain(path.resolve(root, 'subDirA/file2')); }); }); diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index dc1c38ef49..995dfdc175 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-api-docs +## 0.4.2 + +### Patch Changes + +- 9161531b2: Link register API to catalog-import plugin +- Updated dependencies [a08c32ced] +- Updated dependencies [7e0b8cac5] +- Updated dependencies [87c0c53c2] + - @backstage/core@0.4.3 + - @backstage/plugin-catalog@0.2.9 + ## 0.4.1 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index c907288424..23dd66a9a9 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.4.1", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", - "@backstage/plugin-catalog": "^0.2.7", + "@backstage/core": "^0.4.3", + "@backstage/plugin-catalog": "^0.2.9", "@backstage/theme": "^0.2.2", "@kyma-project/asyncapi-react": "^0.14.2", "@material-icons/font": "^1.0.2", @@ -49,8 +49,8 @@ "swagger-ui-react": "^3.37.2" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index f011d224b4..7d67ec0273 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-auth-backend +## 0.2.8 + +### Patch Changes + +- cc046682e: fix bug in token expiration date + ## 0.2.7 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index c55d4e508f..38aed2f792 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.2.7", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -64,7 +64,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.4.2", + "@backstage/cli": "^0.4.4", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/auth-backend/src/identity/TokenFactory.test.ts b/plugins/auth-backend/src/identity/TokenFactory.test.ts index 4303401ee6..8b719799b1 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.test.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.test.ts @@ -87,7 +87,7 @@ describe('TokenFactory', () => { iat: expect.any(Number), exp: expect.any(Number), }); - expect(payload.exp).toBe(payload.iat + keyDurationSeconds * 1000); + expect(payload.exp).toBe(payload.iat + keyDurationSeconds); }); it('should generate new signing keys when the current one expires', async () => { diff --git a/plugins/auth-backend/src/identity/TokenFactory.ts b/plugins/auth-backend/src/identity/TokenFactory.ts index c4c259ed22..36622332e0 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.ts @@ -69,7 +69,7 @@ export class TokenFactory implements TokenIssuer { const sub = params.claims.sub; const aud = 'backstage'; const iat = Math.floor(Date.now() / MS_IN_S); - const exp = iat + this.keyDurationSeconds * MS_IN_S; + const exp = iat + this.keyDurationSeconds; this.logger.info(`Issuing token for ${sub}`); diff --git a/plugins/auth-backend/src/lib/flow/authFlowHelpers.ts b/plugins/auth-backend/src/lib/flow/authFlowHelpers.ts index 22ffc7af88..e70aa0bfee 100644 --- a/plugins/auth-backend/src/lib/flow/authFlowHelpers.ts +++ b/plugins/auth-backend/src/lib/flow/authFlowHelpers.ts @@ -56,7 +56,9 @@ export const postMessageResponse = ( var originInfo = {'type': 'config_info', 'targetOrigin': origin}; (window.opener || window.parent).postMessage(originInfo, '*'); (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin); - window.close(); + setTimeout(() => { + window.close(); + }, 100); // same as the interval of the core-api lib/loginPopup.ts (to address race conditions) `; const hash = crypto.createHash('sha256').update(script).digest('base64'); diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 144627d838..a51001d585 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/plugin-catalog-backend": "^0.5.0", "@backstage/integration": "^0.1.4", @@ -50,8 +50,8 @@ "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index a2b8d7e1a4..ce5b978e7d 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog +## 0.2.9 + +### Patch Changes + +- 7e0b8cac5: Add `CatalogIndexPage` and `CatalogEntityPage`, two new extensions that replace the existing `Router` component. + + Add `EntityLayout` to replace `EntityPageLayout`, using children instead of an element property, and allowing for collection of all `RouteRef` mount points used within tabs. + + Add `EntitySwitch` to be used to select components based on entity data, along with accompanying `isKind`, `isNamespace`, and `isComponentType` filters. + +- 87c0c53c2: Add new `EntityProvider` component, which can be used to provide an entity for the `useEntity` hook. +- Updated dependencies [a08c32ced] +- Updated dependencies [359f9d2d8] + - @backstage/core@0.4.3 + - @backstage/plugin-techdocs@0.5.2 + ## 0.2.8 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 8bdc1fecd0..e8d2309a90 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.2.8", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,9 +32,9 @@ "dependencies": { "@backstage/catalog-client": "^0.3.4", "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-scaffolder": "^0.3.5", - "@backstage/plugin-techdocs": "^0.5.1", + "@backstage/plugin-techdocs": "^0.5.2", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -52,8 +52,8 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@microsoft/microsoft-graph-types": "^1.25.0", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog/src/hooks/useEntity.ts b/plugins/catalog/src/hooks/useEntity.ts index 7b689e8730..289c4e26aa 100644 --- a/plugins/catalog/src/hooks/useEntity.ts +++ b/plugins/catalog/src/hooks/useEntity.ts @@ -55,7 +55,7 @@ export const useEntityFromUrl = (): EntityLoadingStatus => { }; /** - * Grab Entity from the context and it's current loading state. + * Grab Entity from the context and its current loading state. */ export const useEntity = () => { const { entity, loading, error } = useContext<{ diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index a4aca24f3a..f117c660f0 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -50,8 +50,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 41072c9922..b559ca6a86 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -49,8 +49,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 87f5e89a9b..5e71d54073 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-cost-insights +## 0.5.4 + +### Patch Changes + +- 3fca9adb9: Fix links in sample instructions +- Updated dependencies [a08c32ced] + - @backstage/core@0.4.3 + ## 0.5.3 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index a85862eed7..a38a07a3a0 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cost-insights", - "version": "0.5.3", + "version": "0.5.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -56,8 +56,8 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/cost-insights/src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx b/plugins/cost-insights/src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx index 3442de49fc..c3f4b4f79c 100644 --- a/plugins/cost-insights/src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx +++ b/plugins/cost-insights/src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { Box, Typography } from '@material-ui/core'; -import { CodeSnippet } from '@backstage/core'; +import { CodeSnippet, Link } from '@backstage/core'; import { AlertInstructionsLayout } from '../AlertInstructionsLayout'; export const LabelDataflowInstructionsPage = () => { @@ -31,10 +31,10 @@ export const LabelDataflowInstructionsPage = () => { In Cloud Dataflow, labels can be added to a job either programmatically - or via the command-line when launching a job. Note that GCP has - + or via the command-line when launching a job. Note that GCP has{' '} + restrictions - {' '} + {' '} on the length and characters that can be used in labels. @@ -46,9 +46,9 @@ export const LabelDataflowInstructionsPage = () => { DataflowPipelineOptions Dataflow jobs using Beam's{' '} - + DataflowPipelineOptions - {' '} + {' '} directly can use the setLabels function to add one or more labels: "my-dataflow-job For more information on specifying options, see the{' '} - + Dataflow documentation - {' '} + {' '} or{' '} - + Scio Scaladoc - + . diff --git a/plugins/cost-insights/src/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.tsx b/plugins/cost-insights/src/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.tsx index 4fcc34c87f..02b66b0fd1 100644 --- a/plugins/cost-insights/src/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.tsx +++ b/plugins/cost-insights/src/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.tsx @@ -135,7 +135,7 @@ export const ProjectGrowthInstructionsPage = () => { Next, evaluate whether the growth is significant. This helps avoid premature optimization, where cost in engineering time is more than - would be saved from the optimization over a reasonable timeframe. + would be saved from the optimization over a reasonable time frame. We recommend reframing the cost growth itself in terms of engineering @@ -205,7 +205,7 @@ export const ProjectGrowthInstructionsPage = () => { Is the workload using cloud resources efficiently? For compute resources, do the utilization metrics look reasonable? Autoscaling infrastructure, such as Kubernetes, can run workloads more efficiently - without comprimising reliability. + without compromising reliability. Lifecycle diff --git a/plugins/cost-insights/src/utils/duration.ts b/plugins/cost-insights/src/utils/duration.ts index 7a330b6f91..6eebead1d7 100644 --- a/plugins/cost-insights/src/utils/duration.ts +++ b/plugins/cost-insights/src/utils/duration.ts @@ -24,7 +24,7 @@ export const DEFAULT_DURATION = Duration.P30D; * Derive the start date of a given period, assuming two repeating intervals. * * @param duration see comment on Duration enum - * @param endDate from CostInsightsApi.getLastCompleteBillingDate + 1 day + * @param exclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate + 1 day */ export function inclusiveStartDateOf( duration: Duration, diff --git a/plugins/cost-insights/src/utils/mockData.ts b/plugins/cost-insights/src/utils/mockData.ts index ce9e65f1c3..19f9676eea 100644 --- a/plugins/cost-insights/src/utils/mockData.ts +++ b/plugins/cost-insights/src/utils/mockData.ts @@ -234,14 +234,24 @@ export function aggregationFor( 'day', ); + function nextDelta(): number { + const varianceFromBaseline = 0.15; + // Let's give positive vibes in trendlines - higher change for positive delta with >0.5 value + const positiveTrendChance = 0.55; + const normalization = positiveTrendChance - 1; + return baseline * (Math.random() + normalization) * varianceFromBaseline; + } + return [...Array(days).keys()].reduce( (values: DateAggregation[], i: number): DateAggregation[] => { const last = values.length ? values[values.length - 1].amount : baseline; + const date = dayjs(inclusiveStartDateOf(duration, endDate)) + .add(i, 'day') + .format(DEFAULT_DATE_FORMAT); + const amount = Math.max(0, last + nextDelta()); values.push({ - date: dayjs(inclusiveStartDateOf(duration, endDate)) - .add(i, 'day') - .format(DEFAULT_DATE_FORMAT), - amount: Math.max(0, last + (baseline / 20) * (Math.random() * 2 - 1)), + date: date, + amount: amount, }); return values; }, diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 76358cf438..4ec76ad812 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -42,8 +42,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md new file mode 100644 index 0000000000..e1c9ef1717 --- /dev/null +++ b/plugins/fossa/CHANGELOG.md @@ -0,0 +1,9 @@ +# @backstage/plugin-fossa + +## 0.1.1 + +### Patch Changes + +- 7afdfef98: Bump dependency versions of @backstage/core, cli and test-utils +- Updated dependencies [a08c32ced] + - @backstage/core@0.4.3 diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 820092c241..b7878b5b29 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-fossa", - "version": "0.1.0", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 4fe8613e46..823a2fa37c 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index a5612568e7..b9b0e93d6f 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/core-api": "^0.2.7", "@backstage/plugin-catalog": "^0.2.8", "@backstage/theme": "^0.2.2", @@ -51,8 +51,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index a92956d6fa..e6a1092b47 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -42,8 +42,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 310dc96de1..0c42b824fb 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index d42282d738..631e394d71 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -46,8 +46,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 144786d58c..4404b5e845 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -33,7 +33,7 @@ "dependencies": { "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-kubernetes-backend": "^0.2.3", "@backstage/theme": "^0.2.2", "@kubernetes/client-node": "^0.12.1", @@ -46,8 +46,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index a567410290..7bb1427930 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -33,7 +33,7 @@ "dependencies": { "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/core-api": "^0.2.6", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", @@ -47,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index e5c1c70ba2..03b2d83d65 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/org/package.json b/plugins/org/package.json index a8d8f908fb..391311454b 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -33,8 +33,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 6ee51ad1e9..5c8890034f 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/register-component/CHANGELOG.md b/plugins/register-component/CHANGELOG.md index 488d45ec0e..949ac77b56 100644 --- a/plugins/register-component/CHANGELOG.md +++ b/plugins/register-component/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-register-component +## 0.2.6 + +### Patch Changes + +- 1517876fd: Register component plugin is deprecated in favor of @backstage/plugin-catalog-import +- Updated dependencies [a08c32ced] +- Updated dependencies [7e0b8cac5] +- Updated dependencies [87c0c53c2] + - @backstage/core@0.4.3 + - @backstage/plugin-catalog@0.2.9 + ## 0.2.5 ### Patch Changes diff --git a/plugins/register-component/package.json b/plugins/register-component/package.json index dcf981365f..4f161a7398 100644 --- a/plugins/register-component/package.json +++ b/plugins/register-component/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-register-component", - "version": "0.2.5", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", - "@backstage/plugin-catalog": "^0.2.7", + "@backstage/core": "^0.4.3", + "@backstage/plugin-catalog": "^0.2.9", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -45,8 +45,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 6e668df250..90a2d1b218 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -47,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index dcf48f68a8..1a443ceb7c 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -42,6 +42,7 @@ "command-exists-promise": "^2.0.2", "compression": "^1.7.4", "cors": "^2.8.5", + "cross-fetch": "^3.0.6", "dockerode": "^3.2.1", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -49,20 +50,18 @@ "git-url-parse": "^11.4.3", "globby": "^11.0.0", "helmet": "^4.0.0", + "isomorphic-git": "^1.8.0", "jsonschema": "^1.2.6", "morgan": "^1.10.0", - "nodegit": "0.27.0", "uuid": "^8.2.0", "winston": "^3.2.1", - "yaml": "^1.10.0", - "cross-fetch": "^3.0.6" + "yaml": "^1.10.0" }, "devDependencies": { "@backstage/cli": "^0.4.3", "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", - "@types/nodegit": "0.26.11", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "yaml": "^1.10.0" diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts index 4d19069b5e..39efd1c62a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -const mocks = { - Clone: { clone: jest.fn() }, - CheckoutOptions: jest.fn(() => {}), -}; -jest.doMock('nodegit', () => mocks); jest.doMock('fs-extra', () => ({ promises: { mkdtemp: jest.fn(dir => `${dir}-static`), @@ -30,10 +25,16 @@ import { TemplateEntityV1alpha1, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; -import { getVoidLogger } from '@backstage/backend-common'; +import { getVoidLogger, Git } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; describe('AzurePreparer', () => { + const mockGitClient = { + clone: jest.fn(), + }; + + jest.spyOn(Git, 'fromAuth').mockReturnValue(mockGitClient as any); + let mockEntity: TemplateEntityV1alpha1; beforeEach(() => { jest.clearAllMocks(); @@ -77,18 +78,7 @@ describe('AzurePreparer', () => { }; }); - it('calls the clone command with the correct arguments for a repository', async () => { - const preparer = new AzurePreparer(new ConfigReader({})); - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', - expect.any(String), - {}, - ); - }); - - it('calls the clone command with the correct arguments if an access token is provided for a repository', async () => { + it('initializes git client with the correct arguments if an access token is provided for a repository', async () => { const preparer = new AzurePreparer( new ConfigReader({ scaffolder: { @@ -100,36 +90,44 @@ describe('AzurePreparer', () => { }, }), ); + const logger = getVoidLogger(); + await preparer.prepare(mockEntity, { logger }); + + expect(Git.fromAuth).toHaveBeenCalledWith({ + username: 'notempty', + password: 'fake-token', + logger, + }); + }); + it('calls the clone command with the correct arguments for a repository', async () => { + const preparer = new AzurePreparer(new ConfigReader({})); + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', - expect.any(String), - { - fetchOpts: { - callbacks: { - credentials: expect.anything(), - }, - }, - }, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: + 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', + dir: expect.any(String), + }); }); it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new AzurePreparer(new ConfigReader({})); delete mockEntity.spec.path; + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', - expect.any(String), - {}, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: + 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', + dir: expect.any(String), + }); }); it('return the temp directory with the path to the folder if it is specified', async () => { const preparer = new AzurePreparer(new ConfigReader({})); mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity, { logger: getVoidLogger(), }); @@ -142,6 +140,7 @@ describe('AzurePreparer', () => { it('return the working directory with the path to the folder if it is specified', async () => { const preparer = new AzurePreparer(new ConfigReader({})); mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity, { logger: getVoidLogger(), workingDirectory: '/workDir', diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts index 333bf9116c..a38c5f4fdc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts @@ -18,10 +18,9 @@ import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; -import { InputError } from '@backstage/backend-common'; +import { InputError, Git } from '@backstage/backend-common'; import { PreparerBase, PreparerOptions } from './types'; import GitUriParser from 'git-url-parse'; -import { Clone, Cred } from 'nodegit'; import { Config } from '@backstage/config'; export class AzurePreparer implements PreparerBase { @@ -38,6 +37,7 @@ export class AzurePreparer implements PreparerBase { ): Promise { const { protocol, location } = parseLocationAnnotation(template); const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); + const { logger } = opts; if (!['azure/api', 'url'].includes(protocol)) { throw new InputError( @@ -57,19 +57,20 @@ export class AzurePreparer implements PreparerBase { template.spec.path ?? '.', ); - const options = this.privateToken - ? { - fetchOpts: { - callbacks: { - credentials: () => - // Username can anything but the empty string according to: https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page#use-a-pat - Cred.userpassPlaintextNew('notempty', this.privateToken), - }, - }, - } - : {}; + // Username can be anything but the empty string according to: + // https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page#use-a-pat + const git = this.privateToken + ? Git.fromAuth({ + password: this.privateToken, + username: 'notempty', + logger, + }) + : Git.fromAuth({ logger }); - await Clone.clone(repositoryCheckoutUrl, tempDir, options); + await git.clone({ + url: repositoryCheckoutUrl, + dir: tempDir, + }); return path.resolve(tempDir, templateDirectory); } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index 86a870330e..aa040bfe58 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -const mocks = { - Clone: { clone: jest.fn() }, - CheckoutOptions: jest.fn(() => {}), -}; -jest.doMock('nodegit', () => mocks); jest.doMock('fs-extra', () => ({ promises: { mkdtemp: jest.fn(dir => `${dir}-static`), @@ -30,10 +25,16 @@ import { TemplateEntityV1alpha1, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; -import { getVoidLogger } from '@backstage/backend-common'; +import { getVoidLogger, Git } from '@backstage/backend-common'; describe('GitHubPreparer', () => { let mockEntity: TemplateEntityV1alpha1; + const mockGitClient = { + clone: jest.fn(), + }; + + jest.spyOn(Git, 'fromAuth').mockReturnValue(mockGitClient as any); + beforeEach(() => { jest.clearAllMocks(); mockEntity = { @@ -77,28 +78,24 @@ describe('GitHubPreparer', () => { }); it('calls the clone command with the correct arguments for a repository', async () => { const preparer = new GithubPreparer(); + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://github.com/benjdlambert/backstage-graphql-template', - expect.any(String), - { - checkoutBranch: 'master', - }, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: 'https://github.com/benjdlambert/backstage-graphql-template', + dir: expect.any(String), + }); }); it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new GithubPreparer(); delete mockEntity.spec.path; + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://github.com/benjdlambert/backstage-graphql-template', - expect.any(String), - { - checkoutBranch: 'master', - }, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: 'https://github.com/benjdlambert/backstage-graphql-template', + dir: expect.any(String), + }); }); it('return the temp directory with the path to the folder if it is specified', async () => { @@ -128,19 +125,14 @@ describe('GitHubPreparer', () => { it('calls the clone command with the token when provided', async () => { const preparer = new GithubPreparer({ token: 'abc' }); - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://github.com/benjdlambert/backstage-graphql-template', - expect.any(String), - { - checkoutBranch: 'master', - fetchOpts: { - callbacks: { - credentials: expect.any(Function), - }, - }, - }, - ); + const logger = getVoidLogger(); + + await preparer.prepare(mockEntity, { logger }); + + expect(Git.fromAuth).toHaveBeenCalledWith({ + logger, + username: 'abc', + password: 'x-oauth-basic', + }); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts index e6b41907be..e7fa0c9b72 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts @@ -18,10 +18,9 @@ import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; -import { InputError } from '@backstage/backend-common'; +import { InputError, Git } from '@backstage/backend-common'; import { PreparerBase, PreparerOptions } from './types'; import GitUriParser from 'git-url-parse'; -import { Clone, CloneOptions, Cred } from 'nodegit'; export class GithubPreparer implements PreparerBase { token?: string; @@ -36,7 +35,7 @@ export class GithubPreparer implements PreparerBase { ): Promise { const { protocol, location } = parseLocationAnnotation(template); const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); - const { token } = this; + const { logger } = opts; if (!['github', 'url'].includes(protocol)) { throw new InputError( @@ -56,25 +55,21 @@ export class GithubPreparer implements PreparerBase { template.spec.path ?? '.', ); - let cloneOptions: CloneOptions = { - checkoutBranch: parsedGitLocation.ref, - }; + const checkoutLocation = path.resolve(tempDir, templateDirectory); - if (token) { - cloneOptions = { - ...cloneOptions, - fetchOpts: { - callbacks: { - credentials() { - return Cred.userpassPlaintextNew(token, 'x-oauth-basic'); - }, - }, - }, - }; - } + const git = this.token + ? Git.fromAuth({ + username: this.token, + password: 'x-oauth-basic', + logger, + }) + : Git.fromAuth({ logger }); - await Clone.clone(repositoryCheckoutUrl, tempDir, cloneOptions); + await git.clone({ + url: repositoryCheckoutUrl, + dir: tempDir, + }); - return path.resolve(tempDir, templateDirectory); + return checkoutLocation; } } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index 8712507026..8dad349a13 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const mocks = { - Clone: { clone: jest.fn() }, - CheckoutOptions: jest.fn(() => {}), -}; -jest.doMock('nodegit', () => mocks); jest.doMock('fs-extra', () => ({ promises: { mkdtemp: jest.fn(dir => `${dir}-static`), @@ -30,7 +25,7 @@ import { LOCATION_ANNOTATION, } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; +import { getVoidLogger, Git } from '@backstage/backend-common'; const mockEntityWithProtocol = (protocol: string): TemplateEntityV1alpha1 => ({ apiVersion: 'backstage.io/v1alpha1', @@ -72,6 +67,12 @@ const mockEntityWithProtocol = (protocol: string): TemplateEntityV1alpha1 => ({ describe('GitLabPreparer', () => { let mockEntity: TemplateEntityV1alpha1; + const mockGitClient = { + clone: jest.fn(), + }; + + jest.spyOn(Git, 'fromAuth').mockReturnValue(mockGitClient as any); + beforeEach(() => { jest.clearAllMocks(); }); @@ -80,13 +81,13 @@ describe('GitLabPreparer', () => { it(`calls the clone command with the correct arguments for a repository using the ${protocol} protocol`, async () => { const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity = mockEntityWithProtocol(protocol); + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://gitlab.com/benjdlambert/backstage-graphql-template', - expect.any(String), - {}, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: 'https://gitlab.com/benjdlambert/backstage-graphql-template', + dir: expect.any(String), + }); }); it(`calls the clone command with the correct arguments if an access token is provided in integrations for a repository using the ${protocol} protocol`, async () => { @@ -103,19 +104,15 @@ describe('GitLabPreparer', () => { }), ); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://gitlab.com/benjdlambert/backstage-graphql-template', - expect.any(String), - { - fetchOpts: { - callbacks: { - credentials: expect.anything(), - }, - }, - }, - ); + const logger = getVoidLogger(); + + await preparer.prepare(mockEntity, { logger }); + + expect(Git.fromAuth).toHaveBeenCalledWith({ + logger, + username: 'oauth2', + password: 'fake-token', + }); }); it(`calls the clone command with the correct arguments if an access token is provided in scaffolder for a repository using the ${protocol} protocol`, async () => { @@ -127,32 +124,28 @@ describe('GitLabPreparer', () => { }), ); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://gitlab.com/benjdlambert/backstage-graphql-template', - expect.any(String), - { - fetchOpts: { - callbacks: { - credentials: expect.anything(), - }, - }, - }, - ); + const logger = getVoidLogger(); + + await preparer.prepare(mockEntity, { logger }); + + expect(Git.fromAuth).toHaveBeenCalledWith({ + logger, + username: 'oauth2', + password: 'fake-token', + }); }); it(`calls the clone command with the correct arguments for a repository when no path is provided using the ${protocol} protocol`, async () => { const preparer = new GitlabPreparer(new ConfigReader({})); mockEntity = mockEntityWithProtocol(protocol); delete mockEntity.spec.path; + await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - expect(mocks.Clone.clone).toHaveBeenNthCalledWith( - 1, - 'https://gitlab.com/benjdlambert/backstage-graphql-template', - expect.any(String), - {}, - ); + + expect(mockGitClient.clone).toHaveBeenCalledWith({ + url: 'https://gitlab.com/benjdlambert/backstage-graphql-template', + dir: expect.any(String), + }); }); it(`return the temp directory with the path to the folder if it is specified using the ${protocol} protocol`, async () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index c2c2dcd3fd..6e169baa98 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { InputError } from '@backstage/backend-common'; +import { InputError, Git } from '@backstage/backend-common'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -22,7 +22,6 @@ import { } from '@backstage/integration'; import fs from 'fs-extra'; import GitUriParser from 'git-url-parse'; -import { Clone, Cred } from 'nodegit'; import os from 'os'; import path from 'path'; import { parseLocationAnnotation } from '../helpers'; @@ -46,6 +45,7 @@ export class GitlabPreparer implements PreparerBase { opts: PreparerOptions, ): Promise { const { protocol, location } = parseLocationAnnotation(template); + const { logger } = opts; const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); if (!['gitlab', 'gitlab/api', 'url'].includes(protocol)) { @@ -67,17 +67,18 @@ export class GitlabPreparer implements PreparerBase { ); const token = this.getToken(parsedGitLocation.resource); - const options = token - ? { - fetchOpts: { - callbacks: { - credentials: () => Cred.userpassPlaintextNew('oauth2', token), - }, - }, - } - : {}; + const git = token + ? Git.fromAuth({ + password: token, + username: 'oauth2', + logger, + }) + : Git.fromAuth({ logger }); - await Clone.clone(repositoryCheckoutUrl, tempDir, options); + await git.clone({ + url: repositoryCheckoutUrl, + dir: tempDir, + }); return path.resolve(tempDir, templateDirectory); } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.test.ts index 9ea7d2de5f..f1e0cd6175 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.test.ts @@ -13,17 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -jest.mock('nodegit'); -jest.mock('azure-devops-node-api/GitApi'); -jest.mock('azure-devops-node-api/interfaces/GitInterfaces'); -jest.mock('./helpers', () => ({ - pushToRemoteUserPass: jest.fn(), -})); +jest.mock('./helpers'); import { AzurePublisher } from './azure'; import { GitApi } from 'azure-devops-node-api/GitApi'; -import { pushToRemoteUserPass } from './helpers'; +import * as helpers from './helpers'; +import { getVoidLogger } from '@backstage/backend-common'; const { mockGitApi } = require('azure-devops-node-api/GitApi') as { mockGitApi: { @@ -33,6 +28,7 @@ const { mockGitApi } = require('azure-devops-node-api/GitApi') as { describe('Azure Publisher', () => { const publisher = new AzurePublisher(new GitApi('', []), 'fake-token'); + const logger = getVoidLogger(); beforeEach(() => { jest.clearAllMocks(); @@ -50,6 +46,7 @@ describe('Azure Publisher', () => { owner: 'bob', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -63,12 +60,12 @@ describe('Azure Publisher', () => { }, 'project', ); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://dev.azure.com/organization/project/_git/repo', - 'notempty', - 'fake-token', - ); + expect(helpers.initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://dev.azure.com/organization/project/_git/repo', + auth: { username: 'notempty', password: 'fake-token' }, + logger, + }); }); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts index 1e962bf223..ffe6845f01 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts @@ -17,9 +17,9 @@ import { PublisherBase, PublisherOptions, PublisherResult } from './types'; import { GitApi } from 'azure-devops-node-api/GitApi'; import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces'; -import { pushToRemoteUserPass } from './helpers'; import { JsonValue } from '@backstage/config'; import { RequiredTemplateValues } from '../templater'; +import { initRepoAndPush } from './helpers'; export class AzurePublisher implements PublisherBase { private readonly client: GitApi; @@ -33,11 +33,21 @@ export class AzurePublisher implements PublisherBase { async publish({ values, directory, + logger, }: PublisherOptions): Promise { const remoteUrl = await this.createRemote(values); - await pushToRemoteUserPass(directory, remoteUrl, 'notempty', this.token); const catalogInfoUrl = `${remoteUrl}?path=%2Fcatalog-info.yaml`; + await initRepoAndPush({ + dir: directory, + remoteUrl, + auth: { + username: 'notempty', + password: this.token, + }, + logger, + }); + return { remoteUrl, catalogInfoUrl }; } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts index cda64faf25..22f1cd3172 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts @@ -15,10 +15,7 @@ */ jest.mock('@octokit/rest'); -jest.mock('nodegit'); -jest.mock('./helpers', () => ({ - pushToRemoteUserPass: jest.fn(), -})); +jest.mock('./helpers'); import { Octokit } from '@octokit/rest'; import { @@ -27,7 +24,8 @@ import { UsersGetByUsernameResponseData, } from '@octokit/types'; import { GithubPublisher } from './github'; -import { pushToRemoteUserPass } from './helpers'; +import { initRepoAndPush } from './helpers'; +import { getVoidLogger } from '@backstage/backend-common'; const { mockGithubClient } = require('@octokit/rest') as { mockGithubClient: { @@ -38,6 +36,7 @@ const { mockGithubClient } = require('@octokit/rest') as { }; describe('GitHub Publisher', () => { + const logger = getVoidLogger(); beforeEach(() => { jest.clearAllMocks(); }); @@ -69,6 +68,7 @@ describe('GitHub Publisher', () => { access: 'blam/team', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -91,12 +91,12 @@ describe('GitHub Publisher', () => { repo: 'test', permission: 'admin', }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://github.com/backstage/backstage.git', - 'abc', - 'x-oauth-basic', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://github.com/backstage/backstage.git', + auth: { username: 'abc', password: 'x-oauth-basic' }, + logger, + }); }); it('should use octokit to create a repo in the authed user if the organisation property is not set', async () => { @@ -118,6 +118,7 @@ describe('GitHub Publisher', () => { access: 'blam', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -132,12 +133,13 @@ describe('GitHub Publisher', () => { private: false, }); expect(mockGithubClient.repos.addCollaborator).not.toHaveBeenCalled(); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://github.com/backstage/backstage.git', - 'abc', - 'x-oauth-basic', - ); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://github.com/backstage/backstage.git', + auth: { username: 'abc', password: 'x-oauth-basic' }, + logger, + }); }); }); @@ -161,6 +163,7 @@ describe('GitHub Publisher', () => { description: 'description', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -181,12 +184,12 @@ describe('GitHub Publisher', () => { username: 'bob', permission: 'admin', }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://github.com/backstage/backstage.git', - 'abc', - 'x-oauth-basic', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://github.com/backstage/backstage.git', + auth: { username: 'abc', password: 'x-oauth-basic' }, + logger, + }); }); }); @@ -216,6 +219,7 @@ describe('GitHub Publisher', () => { owner: 'bob', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -229,12 +233,12 @@ describe('GitHub Publisher', () => { private: true, visibility: 'internal', }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://github.com/backstage/backstage.git', - 'abc', - 'x-oauth-basic', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://github.com/backstage/backstage.git', + auth: { username: 'abc', password: 'x-oauth-basic' }, + logger, + }); }); }); @@ -263,6 +267,7 @@ describe('GitHub Publisher', () => { owner: 'bob', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ @@ -276,12 +281,12 @@ describe('GitHub Publisher', () => { name: 'test', private: true, }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'https://github.com/backstage/backstage.git', - 'abc', - 'x-oauth-basic', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'https://github.com/backstage/backstage.git', + auth: { username: 'abc', password: 'x-oauth-basic' }, + logger, + }); }); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts index 64976b8e41..39a588882f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts @@ -16,7 +16,7 @@ import { PublisherBase, PublisherOptions, PublisherResult } from './types'; import { Octokit } from '@octokit/rest'; -import { pushToRemoteUserPass } from './helpers'; +import { initRepoAndPush } from './helpers'; import { JsonValue } from '@backstage/config'; import { RequiredTemplateValues } from '../templater'; @@ -46,14 +46,20 @@ export class GithubPublisher implements PublisherBase { async publish({ values, directory, + logger, }: PublisherOptions): Promise { const remoteUrl = await this.createRemote(values); - await pushToRemoteUserPass( - directory, + + await initRepoAndPush({ + dir: directory, remoteUrl, - this.token, - 'x-oauth-basic', - ); + auth: { + username: this.token, + password: 'x-oauth-basic', + }, + logger, + }); + const catalogInfoUrl = remoteUrl.replace( /\.git$/, '/blob/master/catalog-info.yaml', diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts index a87fa6c6d9..2f33358829 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts @@ -14,16 +14,14 @@ * limitations under the License. */ -jest.mock('nodegit'); jest.mock('@gitbeaker/node'); -jest.mock('./helpers', () => ({ - pushToRemoteUserPass: jest.fn(), -})); +jest.mock('./helpers'); import { GitlabPublisher } from './gitlab'; import { Gitlab as GitlabAPI } from '@gitbeaker/core'; import { Gitlab } from '@gitbeaker/node'; -import { pushToRemoteUserPass } from './helpers'; +import { initRepoAndPush } from './helpers'; +import { getVoidLogger } from '@backstage/backend-common'; const { mockGitlabClient } = require('@gitbeaker/node') as { mockGitlabClient: { @@ -34,6 +32,7 @@ const { mockGitlabClient } = require('@gitbeaker/node') as { }; describe('GitLab Publisher', () => { + const logger = getVoidLogger(); const publisher = new GitlabPublisher(new Gitlab({}), 'fake-token'); beforeEach(() => { @@ -56,6 +55,7 @@ describe('GitLab Publisher', () => { owner: 'bob', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ remoteUrl: 'mockclone' }); @@ -63,12 +63,12 @@ describe('GitLab Publisher', () => { namespace_id: 42, name: 'test', }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'mockclone', - 'oauth2', - 'fake-token', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'mockclone', + auth: { username: 'oauth2', password: 'fake-token' }, + logger, + }); }); it('should use gitbeaker to create a repo in the authed user if the namespace property is not set', async () => { @@ -86,6 +86,7 @@ describe('GitLab Publisher', () => { owner: 'bob', }, directory: '/tmp/test', + logger, }); expect(result).toEqual({ remoteUrl: 'mockclone' }); @@ -94,12 +95,12 @@ describe('GitLab Publisher', () => { namespace_id: 21, name: 'test', }); - expect(pushToRemoteUserPass).toHaveBeenCalledWith( - '/tmp/test', - 'mockclone', - 'oauth2', - 'fake-token', - ); + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: '/tmp/test', + remoteUrl: 'mockclone', + auth: { username: 'oauth2', password: 'fake-token' }, + logger, + }); }); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts index 4fae8e8a5c..156a4a249c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts @@ -16,8 +16,8 @@ import { PublisherBase, PublisherOptions, PublisherResult } from './types'; import { Gitlab } from '@gitbeaker/core'; -import { pushToRemoteUserPass } from './helpers'; import { JsonValue } from '@backstage/config'; +import { initRepoAndPush } from './helpers'; import { RequiredTemplateValues } from '../templater'; export class GitlabPublisher implements PublisherBase { @@ -32,9 +32,19 @@ export class GitlabPublisher implements PublisherBase { async publish({ values, directory, + logger, }: PublisherOptions): Promise { const remoteUrl = await this.createRemote(values); - await pushToRemoteUserPass(directory, remoteUrl, 'oauth2', this.token); + + await initRepoAndPush({ + dir: directory, + remoteUrl, + auth: { + username: 'oauth2', + password: this.token, + }, + logger, + }); return { remoteUrl }; } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.test.ts deleted file mode 100644 index 3a317adacd..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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('nodegit'); -import * as NodeGit from 'nodegit'; -import { pushToRemoteCred } from './helpers'; - -const { - Repository, - mockRepo, - mockIndex, - Signature, - Remote, - mockRemote, - Cred, -} = require('nodegit') as { - Repository: jest.Mocked<{ init: any }>; - Signature: jest.Mocked<{ now: any }>; - Cred: jest.Mocked<{ userpassPlaintextNew: any }>; - Remote: jest.Mocked<{ create: any }>; - - mockIndex: jest.Mocked; - mockRepo: jest.Mocked; - mockRemote: jest.Mocked; -}; - -describe('pushToRemoteCred', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const directory = '/tmp/test/dir'; - const remote = 'mockclone'; - const credentialsProvider = () => - NodeGit.Cred.userpassPlaintextNew('username', 'password'); - - it('should call init on the repo with the directory', async () => { - await pushToRemoteCred(directory, remote, credentialsProvider); - - expect(Repository.init).toHaveBeenCalledWith(directory, 0); - }); - - it('should call refresh index on the index and write the new files', async () => { - await pushToRemoteCred(directory, remote, credentialsProvider); - - expect(mockRepo.refreshIndex).toHaveBeenCalled(); - }); - - it('should call add all files and write', async () => { - await pushToRemoteCred(directory, remote, credentialsProvider); - - expect(mockIndex.addAll).toHaveBeenCalled(); - expect(mockIndex.write).toHaveBeenCalled(); - expect(mockIndex.writeTree).toHaveBeenCalled(); - }); - - it('should create a commit with on head with the right name and commiter', async () => { - const mockSignature = { mockSignature: 'bloblly' }; - Signature.now.mockReturnValue(mockSignature); - - await pushToRemoteCred(directory, remote, credentialsProvider); - - expect(Signature.now).toHaveBeenCalledTimes(2); - expect(Signature.now).toHaveBeenCalledWith( - 'Scaffolder', - 'scaffolder@backstage.io', - ); - - expect(mockRepo.createCommit).toHaveBeenCalledWith( - 'HEAD', - mockSignature, - mockSignature, - 'initial commit', - 'mockoid', - [], - ); - }); - - it('creates a remote with the repo and remote', async () => { - await pushToRemoteCred(directory, remote, credentialsProvider); - - expect(Remote.create).toHaveBeenCalledWith(mockRepo, 'origin', 'mockclone'); - }); - - it('shoud push to the remote repo', async () => { - await pushToRemoteCred(directory, remote, credentialsProvider); - - const [remotes, { callbacks }] = mockRemote.push.mock - .calls[0] as NodeGit.PushOptions[]; - - expect(remotes).toEqual(['refs/heads/master:refs/heads/master']); - - callbacks?.credentials?.(); - - expect(Cred.userpassPlaintextNew).toHaveBeenCalledWith( - 'username', - 'password', - ); - }); -}); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts index 51f5a4c854..796e48b8f8 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts @@ -13,43 +13,57 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Repository, Remote, Signature, Cred } from 'nodegit'; -export async function pushToRemoteCred( - directory: string, - remote: string, - credentialsProvider: () => Cred, -): Promise { - const repo = await Repository.init(directory, 0); - const index = await repo.refreshIndex(); - await index.addAll(); - await index.write(); - const oid = await index.writeTree(); - await repo.createCommit( - 'HEAD', - Signature.now('Scaffolder', 'scaffolder@backstage.io'), - Signature.now('Scaffolder', 'scaffolder@backstage.io'), - 'initial commit', - oid, - [], - ); +import globby from 'globby'; +import { Logger } from 'winston'; +import { Git } from '@backstage/backend-common'; - const remoteRepo = await Remote.create(repo, 'origin', remote); +export async function initRepoAndPush({ + dir, + remoteUrl, + auth, + logger, +}: { + dir: string; + remoteUrl: string; + auth: { username: string; password: string }; + logger: Logger; +}): Promise { + const git = Git.fromAuth({ + username: auth.username, + password: auth.password, + logger, + }); - await remoteRepo.push(['refs/heads/master:refs/heads/master'], { - callbacks: { - credentials: credentialsProvider, - }, + await git.init({ + dir, + }); + + const paths = await globby(['./**', './**/.*'], { + cwd: dir, + gitignore: true, + dot: true, + }); + + for (const filepath of paths) { + await git.add({ dir, filepath }); + } + + await git.commit({ + dir, + message: 'Initial commit', + author: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, + committer: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, + }); + + await git.addRemote({ + dir, + url: remoteUrl, + remote: 'origin', + }); + + await git.push({ + dir, + remote: 'origin', }); } - -export async function pushToRemoteUserPass( - directory: string, - remote: string, - username: string, - password: string, -): Promise { - return pushToRemoteCred(directory, remote, () => - Cred.userpassPlaintextNew(username, password), - ); -} diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/types.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/types.ts index f3bc59e19d..bc6b63cc57 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/types.ts @@ -17,6 +17,7 @@ import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { RequiredTemplateValues } from '../templater'; import { JsonValue } from '@backstage/config'; import { RemoteProtocol } from '../types'; +import { Logger } from 'winston'; /** * Publisher is in charge of taking a folder created by @@ -34,6 +35,7 @@ export type PublisherBase = { export type PublisherOptions = { values: RequiredTemplateValues & Record; + logger: Logger; directory: string; }; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index ac3b1c80ec..ffd4d6487c 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -159,6 +159,7 @@ export async function createRouter( const result = await publisher.publish({ values: ctx.values, directory: ctx.resultDir, + logger: ctx.logger, }); return result; }, diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index afebecceac..8cd45779e1 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.8", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -50,8 +50,8 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/search/package.json b/plugins/search/package.json index 9f31c0fd0e..1111e67abe 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/plugin-catalog": "^0.2.7", "@backstage/catalog-model": "^0.6.0", "@backstage/theme": "^0.2.2", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 4284c90688..5dcba49cf0 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", - "@backstage/plugin-catalog": "^0.2.8", + "@backstage/core": "^0.4.3", + "@backstage/plugin-catalog": "^0.2.9", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -46,8 +46,8 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index bc8cd02691..05cc32d681 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -46,8 +46,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index abcd48a43f..ea30f15a67 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/test-utils": "^0.1.5", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", @@ -44,8 +44,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 5db8bfdada..a16449d9e3 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-techdocs-backend +## 0.5.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. + + ``` + + const directoryPreparer = new DirectoryPreparer(logger); + const commonGitPreparer = new CommonGitPreparer(logger); + + const directoryPreparer = new DirectoryPreparer(config, logger); + const commonGitPreparer = new CommonGitPreparer(config, logger); + ``` + +- 359f9d2d8: Added configuration schema for the commonly used properties of techdocs and techdocs-backend plugins +- Updated dependencies [8804e8981] + - @backstage/techdocs-common@0.3.1 + ## 0.5.0 ### Minor Changes diff --git a/plugins/techdocs-backend/config.d.ts b/plugins/techdocs-backend/config.d.ts new file mode 100644 index 0000000000..b51d86138a --- /dev/null +++ b/plugins/techdocs-backend/config.d.ts @@ -0,0 +1,49 @@ +/* + * 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. + */ +/** + * techdocs schema below is an abstract of what's used within techdocs-backend and for its visibility + * to view the complete techdoc schema please refer: plugins/techdocs/config.d.ts + * */ +export interface Config { + /** Configuration options for the techdocs-backend plugin */ + techdocs: { + /** + * attr: 'storageUrl' - accepts a string value + * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs + */ + storageUrl: string; + /** + * documentation building process depends on the builder attr + * attr: 'builder' - accepts a string value + * e.g. builder: 'local' + * alternative: 'external' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + */ + builder: 'local' | 'external'; + /** + * techdocs publisher information + */ + publisher: { + /** + * attr: 'type' - accepts a string value + * e.g. type: 'local' + * aleternatives: 'googleGcs' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + */ + type: 'local' | 'googleGcs' | 'awsS3'; + }; + }; +} diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index cbe872b86a..ed19e4e23a 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.5.0", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@backstage/backend-common": "^0.4.1", "@backstage/catalog-model": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/techdocs-common": "^0.3.0", + "@backstage/techdocs-common": "^0.3.1", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", @@ -44,10 +44,12 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.4.3", + "@backstage/cli": "^0.4.4", "supertest": "^4.0.2" }, "files": [ - "dist" - ] + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/techdocs-backend/src/DocsBuilder/builder.ts b/plugins/techdocs-backend/src/DocsBuilder/builder.ts index 67d0dfb89e..863f587a96 100644 --- a/plugins/techdocs-backend/src/DocsBuilder/builder.ts +++ b/plugins/techdocs-backend/src/DocsBuilder/builder.ts @@ -16,6 +16,7 @@ import Docker from 'dockerode'; import { Logger } from 'winston'; import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import { PreparerBuilder, PublisherBase, @@ -40,6 +41,7 @@ type DocsBuilderArguments = { entity: Entity; logger: Logger; dockerClient: Docker; + config: Config; }; export class DocsBuilder { @@ -49,6 +51,7 @@ export class DocsBuilder { private entity: Entity; private logger: Logger; private dockerClient: Docker; + private config: Config; constructor({ preparers, @@ -57,6 +60,7 @@ export class DocsBuilder { entity, logger, dockerClient, + config, }: DocsBuilderArguments) { this.preparer = preparers.get(entity); this.generator = generators.get(entity); @@ -64,6 +68,7 @@ export class DocsBuilder { this.entity = entity; this.logger = logger; this.dockerClient = dockerClient; + this.config = config; } public async build() { @@ -109,7 +114,11 @@ export class DocsBuilder { // Unless docs are stored locally const nonAgeCheckTypes = ['dir', 'file', 'url']; if (!nonAgeCheckTypes.includes(type)) { - const lastCommit = await getLastCommitTimestamp(target, this.logger); + const lastCommit = await getLastCommitTimestamp( + target, + this.config, + this.logger, + ); const storageTimeStamp = buildMetadataStorage.getTimestamp(); // Check if documentation source is newer than what we have diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index a64f581a1e..37d5dd59ed 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -131,6 +131,7 @@ export async function createRouter({ dockerClient, logger, entity, + config, }); if (publisherType === 'local') { if (!(await docsBuilder.docsUpToDate())) { diff --git a/plugins/techdocs-backend/src/service/standaloneServer.ts b/plugins/techdocs-backend/src/service/standaloneServer.ts index 65a286feef..721c10a1ec 100644 --- a/plugins/techdocs-backend/src/service/standaloneServer.ts +++ b/plugins/techdocs-backend/src/service/standaloneServer.ts @@ -52,7 +52,7 @@ export async function startStandaloneServer( logger.debug('Creating application...'); const preparers = new Preparers(); - const directoryPreparer = new DirectoryPreparer(logger); + const directoryPreparer = new DirectoryPreparer(config, logger); preparers.register('dir', directoryPreparer); const generators = new Generators(); diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 932f551914..8bd79e4139 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs +## 0.5.2 + +### Patch Changes + +- 359f9d2d8: Added configuration schema for the commonly used properties of techdocs and techdocs-backend plugins +- Updated dependencies [a08c32ced] +- Updated dependencies [7e0b8cac5] +- Updated dependencies [8804e8981] +- Updated dependencies [87c0c53c2] +- Updated dependencies [86c3c652a] +- Updated dependencies [27f2af935] + - @backstage/core-api@0.2.8 + - @backstage/core@0.4.3 + - @backstage/plugin-catalog@0.2.9 + - @backstage/techdocs-common@0.3.1 + ## 0.5.1 ### Patch Changes diff --git a/plugins/techdocs/config.d.ts b/plugins/techdocs/config.d.ts new file mode 100644 index 0000000000..543579e85f --- /dev/null +++ b/plugins/techdocs/config.d.ts @@ -0,0 +1,101 @@ +/* + * 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 interface Config { + /** Configuration options for the techdocs plugin */ + techdocs: { + /** + * attr: 'requestUrl' - accepts a string value + * e.g. requestUrl: http://localhost:7000/api/techdocs + * @visibility frontend + */ + requestUrl: string; + /** + * attr: 'storageUrl' - accepts a string value + * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs + */ + storageUrl: string; + /** + * documentation building process depends on the builder attr + * attr: 'builder' - accepts a string value + * e.g. builder: 'local' + * alternative: 'external' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + * @visibility frontend + */ + builder: 'local' | 'external'; + + /** + * techdocs publisher information + */ + generators?: { + /** + * attr: 'techdocs' - accepts a string value + * e.g. type: 'docker' + * aleternatives: 'local' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + */ + techdocs: 'local' | 'docker'; + }; + + /** + * techdocs publisher information + */ + publisher?: + | { + /** + * attr: 'type' - accepts a string value + * e.g. type: 'local' + * aleternatives: 'googleGcs' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + */ + type: 'local' | 'awsS3'; + } + | { + /** + * attr: 'type' - accepts a string value + * e.g. type: 'googleGcs' + * aleternatives: 'googleGcs' etc. + * @see http://backstage.io/docs/features/techdocs/configuration + */ + type: 'googleGcs'; + + /** + * googleGcs required when 'type' is set to googleGcs + */ + googleGcs?: { + /** + * API key used to write to a storage bucket. + * attr: 'credentials' - accepts a string value + * @visibility secret + */ + credentials: string; + /** + * GCP Project ID where the Cloud Storage Bucket is hosted. + * attr: 'projectId' - accepts a string value + * @visibility secret + */ + projectId: string; + /** + * Cloud Storage Bucket Name + * attr: 'bucketName' - accepts a string value + * @visibility secret + */ + bucketName: string; + }; + }; + }; +} diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c9f8bc5da2..b87c158bc4 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.5.1", + "version": "0.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ }, "dependencies": { "@backstage/catalog-model": "^0.6.0", - "@backstage/core": "^0.4.2", - "@backstage/core-api": "^0.2.7", - "@backstage/plugin-catalog": "^0.2.8", + "@backstage/core": "^0.4.3", + "@backstage/core-api": "^0.2.8", + "@backstage/plugin-catalog": "^0.2.9", "@backstage/test-utils": "^0.1.6", "@backstage/theme": "^0.2.2", - "@backstage/techdocs-common": "^0.3.0", + "@backstage/techdocs-common": "^0.3.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -50,8 +50,8 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", @@ -63,85 +63,8 @@ "msw": "^0.21.2" }, "files": [ - "dist" + "dist", + "config.d.ts" ], - "configSchema": { - "$schema": "https://backstage.io/schema/config-v1", - "title": "@backstage/techdocs", - "type": "object", - "properties": { - "techdocs": { - "type": "object", - "properties": { - "requestUrl": { - "type": "string", - "visibility": "frontend" - }, - "storageUrl": { - "type": "string", - "visibility": "backend" - }, - "generators": { - "type": "object", - "properties": { - "techdocs": { - "type": "string", - "visibility": "backend" - } - } - }, - "builder": { - "type": "string", - "visibility": "frontend" - }, - "publisher": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "local", - "visibility": "backend" - } - } - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "googleGcs", - "visibility": "backend" - }, - "googleGcs": { - "type": "object", - "properties": { - "credentials": { - "type": "string", - "visibility": "secret" - }, - "projectId": { - "type": "string", - "visibility": "secret" - }, - "bucketName": { - "type": "string", - "visibility": "secret" - } - } - } - } - } - ] - } - }, - "required": [ - "requestUrl", - "storageUrl", - "builder" - ] - } - } - } + "configSchema": "config.d.ts" } diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 4c9e8ac4fc..d238242a65 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 2986dbe7bf..21ee3787df 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -30,7 +30,7 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.4.2", + "@backstage/core": "^0.4.3", "@backstage/theme": "^0.2.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.4.3", - "@backstage/dev-utils": "^0.1.6", + "@backstage/cli": "^0.4.4", + "@backstage/dev-utils": "^0.1.7", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/scripts/create-github-release.js b/scripts/create-github-release.js old mode 100644 new mode 100755 diff --git a/scripts/migrate-location-types.js b/scripts/migrate-location-types.js old mode 100644 new mode 100755 diff --git a/yarn.lock b/yarn.lock index 195f746693..957a7cebe4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,10 +1666,10 @@ yup "^0.29.3" "@backstage/core@^0.3.0": - version "0.4.1" + version "0.4.2" dependencies: "@backstage/config" "^0.1.2" - "@backstage/core-api" "^0.2.6" + "@backstage/core-api" "^0.2.7" "@backstage/theme" "^0.2.2" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" @@ -3921,9 +3921,9 @@ universal-user-agent "^6.0.0" "@octokit/openapi-types@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.0.0.tgz#6d8f8ad9db3b75a39115f5def2654df8bed39f28" - integrity sha512-J4bfM7lf8oZvEAdpS71oTvC1ofKxfEZgU5vKVwzZKi4QPiL82udjpseJwxPid9Pu2FNmyRQOX4iEj6W1iOSnPw== + version "2.0.1" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.0.1.tgz#7453d8281ce66b8ed1607f7ac7d751c3baffd2cc" + integrity sha512-9AuC04PUnZrjoLiw3uPtwGh9FE4Q3rTqs51oNlQ0rkwgE8ftYsOC+lsrQyvCvWm85smBbSc0FNRKKumvGyb44Q== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -4348,11 +4348,6 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^2.0.0": - version "2.1.1" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1" - integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg== - "@sindresorhus/is@^3.1.1": version "3.1.2" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.2.tgz#548650de521b344e3781fbdb0ece4aa6f729afb8" @@ -5110,7 +5105,7 @@ dependencies: defer-to-connect "^1.0.1" -"@szmarczak/http-timer@^4.0.0", "@szmarczak/http-timer@^4.0.5": +"@szmarczak/http-timer@^4.0.5": version "4.0.5" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152" integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ== @@ -5822,7 +5817,7 @@ resolved "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== -"@types/keyv@*", "@types/keyv@^3.1.1": +"@types/keyv@*": version "3.1.1" resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw== @@ -5977,20 +5972,6 @@ resolved "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz#fe1cc3aa465a3ea6858b793fd380b66c39919766" integrity sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw== -"@types/nodegit@0.26.11": - version "0.26.11" - resolved "https://registry.npmjs.org/@types/nodegit/-/nodegit-0.26.11.tgz#0cbc5e929f23e5ffc536920e3a887e0b3f46d1a4" - integrity sha512-BGrY9F8lBtfU+Ne1Pjb9k/PUsfSCUAqPXgKkTkM6mc5213H5VAoM12zG/sz/cr3jI3AXcngNbAYWlqSrXsWJug== - dependencies: - "@types/node" "*" - -"@types/nodegit@^0.26.12": - version "0.26.12" - resolved "https://registry.npmjs.org/@types/nodegit/-/nodegit-0.26.12.tgz#93afb4cb85d3a48d392c3232699c9c07d8251a36" - integrity sha512-4YpeTImFZNJ1cve4lEueHFVS8rAs8XpZqlmx+Bm9bMc+XMiCrcwaUf6peN7pod7Rl3esVlGP1zdBB7Z12eMVAA== - dependencies: - "@types/node" "*" - "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -7643,6 +7624,11 @@ async-limiter@~1.0.0: resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async-lock@^1.1.0: + version "1.2.4" + resolved "https://registry.npmjs.org/async-lock/-/async-lock-1.2.4.tgz#80d0d612383045dd0c30eb5aad08510c1397cb91" + integrity sha512-UBQJC2pbeyGutIfYmErGc9RaJYnpZ1FHaxuKwb0ahvGiiCkPUf3p67Io+YLPmmv3RHY+mF6JEtNW8FlHsraAaA== + async-retry@^1.2.1: version "1.3.1" resolved "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55" @@ -8280,14 +8266,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - bl@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" @@ -8546,19 +8524,6 @@ btoa@^1.2.1: resolved "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -8569,11 +8534,6 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -8742,14 +8702,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cacheable-lookup@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz#87be64a18b925234875e10a9bb1ebca4adce6b38" - integrity sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg== - dependencies: - "@types/keyv" "^3.1.1" - keyv "^4.0.0" - cacheable-lookup@^5.0.3: version "5.0.3" resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3" @@ -9057,7 +9009,7 @@ chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1, chokidar@^3.4.1, chokidar@^3. optionalDependencies: fsevents "~2.1.2" -chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -9121,6 +9073,11 @@ clean-css@^4.2.3: dependencies: source-map "~0.6.0" +clean-git-ref@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz#dcc0ca093b90e527e67adb5a5e55b1af6816dcd9" + integrity sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -10716,13 +10673,6 @@ decompress-response@^4.2.0: dependencies: mimic-response "^2.0.0" -decompress-response@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f" - integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw== - dependencies: - mimic-response "^2.0.0" - decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -10981,6 +10931,11 @@ diff-sequences@^26.6.2: resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +diff3@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz#d4e5c3a4cdf4e5fe1211ab42e693fcb4321580fc" + integrity sha1-1OXDpM305f4SEatC5pP8tDIVgPw= + diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -12866,7 +12821,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^7.0.0, fs-extra@^7.0.1: +fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -13438,27 +13393,6 @@ google-p12-pem@^3.0.3: dependencies: node-forge "^0.10.0" -got@^10.7.0: - version "10.7.0" - resolved "https://registry.npmjs.org/got/-/got-10.7.0.tgz#62889dbcd6cca32cd6a154cc2d0c6895121d091f" - integrity sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg== - dependencies: - "@sindresorhus/is" "^2.0.0" - "@szmarczak/http-timer" "^4.0.0" - "@types/cacheable-request" "^6.0.1" - cacheable-lookup "^2.0.0" - cacheable-request "^7.0.1" - decompress-response "^5.0.0" - duplexer3 "^0.1.4" - get-stream "^5.0.0" - lowercase-keys "^2.0.0" - mimic-response "^2.1.0" - p-cancelable "^2.0.0" - p-event "^4.0.0" - responselike "^2.0.0" - to-readable-stream "^2.0.0" - type-fest "^0.10.0" - got@^11.5.2: version "11.6.0" resolved "https://registry.npmjs.org/got/-/got-11.6.0.tgz#4978c78f3cbc3a45ee95381f8bb6efd1db1f4638" @@ -15201,6 +15135,23 @@ isomorphic-form-data@~2.0.0: dependencies: form-data "^2.3.2" +isomorphic-git@^1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.8.0.tgz#50440650a64706a321cbea1af955c1cf1110b238" + integrity sha512-TWJvQh+++eFrEG0IFS/jLhMwsBoCOX1/Dsw9q8no59Mp1K0jEjSHXFWv2P04PwkxcIpePkXVBI5YFcFT2nkuQg== + dependencies: + async-lock "^1.1.0" + clean-git-ref "^2.0.1" + crc-32 "^1.2.0" + diff3 "0.0.3" + ignore "^5.1.4" + minimisted "^2.0.0" + pako "^1.0.10" + pify "^4.0.1" + readable-stream "^3.4.0" + sha.js "^2.4.9" + simple-get "^3.0.2" + isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" @@ -15944,7 +15895,7 @@ json3@^3.3.2: resolved "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@2.x, json5@^2.1.0, json5@^2.1.1, json5@^2.1.2: +json5@2.x, json5@^2.1.1, json5@^2.1.2: version "2.1.3" resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== @@ -17456,7 +17407,7 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mimic-response@^2.0.0, mimic-response@^2.1.0: +mimic-response@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== @@ -17526,6 +17477,13 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1. resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimisted@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz#d059fb905beecf0774bc3b308468699709805cb1" + integrity sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA== + dependencies: + minimist "^1.2.5" + minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -17969,23 +17927,6 @@ node-gyp@3.x: tar "^2.0.0" which "1" -node-gyp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-4.0.0.tgz#972654af4e5dd0cd2a19081b4b46fe0442ba6f45" - integrity sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA== - dependencies: - glob "^7.0.3" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3 || 4" - osenv "0" - request "^2.87.0" - rimraf "2" - semver "~5.3.0" - tar "^4.4.8" - which "1" - node-gyp@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz#8e31260a7af4a2e2f994b0673d4e0b3866156332" @@ -18075,22 +18016,6 @@ node-pre-gyp@^0.11.0: semver "^5.3.0" tar "^4" -node-pre-gyp@^0.13.0: - version "0.13.0" - resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" - integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - node-releases@^1.1.52, node-releases@^1.1.58: version "1.1.60" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" @@ -18119,21 +18044,6 @@ node-request-interceptor@^0.5.1: debug "^4.1.1" headers-utils "^1.2.0" -nodegit@0.27.0, nodegit@^0.27.0: - version "0.27.0" - resolved "https://registry.npmjs.org/nodegit/-/nodegit-0.27.0.tgz#4e8cc236f60e1c97324a5acff99056fe116a6ebe" - integrity sha512-E9K4gPjWiA0b3Tx5lfWCzG7Cvodi2idl3V5UD2fZrOrHikIfrN7Fc2kWLtMUqqomyoToYJLeIC8IV7xb1CYRLA== - dependencies: - fs-extra "^7.0.0" - got "^10.7.0" - json5 "^2.1.0" - lodash "^4.17.14" - nan "^2.14.0" - node-gyp "^4.0.0" - node-pre-gyp "^0.13.0" - ramda "^0.25.0" - tar-fs "^1.16.3" - nodemon@^2.0.2: version "2.0.6" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.6.tgz#1abe1937b463aaf62f0d52e2b7eaadf28cc2240d" @@ -18718,7 +18628,7 @@ p-each-series@^2.1.0: resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== -p-event@^4.0.0, p-event@^4.1.0: +p-event@^4.1.0: version "4.2.0" resolved "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== @@ -18908,7 +18818,7 @@ packet-reader@1.0.0: resolved "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== -pako@~1.0.5: +pako@^1.0.10, pako@~1.0.5: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -20253,14 +20163,6 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" -pump@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" - integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - pump@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -20406,11 +20308,6 @@ ramda@^0.21.0: resolved "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= -ramda@^0.25.0: - version "0.25.0" - resolved "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" - integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== - ramda@^0.26, ramda@~0.26.1: version "0.26.1" resolved "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" @@ -21169,7 +21066,7 @@ read@1, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -21856,9 +21753,9 @@ rollup-plugin-dts@1.4.13: "@babel/code-frame" "^7.10.4" rollup-plugin-esbuild@2.6.x: - version "2.6.0" - resolved "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-2.6.0.tgz#80336399b113a179ccb2af5bdf7c03f061f37146" - integrity sha512-wtyDAX8kNABrBfwkrrG2xLRKRGSWUyMBURS067IRvRMpgJlLRo14WcFl95uGc4iYWfdAx436/z1LMzYqdlY4ig== + version "2.6.1" + resolved "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-2.6.1.tgz#5785532940d49adf1bff5b38e9bd9089262d4e7a" + integrity sha512-hskMEQQ4Vxlyoeg1OWlFTwWHIhpNaw6q+diOT7p9pdkk34m9Mbk3aymS/JbTqLXy/AbJi22iuXrucknKpeczfg== dependencies: "@rollup/pluginutils" "^4.1.0" joycon "^2.2.5" @@ -22243,7 +22140,7 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8, sha.js@^2.4.9: version "2.4.11" resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -22354,7 +22251,7 @@ simple-concat@^1.0.0: resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== -simple-get@^3.0.3: +simple-get@^3.0.2, simple-get@^3.0.3: version "3.1.0" resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA== @@ -23465,16 +23362,6 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar-fs@^1.16.3: - version "1.16.3" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" - integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== - dependencies: - chownr "^1.0.1" - mkdirp "^0.5.1" - pump "^1.0.0" - tar-stream "^1.1.2" - tar-fs@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" @@ -23485,19 +23372,6 @@ tar-fs@~2.0.1: pump "^3.0.0" tar-stream "^2.0.0" -tar-stream@^1.1.2: - version "1.6.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - tar-stream@^2.0.0, tar-stream@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" @@ -23837,11 +23711,6 @@ to-arraybuffer@^1.0.0: resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -23859,11 +23728,6 @@ to-readable-stream@^1.0.0: resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== -to-readable-stream@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8" - integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w== - to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" @@ -24164,11 +24028,6 @@ type-detect@4.0.8: resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.10.0: - version "0.10.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz#7f06b2b9fbfc581068d1341ffabd0349ceafc642" - integrity sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw== - type-fest@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"