Backstage is an open platform for building developer portals.
+
+
The philosophy behind Backstage is simple: Don’t expose your engineers to the full complexity of your infrastructure tooling. Engineers should be shipping code β not figuring out a whole new toolset every time they want to implement the basics. Backstage allows you add “stuff” (tooling, services, features, etc.) by adding a plugin, instead of building a new tool. This saves you work and avoids the need of your team to learn how to use and support yet another tool.
As companies grow, their infrastructure systems get messier. Backstage unifies all your infrastructure tooling, services, and documentation with a single, consistent UI.
+
+
This blog post provides more examples of how Backstage is used inside Spotify:
We created Backstage about 4 years ago. While our internal version of Backstage has had the benefit of time to mature and evolve, the first iteration of our open source version is still nascent. We are envisioning three phases of the project and we have already begun work on various aspects of these phases:
+
+
+
π£ Phase 1: Extensible frontend platform (now) - You will be able to easily create a single consistent UI layer for your internal infrastructure and tools. A set of reusable UX patterns and components help ensure a consistent experience between tools.
+
π’ Phase 2: Manage your stuff (next 2–3 months) - Manage anything from microservices to software components to infrastructure and your service catalog. Regardless of whether you want to create a new library, view service deployment status in Kubernetes, or check the test coverage for a website – Backstage will provide all of those tools - and many more - in a single developer portal.
+
π Phase 3: Ecosystem (later) - Everyone’s infrastructure stack is different. By fostering a vibrant community of contributors we hope to provide an ecosystem of Open Source plugins/integrations that allows you to pick the tools that match your stack.
+
+
+
Check out our Milestones and open RFCs how they relate to the three Phases outlined above.
+
+
Our vision for Backstage is for it to become the trusted standard toolbox (read: UX layer) for the open source infrastructure landscape. Think of it like Kubernetes for developer experience. We realize this is an ambitious goal. We canβt do it alone. If this sounds interesting or you’d like to help us shape our product vision, we’d love to talk. You can email me directly: alund@spotify.com.
+
+
Overview
+
+
The Backstage platform consists of a number of different components:
+
+
+
app - Main web application that users interact with. It’s built up by a number of different Plugins. This repo contains an example implementation of an app (located in packages/example-app) and you can easily get started with your own app by creating one.
+
plugins - Each plugin is treated as a self-contained web app and can include almost any type of content. Plugins all use a common set of platform API’s and reusable UI components. Plugins can fetch data either from the backend or through any RESTful API exposed through the proxy.
+
backend - GraphQL aggregation service that holds the model of your software ecosystem, including organisational information and what team owns what software. The backend also has a Plugin model for extending its graph.
+
proxy * - Terminates HTTPS and exposes any RESTful API to Plugins.
+
identity * - A backend service that holds your organisation’s metadata.
+
+
+
* not yet released
+
+
+
+overview
+
+
+
Getting started
+
+
To run a Backstage app, you will need to have the following installed:
Give us a star βοΈ - If you are using Backstage or think it is an interesting project, we would love a star β€οΈ
+
+
+
Or, if you are an open source developer and are interested in joining our team, please reach out to foss-opportunities@spotify.com
+
+
License
+
+
Copyright 2020 Spotify AB.
+
+
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+
+
+
diff --git a/packages/app/package.json b/packages/app/package.json
index 7ccb6c9a91..da1d02a5be 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -20,6 +20,7 @@
"dependencies": {
"@backstage/cli": "^0.1.1-alpha.4",
"@backstage/core": "^0.1.1-alpha.4",
+ "@backstage/plugin-circleci": "^0.1.1-alpha.4",
"@backstage/plugin-home-page": "^0.1.1-alpha.4",
"@backstage/plugin-inventory": "^0.1.1-alpha.4",
"@backstage/plugin-lighthouse": "^0.1.1-alpha.4",
diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts
index a7e425b869..31546c6ba6 100644
--- a/packages/app/src/plugins.ts
+++ b/packages/app/src/plugins.ts
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
export { plugin as HomePagePlugin } from '@backstage/plugin-home-page';
export { plugin as WelcomePlugin } from '@backstage/plugin-welcome';
export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse';
export { plugin as InventoryPlugin } from '@backstage/plugin-inventory';
export { plugin as TechRadar } from '@backstage/plugin-tech-radar';
+export { plugin as Circleci } from '@backstage/plugin-circleci';
diff --git a/plugins/circleci/.eslintrc.js b/plugins/circleci/.eslintrc.js
new file mode 100644
index 0000000000..13573efa9c
--- /dev/null
+++ b/plugins/circleci/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: [require.resolve('@backstage/cli/config/eslint')],
+};
diff --git a/plugins/circleci/README.md b/plugins/circleci/README.md
new file mode 100644
index 0000000000..46d48e9411
--- /dev/null
+++ b/plugins/circleci/README.md
@@ -0,0 +1,6 @@
+# Title
+Welcome to the circleci plugin!
+
+## Sub-section 1
+
+## Sub-section 2
diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json
new file mode 100644
index 0000000000..80603f4029
--- /dev/null
+++ b/plugins/circleci/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "@backstage/plugin-circleci",
+ "version": "0.1.1-alpha.4",
+ "main": "dist/index.cjs.js",
+ "types": "dist/index.d.ts",
+ "license": "Apache-2.0",
+ "private": true,
+ "scripts": {
+ "build": "backstage-cli plugin:build",
+ "lint": "backstage-cli lint",
+ "test": "backstage-cli test",
+ "clean": "backstage-cli clean"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.1.1-alpha.4",
+ "@testing-library/jest-dom": "^4.2.4",
+ "@testing-library/react": "^9.3.2",
+ "@testing-library/user-event": "^7.1.2",
+ "@types/jest": "^24.0.0",
+ "@types/node": "^12.0.0",
+ "@types/testing-library__jest-dom": "5.0.2",
+ "jest-fetch-mock": "^3.0.3"
+ },
+ "dependencies": {
+ "@backstage/core": "^0.1.1-alpha.4",
+ "@backstage/theme": "^0.1.1-alpha.4",
+ "@material-ui/core": "^4.9.1",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.45",
+ "circleci-api": "^4.0.0",
+ "react": "16.13.1",
+ "react-dom": "16.13.1",
+ "react-use": "^13.0.0"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/circleci/src/components/ExampleComponent/ExampleComponent.test.tsx b/plugins/circleci/src/components/ExampleComponent/ExampleComponent.test.tsx
new file mode 100644
index 0000000000..ef0f3f9632
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleComponent/ExampleComponent.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * 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 React from 'react';
+import { render } from '@testing-library/react';
+import mockFetch from 'jest-fetch-mock';
+import ExampleComponent from './ExampleComponent';
+import { ThemeProvider } from '@material-ui/core';
+import { lightTheme } from '@backstage/theme';
+
+describe('ExampleComponent', () => {
+ it('should render', () => {
+ mockFetch.mockResponse(() => new Promise(() => {}));
+ const rendered = render(
+
+
+ ,
+ );
+ expect(rendered.getByText('Welcome to circleci!')).toBeInTheDocument();
+ });
+});
diff --git a/plugins/circleci/src/components/ExampleComponent/ExampleComponent.tsx b/plugins/circleci/src/components/ExampleComponent/ExampleComponent.tsx
new file mode 100644
index 0000000000..72b5e0e798
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleComponent/ExampleComponent.tsx
@@ -0,0 +1,59 @@
+/*
+ * 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 React, { FC } from 'react';
+import { Typography, Grid } from '@material-ui/core';
+import {
+ InfoCard,
+ Header,
+ Page,
+ pageTheme,
+ Content,
+ ContentHeader,
+ HeaderLabel,
+ SupportButton,
+} from '@backstage/core';
+import ExampleFetchComponent from '../ExampleFetchComponent';
+
+const ExampleComponent: FC<{}> = () => (
+
+
+
+
+
+
+
+ A description of your plugin goes here.
+
+
+
+
+
+ All content should be wrapped in a card like this.
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export default ExampleComponent;
diff --git a/plugins/circleci/src/components/ExampleComponent/index.ts b/plugins/circleci/src/components/ExampleComponent/index.ts
new file mode 100644
index 0000000000..e785d45082
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleComponent/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 { default } from './ExampleComponent';
diff --git a/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx b/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx
new file mode 100644
index 0000000000..7fecdc6f11
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx
@@ -0,0 +1,28 @@
+/*
+ * 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 React from 'react';
+import { render } from '@testing-library/react';
+import mockFetch from 'jest-fetch-mock';
+import ExampleFetchComponent from './ExampleFetchComponent';
+
+describe('ExampleFetchComponent', () => {
+ it('should render', async () => {
+ mockFetch.mockResponse(() => new Promise(() => {}));
+ const rendered = render();
+ expect(await rendered.findByTestId('progress')).toBeInTheDocument();
+ });
+});
diff --git a/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx b/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx
new file mode 100644
index 0000000000..7342da7d71
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx
@@ -0,0 +1,151 @@
+/*
+ * 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 React, { FC } from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Alert from '@material-ui/lab/Alert';
+import { useAsync } from 'react-use';
+import { Progress } from '@backstage/core';
+
+import { CircleCI, GitType, CircleCIOptions } from "circleci-api";
+
+const CIRCLECI_TOKEN: string = "943aa82531ccaab192b4c4bc614507dff31c094c";
+
+// Configure the factory with some defaults
+const options: CircleCIOptions = {
+ // Required for all requests
+ token: CIRCLECI_TOKEN, // Set your CircleCi API token
+
+ // Optional
+ // Anything set here can be overriden when making the request
+
+ // Git information is required for project/build/etc endpoints
+ vcs: {
+ type: GitType.GITHUB, // default: github
+ owner: "CircleCITest3",
+ repo: "circleci-test"
+ },
+
+ // Optional query params for requests
+ // options: {
+ // branch: "master", // default: master
+ // }
+};
+
+const api = new CircleCI(options);
+
+api.builds()
+ .then((v) => console.log("token is valid"))
+ .catch(() => console.error("invalid token"));
+
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 650,
+ },
+ avatar: {
+ height: 32,
+ width: 32,
+ borderRadius: '50%',
+ },
+});
+
+type User = {
+ gender: string; // "male"
+ name: {
+ title: string; // "Mr",
+ first: string; // "Duane",
+ last: string; // "Reed"
+ };
+ location: object; // {street: {number: 5060, name: "Hickory Creek Dr"}, city: "Albany", state: "New South Wales",β¦}
+ email: string; // "duane.reed@example.com"
+ login: object; // {uuid: "4b785022-9a23-4ab9-8a23-cb3fb43969a9", username: "blackdog796", password: "patch",β¦}
+ dob: object; // {date: "1983-06-22T12:30:23.016Z", age: 37}
+ registered: object; // {date: "2006-06-13T18:48:28.037Z", age: 14}
+ phone: string; // "07-2154-5651"
+ cell: string; // "0405-592-879"
+ id: {
+ name: string; // "TFN",
+ value: string; // "796260432"
+ };
+ picture: { medium: string }; // {medium: "https://randomuser.me/api/portraits/men/95.jpg",β¦}
+ nat: string; // "AU"
+};
+
+type DenseTableProps = {
+ users: User[];
+};
+
+export const DenseTable: FC = ({ users }) => {
+ const classes = useStyles();
+
+ return (
+
+
+
+ );
+};
+
+const ExampleFetchComponent: FC<{}> = () => {
+ // const { value, loading, error } = useAsync(async (): Promise => {
+ // const response = await fetch('https://randomuser.me/api/?results=20');
+ // const data = await response.json();
+ // return data.results;
+ // }, []);
+
+ if (loading) {
+ return ;
+ } else if (error) {
+ return {error.message};
+ }
+
+ return ;
+};
+
+export default ExampleFetchComponent;
diff --git a/plugins/circleci/src/components/ExampleFetchComponent/index.ts b/plugins/circleci/src/components/ExampleFetchComponent/index.ts
new file mode 100644
index 0000000000..28482f9fe1
--- /dev/null
+++ b/plugins/circleci/src/components/ExampleFetchComponent/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 { default } from './ExampleFetchComponent';
diff --git a/plugins/circleci/src/index.ts b/plugins/circleci/src/index.ts
new file mode 100644
index 0000000000..3a0a0fe2d3
--- /dev/null
+++ b/plugins/circleci/src/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 { plugin } from './plugin';
diff --git a/plugins/circleci/src/plugin.test.ts b/plugins/circleci/src/plugin.test.ts
new file mode 100644
index 0000000000..821a503257
--- /dev/null
+++ b/plugins/circleci/src/plugin.test.ts
@@ -0,0 +1,23 @@
+/*
+ * 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 { plugin } from './plugin';
+
+describe('circleci', () => {
+ it('should export plugin', () => {
+ expect(plugin).toBeDefined();
+ });
+});
diff --git a/plugins/circleci/src/plugin.ts b/plugins/circleci/src/plugin.ts
new file mode 100644
index 0000000000..2c56b4eec2
--- /dev/null
+++ b/plugins/circleci/src/plugin.ts
@@ -0,0 +1,24 @@
+/*
+ * 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 { createPlugin } from '@backstage/core';
+import ExampleComponent from './components/ExampleFetchComponent';
+
+export const plugin = createPlugin({
+ id: 'circleci',
+ register({ router }) {
+ router.registerRoute('/circleci', ExampleComponent);
+ },
+});
diff --git a/plugins/circleci/src/setupTests.ts b/plugins/circleci/src/setupTests.ts
new file mode 100644
index 0000000000..1a907ab8e6
--- /dev/null
+++ b/plugins/circleci/src/setupTests.ts
@@ -0,0 +1,18 @@
+/*
+ * 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 '@testing-library/jest-dom/extend-expect';
+require('jest-fetch-mock').enableMocks();
diff --git a/plugins/circleci/tsconfig.json b/plugins/circleci/tsconfig.json
new file mode 100644
index 0000000000..7b73db2f0f
--- /dev/null
+++ b/plugins/circleci/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": ["src"],
+ "compilerOptions": {
+ "baseUrl": "src"
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index f17fc840c8..cd2016d0d0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5290,6 +5290,13 @@ aws4@^1.8.0:
resolved "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
+axios@^0.19.0:
+ version "0.19.2"
+ resolved "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
+ integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
+ dependencies:
+ follow-redirects "1.5.10"
+
axobject-query@^2.0.2:
version "2.1.2"
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799"
@@ -6460,6 +6467,13 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
+circleci-api@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/circleci-api/-/circleci-api-4.0.0.tgz#d773fe68f4a59e1968881269883a23b0805b3546"
+ integrity sha512-D/THFyhOv6THSkYXJhrOLIOmV7fmyDqgs1+pBFMAqDR+ywXszxa2Dqx1Zw+YD3O2zD2y5LQOifCDT96VidRG7Q==
+ dependencies:
+ axios "^0.19.0"
+
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -7769,7 +7783,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
dependencies:
ms "2.0.0"
-debug@3.1.0:
+debug@3.1.0, debug@=3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
@@ -9499,6 +9513,13 @@ focus-lock@^0.6.6:
resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-0.6.6.tgz#98119a755a38cfdbeda0280eaa77e307eee850c7"
integrity sha512-Dx69IXGCq1qsUExWuG+5wkiMqVM/zGx/reXSJSLogECwp3x6KeNQZ+NAetgxEFpnC41rD8U3+jRCW68+LNzdtw==
+follow-redirects@1.5.10:
+ version "1.5.10"
+ resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
+ dependencies:
+ debug "=3.1.0"
+
follow-redirects@^1.0.0:
version "1.10.0"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz#01f5263aee921c6a54fb91667f08f4155ce169eb"