diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..c69a5cb18f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,31 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space + +[*.html] +indent_style = space +indent_size = 2 + +[*.{ts,json,js,tsx,jsx}] +indent_style = space +indent_size = 2 + +[*.md] +indent_size = 2 +indent_style = space + +[Dockerfile] +indent_style = space +indent_size = 2 + +[*.{yml,yaml}] +indent_size = 2 +indent_style = space diff --git a/.eslintrc.js b/.eslintrc.js index a7cf9c3694..c227c17938 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,21 +1,4 @@ -const copyrightTemplate = `/* - * 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. - */ - -`; - +const path = require('path') const base = require('@spotify-backstage/cli/config/eslint'); module.exports = { @@ -25,8 +8,7 @@ module.exports = { 'notice/notice': [ 'error', { - template: copyrightTemplate, - onNonMatchingHeader: 'replace', + templateFile: path.resolve(__dirname, "scripts/copyright.js"), }, ], }, diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md new file mode 100644 index 0000000000..8c1733a6a6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_template.md @@ -0,0 +1,35 @@ +--- +name: 'Bug Report' +about: 'Create Bug Report' +--- + + + +## Expected Behavior + + +## Current Behavior + + +## Possible Solution + + + +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + + +## Your Environment + +* NodeJS Version (v12): +* Operating System and Version (e.g. Ubuntu 14.04): +* Browser Information: \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_template.md b/.github/ISSUE_TEMPLATE/feature_template.md new file mode 100644 index 0000000000..17b543c27a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_template.md @@ -0,0 +1,18 @@ +--- +name: 'Feature Request' +about: 'Suggest new features and changes' +--- + + + +## Feature Suggestion + + + +## Possible Implementation + + +## Context + + + \ No newline at end of file diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml new file mode 100644 index 0000000000..31bf396f5f --- /dev/null +++ b/.github/workflows/cli.yml @@ -0,0 +1,49 @@ +name: CLI Test + +on: + pull_request: + paths: ['.github/workflows/cli.yml', 'packages/cli/**'] + types: [opened, reopened, edited, synchronize] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + node-version: [12.x] + + name: Node ${{ matrix.node-version }} on ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: find location of yarn cache + id: yarn-cache + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v1 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: use node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: yarn install + - run: yarn build + # This creates a new plugin and pollutes the workspace, so it should be run last. + - name: verify app serve and plugin creation + shell: bash + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + sudo sysctl fs.inotify.max_user_watches=524288 + fi + node scripts/cli-e2e-test.js + - name: yarn lint, test after plugin creation + working-directory: plugins/test-plugin + run: | + yarn lint + yarn test + env: + CI: true diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 5db1f65aa3..5c8e5c43b9 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -13,9 +13,8 @@ jobs: node-version: [12.x] steps: - - name: checkout code - uses: actions/checkout@v2 - - name: get yarn cache + - uses: actions/checkout@v2 + - name: find location of yarn cache id: yarn-cache run: echo "::set-output name=dir::$(yarn cache dir)" - uses: actions/cache@v1 @@ -31,12 +30,8 @@ jobs: - name: yarn install, build, and test run: | yarn install + yarn lint yarn build yarn test env: CI: true - # This creates a new plugin and pollutes the workspace, so it should be run last. - - name: verify app serve and plugin creation - run: | - sudo sysctl fs.inotify.max_user_watches=524288 - node scripts/cli-e2e-test.js diff --git a/README.md b/README.md index fd3bcb72d7..629bfdc376 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ +![headline](docs/headline.png) + # [Backstage](https://backstage.io) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![](https://github.com/spotify/backstage/workflows/Frontend%20CI/badge.svg) [![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.gg/EBHEGzX) +![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) + ## What is Backstage? 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. -![headline](headline.png) - For more information go to [backstage.io](https://backstage.io) ## What problem does Backstage solve? -As companies grow, their infrastructure systems get messier. Backstage unifies all your infrastructure tooling, services, and documentation with a single, consistent UI. +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: @@ -25,11 +27,11 @@ https://labs.spotify.com/2020/03/17/what-the-heck-is-backstage-anyway/ 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 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 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. +- 🐇 **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](https://github.com/spotify/backstage/milestones) and how they relate to the 3 Phases outlined above. diff --git a/docs/headline.png b/docs/headline.png new file mode 100644 index 0000000000..b0f9cb8b5c Binary files /dev/null and b/docs/headline.png differ diff --git a/headline.png b/headline.png deleted file mode 100644 index 063f5be00b..0000000000 Binary files a/headline.png and /dev/null differ diff --git a/packages/cli/.eslintrc.js b/packages/cli/.eslintrc.js index 182a6df30a..f3f858836d 100644 --- a/packages/cli/.eslintrc.js +++ b/packages/cli/.eslintrc.js @@ -1,4 +1,5 @@ module.exports = { + ignorePatterns: ['templates/**'], rules: { 'no-console': 0, }, diff --git a/packages/cli/src/commands/plugin/assets.d.ts b/packages/cli/src/commands/plugin/assets.d.ts index 34ba07f75c..54523e926b 100644 --- a/packages/cli/src/commands/plugin/assets.d.ts +++ b/packages/cli/src/commands/plugin/assets.d.ts @@ -1,3 +1,19 @@ +/* + * 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. + */ + /// /// /// diff --git a/packages/cli/src/commands/plugin/build.ts b/packages/cli/src/commands/plugin/build.ts index ff95bb994a..4c2113eb2a 100644 --- a/packages/cli/src/commands/plugin/build.ts +++ b/packages/cli/src/commands/plugin/build.ts @@ -16,10 +16,27 @@ import { Command } from 'commander'; import fs from 'fs-extra'; -import recursive from 'recursive-readdir'; import path from 'path'; +import recursive from 'recursive-readdir'; import { run } from '../../helpers/run'; +const copyStaticAssets = async () => { + const pluginRoot = fs.realpathSync(process.cwd()); + const source = path.resolve(pluginRoot, 'src'); + const destination = path.resolve(pluginRoot, 'dist', 'cjs'); + const assetFiles = await recursive(source, [ + '**/*.tsx', + '**/*.ts', + '**/*.js', + ]); + assetFiles.forEach(file => { + const fileToBeCopied = file.replace(source, destination); + const dirForFileToBeCopied = path.dirname(fileToBeCopied); + fs.ensureDirSync(dirForFileToBeCopied); + fs.copyFileSync(file, file.replace(source, destination).toString()); + }); +}; + export default async (cmd: Command) => { const args = [ '--outDir', @@ -37,20 +54,3 @@ export default async (cmd: Command) => { await copyStaticAssets(); await run('tsc', args); }; - -const copyStaticAssets = async () => { - const pluginRoot = fs.realpathSync(process.cwd()); - const source = path.resolve(pluginRoot, 'src'); - const destination = path.resolve(pluginRoot, 'dist', 'cjs'); - const assetFiles = await recursive(source, [ - '**/*.tsx', - '**/*.ts', - '**/*.js', - ]); - assetFiles.forEach(file => { - const fileToBeCopied = file.replace(source, destination); - const dirForFileToBeCopied = path.dirname(fileToBeCopied); - fs.ensureDirSync(dirForFileToBeCopied); - fs.copyFileSync(file, file.replace(source, destination).toString()); - }); -}; diff --git a/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs b/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs index 2bb43d5cce..4801dea6dd 100644 --- a/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs +++ b/packages/cli/templates/default-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs @@ -1,3 +1,4 @@ +/* eslint-disable react/prop-types */ /* * Copyright 2020 Spotify AB * diff --git a/packages/cli/templates/default-plugin/src/plugin.test.ts.hbs b/packages/cli/templates/default-plugin/src/plugin.test.ts.hbs index 0139d97727..4e94ca5d50 100644 --- a/packages/cli/templates/default-plugin/src/plugin.test.ts.hbs +++ b/packages/cli/templates/default-plugin/src/plugin.test.ts.hbs @@ -1,3 +1,19 @@ +/* + * 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('{{ id }}', () => { diff --git a/packages/cli/templates/default-plugin/src/plugin.ts.hbs b/packages/cli/templates/default-plugin/src/plugin.ts.hbs index 830de5f553..ccac096007 100644 --- a/packages/cli/templates/default-plugin/src/plugin.ts.hbs +++ b/packages/cli/templates/default-plugin/src/plugin.ts.hbs @@ -1,3 +1,19 @@ +/* + * 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 '@spotify-backstage/core'; import ExampleComponent from './components/ExampleComponent'; diff --git a/packages/core/src/testUtils/logCollector.js b/packages/core/src/testUtils/logCollector.js index 57b30c8f5c..c3ffa525b3 100644 --- a/packages/core/src/testUtils/logCollector.js +++ b/packages/core/src/testUtils/logCollector.js @@ -15,6 +15,7 @@ */ /* eslint-disable no-console */ +/* eslint-disable no-param-reassign */ // If the callback function is async this one will be too. export function withLogCollector(logsToCollect, callback) { diff --git a/scripts/copyright.js b/scripts/copyright.js new file mode 100644 index 0000000000..4376d55847 --- /dev/null +++ b/scripts/copyright.js @@ -0,0 +1,15 @@ +/* + * Copyright <%= YEAR %> 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. + */ diff --git a/yarn.lock b/yarn.lock index dda14de215..a6914db055 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10772,12 +10772,12 @@ load-json-file@^5.3.0: type-fest "^0.3.0" loader-fs-cache@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz#54cedf6b727e1779fd8f01205f05f6e88706f086" - integrity sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw== + version "1.0.3" + resolved "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz#f08657646d607078be2f0a032f8bd69dd6f277d9" + integrity sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA== dependencies: find-cache-dir "^0.1.1" - mkdirp "0.5.1" + mkdirp "^0.5.1" loader-runner@^2.4.0: version "2.4.0" @@ -11435,16 +11435,16 @@ minimist-options@^3.0.1: arrify "^1.0.1" is-plain-obj "^1.1.0" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -11537,12 +11537,12 @@ mkdirp@*: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== -mkdirp@0.5.1, mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.3" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c" + integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg== dependencies: - minimist "0.0.8" + minimist "^1.2.5" modify-values@^1.0.0: version "1.0.1"