diff --git a/ADOPTERS.md b/ADOPTERS.md
index dc02ad3b85..0ba3e3196b 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -12,3 +12,4 @@
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
+| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce39a9f8d2..20ae9a414d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,15 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re
> Collect changes for the next release below
+- The backend plugin
+ [service builder](https://github.com/spotify/backstage/blob/master/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts)
+ no longer adds `express.json()` automatically to all routes. While convenient
+ in a lot of cases, it also led to problems where for example the proxy
+ middleware could hang because the body had already been altered and could not
+ be streamed. Also, plugins that rather wanted to handle e.g. form encoded data
+ still had to cater to that manually. We therefore decided to let plugins add
+ `express.json()` themselves if they happen to deal with JSON data.
+
## v0.1.1-alpha.20
- Includes https://github.com/spotify/backstage/pull/2097 to resolve issues with create-plugin command.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5b8febd1d2..853332f74d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,4 @@
----
-id: CONTRIBUTING
-title: Contributing
----
+# Contributing to Backstage
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.
@@ -31,7 +28,7 @@ What kind of plugins should/could be created? Some inspiration from the 120+ plu
## Suggesting a plugin
-If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?template=plugin_template.md). This helps the community know what plugins are in development.
+If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). This helps the community know what plugins are in development.
You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work.
diff --git a/README.md b/README.md
index b5e8704548..4009864edc 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@ Take a look at the [Getting Started](https://backstage.io/docs/getting-started/i
## Documentation
-- [Main documentation](https://backstage.io/docs/overview/what-is-backstage)
+- [Main documentation](https://backstage.io/docs)
- [Service Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview)
- [Architecture](https://backstage.io/docs/overview/architecture-terminology) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview))
- [Designing for Backstage](https://backstage.io/docs/dls/design)
diff --git a/app-config.yaml b/app-config.yaml
index ba556873aa..7a8863495e 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -49,7 +49,7 @@ lighthouse:
catalog:
rules:
- allow: [Component, API, Group, Template]
+ - allow: [Component, API, Group, Template, Location]
processors:
githubApi:
privateToken:
diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md
index acfaf115de..be6314e494 100644
--- a/docs/features/software-catalog/configuration.md
+++ b/docs/features/software-catalog/configuration.md
@@ -23,30 +23,31 @@ configuration.
## Catalog Rules
By default the catalog will only allow ingestion of entities with the kind
-`Component` and `API`. In order to allow entities of other kinds to be added,
-you need to add rules to the catalog. Rules are added either in a separate
-`catalog.rules` key, or added to statically configured locations.
+`Component`, `API` and `Location`. In order to allow entities of other kinds to
+be added, you need to add rules to the catalog. Rules are added either in a
+separate `catalog.rules` key, or added to statically configured locations.
For example, given the following configuration:
```yaml
catalog:
rules:
- - allow: [Component, API, Template]
+ - allow: [Component, API, Location, Template]
locations:
- type: github
target: https://github.com/org/example/blob/master/org-data.yaml
- allow: [Group]
+ rules:
+ - allow: [Group]
```
-We are able to add entities of kind `Component`, `API`, or `Template` from any
-location, and `Group` entities from the `org-data.yaml`, which will also be read
-as statically configured location.
+We are able to add entities of kind `Component`, `API`, `Location`, or
+`Template` from any location, and `Group` entities from the `org-data.yaml`,
+which will also be read as statically configured location.
Note that if the `catalog.rules` key is present it will replace the default
-value, meaning that you need to add rules for `Component` and `API` kinds if you
-want those to be allowed.
+value, meaning that you need to add rules for the default kinds if you want
+those to still be allowed.
The following configuration will reject any kind of entities from being added to
the catalog:
diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md
index 16419b4dfe..4f7af7c015 100644
--- a/docs/features/software-templates/adding-templates.md
+++ b/docs/features/software-templates/adding-templates.md
@@ -67,7 +67,8 @@ catalog:
locations:
- type: github
target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml
- allow: [Template]
+ rules:
+ - allow: [Template]
```
Templates can also be added by posting the to the catalog directly. Note that if
@@ -77,7 +78,7 @@ to be ingested from any source, for example:
```yaml
catalog:
rules:
- allow: [Component, API, Template]
+ - allow: [Component, API, Template]
```
For loading from a file, the following command should work when the backend is
diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md
index a84bc525c9..5a06f4544f 100644
--- a/docs/overview/roadmap.md
+++ b/docs/overview/roadmap.md
@@ -79,18 +79,26 @@ guidelines to get started.
- Further improvements to platform documentation
+### Plugins
+
+Building and maintaining [plugins](https://backstage.io/plugins) is the work of
+the entire Backstage community.
+
+A list of plugins that are in development is
+[available here](https://github.com/spotify/backstage/issues?q=is%3Aissue+is%3Aopen+label%3Aplugin+sort%3Areactions-%2B1-desc).
+We strongly recommend to upvote ๐ plugins you are interested in. This helps us
+and the community prioritize what plugins to build.
+
+Are you missing a plugin for your favorite tool? Please
+[suggest a new one](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME).
+Chances are that someone will jump in and help build it.
+
### Future work ๐ฎ
- **[Backstage platform is stable](https://github.com/spotify/backstage/milestone/19)** -
The platform APIs and features are stable and can be depended on for
production use. After this plugins will require little to no maintenance.
-- **[Plugin marketplace](https://github.com/spotify/backstage/issues/2009)** -
- As the ecosystem of Backstage plugins continues to grow it is becoming
- increasingly hard to keep track of what plugins are available. To solve this
- we imagine a "Plugin marketplace" that helps with discovery and installation
- of plugins.
-
- **Deploy a product demo at `demo.backstage.io`** - Deploy a typical Backstage
deployment available publicly so that people can click around and get a feel
for the product without having to install anything.
@@ -111,6 +119,7 @@ guidelines to get started.
### Completed milestones โ
+- [Plugin marketplace](https://backstage.io/plugins)
- [Improved and move documentation to backstage.io](https://backstage.io/docs/overview/what-is-backstage)
- [Backstage Service Catalog (alpha)](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha)
- [Backstage Software Templates (alpha)](https://backstage.io/blog/2020/08/05/announcing-backstage-software-templates)
diff --git a/docs/plugins/publishing.md b/docs/plugins/publishing.md
index 1d16ebb047..6fee4f9b1d 100644
--- a/docs/plugins/publishing.md
+++ b/docs/plugins/publishing.md
@@ -39,4 +39,18 @@ $ git push origin -u new-release
And then create a PR. Once the PR is approved and merged into master, the master
build will publish new versions of all bumped packages.
+### Include new changes in existing release PR
+
+If you want to include some last minute changes to an existing release PR,
+follow these instructions:
+
+```sh
+$ git checkout master
+$ git pull
+$ git checkout new-release
+$ git reset --hard master
+$ yarn release
+$ git push --force
+```
+
[Back to Docs](../README.md)
diff --git a/microsite/core/Footer.js b/microsite/core/Footer.js
index 407bebca84..761862c1fc 100644
--- a/microsite/core/Footer.js
+++ b/microsite/core/Footer.js
@@ -45,6 +45,9 @@ class Footer extends React.Component {
Community
Support chatroom
+
+ Contributing
+
Subscribe to our newsletter
diff --git a/microsite/data/plugins/api-docs.yaml b/microsite/data/plugins/api-docs.yaml
index b7f85b62b3..babcbf74f1 100644
--- a/microsite/data/plugins/api-docs.yaml
+++ b/microsite/data/plugins/api-docs.yaml
@@ -5,5 +5,5 @@ authorUrl: https://sda.se/
category: Discovery
description: Components to discover and display API entities as an extension to the catalog plugin.
documentation: https://github.com/spotify/backstage/blob/master/plugins/api-docs/README.md
-iconUrl: https://github.com/spotify/backstage/raw/master/plugins/api-docs/docs/entity_tab_api.png
+iconUrl: https://thecoders.io/wp-content/uploads/2019/11/tech-swagger.svg
npmPackageName: '@backstage/plugin-api-docs'
diff --git a/microsite/data/plugins/circleci.yaml b/microsite/data/plugins/circleci.yaml
index c8a3677614..6937064815 100644
--- a/microsite/data/plugins/circleci.yaml
+++ b/microsite/data/plugins/circleci.yaml
@@ -5,5 +5,5 @@ authorUrl: https://www.spotify.com/
category: CI
description: Automate your development process with CI hosted in the cloud or on a private server.
documentation: https://github.com/spotify/backstage/tree/master/plugins/circleci
-iconUrl: https://d3r49iyjzglexf.cloudfront.net/logo-wordmark-26f8eaea9b0f6e13b90d3f4a8fd8fda31490f5af41daab98bbede45037682576.svg
+iconUrl: https://www.saaves.com/storage/brochure/logo-circleci-icon1583764538.png
npmPackageName: '@backstage/plugin-circleci'
diff --git a/microsite/data/plugins/github-actions.yaml b/microsite/data/plugins/github-actions.yaml
new file mode 100644
index 0000000000..b384980b2a
--- /dev/null
+++ b/microsite/data/plugins/github-actions.yaml
@@ -0,0 +1,13 @@
+---
+title: GitHub Actions
+author: Spotify
+authorUrl: https://www.spotify.com/
+category: CI
+description: GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub.
+documentation: https://github.com/spotify/backstage/tree/master/plugins/github-actions
+iconUrl: https://avatars2.githubusercontent.com/u/44036562?s=400&v=4
+npmPackageName: '@backstage/plugin-github-actions'
+tags:
+ - ci
+ - cd
+ - github
diff --git a/microsite/data/plugins/tech-radar.yaml b/microsite/data/plugins/tech-radar.yaml
index a20667e8f0..585e204b12 100644
--- a/microsite/data/plugins/tech-radar.yaml
+++ b/microsite/data/plugins/tech-radar.yaml
@@ -5,5 +5,5 @@ authorUrl: https://www.spotify.com/
category: Discovery
description: Visualize the your company's official guidelines of different areas of software development.
documentation: https://github.com/spotify/backstage/tree/master/plugins/tech-radar
-iconUrl: https://github.com/spotify/backstage/raw/master/plugins/tech-radar/docs/screenshot.png
+iconUrl: https://img.icons8.com/officel/2x/radar.png
npmPackageName: '@backstage/plugin-tech-radar'
diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js
index 986db4b732..7a58ede25f 100644
--- a/microsite/pages/en/index.js
+++ b/microsite/pages/en/index.js
@@ -455,12 +455,8 @@ class Index extends React.Component {
Share with the community
- Building{' '}
-
- open source plugins
- {' '}
- contributes to the entire Backstage ecosystem, which benefits
- everyone
+ Building open source plugins contributes
+ to the entire Backstage ecosystem, which benefits everyone
@@ -472,7 +468,7 @@ class Index extends React.Component {
Build a plugin
-
+
Contribute
diff --git a/microsite/pages/en/plugins.js b/microsite/pages/en/plugins.js
index 916f34c21e..8c5f017e24 100644
--- a/microsite/pages/en/plugins.js
+++ b/microsite/pages/en/plugins.js
@@ -29,13 +29,14 @@ const Plugins = () => (
-
Plugins
+
Plugin marketplace
+
Open source plugins that you can add to your Backstage deployment
+ See what plugins are already{' '}
+
+ in progress
+ {' '}
+ and ๐. Missing a plugin for your favorite tool? Please{' '}
+
+ suggest
+ {' '}
+ a new one.
+
+
+
diff --git a/microsite/static/css/plugins.css b/microsite/static/css/plugins.css
index 042e2954e1..96fe3dac35 100644
--- a/microsite/static/css/plugins.css
+++ b/microsite/static/css/plugins.css
@@ -1,111 +1,112 @@
.PluginCard {
- background-color: #272822;
- height: 100%;
- padding: 16px;
- display: flex;
- flex-direction: column;
+ background-color: #272822;
+ height: 100%;
+ padding: 16px;
+ display: flex;
+ flex-direction: column;
}
.grid {
- display: grid;
- grid-gap: 1rem;
- grid-template-columns: repeat(4, 1fr);
- grid-auto-rows: 1fr;
- padding-top: 32px;
+ display: grid;
+ grid-gap: 1rem;
+ grid-template-columns: repeat(4, 1fr);
+ grid-auto-rows: 1fr;
+ padding-top: 32px;
}
@media (max-width: 1200px) {
- .grid {
- grid-template-columns: repeat(3, 1fr);
- }
+ .grid {
+ grid-template-columns: repeat(3, 1fr);
+ }
}
@media only screen and (max-width: 815px) {
- .grid {
- grid-template-columns: repeat(2, 1fr);
- }
+ .grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
}
.PluginCard img {
- float: left;
- margin: 0px 16px 8px 0px;
- height: 100px;
- width: 100px;
+ float: left;
+ margin: 0px 16px 8px 0px;
+ height: 80px;
+ width: 80px;
}
.PluginCardHeader {
- max-height: fit-content;
- min-height: fit-content;
+ max-height: fit-content;
+ min-height: fit-content;
}
.PluginCardTitle {
- color: white;
- vertical-align: top;
- margin: 8px 0px 0px 16px;
+ color: white;
+ vertical-align: top;
+ margin: 8px 0px 0px 16px;
}
.PluginAddNewButton {
- position: absolute;
- bottom: 16px;
- right: 0px;
+ position: absolute;
+ bottom: 16px;
+ right: 0px;
}
.ButtonFilled {
- padding: 4px 8px;
- border-radius: 4px;
- background-color: #36BAA2;
- color: white;
- margin-top: 36px;
+ padding: 4px 8px;
+ border-radius: 4px;
+ background-color: #36baa2;
+ color: white;
+ margin-top: 36px;
}
.ButtonFilled:hover {
- border: 1px solid #36BAA2;
- background-color: transparent;
+ border: 1px solid #36baa2;
+ background-color: transparent;
}
.ChipOutlined {
- font-size: small;
- border-radius: 16px;
- padding: 2px 8px;
- border: 1px solid #36BAA2;
- color: #36BAA2;
+ font-size: small;
+ border-radius: 16px;
+ padding: 2px 8px;
+ border: 1px solid #36baa2;
+ color: #36baa2;
}
.PluginCardLink {
- padding: 2px 8px;
- position: absolute;
- bottom: 0;
- right: 0;
+ padding: 2px 8px;
+ position: absolute;
+ bottom: 0;
+ right: 0;
}
.PluginPageLayout {
- margin: auto;
- max-width: 1430px;
- padding: 20px;
+ margin: auto;
+ max-width: 1430px;
+ padding: 20px;
}
.PluginPageHeader {
- position: relative;
+ position: relative;
}
.PluginPageHeader h2 {
- display: inline-block;
+ display: inline-block;
}
.PluginCardBody {
- padding-top: 8px;
+ padding-top: 8px;
}
.PluginCardFooter {
- position: relative;
- min-height: 2em;
+ position: relative;
+ min-height: 2em;
}
-.Author, .Author a {
- margin-bottom: 0.25em;
- color: rgba(255,255,255, 0.6);
+.Author,
+.Author a {
+ margin-bottom: 0.25em;
+ color: rgba(255, 255, 255, 0.6);
}
- .Author a:hover {
- color: white;
+.Author a:hover {
+ color: white;
}
diff --git a/packages/app/package.json b/packages/app/package.json
index 11e900a4f1..e017a6f322 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -2,6 +2,7 @@
"name": "example-app",
"version": "0.1.1-alpha.20",
"private": true,
+ "bundled": true,
"dependencies": {
"@backstage/cli": "^0.1.1-alpha.20",
"@backstage/catalog-model": "^0.1.1-alpha.20",
diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json
index 92d301d7e3..248e638ead 100644
--- a/packages/backend-common/package.json
+++ b/packages/backend-common/package.json
@@ -46,7 +46,8 @@
"prom-client": "^12.0.0",
"selfsigned": "^1.10.7",
"stoppable": "^1.1.0",
- "winston": "^3.2.1"
+ "winston": "^3.2.1",
+ "logform": "^2.1.1"
},
"peerDependencies": {
"pg-connection-string": "^2.3.0"
diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts
index f499613851..c527f5fea1 100644
--- a/packages/backend-common/src/index.ts
+++ b/packages/backend-common/src/index.ts
@@ -20,4 +20,5 @@ export * from './errors';
export * from './logging';
export * from './middleware';
export * from './service';
+export * from './paths';
export * from './hot';
diff --git a/packages/backend-common/src/logging/formats.ts b/packages/backend-common/src/logging/formats.ts
new file mode 100644
index 0000000000..5f00448744
--- /dev/null
+++ b/packages/backend-common/src/logging/formats.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 * as winston from 'winston';
+import { TransformableInfo } from 'logform';
+
+const coloredTemplate = (info: TransformableInfo) => {
+ const { timestamp, level, message, plugin, service } = 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}`;
+};
+
+export const coloredFormat = winston.format.combine(
+ winston.format.timestamp(),
+ winston.format.colorize({
+ colors: { timestamp: 'dim', prefix: 'blue' },
+ }),
+ winston.format.printf(coloredTemplate),
+);
diff --git a/packages/backend-common/src/logging/rootLogger.ts b/packages/backend-common/src/logging/rootLogger.ts
index fd2f3a1c8b..306ed23444 100644
--- a/packages/backend-common/src/logging/rootLogger.ts
+++ b/packages/backend-common/src/logging/rootLogger.ts
@@ -14,17 +14,14 @@
* limitations under the License.
*/
import * as winston from 'winston';
+import { coloredFormat } from './formats';
let rootLogger: winston.Logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format:
process.env.NODE_ENV === 'production'
? winston.format.json()
- : winston.format.combine(
- winston.format.colorize(),
- winston.format.timestamp(),
- winston.format.simple(),
- ),
+ : coloredFormat,
defaultMeta: { service: 'backstage' },
transports: [
new winston.transports.Console({
diff --git a/packages/backend-common/src/paths.ts b/packages/backend-common/src/paths.ts
new file mode 100644
index 0000000000..402c0e2252
--- /dev/null
+++ b/packages/backend-common/src/paths.ts
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/* eslint-disable @typescript-eslint/camelcase */
+
+import { resolve as resolvePath } from 'path';
+
+/**
+ * Resolve a path relative to the root of a package directory.
+ * Additional path arguments are resolved relative to the package dir.
+ *
+ * This is particularly useful when you want to access assets shipped with
+ * your backend plugin package. When doing so, do not forget to include the assets
+ * in your published package by adding them to `files` in your `package.json`.
+ */
+export function resolvePackagePath(name: string, ...paths: string[]) {
+ const req =
+ typeof __non_webpack_require__ === 'undefined'
+ ? require
+ : __non_webpack_require__;
+
+ return resolvePath(req.resolve(`${name}/package.json`), '..', ...paths);
+}
diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts
index df69387e40..10f9ca4d9b 100644
--- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts
+++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts
@@ -135,7 +135,6 @@ export class ServiceBuilderImpl implements ServiceBuilder {
app.use(cors(corsOptions));
}
app.use(compression());
- app.use(express.json());
if (this.enableMetrics) {
app.use(metricsHandler());
}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 7393ede81e..a2a9e41a92 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -46,6 +46,6 @@
"@types/dockerode": "^2.5.32",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5",
- "@types/helmet": "^0.0.47"
+ "@types/helmet": "^0.0.48"
}
}
diff --git a/packages/cli/src/commands/create-plugin/createPlugin.ts b/packages/cli/src/commands/create-plugin/createPlugin.ts
index 47b883882b..5e6882a4a0 100644
--- a/packages/cli/src/commands/create-plugin/createPlugin.ts
+++ b/packages/cli/src/commands/create-plugin/createPlugin.ts
@@ -28,6 +28,7 @@ import {
} from '../../lib/codeowners';
import { paths } from '../../lib/paths';
import { Task, templatingTask } from '../../lib/tasks';
+import { version as backstageVersion } from '../../lib/version';
const exec = promisify(execCb);
@@ -239,7 +240,11 @@ export default async () => {
await createTemporaryPluginFolder(tempDir);
Task.section('Preparing files');
- await templatingTask(templateDir, tempDir, { ...answers, version });
+ await templatingTask(templateDir, tempDir, {
+ ...answers,
+ version,
+ backstageVersion,
+ });
Task.section('Moving to final location');
await movePlugin(tempDir, pluginDir, answers.id);
diff --git a/packages/cli/src/commands/plugin/diff.ts b/packages/cli/src/commands/plugin/diff.ts
index 66db692ab4..99af093f2c 100644
--- a/packages/cli/src/commands/plugin/diff.ts
+++ b/packages/cli/src/commands/plugin/diff.ts
@@ -25,7 +25,7 @@ import {
yesPromptFunc,
} from '../../lib/diff';
import { paths } from '../../lib/paths';
-import { version } from '../../lib/version';
+import { version as backstageVersion } from '../../lib/version';
export type PluginData = {
id: string;
@@ -62,9 +62,12 @@ export default async (cmd: Command) => {
promptFunc = yesPromptFunc;
}
+ const { version } = await fs.readJson(paths.resolveTargetRoot('lerna.json'));
+
const data = await readPluginData();
const templateFiles = await diffTemplateFiles('default-plugin', {
version,
+ backstageVersion,
...data,
});
await handleAllFiles(fileHandlers, templateFiles, promptFunc);
diff --git a/packages/cli/src/commands/testCommand.ts b/packages/cli/src/commands/testCommand.ts
index 9969aee3b4..2c3f9fe895 100644
--- a/packages/cli/src/commands/testCommand.ts
+++ b/packages/cli/src/commands/testCommand.ts
@@ -57,6 +57,12 @@ export default async (cmd: Command) => {
}
}
+ // This is the only thing that is not implemented by jest.run(), so we do it here instead
+ // https://github.com/facebook/jest/blob/cd8828f7bbec6e55b4df5e41e853a5133c4a3ee1/packages/jest-cli/bin/jest.js#L12
+ if (!process.env.NODE_ENV) {
+ (process.env as any).NODE_ENV = 'test';
+ }
+
// eslint-disable-next-line jest/no-jest-import
await require('jest').run(args);
};
diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts
index f5f233854f..e3cc8af8d1 100644
--- a/packages/cli/src/lib/bundler/backend.ts
+++ b/packages/cli/src/lib/bundler/backend.ts
@@ -25,7 +25,7 @@ export async function serveBackend(
},
) {
const paths = resolveBundlingPaths(options);
- const config = createBackendConfig(paths, {
+ const config = await createBackendConfig(paths, {
...options,
isDev: true,
});
diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts
index 61f4448dd9..118cb1b40c 100644
--- a/packages/cli/src/lib/bundler/config.ts
+++ b/packages/cli/src/lib/bundler/config.ts
@@ -15,6 +15,7 @@
*/
import fs from 'fs-extra';
+import { resolve as resolvePath } from 'path';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';
@@ -171,14 +172,23 @@ export async function createConfig(
};
}
-export function createBackendConfig(
+export async function createBackendConfig(
paths: BundlingPaths,
options: BackendBundlingOptions,
-): webpack.Configuration {
+): Promise {
const { checksEnabled, isDev } = options;
const { loaders } = transforms(options);
+ // Find all local monorepo packages and their node_modules, and mark them as external.
+ const LernaProject = require('@lerna/project');
+ const project = new LernaProject(cliPaths.targetDir);
+ const packages = await project.getPackages();
+ const localPackageNames = packages.map((p: any) => p.name);
+ const moduleDirs = packages.map((p: any) =>
+ resolvePath(p.location, 'node_modules'),
+ );
+
return {
mode: isDev ? 'development' : 'production',
profile: false,
@@ -193,11 +203,8 @@ export function createBackendConfig(
externals: [
nodeExternals({
modulesDir: paths.rootNodeModules,
- allowlist: ['webpack/hot/poll?100', /\@backstage\/.*/],
- }),
- nodeExternals({
- modulesDir: paths.targetNodeModules,
- allowlist: ['webpack/hot/poll?100', /\@backstage\/.*/],
+ additionalModuleDirs: moduleDirs,
+ allowlist: ['webpack/hot/poll?100', ...localPackageNames],
}),
],
target: 'node' as const,
@@ -219,7 +226,7 @@ export function createBackendConfig(
resolve: {
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
mainFields: ['browser', 'module', 'main'],
- modules: [paths.targetNodeModules, paths.rootNodeModules],
+ modules: [paths.rootNodeModules, ...moduleDirs],
plugins: [
new ModuleScopePlugin(
[paths.targetSrc, paths.targetDev],
diff --git a/packages/cli/src/lib/bundler/paths.ts b/packages/cli/src/lib/bundler/paths.ts
index 70e82d8d48..390e41a345 100644
--- a/packages/cli/src/lib/bundler/paths.ts
+++ b/packages/cli/src/lib/bundler/paths.ts
@@ -63,7 +63,6 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) {
targetDev: paths.resolveTarget('dev'),
targetEntry: resolveTargetModule(entry),
targetTsConfig: paths.resolveTargetRoot('tsconfig.json'),
- targetNodeModules: paths.resolveTarget('node_modules'),
targetPackageJson: paths.resolveTarget('package.json'),
rootNodeModules: paths.resolveTargetRoot('node_modules'),
root: paths.targetRoot,
diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts
index d65d1af304..fda85dd68a 100644
--- a/packages/cli/src/lib/packager/index.ts
+++ b/packages/cli/src/lib/packager/index.ts
@@ -26,6 +26,7 @@ type LernaPackage = {
private: boolean;
location: string;
scripts: Record;
+ get(key: string): any;
};
type FileEntry =
@@ -107,6 +108,26 @@ async function moveToDistWorkspace(
strip: 1,
});
await fs.remove(archivePath);
+
+ // We remove the dependencies from package.json of packages that are marked
+ // as bundled, so that yarn doesn't try to install them.
+ if (target.get('bundled')) {
+ const pkgJson = await fs.readJson(
+ resolvePath(absoluteOutputPath, 'package.json'),
+ );
+ delete pkgJson.dependencies;
+ delete pkgJson.devDependencies;
+ delete pkgJson.peerDependencies;
+ delete pkgJson.optionalDependencies;
+
+ await fs.writeJson(
+ resolvePath(absoluteOutputPath, 'package.json'),
+ pkgJson,
+ {
+ spaces: 2,
+ },
+ );
+ }
}),
);
}
diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs
index 4e85bf39bd..38d4e41b5b 100644
--- a/packages/cli/templates/default-plugin/package.json.hbs
+++ b/packages/cli/templates/default-plugin/package.json.hbs
@@ -21,8 +21,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/core": "^{{version}}",
- "@backstage/theme": "^{{version}}",
+ "@backstage/core": "^{{backstageVersion}}",
+ "@backstage/theme": "^{{backstageVersion}}",
"@material-ui/core": "^4.9.1",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -31,8 +31,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
- "@backstage/cli": "^{{version}}",
- "@backstage/dev-utils": "^{{version}}",
+ "@backstage/cli": "^{{backstageVersion}}",
+ "@backstage/dev-utils": "^{{backstageVersion}}",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
diff --git a/packages/core/src/layout/Page/Page.stories.tsx b/packages/core/src/layout/Page/Page.stories.tsx
new file mode 100644
index 0000000000..786b4740fd
--- /dev/null
+++ b/packages/core/src/layout/Page/Page.stories.tsx
@@ -0,0 +1,114 @@
+/*
+ * 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 {
+ Header,
+ Page,
+ HeaderLabel,
+ ContentHeader,
+ Content,
+ pageTheme,
+} from '../';
+import { SupportButton, Table, StatusOK, TableColumn } from '../../components';
+import { Box, Typography, Link, Chip, Button } from '@material-ui/core';
+
+export default {
+ title: 'Example Plugin',
+ component: Page,
+};
+
+interface TableData {
+ id: number;
+ branch: string;
+ hash: string;
+ status: string;
+}
+
+const generateTestData = (rows = 10) => {
+ const data: Array = [];
+ while (data.length <= rows) {
+ data.push({
+ id: data.length + 18534,
+ branch: 'techdocs: modify documentation header',
+ hash: 'techdocs/docs-header 5749c98e3f61f8bb116e5cb87b0e4e1 ',
+ status: 'Success',
+ });
+ }
+ return data;
+};
+
+const columns: TableColumn[] = [
+ {
+ title: 'ID',
+ field: 'id',
+ highlight: true,
+ type: 'numeric',
+ width: '80px',
+ },
+ {
+ title: 'Message/Source',
+ highlight: true,
+ render: (row: Partial) => (
+ <>
+ {row.branch}
+ {row.hash}
+ >
+ ),
+ },
+ {
+ title: 'Status',
+ render: (row: Partial) => (
+
+
+ {row.status}
+
+ ),
+ },
+ {
+ title: 'Tags',
+ render: () => ,
+ width: '10%',
+ },
+];
+
+export const PluginWithTable = () => {
+ return (
+
+
+
+
+
+
+
+
+
+ This Plugin is an example. This text could provide usefull
+ information for the user.
+
+
+