Merge branch 'backstage:master' into master

This commit is contained in:
djamaile
2021-12-09 23:23:19 +01:00
committed by GitHub
621 changed files with 15686 additions and 3862 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-github-actions': patch
---
Show empty state only when workflow API call has completed
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-azure-devops-common': patch
---
feat: Created pull request card component and initial pull request dashboard page.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/integration': patch
---
Narrow the types returned by the request option functions, to only the specifics that they actually do return. The reason for this change is that a full `RequestInit` is unfortunate to return because it's different between `cross-fetch` and `node-fetch`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Removed unused scaffolder visibility configuration; this has been moved to publish actions. Deprecated scaffolder provider configuration keys; these should use the integrations configuration instead.
-51
View File
@@ -1,51 +0,0 @@
---
'@backstage/create-app': patch
---
Incorporate usage of the tokenManager into the backend created using `create-app`.
In existing backends, update the `PluginEnvironment` to include a `tokenManager`:
```diff
// packages/backend/src/types.ts
...
import {
...
+ TokenManager,
} from '@backstage/backend-common';
export type PluginEnvironment = {
...
+ tokenManager: TokenManager;
};
```
Then, create a `ServerTokenManager`. This can either be a `noop` that requires no secret and validates all requests by default, or one that uses a secret from your `app-config.yaml` to generate and validate tokens.
```diff
// packages/backend/src/index.ts
...
import {
...
+ ServerTokenManager,
} from '@backstage/backend-common';
...
function makeCreateEnv(config: Config) {
...
// CHOOSE ONE
// TokenManager not requiring a secret
+ const tokenManager = ServerTokenManager.noop();
// OR TokenManager requiring a secret
+ const tokenManager = ServerTokenManager.fromConfig(config);
...
return (plugin: string): PluginEnvironment => {
...
- return { logger, cache, database, config, reader, discovery };
+ return { logger, cache, database, config, reader, discovery, tokenManager };
};
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes-backend': patch
---
Added apiVersionOverrides config to allow for specifying api versions to use for kubernetes objects
-19
View File
@@ -1,19 +0,0 @@
---
'@backstage/config-loader': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-badges-backend': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-tech-insights-backend': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-todo-backend': patch
---
Align on usage of `cross-fetch` vs `node-fetch` in frontend vs backend packages, and remove some unnecessary imports of either one of them
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-user-settings': patch
---
The theme switcher now renders the title of themes instead of their variant
-28
View File
@@ -1,28 +0,0 @@
---
'@backstage/plugin-techdocs-backend': minor
---
**BREAKING** `DefaultTechDocsCollator` has a new required option `tokenManager`. See the create-app changelog for how to create a `tokenManager` and add it to the `PluginEnvironment`. It can then be passed to the collator in `createPlugin`:
```diff
// packages/backend/src/plugins/search.ts
...
export default async function createPlugin({
...
+ tokenManager,
}: PluginEnvironment) {
...
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
+ tokenManager,
}),
});
...
}
```
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-permission-node': minor
'@backstage/plugin-permission-backend': patch
---
Rename and adjust permission policy return type to reduce nesting
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-common': patch
---
Create a `TokenManager` interface and `ServerTokenManager` implementation to generate and validate server tokens for authenticated backend-to-backend API requests.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes-backend': patch
---
Query CronJobs from Kubernetes with apiGroup BatchV1beta1
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': minor
---
Remove the `backend:build-image` command from the CLI and added more deprecation warnings to other deprecated fields like `--lax` and `remove-plugin`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-circleci': patch
---
Fixed a bug in the `CircleCI` plugin where restarting builds was hard-coded to GitHub rather than introspecting the entity source location.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/cli': patch
'@techdocs/cli': patch
---
Bump react-dev-utils to v12
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
build(dependencies): bump `style-loader` from 1.2.1 to 3.3.1
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-plugin-api': patch
---
Tweaked the logged deprecation warning for `createRouteRef` to hopefully make it more clear.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search': patch
---
Add optional icon and secondaryAction properties for DefaultResultListItem component
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search': patch
---
Add a new optional clearButton property to the SearchBar component. The default value for this new property is true.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/backend-common': patch
'@backstage/plugin-catalog-graphql': patch
---
Move to using node-fetch internally instead of cross-fetch
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Expose catalog lib in plugin-auth-backend, i.e `CatalogIdentityClient` class is exposed now.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-app-api': patch
---
Fixed a bug where `useRouteRef` would fail in situations where relative navigation was needed and the app was is mounted on a sub-path. This would typically show up as a failure to navigate to a tab on an entity page.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Add options to spawn in runCommand helper
-17
View File
@@ -1,17 +0,0 @@
---
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-azure-devops-backend': patch
---
**Backend**
- Created new `/dashboard-pull-requests/:projectName` endpoint
- Created new `/all-teams` endpoint
- Implemented pull request policy evaluation conversion
**Frontend**
- Refactored `PullRequestsPage` and added new properties for `projectName` and `pollingInterval`
- Fixed spacing issue between repo link and creation date in `PullRequestCard`
- Added missing condition to `PullRequestCardPolicy` for `RequiredReviewers`
- Updated `useDashboardPullRequests` hook to implement long polling for pull requests
+14
View File
@@ -0,0 +1,14 @@
---
'@backstage/plugin-apache-airflow': minor
---
Introduces a new plugin for the Apache Airflow workflow management platform.
This implementation has been tested with the Apache Airflow v2 API,
authenticating with basic authentication through the Backstage proxy plugin.
Supported functionality includes:
- Information card of version information of the Airflow instance
- Information card of instance health for the meta-database and scheduler
- Table of DAGs with meta information and status, along with a link to view
details in the Airflow UI
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes': patch
---
Added accordions to display information on Jobs and CronJobs in the kubernetes plugin. Updated the PodsTable with fewer default columns and the ability to pass in additional ones depending on the use case.
-17
View File
@@ -1,17 +0,0 @@
---
'@backstage/plugin-scaffolder': patch
---
Add group filtering to the scaffolder page so that individuals can surface specific templates to end users ahead of others, or group templates together. This can be accomplished by passing in a `groups` prop to the `ScaffolderPage`
```
<ScaffolderPage
groups={[
{
title: "Recommended",
filter: entity =>
entity?.metadata?.tags?.includes('recommended') ?? false,
},
]}
/>
```
-27
View File
@@ -1,27 +0,0 @@
---
'@backstage/plugin-catalog-backend': minor
---
**BREAKING** `DefaultCatalogCollator` has a new required option `tokenManager`. See the create-app changelog for how to create a `tokenManager` and add it to the `PluginEnvironment`. It can then be passed to the collator in `createPlugin`:
```diff
// packages/backend/src/plugins/search.ts
...
export default async function createPlugin({
...
+ tokenManager,
}: PluginEnvironment) {
...
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultCatalogCollator.fromConfig(config, {
discovery,
+ tokenManager,
}),
});
...
}
```
+3
View File
@@ -23,10 +23,13 @@
/plugins/azure-devops @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-backend @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-common @backstage/reviewers @marleypowell @awanlin
/plugins/jenkins @backstage/reviewers @timja
/plugins/jenkins-backend @backstage/reviewers @timja
/plugins/kafka @backstage/reviewers @nirga
/plugins/kafka-backend @backstage/reviewers @nirga
/plugins/scaffolder-backend-module-yeoman @backstage/reviewers @pawelmitka
/plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski
/plugins/git-release-manager @backstage/reviewers @erikengervall
/tech-insights-backend @backstage/reviewers @xantier @iain-b
/tech-insights-backend-module-jsonfc @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-common @backstage/reviewers @xantier @iain-b
+4 -2
View File
@@ -5,7 +5,7 @@
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
@@ -72,4 +72,6 @@
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
| [LogMeIn](https://www.logmein.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. |
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon), [Gauthier Roebroeck](https://github.com/gauthier-roebroeck-mox) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
+8
View File
@@ -97,6 +97,11 @@ proxy:
headers:
Authorization: ${ILERT_AUTH_HEADER}
'/airflow':
target: https://your.airflow.instance.com/api/v1
headers:
Authorization: ${AIRFLOW_BASIC_AUTH_HEADER}
organization:
name: My Company
@@ -437,3 +442,6 @@ azureDevOps:
host: dev.azure.com
token: my-token
organization: my-company
apacheAirflow:
baseUrl: https://your.airflow.instance.com
+26 -78
View File
@@ -13,9 +13,9 @@
figures "^1.7.0"
"@cypress/request@^2.88.5":
version "2.88.5"
resolved "https://registry.npmjs.org/@cypress/request/-/request-2.88.5.tgz#8d7ecd17b53a849cfd5ab06d5abe7d84976375d7"
integrity sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA==
version "2.88.10"
resolved "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce"
integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
@@ -24,19 +24,17 @@
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
http-signature "~1.3.6"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
uuid "^8.3.2"
"@cypress/xvfb@^1.2.4":
version "1.2.4"
@@ -68,16 +66,6 @@
resolved "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
ajv@^6.12.3:
version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-escapes@^3.0.0:
version "3.2.0"
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
@@ -539,16 +527,6 @@ extsprintf@^1.2.0:
resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
@@ -645,19 +623,6 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0:
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.5.tgz#bc18864a6c9fc7b303f2e2abdb9155ad178fbe29"
integrity sha512-kBBSQbz2K0Nyn+31j/w36fUfxkBW9/gfwRWdUY1ULReH3iokVJgddZAFcD1D0xlgTmFxJCbUkUclAlc6/IDJkw==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.3:
version "5.1.5"
resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
ajv "^6.12.3"
har-schema "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
@@ -675,14 +640,14 @@ has-flag@^4.0.0:
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
http-signature@~1.3.6:
version "1.3.6"
resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9"
integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
jsprim "^2.0.2"
sshpk "^1.14.1"
human-signals@^1.1.1:
version "1.1.1"
@@ -796,15 +761,10 @@ jsbn@~0.1.0:
resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-schema@0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
json-stringify-safe@~5.0.1:
version "5.0.1"
@@ -820,14 +780,14 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
jsprim@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d"
integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
json-schema "0.4.0"
verror "1.10.0"
lazy-ass@^1.6.0:
@@ -985,11 +945,6 @@ number-is-nan@^1.0.0:
resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -1084,7 +1039,7 @@ punycode@1.3.2:
resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
punycode@^2.1.0, punycode@^2.1.1:
punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
@@ -1191,7 +1146,7 @@ slice-ansi@0.0.4:
resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
sshpk@^1.7.0:
sshpk@^1.14.1:
version "1.16.1"
resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
@@ -1353,13 +1308,6 @@ untildify@^4.0.0:
resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
url@^0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -1373,10 +1321,10 @@ util-deprecate@~1.0.1:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
verror@1.10.0:
version "1.10.0"
+1 -1
View File
@@ -291,7 +291,7 @@ The figure below shows the relationship between
<span style="color: #b85450">fooApiRef</span>.
<div style="text-align:center">
<img src="../assets/utility-apis-fig1.svg" alt="Figure showing the relationship between utility APIs, the apps that provide them, and the plugins that consume them">
<img src="../assets/utility-apis-fig1.svg" alt="Figure showing the relationship between utility APIs, the apps that provide them, and the plugins that consume them" />
</div>
The current method for connecting Utility API providers and consumers is via the
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 64 KiB

+16 -4
View File
@@ -26,6 +26,7 @@ kubernetes:
name: minikube
authProvider: 'serviceAccount'
skipTLSVerify: false
skipMetricsLookup: true
serviceAccountToken: ${K8S_MINIKUBE_TOKEN}
dashboardUrl: http://127.0.0.1:64713 # url copied from running the command: minikube service kubernetes-dashboard -n kubernetes-dashboard
dashboardApp: standard
@@ -37,6 +38,7 @@ kubernetes:
projectId: 'gke-clusters'
region: 'europe-west1'
skipTLSVerify: true
skipMetricsLookup: true
```
### `serviceLocatorMethod`
@@ -86,8 +88,13 @@ cluster. Valid values are:
##### `clusters.\*.skipTLSVerify`
This determines whether or not the Kubernetes client verifies the TLS
certificate presented by the API server. Defaults to `false`.
This determines whether the Kubernetes client verifies the TLS certificate
presented by the API server. Defaults to `false`.
##### `clusters.\*.skipMetricsLookup`
This determines whether the Kubernetes client looks up resource metrics
CPU/Memory for pods returned by the API server. Defaults to `false`.
##### `clusters.\*.serviceAccountToken` (optional)
@@ -188,8 +195,13 @@ regions.
##### `skipTLSVerify`
This determines whether or not the Kubernetes client verifies the TLS
certificate presented by the API server. Defaults to `false`.
This determines whether the Kubernetes client verifies the TLS certificate
presented by the API server. Defaults to `false`.
##### `skipMetricsLookup`
This determines whether the Kubernetes client looks up resource metrics
CPU/Memory for pods returned by the API server. Defaults to `false`.
### `customResources` (optional)
+4 -2
View File
@@ -114,13 +114,15 @@ const routes = (
In `Root.tsx`, add the `SidebarSearchModal` component:
```bash
import { SidebarSearchModal } from '@backstage/plugin-search';
import { SidebarSearchModal, SearchContextProvider } from '@backstage/plugin-search';
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
<SidebarSearchModal />
<SearchContextProvider>
<SidebarSearchModal />
</SearchContextProvider>
<SidebarDivider />
...
```
@@ -11,13 +11,13 @@ would be good to also have some files in there that can be templated in.
A simple `template.yaml` definition might look something like this:
```yaml
apiVersion: backstage.io/v1beta2
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: v1beta2-demo
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta2 template demo
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service
@@ -55,7 +55,7 @@ spec:
input:
url: ./template
values:
name: '{{ parameters.name }}'
name: ${{ parameters.name }}
- id: fetch-docs
name: Fetch Docs
@@ -69,14 +69,14 @@ spec:
action: publish:github
input:
allowedHosts: ['github.com']
description: 'This is {{ parameters.name }}'
repoUrl: '{{ parameters.repoUrl }}'
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
- id: register
name: Register
action: catalog:register
input:
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
```
@@ -18,17 +18,31 @@ The next step is to add
[add templates](http://backstage.io/docs/features/software-templates/adding-templates)
to your Backstage app.
### GitHub
### Publishing defaults
For GitHub, you can configure who can see the new repositories that are created
by specifying `visibility` option. Valid options are `public`, `private` and
`internal`. The `internal` option is for GitHub Enterprise clients, which means
public within the enterprise.
Software templates can define _publish_ actions, such as `publish:github`, to
create new repositories or submit pull / merge requests to existing
repositories. You can configure the author and commit message through the
`scaffolder` configuration in `app-config.yaml`:
```yaml
scaffolder:
github:
visibility: public # or 'internal' or 'private'
defaultAuthor:
name: M.C. Hammer # Defaults to `Scaffolder`
email: hammer@donthurtem.com # Defaults to `scaffolder@backstage.io`
defaultCommitMessage: "U can't touch this" # Defaults to 'Initial commit'
```
To configure who can see the new repositories created from software templates,
add the `repoVisibility` key within a software template:
```yaml
- id: publish
name: Publish
action: publish:github
input:
repoUrl: '{{ parameters.repoUrl }}'
repoVisibility: public # or 'internal' or 'private'
```
### Disabling Docker in Docker situation (Optional)
+1 -1
View File
@@ -12,7 +12,7 @@ code, template in some variables, and then publish the template to some
locations like GitHub or GitLab.
<video width="100%" height="100%" controls>
<source src="https://backstage.io/blog/assets/2020-08-05/feature.mp4" type="video/mp4">
<source src="https://backstage.io/blog/assets/2020-08-05/feature.mp4" type="video/mp4" />
</video>
### Getting Started
@@ -6,21 +6,21 @@ description: Details around creating your own custom Software Templates
Templates are stored in the **Software Catalog** under a kind `Template`. You
can create your own templates with a small `yaml` definition which describes the
template and it's metadata, along with some input variables that your template
template and its metadata, along with some input variables that your template
will need, and then a list of actions which are then executed by the scaffolding
service.
Let's take a look at a simple example:
```yaml
# Notice the v1beta2 version
apiVersion: backstage.io/v1beta2
# Notice the v1beta3 version
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: v1beta2-demo
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta2 template demo
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service
@@ -66,8 +66,8 @@ spec:
input:
url: ./template
values:
name: '{{ parameters.name }}'
owner: '{{ parameters.owner }}'
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
- id: fetch-docs
name: Fetch Docs
@@ -81,20 +81,20 @@ spec:
action: publish:github
input:
allowedHosts: ['github.com']
description: 'This is {{ parameters.name }}'
repoUrl: '{{ parameters.repoUrl }}'
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
- id: register
name: Register
action: catalog:register
input:
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
# some outputs which are saved along with the job for use in the frontend
output:
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
entityRef: '{{ steps.register.output.entityRef }}'
remoteUrl: ${{ steps.publish.output.remoteUrl }}
entityRef: ${{ steps.register.output.entityRef }}
```
Let's dive in and pick apart what each of these sections do and what they are.
@@ -183,12 +183,12 @@ this:
It would look something like the following in a template:
```yaml
apiVersion: backstage.io/v1beta2
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta2-demo
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta2 template demo
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service
@@ -315,12 +315,12 @@ template. These follow the same standard format:
```yaml
- id: fetch-base # A unique id for the step
name: Fetch Base # A title displayed in the frontend
if: '{{ parameters.name }}' # Optional condition, skip the step if not truthy
if: ${{ parameters.name }} # Optional condition, skip the step if not truthy
action: fetch:template # An action to call
input: # Input that is passed as arguments to the action handler
url: ./template
values:
name: '{{ parameters.name }}'
name: ${{ parameters.name }}
```
By default we ship some [built in actions](./builtin-actions.md) that you can
@@ -338,22 +338,19 @@ The main two that are used are the following:
```yaml
output:
remoteUrl: '{{ steps.publish.output.remoteUrl }}' # link to the remote repository
entityRef: '{{ steps.register.output.entityRef }}' # link to the entity that has been ingested to the catalog
remoteUrl: ${{ steps.publish.output.remoteUrl }} # link to the remote repository
entityRef: ${{ steps.register.output.entityRef }} # link to the entity that has been ingested to the catalog
```
### The templating syntax
You might have noticed variables wrapped in `{{ }}` in the examples. These are
`handlebars` template strings for linking and gluing the different parts of the
template together. All the form inputs from the `parameters` section will be
available by using this template syntax (for example,
`{{ parameters.firstName }}` inserts the value of `firstName` from the
parameters). This is great for passing the values from the form into different
steps and reusing these input variables. To pass arrays or objects use the
`json` custom [helper](https://handlebarsjs.com/guide/expressions.html#helpers).
For example, `{{ json parameters.nicknames }}` will insert the result of calling
`JSON.stringify` on the value of the `nicknames` parameter.
You might have noticed variables wrapped in `${{ }}` in the examples. These are
template strings for linking and gluing the different parts of the template
together. All the form inputs from the `parameters` section will be available by
using this template syntax (for example, `${{ parameters.firstName }}` inserts
the value of `firstName` from the parameters). This is great for passing the
values from the form into different steps and reusing these input variables.
These template strings preserve the type of the parameter.
As you can see above in the `Outputs` section, `actions` and `steps` can also
output things. You can grab that output using `steps.$stepId.output.$property`.
+7 -7
View File
@@ -40,7 +40,7 @@ storage system (e.g. AWS S3, GCS or Azure Blob Storage). Read more in
## Recommended deployment
This is how we recommend deploying TechDocs in production environment.
This is how we recommend deploying TechDocs in a production environment.
<img data-zoomable src="../../assets/techdocs/architecture-recommended.drawio.svg" alt="TechDocs Architecture diagram" />
@@ -58,12 +58,12 @@ Similar to how it is done in the Basic setup, the TechDocs Reader requests
your configured storage solution for the necessary files and returns them to
TechDocs Reader.
Note about caching: We have noticed internally that some storage providers can
be quite slow, which is why we are recommending a cache that sits between the
TechDocs Reader and the Storage.
_Feel free to suggest better ideas to us in #docs-like-code channel in Discord
or via a GitHub issue._
Depending on your chosen cloud storage provider and its real-world proximity to
your backend server, there may be a comparably high amount of latency when
loading TechDocs sites using this deployment approach. If you encounter this,
you can optionally configure the `techdocs-backend` to cache responses in a
cache store
[supported by Backstage](../../overview/architecture-overview.md#cache).
### Security consideration
+16
View File
@@ -135,6 +135,22 @@ techdocs:
# the old, case-sensitive entity triplet behavior.
legacyUseCaseSensitiveTripletPaths: false
# techdocs.cache is optional, and is only recommended when you've configured
# an external techdocs.publisher.type above. Also requires backend.cache to
# be configured with a valid cache store.
cache:
# Represents the number of milliseconds a statically built asset should
# stay cached. Cache invalidation is handled automatically by the frontend,
# which compares the build times in cached metadata vs. canonical storage,
# allowing long TTLs (e.g. 1 month/year)
ttl: 3600000
# (Optional) The time (in milliseconds) that the TechDocs backend will wait
# for a cache service to respond before continuing on as though the cached
# object was not found (e.g. when the cache sercice is unavailable). The
# default value is 1000
readTimeout: 500
# (Optional and Legacy) TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
# You don't have to specify this anymore.
+1 -1
View File
@@ -36,7 +36,7 @@ This will create a new Backstage App inside the current folder. The name of the
app-folder is the name that was provided when prompted.
<p align='center'>
<img src='../assets/getting-started/create-app_output.png' width='600' alt='create app'>
<img src='../assets/getting-started/create-app_output.png' width='600' alt='create app' />
</p>
Inside that directory, it will generate all the files and folder structure
+3 -3
View File
@@ -58,7 +58,7 @@ The wizard will ask you
SQLite option.
<p align='center'>
<img src='../assets/getting-started/wizard.png' alt='Screenshot of the wizard asking for a name for the app, and a selection menu for the database.'>
<img src='../assets/getting-started/wizard.png' alt='Screenshot of the wizard asking for a name for the app, and a selection menu for the database.' />
</p>
### Run the Backstage app
@@ -73,7 +73,7 @@ yarn dev
```
<p align='center'>
<img src='../assets/getting-started/startup.png' alt='Screenshot of the command output, with the message web pack compiled successfully.'>
<img src='../assets/getting-started/startup.png' alt='Screenshot of the command output, with the message web pack compiled successfully.'/>
</p>
It might take a little while, but as soon as the message
@@ -84,7 +84,7 @@ database will be cleared when you restart the app, so you'll most likely want to
carry on with the database steps.
<p align='center'>
<img src='../assets/getting-started/portal.png' alt='Screenshot of the Backstage portal.'>
<img src='../assets/getting-started/portal.png' alt='Screenshot of the Backstage portal.'/>
</p>
The most common next steps are to move to a persistent database, configure
+2
View File
@@ -165,6 +165,7 @@ common example being the `migrations` directory.
Usage: backstage-cli backend:build [options]
Options:
--minify Minify the generated code
-h, --help display help for command
```
@@ -371,6 +372,7 @@ the monorepo.
Usage: backstage-cli plugin:build [options]
Options:
--minify Minify the generated code
-h, --help display help for command
```
@@ -7,7 +7,7 @@ authorURL: https://twitter.com/stalund
**TL;DR** Today we are announcing a new Backstage feature: Software Templates. Simplify setup, standardize tooling, and deploy with the click of a button. Using automated templates, your engineers can spin up a new microservice, website, or other software component with your organizations best practices built-in, right from the start.
<video width="100%" height="100%" controls>
<source src="/blog/assets/2020-08-05/feature.mp4" type="video/mp4">
<source src="/blog/assets/2020-08-05/feature.mp4" type="video/mp4" />
</video>
<!--truncate-->
+1 -1
View File
@@ -19,7 +19,7 @@
"@spotify/prettier-config": "^12.0.0",
"docusaurus": "^2.0.0-alpha.70",
"js-yaml": "^4.1.0",
"prettier": "^2.5.0",
"prettier": "^2.5.1",
"yarn-lock-check": "^1.0.5"
},
"prettier": "@spotify/prettier-config"
+4 -4
View File
@@ -5190,10 +5190,10 @@ prepend-http@^2.0.0:
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
prettier@^2.5.0:
version "2.5.0"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893"
integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==
prettier@^2.5.1:
version "2.5.1"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
prismjs@^1.22.0:
version "1.25.0"
+2 -1
View File
@@ -63,7 +63,8 @@
"devDependencies": {
"@changesets/cli": "^2.14.0",
"@octokit/rest": "^18.12.0",
"@spotify/prettier-config": "^11.0.0",
"@spotify/prettier-config": "^12.0.0",
"@types/node": "^14.14.32",
"@types/webpack": "^5.28.0",
"command-exists": "^1.2.9",
"cross-env": "^7.0.0",
+10
View File
@@ -1,5 +1,15 @@
# @backstage/app-defaults
## 0.1.2
### Patch Changes
- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used.
- Updated dependencies
- @backstage/core-components@0.8.0
- @backstage/core-plugin-api@0.3.0
- @backstage/core-app-api@0.2.0
## 0.1.1
### Patch Changes
+11 -9
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "0.1.1",
"version": "0.1.2",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,23 +29,25 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core-components": "^0.7.4",
"@backstage/core-app-api": "^0.1.21",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/theme": "^0.2.13",
"@backstage/core-components": "^0.8.0",
"@backstage/core-app-api": "^0.2.0",
"@backstage/core-plugin-api": "^0.3.0",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"react": "^16.12.0",
"react-router-dom": "6.0.0-beta.0"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/test-utils": "^0.1.22",
"@backstage/cli": "^0.10.1",
"@backstage/test-utils": "^0.1.24",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32",
"@types/react": "*"
"@types/react": "^16.13.1 || ^17.0.0"
},
"files": [
"dist"
+65
View File
@@ -1,5 +1,70 @@
# example-app
## 0.2.56
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.0
- @backstage/core-plugin-api@0.3.0
- @backstage/plugin-cloudbuild@0.2.29
- @backstage/plugin-catalog@0.7.4
- @backstage/core-app-api@0.2.0
- @backstage/plugin-scaffolder@0.11.14
- @backstage/plugin-kubernetes@0.5.0
- @backstage/app-defaults@0.1.2
- @backstage/integration-react@0.1.15
- @backstage/plugin-api-docs@0.6.18
- @backstage/plugin-azure-devops@0.1.6
- @backstage/plugin-badges@0.2.16
- @backstage/plugin-catalog-graph@0.2.3
- @backstage/plugin-catalog-import@0.7.5
- @backstage/plugin-catalog-react@0.6.5
- @backstage/plugin-circleci@0.2.31
- @backstage/plugin-code-coverage@0.1.19
- @backstage/plugin-cost-insights@0.11.13
- @backstage/plugin-explore@0.3.22
- @backstage/plugin-gcp-projects@0.3.10
- @backstage/plugin-github-actions@0.4.26
- @backstage/plugin-graphiql@0.2.24
- @backstage/plugin-home@0.4.7
- @backstage/plugin-jenkins@0.5.14
- @backstage/plugin-kafka@0.2.22
- @backstage/plugin-lighthouse@0.2.31
- @backstage/plugin-newrelic@0.3.10
- @backstage/plugin-org@0.3.30
- @backstage/plugin-pagerduty@0.3.19
- @backstage/plugin-rollbar@0.3.20
- @backstage/plugin-search@0.5.1
- @backstage/plugin-sentry@0.3.30
- @backstage/plugin-shortcuts@0.1.15
- @backstage/plugin-tech-insights@0.1.1
- @backstage/plugin-tech-radar@0.4.13
- @backstage/plugin-techdocs@0.12.9
- @backstage/plugin-todo@0.1.16
- @backstage/plugin-user-settings@0.3.13
- @backstage/cli@0.10.1
## 0.2.55
### Patch Changes
- Updated dependencies
- @backstage/plugin-azure-devops@0.1.5
- @backstage/core-components@0.7.6
- @backstage/theme@0.2.14
- @backstage/plugin-user-settings@0.3.12
- @backstage/plugin-api-docs@0.6.16
- @backstage/cli@0.10.0
- @backstage/plugin-circleci@0.2.30
- @backstage/core-plugin-api@0.2.2
- @backstage/plugin-search@0.5.0
- @backstage/plugin-tech-insights@0.1.0
- @backstage/core-app-api@0.1.24
- @backstage/plugin-kubernetes@0.4.22
- @backstage/plugin-scaffolder@0.11.13
- @backstage/plugin-techdocs@0.12.8
## 0.2.53
### Patch Changes
+45 -44
View File
@@ -1,62 +1,63 @@
{
"name": "example-app",
"version": "0.2.53",
"version": "0.2.56",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/app-defaults": "^0.1.1",
"@backstage/app-defaults": "^0.1.2",
"@backstage/catalog-model": "^0.9.7",
"@backstage/cli": "^0.9.0",
"@backstage/core-app-api": "^0.1.21",
"@backstage/core-components": "^0.7.4",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/integration-react": "^0.1.14",
"@backstage/plugin-api-docs": "^0.6.14",
"@backstage/plugin-azure-devops": "^0.1.4",
"@backstage/plugin-badges": "^0.2.14",
"@backstage/plugin-catalog": "^0.7.3",
"@backstage/plugin-catalog-graph": "^0.2.2",
"@backstage/plugin-catalog-import": "^0.7.4",
"@backstage/plugin-catalog-react": "^0.6.4",
"@backstage/plugin-circleci": "^0.2.29",
"@backstage/plugin-cloudbuild": "^0.2.28",
"@backstage/plugin-code-coverage": "^0.1.18",
"@backstage/plugin-cost-insights": "^0.11.11",
"@backstage/plugin-explore": "^0.3.21",
"@backstage/plugin-gcp-projects": "^0.3.9",
"@backstage/plugin-github-actions": "^0.4.24",
"@backstage/plugin-graphiql": "^0.2.21",
"@backstage/plugin-home": "^0.4.6",
"@backstage/plugin-jenkins": "^0.5.12",
"@backstage/plugin-kafka": "^0.2.21",
"@backstage/plugin-kubernetes": "^0.4.20",
"@backstage/plugin-lighthouse": "^0.2.30",
"@backstage/plugin-newrelic": "^0.3.9",
"@backstage/plugin-org": "^0.3.28",
"@backstage/plugin-pagerduty": "0.3.18",
"@backstage/plugin-rollbar": "^0.3.19",
"@backstage/plugin-scaffolder": "^0.11.11",
"@backstage/plugin-search": "^0.4.18",
"@backstage/plugin-sentry": "^0.3.29",
"@backstage/plugin-shortcuts": "^0.1.14",
"@backstage/plugin-tech-radar": "^0.4.12",
"@backstage/plugin-techdocs": "^0.12.6",
"@backstage/plugin-todo": "^0.1.15",
"@backstage/plugin-user-settings": "^0.3.11",
"@backstage/cli": "^0.10.1",
"@backstage/core-app-api": "^0.2.0",
"@backstage/core-components": "^0.8.0",
"@backstage/core-plugin-api": "^0.3.0",
"@backstage/integration-react": "^0.1.15",
"@backstage/plugin-api-docs": "^0.6.18",
"@backstage/plugin-azure-devops": "^0.1.6",
"@backstage/plugin-apache-airflow": "^0.0.0",
"@backstage/plugin-badges": "^0.2.16",
"@backstage/plugin-catalog": "^0.7.4",
"@backstage/plugin-catalog-graph": "^0.2.3",
"@backstage/plugin-catalog-import": "^0.7.5",
"@backstage/plugin-catalog-react": "^0.6.5",
"@backstage/plugin-circleci": "^0.2.31",
"@backstage/plugin-cloudbuild": "^0.2.29",
"@backstage/plugin-code-coverage": "^0.1.19",
"@backstage/plugin-cost-insights": "^0.11.13",
"@backstage/plugin-explore": "^0.3.22",
"@backstage/plugin-gcp-projects": "^0.3.10",
"@backstage/plugin-github-actions": "^0.4.26",
"@backstage/plugin-graphiql": "^0.2.24",
"@backstage/plugin-home": "^0.4.7",
"@backstage/plugin-jenkins": "^0.5.14",
"@backstage/plugin-kafka": "^0.2.22",
"@backstage/plugin-kubernetes": "^0.5.0",
"@backstage/plugin-lighthouse": "^0.2.31",
"@backstage/plugin-newrelic": "^0.3.10",
"@backstage/plugin-org": "^0.3.30",
"@backstage/plugin-pagerduty": "0.3.19",
"@backstage/plugin-rollbar": "^0.3.20",
"@backstage/plugin-scaffolder": "^0.11.14",
"@backstage/plugin-search": "^0.5.1",
"@backstage/plugin-sentry": "^0.3.30",
"@backstage/plugin-shortcuts": "^0.1.15",
"@backstage/plugin-tech-radar": "^0.4.13",
"@backstage/plugin-techdocs": "^0.12.9",
"@backstage/plugin-todo": "^0.1.16",
"@backstage/plugin-user-settings": "^0.3.13",
"@backstage/search-common": "^0.2.0",
"@backstage/theme": "^0.2.11",
"@backstage/plugin-tech-insights": "^0.1.1",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@octokit/rest": "^18.5.3",
"@roadiehq/backstage-plugin-buildkite": "^1.0.8",
"@roadiehq/backstage-plugin-github-insights": "^1.1.23",
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.13",
"@roadiehq/backstage-plugin-travis-ci": "^1.0.11",
"history": "^5.0.0",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-hot-loader": "^4.12.21",
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
@@ -64,7 +65,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/test-utils": "^0.1.22",
"@backstage/test-utils": "^0.1.24",
"@rjsf/core": "^3.2.1",
"@testing-library/cypress": "^8.0.2",
"@testing-library/jest-dom": "^5.10.1",
+2
View File
@@ -87,6 +87,7 @@ import { providers } from './identityProviders';
import * as plugins from './plugins';
import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
const app = createApp({
apis,
@@ -218,6 +219,7 @@ const routes = (
/>
<Route path="/settings" element={<UserSettingsPage />} />
<Route path="/azure-pull-requests" element={<AzurePullRequestsPage />} />
<Route path="/apache-airflow" element={<ApacheAirflowPage />} />
</FlatRoutes>
);
+7 -2
View File
@@ -29,7 +29,10 @@ import LogoIcon from './LogoIcon';
import { NavLink } from 'react-router-dom';
import { GraphiQLIcon } from '@backstage/plugin-graphiql';
import { Settings as SidebarSettings } from '@backstage/plugin-user-settings';
import { SidebarSearchModal } from '@backstage/plugin-search';
import {
SidebarSearchModal,
SearchContextProvider,
} from '@backstage/plugin-search';
import { Shortcuts } from '@backstage/plugin-shortcuts';
import {
Sidebar,
@@ -80,7 +83,9 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
<SidebarSearchModal />
<SearchContextProvider>
<SidebarSearchModal />
</SearchContextProvider>
<SidebarDivider />
{/* Global nav, not org-specific */}
<SidebarItem icon={HomeIcon} to="catalog" text="Home" />
@@ -106,10 +106,7 @@ import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
import { EntityTodoContent } from '@backstage/plugin-todo';
import { Button, Grid } from '@material-ui/core';
import BadgeIcon from '@material-ui/icons/CallToAction';
import {
EntityBuildkiteContent,
isBuildkiteAvailable,
} from '@roadiehq/backstage-plugin-buildkite';
import {
EntityGithubInsightsContent,
EntityGithubInsightsLanguagesCard,
@@ -168,10 +165,6 @@ export const cicdContent = (
<EntityJenkinsContent />
</EntitySwitch.Case>
<EntitySwitch.Case if={isBuildkiteAvailable}>
<EntityBuildkiteContent />
</EntitySwitch.Case>
<EntitySwitch.Case if={isCircleCIAvailable}>
<EntityCircleCIContent />
</EntitySwitch.Case>
+20
View File
@@ -1,5 +1,25 @@
# @backstage/backend-common
## 0.9.13
### Patch Changes
- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly
- 5a008576c4: Add possibility to use custom error handler
- 98a9c35f0c: Add options argument to support additional database migrations configuration
- 6298de32dd: Add knexConfig config section
## 0.9.12
### Patch Changes
- 905dd952ac: Create a `TokenManager` interface and `ServerTokenManager` implementation to generate and validate server tokens for authenticated backend-to-backend API requests.
- 6b500622d5: Move to using node-fetch internally instead of cross-fetch
- 54989b671d: Fixed a potential crash in the log redaction code
- Updated dependencies
- @backstage/integration@0.6.10
- @backstage/config-loader@0.8.1
## 0.9.11
### Patch Changes
+37 -71
View File
@@ -175,23 +175,22 @@ export function createStatusCheckRouter(options: {
// @public (undocumented)
export class DatabaseManager {
forPlugin(pluginId: string): PluginDatabaseManager;
static fromConfig(config: Config): DatabaseManager;
static fromConfig(
config: Config,
options?: DatabaseManagerOptions,
): DatabaseManager;
}
// @public
export type DatabaseManagerOptions = {
migrations?: PluginDatabaseManager['migrations'];
};
// @public (undocumented)
export class DockerContainerRunner implements ContainerRunner {
constructor({ dockerClient }: { dockerClient: Docker });
constructor(options: { dockerClient: Docker });
// (undocumented)
runContainer({
imageName,
command,
args,
logStream,
mountDirs,
workingDir,
envVars,
pullImage,
}: RunContainerOptions): Promise<void>;
runContainer(options: RunContainerOptions): Promise<void>;
}
// @public
@@ -227,34 +226,17 @@ export function getVoidLogger(): winston.Logger;
// @public (undocumented)
export class Git {
// (undocumented)
add({ dir, filepath }: { dir: string; filepath: string }): Promise<void>;
add(options: { dir: string; filepath: string }): Promise<void>;
// (undocumented)
addRemote({
dir,
url,
remote,
}: {
addRemote(options: {
dir: string;
remote: string;
url: string;
}): Promise<void>;
// (undocumented)
clone({
url,
dir,
ref,
}: {
url: string;
dir: string;
ref?: string;
}): Promise<void>;
clone(options: { url: string; dir: string; ref?: string }): Promise<void>;
// (undocumented)
commit({
dir,
message,
author,
committer,
}: {
commit(options: {
dir: string;
message: string;
author: {
@@ -267,41 +249,22 @@ export class Git {
};
}): Promise<string>;
// (undocumented)
currentBranch({
dir,
fullName,
}: {
currentBranch(options: {
dir: string;
fullName?: boolean;
}): Promise<string | undefined>;
// (undocumented)
fetch({ dir, remote }: { dir: string; remote?: string }): Promise<void>;
fetch(options: { dir: string; remote?: string }): Promise<void>;
// (undocumented)
static fromAuth: ({
username,
password,
logger,
}: {
username?: string | undefined;
password?: string | undefined;
logger?: Logger_2 | undefined;
static fromAuth: (options: {
username?: string;
password?: string;
logger?: Logger_2;
}) => Git;
// (undocumented)
init({
dir,
defaultBranch,
}: {
dir: string;
defaultBranch?: string;
}): Promise<void>;
init(options: { dir: string; defaultBranch?: string }): Promise<void>;
// (undocumented)
merge({
dir,
theirs,
ours,
author,
committer,
}: {
merge(options: {
dir: string;
theirs: string;
ours?: string;
@@ -315,17 +278,11 @@ export class Git {
};
}): Promise<MergeResult>;
// (undocumented)
push({ dir, remote }: { dir: string; remote: string }): Promise<PushResult>;
push(options: { dir: string; remote: string }): Promise<PushResult>;
// (undocumented)
readCommit({
dir,
sha,
}: {
dir: string;
sha: string;
}): Promise<ReadCommitResult>;
readCommit(options: { dir: string; sha: string }): Promise<ReadCommitResult>;
// (undocumented)
resolveRef({ dir, ref }: { dir: string; ref: string }): Promise<string>;
resolveRef(options: { dir: string; ref: string }): Promise<string>;
}
// @public
@@ -395,6 +352,9 @@ export type PluginCacheManager = {
// @public
export interface PluginDatabaseManager {
getClient(): Promise<Knex>;
migrations?: {
skip?: boolean;
};
}
// @public
@@ -561,6 +521,8 @@ export type ServiceBuilder = {
setRequestLoggingHandler(
requestLoggingHandler: RequestLoggingHandlerFactory,
): ServiceBuilder;
setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder;
disableDefaultErrorHandler(): ServiceBuilder;
start(): Promise<Server>;
};
@@ -623,8 +585,8 @@ export type UrlReaderPredicateTuple = {
// @public
export class UrlReaders {
static create({ logger, config, factories }: UrlReadersOptions): UrlReader;
static default({ logger, config, factories }: UrlReadersOptions): UrlReader;
static create(options: UrlReadersOptions): UrlReader;
static default(options: UrlReadersOptions): UrlReader;
}
// @public (undocumented)
@@ -642,4 +604,8 @@ export function useHotCleanup(
// @public
export function useHotMemoize<T>(_module: NodeModule, valueFactory: () => T): T;
// Warnings were encountered during analysis:
//
// src/database/types.d.ts:23:12 - (tsdoc-undefined-tag) The TSDoc tag "@default" is not defined in this configuration
```
+14
View File
@@ -96,6 +96,12 @@ export interface Config {
* @default database
*/
pluginDivisionMode?: 'database' | 'schema';
/**
* Arbitrary config object to pass to knex when initializing
* (https://knexjs.org/#Installation-client). Most notable is the debug
* and asyncStackTraces booleans
*/
knexConfig?: object;
/** Plugin specific database configuration and client override */
plugin?: {
[pluginId: string]: {
@@ -111,6 +117,14 @@ export interface Config {
* Defaults to base config if unspecified.
*/
ensureExists?: boolean;
/**
* Arbitrary config object to pass to knex when initializing
* (https://knexjs.org/#Installation-client). Most notable is the
* debug and asyncStackTraces booleans.
*
* This is merged recursively into the base knexConfig
*/
knexConfig?: object;
};
};
};
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.9.11",
"version": "0.9.13",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -31,9 +31,9 @@
"dependencies": {
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.8.0",
"@backstage/config-loader": "^0.8.1",
"@backstage/errors": "^0.1.5",
"@backstage/integration": "^0.6.9",
"@backstage/integration": "^0.6.10",
"@backstage/types": "^0.1.1",
"@google-cloud/storage": "^5.8.0",
"@lerna/project": "^4.0.0",
@@ -81,8 +81,8 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.9.1",
"@backstage/test-utils": "^0.1.23",
"@backstage/cli": "^0.10.1",
"@backstage/test-utils": "^0.1.24",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
@@ -36,25 +36,45 @@ describe('DatabaseManager', () => {
afterEach(() => jest.resetAllMocks());
describe('DatabaseManager.fromConfig', () => {
it('accesses the backend.database key', () => {
const config = new ConfigReader({
backend: {
database: {
client: 'pg',
connection: {
host: 'localhost',
user: 'foo',
password: 'bar',
database: 'foodb',
},
const backendConfig = {
backend: {
database: {
client: 'pg',
connection: {
host: 'localhost',
user: 'foo',
password: 'bar',
database: 'foodb',
},
},
});
},
};
it('accesses the backend.database key', () => {
const config = new ConfigReader(backendConfig);
const getConfigSpy = jest.spyOn(config, 'getConfig');
DatabaseManager.fromConfig(config);
expect(getConfigSpy).toHaveBeenCalledWith('backend.database');
});
it('handles default options', () => {
const config = new ConfigReader(backendConfig);
const database = DatabaseManager.fromConfig(config);
const client = database.forPlugin('test');
expect(client.migrations?.skip).toBe(false);
});
it('handles migrations options', () => {
const config = new ConfigReader(backendConfig);
const database = DatabaseManager.fromConfig(config, {
migrations: { skip: true },
});
const client = database.forPlugin('test');
expect(client.migrations?.skip).toBe(true);
});
});
describe('DatabaseManager.forPlugin', () => {
@@ -505,5 +525,42 @@ describe('DatabaseManager', () => {
'database_name_overriden',
);
});
it('fetches and merges additional knex config', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'pg',
connection: {
host: 'localhost',
database: 'foodb',
},
knexConfig: {
something: false,
},
plugin: {
testdbname: {
knexConfig: {
debug: true,
},
},
},
},
},
}),
);
await testManager.forPlugin('testdbname').getClient();
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
const [baseConfig] = mockCalls[0];
expect(baseConfig.data).toEqual(
expect.objectContaining({
debug: true,
something: false,
}),
);
});
});
});
@@ -14,20 +14,20 @@
* limitations under the License.
*/
import { Knex } from 'knex';
import { omit } from 'lodash';
import { Config, ConfigReader } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { Knex } from 'knex';
import { merge, omit } from 'lodash';
import { mergeDatabaseConfig } from './config';
import {
createNameOverride,
ensureDatabaseExists,
normalizeConnection,
createSchemaOverride,
ensureSchemaExists,
createDatabaseClient,
createNameOverride,
createSchemaOverride,
ensureDatabaseExists,
ensureSchemaExists,
normalizeConnection,
} from './connection';
import { PluginDatabaseManager } from './types';
import { mergeDatabaseConfig } from './config';
/**
* Provides a config lookup path for a plugin's config block.
@@ -36,6 +36,15 @@ function pluginPath(pluginId: string): string {
return `plugin.${pluginId}`;
}
/**
* Configuration options object.
*
* @public
*/
export type DatabaseManagerOptions = {
migrations?: PluginDatabaseManager['migrations'];
};
/** @public */
export class DatabaseManager {
/**
@@ -47,19 +56,25 @@ export class DatabaseManager {
* names if config is not provided.
*
* @param config - The loaded application configuration.
* @param options - An optional configuration object.
*/
static fromConfig(config: Config): DatabaseManager {
static fromConfig(
config: Config,
options?: DatabaseManagerOptions,
): DatabaseManager {
const databaseConfig = config.getConfig('backend.database');
return new DatabaseManager(
databaseConfig,
databaseConfig.getOptionalString('prefix'),
options,
);
}
private constructor(
private readonly config: Config,
private readonly prefix: string = 'backstage_plugin_',
private readonly options?: DatabaseManagerOptions,
) {}
/**
@@ -76,6 +91,10 @@ export class DatabaseManager {
getClient(): Promise<Knex> {
return _this.getDatabase(pluginId);
},
migrations: {
skip: false,
..._this.options?.migrations,
},
};
}
@@ -138,6 +157,24 @@ export class DatabaseManager {
};
}
/**
* Provides the knexConfig which should be used for a given plugin.
*
* @param pluginId Plugin to get the knexConfig for
* @returns the merged kexConfig value or undefined if it isn't specified
*/
private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {
const pluginConfig = this.config
.getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)
?.get<JsonObject>();
const baseConfig = this.config
.getOptionalConfig('knexConfig')
?.get<JsonObject>();
return merge(baseConfig, pluginConfig);
}
private getEnsureExistsConfig(pluginId: string): boolean {
const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true;
return (
@@ -200,6 +237,7 @@ export class DatabaseManager {
const { client } = this.getClientType(pluginId);
return {
...this.getAdditionalKnexConfig(pluginId),
client,
connection: this.getConnectionConfig(pluginId),
};
@@ -30,6 +30,18 @@ export interface PluginDatabaseManager {
* stores so that plugins are discouraged from database integration.
*/
getClient(): Promise<Knex>;
/**
* This property is used to control the behavior of database migrations.
*/
migrations?: {
/**
* skip database migrations. Useful if connecting to a read-only database.
*
* @default false
*/
skip?: boolean;
};
}
/**
@@ -54,10 +54,13 @@ export function setRootLoggerRedactionList(redactionList: string[]) {
* and replaces them with the corresponding identifier.
*/
function redactLogLine(info: winston.Logform.TransformableInfo) {
// TODO(hhogg): The logger is created before the config is loaded,
// because the logger is needed in the config loader. There is a risk of
// a secret being logged out during the config loading stage.
if (redactionRegExp) {
// TODO(hhogg): The logger is created before the config is loaded, because the
// logger is needed in the config loader. There is a risk of a secret being
// logged out during the config loading stage.
// TODO(freben): Added a check that info.message actually was a string,
// because it turned out that this was not necessarily guaranteed.
// https://github.com/backstage/backstage/issues/8306
if (redactionRegExp && typeof info.message === 'string') {
info.message = info.message.replace(redactionRegExp, '[REDACTED]');
}
@@ -46,7 +46,8 @@ export class UrlReaders {
/**
* Creates a UrlReader without any known types.
*/
static create({ logger, config, factories }: UrlReadersOptions): UrlReader {
static create(options: UrlReadersOptions): UrlReader {
const { logger, config, factories } = options;
const mux = new UrlReaderPredicateMux(logger);
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
config,
@@ -68,7 +69,8 @@ export class UrlReaders {
*
* Any additional factories passed will be loaded before the default ones.
*/
static default({ logger, config, factories = [] }: UrlReadersOptions) {
static default(options: UrlReadersOptions) {
const { logger, config, factories = [] } = options;
return UrlReaders.create({
logger,
config,
+32 -74
View File
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import git, {
ProgressCallback,
MergeResult,
@@ -42,44 +43,32 @@ export class Git {
},
) {}
async add({
dir,
filepath,
}: {
dir: string;
filepath: string;
}): Promise<void> {
async add(options: { dir: string; filepath: string }): Promise<void> {
const { dir, filepath } = options;
this.config.logger?.info(`Adding file {dir=${dir},filepath=${filepath}}`);
return git.add({ fs, dir, filepath });
}
async addRemote({
dir,
url,
remote,
}: {
async addRemote(options: {
dir: string;
remote: string;
url: string;
}): Promise<void> {
const { dir, url, remote } = options;
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,
}: {
async commit(options: {
dir: string;
message: string;
author: { name: string; email: string };
committer: { name: string; email: string };
}): Promise<string> {
const { dir, message, author, committer } = options;
this.config.logger?.info(
`Committing file to repo {dir=${dir},message=${message}}`,
);
@@ -87,15 +76,12 @@ export class Git {
return git.commit({ fs, dir, message, author, committer });
}
async clone({
url,
dir,
ref,
}: {
async clone(options: {
url: string;
dir: string;
ref?: string;
}): Promise<void> {
const { url, dir, ref } = options;
this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`);
return git.clone({
fs,
@@ -114,51 +100,35 @@ export class Git {
}
// https://isomorphic-git.org/docs/en/currentBranch
async currentBranch({
dir,
fullName,
}: {
async currentBranch(options: {
dir: string;
fullName?: boolean;
}): Promise<string | undefined> {
const fullname = fullName ?? false;
return git.currentBranch({ fs, dir, fullname }) as Promise<
const { dir, fullName = false } = options;
return git.currentBranch({ fs, dir, fullname: fullName }) as Promise<
string | undefined
>;
}
// https://isomorphic-git.org/docs/en/fetch
async fetch({
dir,
remote,
}: {
dir: string;
remote?: string;
}): Promise<void> {
const remoteValue = remote ?? 'origin';
async fetch(options: { dir: string; remote?: string }): Promise<void> {
const { dir, remote = 'origin' } = options;
this.config.logger?.info(
`Fetching remote=${remoteValue} for repository {dir=${dir}}`,
`Fetching remote=${remote} for repository {dir=${dir}}`,
);
await git.fetch({
fs,
http,
dir,
remote: remoteValue,
remote,
onProgress: this.onProgressHandler(),
headers: {
'user-agent': 'git/@isomorphic-git',
},
headers: { 'user-agent': 'git/@isomorphic-git' },
onAuth: this.onAuth,
});
}
async init({
dir,
defaultBranch = 'master',
}: {
dir: string;
defaultBranch?: string;
}): Promise<void> {
async init(options: { dir: string; defaultBranch?: string }): Promise<void> {
const { dir, defaultBranch = 'master' } = options;
this.config.logger?.info(`Init git repository {dir=${dir}}`);
return git.init({
@@ -169,19 +139,14 @@ export class Git {
}
// https://isomorphic-git.org/docs/en/merge
async merge({
dir,
theirs,
ours,
author,
committer,
}: {
async merge(options: {
dir: string;
theirs: string;
ours?: string;
author: { name: string; email: string };
committer: { name: string; email: string };
}): Promise<MergeResult> {
const { dir, theirs, ours, author, committer } = options;
this.config.logger?.info(
`Merging branch '${theirs}' into '${ours}' for repository {dir=${dir}}`,
);
@@ -197,7 +162,8 @@ export class Git {
});
}
async push({ dir, remote }: { dir: string; remote: string }) {
async push(options: { dir: string; remote: string }) {
const { dir, remote } = options;
this.config.logger?.info(
`Pushing directory to remote {dir=${dir},remote=${remote}}`,
);
@@ -215,24 +181,17 @@ export class Git {
}
// https://isomorphic-git.org/docs/en/readCommit
async readCommit({
dir,
sha,
}: {
async readCommit(options: {
dir: string;
sha: string;
}): Promise<ReadCommitResult> {
const { dir, sha } = options;
return git.readCommit({ fs, dir, oid: sha });
}
// https://isomorphic-git.org/docs/en/resolveRef
async resolveRef({
dir,
ref,
}: {
dir: string;
ref: string;
}): Promise<string> {
async resolveRef(options: { dir: string; ref: string }): Promise<string> {
const { dir, ref } = options;
return git.resolveRef({ fs, dir, ref });
}
@@ -256,13 +215,12 @@ export class Git {
};
};
static fromAuth = ({
username,
password,
logger,
}: {
static fromAuth = (options: {
username?: string;
password?: string;
logger?: Logger;
}) => new Git({ username, password, logger });
}) => {
const { username, password, logger } = options;
return new Git({ username, password, logger });
};
}
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import { applyCspDirectives } from './ServiceBuilderImpl';
import { NextFunction, Request, Response } from 'express';
import { applyCspDirectives, ServiceBuilderImpl } from './ServiceBuilderImpl';
describe('ServiceBuilderImpl', () => {
describe('applyCspDirectives', () => {
@@ -33,4 +34,27 @@ describe('ServiceBuilderImpl', () => {
expect(result!['upgrade-insecure-requests']).toBeUndefined();
});
});
describe('setCustomErrorHandler', () => {
it('check if custom error handler is undefined', () => {
const serviceBuilder = new ServiceBuilderImpl(module);
const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder);
expect(serviceBuilderProto.errorHandler).toBeUndefined();
});
it('adds custom error handler', () => {
const serviceBuilder = new ServiceBuilderImpl(module);
const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder);
const customErrorHandler = (
error: Error,
_req: Request,
_res: Response,
next: NextFunction,
) => {
next(error);
};
serviceBuilderProto.setErrorHandler(customErrorHandler);
expect(serviceBuilderProto.errorHandler).toEqual(customErrorHandler);
});
});
});
@@ -17,7 +17,7 @@
import { Config } from '@backstage/config';
import compression from 'compression';
import cors from 'cors';
import express, { Router } from 'express';
import express, { Router, ErrorRequestHandler } from 'express';
import helmet from 'helmet';
import * as http from 'http';
import stoppable from 'stoppable';
@@ -25,7 +25,7 @@ import { Logger } from 'winston';
import { useHotCleanup } from '../../hot';
import { getRootLogger } from '../../logging';
import {
errorHandler,
errorHandler as defaultErrorHandler,
notFoundHandler,
requestLoggingHandler as defaultRequestLoggingHandler,
} from '../../middleware';
@@ -66,6 +66,8 @@ export class ServiceBuilderImpl implements ServiceBuilder {
private httpsSettings: HttpsSettings | undefined;
private routers: [string, Router][];
private requestLoggingHandler: RequestLoggingHandlerFactory | undefined;
private errorHandler: ErrorRequestHandler | undefined;
private useDefaultErrorHandler: boolean;
// Reference to the module where builder is created - needed for hot module
// reloading
private module: NodeModule;
@@ -73,6 +75,7 @@ export class ServiceBuilderImpl implements ServiceBuilder {
constructor(moduleRef: NodeModule) {
this.routers = [];
this.module = moduleRef;
this.useDefaultErrorHandler = true;
}
loadConfig(config: Config): ServiceBuilder {
@@ -152,6 +155,16 @@ export class ServiceBuilderImpl implements ServiceBuilder {
return this;
}
setErrorHandler(errorHandler: ErrorRequestHandler) {
this.errorHandler = errorHandler;
return this;
}
disableDefaultErrorHandler() {
this.useDefaultErrorHandler = false;
return this;
}
async start(): Promise<http.Server> {
const app = express();
const { port, host, logger, corsOptions, httpsSettings, helmetOptions } =
@@ -169,7 +182,14 @@ export class ServiceBuilderImpl implements ServiceBuilder {
app.use(root, route);
}
app.use(notFoundHandler());
app.use(errorHandler());
if (this.errorHandler) {
app.use(this.errorHandler);
}
if (this.useDefaultErrorHandler) {
app.use(defaultErrorHandler());
}
const server: http.Server = httpsSettings
? await createHttpsServer(app, httpsSettings, logger)
+16 -1
View File
@@ -16,7 +16,7 @@
import { Config } from '@backstage/config';
import cors from 'cors';
import { Router, RequestHandler } from 'express';
import { Router, RequestHandler, ErrorRequestHandler } from 'express';
import { Server } from 'http';
import { Logger } from 'winston';
@@ -98,6 +98,21 @@ export type ServiceBuilder = {
requestLoggingHandler: RequestLoggingHandlerFactory,
): ServiceBuilder;
/**
* Sets an additional errorHandler to run before the defaultErrorHandler.
*
* For execution of only the custom error handler make sure to also invoke disableDefaultErrorHandler()
* otherwise the defaultErrorHandler is executed at the end of the error middleware chain.
*
* @param errorHandler - an error handler
*/
setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder;
/**
* Disables the default error handler
*/
disableDefaultErrorHandler(): ServiceBuilder;
/**
* Starts the server using the given settings.
*/
@@ -28,20 +28,22 @@ export type UserOptions = {
export class DockerContainerRunner implements ContainerRunner {
private readonly dockerClient: Docker;
constructor({ dockerClient }: { dockerClient: Docker }) {
this.dockerClient = dockerClient;
constructor(options: { dockerClient: Docker }) {
this.dockerClient = options.dockerClient;
}
async runContainer({
imageName,
command,
args,
logStream = new PassThrough(),
mountDirs = {},
workingDir,
envVars = {},
pullImage = true,
}: RunContainerOptions) {
async runContainer(options: RunContainerOptions) {
const {
imageName,
command,
args,
logStream = new PassThrough(),
mountDirs = {},
workingDir,
envVars = {},
pullImage = true,
} = options;
// Show a better error message when Docker is unavailable.
try {
await this.dockerClient.ping();
+3 -3
View File
@@ -29,7 +29,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.9.10",
"@backstage/backend-common": "^0.9.12",
"@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.4",
"@backstage/types": "^0.1.1",
@@ -43,8 +43,8 @@
"zod": "^3.9.5"
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.1.9",
"@backstage/cli": "^0.9.0",
"@backstage/backend-test-utils": "^0.1.10",
"@backstage/cli": "^0.10.0",
"jest": "^26.0.1",
"wait-for-expect": "^3.0.2"
},
+8
View File
@@ -1,5 +1,13 @@
# @backstage/backend-test-utils
## 0.1.10
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.9.12
- @backstage/cli@0.10.0
## 0.1.9
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-test-utils",
"description": "Test helpers library for Backstage backends",
"version": "0.1.9",
"version": "0.1.10",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -30,8 +30,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.9.10",
"@backstage/cli": "^0.9.0",
"@backstage/backend-common": "^0.9.12",
"@backstage/cli": "^0.10.0",
"@backstage/config": "^0.1.9",
"knex": "^0.95.1",
"mysql2": "^2.2.5",
@@ -41,7 +41,7 @@
"uuid": "^8.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.10.0",
"jest": "^26.0.1"
},
"files": [
+41
View File
@@ -1,5 +1,46 @@
# example-backend
## 0.2.56
### Patch Changes
- Updated dependencies
- @backstage/plugin-auth-backend@0.5.0
- @backstage/plugin-scaffolder-backend@0.15.16
- @backstage/plugin-kubernetes-backend@0.4.0
- @backstage/backend-common@0.9.13
- @backstage/plugin-catalog-backend@0.19.1
- @backstage/plugin-search-backend@0.2.8
- @backstage/plugin-search-backend-module-elasticsearch@0.0.6
- @backstage/plugin-search-backend-module-pg@0.2.2
- @backstage/plugin-techdocs-backend@0.12.0
- @backstage/plugin-todo-backend@0.1.15
- @backstage/plugin-scaffolder-backend-module-rails@0.2.0
- @backstage/plugin-azure-devops-backend@0.2.4
- example-app@0.2.56
## 0.2.55
### Patch Changes
- Updated dependencies
- @backstage/integration@0.6.10
- @backstage/plugin-scaffolder-backend@0.15.15
- @backstage/plugin-auth-backend@0.4.10
- @backstage/plugin-kubernetes-backend@0.3.20
- @backstage/plugin-badges-backend@0.1.13
- @backstage/plugin-catalog-backend@0.19.0
- @backstage/plugin-code-coverage-backend@0.1.16
- @backstage/plugin-jenkins-backend@0.1.9
- @backstage/plugin-tech-insights-backend@0.1.3
- @backstage/plugin-techdocs-backend@0.11.0
- @backstage/plugin-todo-backend@0.1.14
- @backstage/backend-common@0.9.12
- @backstage/plugin-azure-devops-backend@0.2.3
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.2
- @backstage/plugin-tech-insights-node@0.1.1
- example-app@0.2.55
## 0.2.54
### Patch Changes
+22 -22
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.54",
"version": "0.2.56",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -24,39 +24,39 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.9.11",
"@backstage/backend-common": "^0.9.13",
"@backstage/catalog-client": "^0.5.2",
"@backstage/catalog-model": "^0.9.7",
"@backstage/config": "^0.1.10",
"@backstage/integration": "^0.6.8",
"@backstage/integration": "^0.6.10",
"@backstage/plugin-app-backend": "^0.3.19",
"@backstage/plugin-auth-backend": "^0.4.9",
"@backstage/plugin-azure-devops-backend": "^0.2.2",
"@backstage/plugin-badges-backend": "^0.1.12",
"@backstage/plugin-catalog-backend": "^0.18.0",
"@backstage/plugin-code-coverage-backend": "^0.1.15",
"@backstage/plugin-auth-backend": "^0.5.0",
"@backstage/plugin-azure-devops-backend": "^0.2.4",
"@backstage/plugin-badges-backend": "^0.1.13",
"@backstage/plugin-catalog-backend": "^0.19.1",
"@backstage/plugin-code-coverage-backend": "^0.1.16",
"@backstage/plugin-graphql-backend": "^0.1.9",
"@backstage/plugin-jenkins-backend": "^0.1.8",
"@backstage/plugin-kubernetes-backend": "^0.3.19",
"@backstage/plugin-jenkins-backend": "^0.1.9",
"@backstage/plugin-kubernetes-backend": "^0.4.0",
"@backstage/plugin-kafka-backend": "^0.2.12",
"@backstage/plugin-proxy-backend": "^0.2.14",
"@backstage/plugin-rollbar-backend": "^0.1.16",
"@backstage/plugin-scaffolder-backend": "^0.15.14",
"@backstage/plugin-scaffolder-backend-module-rails": "^0.1.7",
"@backstage/plugin-search-backend": "^0.2.7",
"@backstage/plugin-scaffolder-backend": "^0.15.16",
"@backstage/plugin-scaffolder-backend-module-rails": "^0.2.0",
"@backstage/plugin-search-backend": "^0.2.8",
"@backstage/plugin-search-backend-node": "^0.4.2",
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.5",
"@backstage/plugin-search-backend-module-pg": "^0.2.1",
"@backstage/plugin-techdocs-backend": "^0.10.9",
"@backstage/plugin-tech-insights-backend": "^0.1.2",
"@backstage/plugin-tech-insights-node": "^0.1.0",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.1",
"@backstage/plugin-todo-backend": "^0.1.13",
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.6",
"@backstage/plugin-search-backend-module-pg": "^0.2.2",
"@backstage/plugin-techdocs-backend": "^0.12.0",
"@backstage/plugin-tech-insights-backend": "^0.1.3",
"@backstage/plugin-tech-insights-node": "^0.1.1",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.2",
"@backstage/plugin-todo-backend": "^0.1.15",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
"azure-devops-node-api": "^11.0.1",
"dockerode": "^3.3.1",
"example-app": "^0.2.53",
"example-app": "^0.2.56",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"express-prom-bundle": "^6.3.6",
@@ -68,7 +68,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.9.1",
"@backstage/cli": "^0.10.1",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
+2
View File
@@ -29,6 +29,7 @@ export default async function createPlugin({
config,
discovery,
reader,
cache,
}: PluginEnvironment): Promise<Router> {
// Preparers are responsible for fetching source files for documentation.
const preparers = await Preparers.fromConfig(config, {
@@ -64,5 +65,6 @@ export default async function createPlugin({
logger,
config,
discovery,
cache,
});
}
+1 -1
View File
@@ -35,7 +35,7 @@
"cross-fetch": "^3.0.6"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.10.0",
"@types/jest": "^26.0.7",
"msw": "^0.35.0"
},
+1 -1
View File
@@ -42,7 +42,7 @@
"yup": "^0.32.9"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.10.0",
"@types/jest": "^26.0.7",
"@types/lodash": "^4.14.151",
"yaml": "^1.9.2"
+26
View File
@@ -1,5 +1,31 @@
# @backstage/cli
## 0.10.1
### Patch Changes
- 0ebb05eee2: Add cli option to minify the generated code of a plugin or backend package
```
backstage-cli plugin:build --minify
backstage-cli backend:build --minify
```
- cd450844f6: Updated the frontend plugin template to put React dependencies in `peerDependencies` by default, as well as allowing both React v16 and v17. This change can be applied to existing plugins by running `yarn backstage-cli plugin:diff` within the plugin package directory.
## 0.10.0
### Minor Changes
- ea99ef5198: Remove the `backend:build-image` command from the CLI and added more deprecation warnings to other deprecated fields like `--lax` and `remove-plugin`
### Patch Changes
- e7230ef814: Bump react-dev-utils to v12
- 416b68675d: build(dependencies): bump `style-loader` from 1.2.1 to 3.3.1
- Updated dependencies
- @backstage/config-loader@0.8.1
## 0.9.1
### Patch Changes
+15 -16
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.9.1",
"version": "0.10.1",
"private": false,
"publishConfig": {
"access": "public"
@@ -30,7 +30,7 @@
"dependencies": {
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.8.0",
"@backstage/config-loader": "^0.8.1",
"@backstage/errors": "^0.1.5",
"@backstage/types": "^0.1.1",
"@hot-loader/react-dom": "^16.13.0",
@@ -38,9 +38,9 @@
"@lerna/project": "^4.0.0",
"@octokit/request": "^5.4.12",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-json": "^4.0.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-yaml": "^3.0.0",
"@rollup/plugin-yaml": "^3.1.0",
"@spotify/eslint-config-base": "^12.0.0",
"@spotify/eslint-config-react": "^12.0.0",
"@spotify/eslint-config-typescript": "^12.0.0",
@@ -62,7 +62,7 @@
"css-loader": "^5.2.6",
"dashify": "^2.0.0",
"diff": "^5.0.0",
"esbuild": "^0.8.56",
"esbuild": "^0.14.1",
"eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-formatter-friendly": "^7.0.0",
@@ -89,14 +89,13 @@
"ora": "^5.3.0",
"postcss": "^8.1.0",
"process": "^0.11.10",
"react": "^16.0.0",
"react-dev-utils": "^12.0.0-next.47",
"react-hot-loader": "^4.12.21",
"recursive-readdir": "^2.2.2",
"replace-in-file": "^6.0.0",
"rollup": "2.44.x",
"rollup-plugin-dts": "^3.0.1",
"rollup-plugin-esbuild": "2.6.x",
"rollup": "^2.60.2",
"rollup-plugin-dts": "^4.0.1",
"rollup-plugin-esbuild": "^4.7.2",
"rollup-plugin-peer-deps-external": "^2.2.2",
"rollup-plugin-postcss": "^4.0.0",
"rollup-pluginutils": "^2.8.2",
@@ -117,14 +116,14 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-common": "^0.9.11",
"@backstage/backend-common": "^0.9.13",
"@backstage/config": "^0.1.11",
"@backstage/core-components": "^0.7.5",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.23",
"@backstage/theme": "^0.2.13",
"@backstage/core-components": "^0.8.0",
"@backstage/core-plugin-api": "^0.3.0",
"@backstage/core-app-api": "^0.2.0",
"@backstage/dev-utils": "^0.2.14",
"@backstage/test-utils": "^0.1.24",
"@backstage/theme": "^0.2.14",
"@types/diff": "^5.0.0",
"@types/express": "^4.17.6",
"@types/fs-extra": "^9.0.1",
+3 -1
View File
@@ -14,10 +14,12 @@
* limitations under the License.
*/
import { Command } from 'commander';
import { buildPackage, Output } from '../../lib/builder';
export default async () => {
export default async (cmd: Command) => {
await buildPackage({
outputs: new Set([Output.cjs, Output.types]),
minify: cmd.minify,
});
};
+2
View File
@@ -47,6 +47,7 @@ export function registerCommands(program: CommanderStatic) {
program
.command('backend:build')
.description('Build a backend plugin')
.option('--minify', 'Minify the generated code')
.action(lazy(() => import('./backend/build').then(m => m.default)));
program
@@ -116,6 +117,7 @@ export function registerCommands(program: CommanderStatic) {
program
.command('plugin:build')
.description('Build a plugin')
.option('--minify', 'Minify the generated code')
.action(lazy(() => import('./plugin/build').then(m => m.default)));
program
+3 -1
View File
@@ -14,10 +14,12 @@
* limitations under the License.
*/
import { Command } from 'commander';
import { buildPackage, Output } from '../../lib/builder';
export default async () => {
export default async (cmd: Command) => {
await buildPackage({
outputs: new Set([Output.esm, Output.types]),
minify: cmd.minify,
});
};
+1
View File
@@ -100,6 +100,7 @@ export const makeConfigs = async (
}),
esbuild({
target: 'es2019',
minify: options.minify,
}),
],
});
+1
View File
@@ -22,4 +22,5 @@ export enum Output {
export type BuildOptions = {
outputs: Set<Output>;
minify?: boolean;
};
+21 -3
View File
@@ -75,7 +75,9 @@ class PackageJsonHandler {
await this.syncScripts();
await this.syncPublishConfig();
await this.syncDependencies('dependencies');
await this.syncDependencies('peerDependencies', true);
await this.syncDependencies('devDependencies');
await this.syncReactDeps();
}
// Make sure a field inside package.json is in sync. This mutates the targetObj and writes package.json on change.
@@ -207,12 +209,12 @@ class PackageJsonHandler {
}
}
private async syncDependencies(fieldName: string) {
private async syncDependencies(fieldName: string, required: boolean = false) {
const pkgDeps = this.pkg[fieldName];
const targetDeps = (this.targetPkg[fieldName] =
this.targetPkg[fieldName] || {});
if (!pkgDeps) {
if (!pkgDeps && !required) {
return;
}
@@ -231,10 +233,26 @@ class PackageJsonHandler {
continue;
}
await this.syncField(key, pkgDeps, targetDeps, fieldName, true, true);
await this.syncField(
key,
pkgDeps,
targetDeps,
fieldName,
true,
!required,
);
}
}
private async syncReactDeps() {
const targetDeps = (this.targetPkg.dependencies =
this.targetPkg.dependencies || {});
// Remove these from from deps since they're now in peerDeps
await this.syncField('react', {}, targetDeps, 'dependencies');
await this.syncField('react-dom', {}, targetDeps, 'dependencies');
}
private async write() {
await this.writeFunc(`${JSON.stringify(this.targetPkg, null, 2)}\n`);
}
+2 -2
View File
@@ -66,7 +66,7 @@ export const version = findVersion();
export const isDev = fs.pathExistsSync(paths.resolveOwn('src'));
export function createPackageVersionProvider(lockfile?: Lockfile) {
return (name: string, versionHint?: string) => {
return (name: string, versionHint?: string): string => {
const packageVersion = packageVersions[name];
const targetVersion = versionHint || packageVersion;
if (!targetVersion) {
@@ -94,6 +94,6 @@ export function createPackageVersionProvider(lockfile?: Lockfile) {
if (semver.parse(versionHint)?.prerelease.length) {
return versionHint!;
}
return `^${versionHint}`;
return versionHint?.match(/^[\d\.]+$/) ? `^${versionHint}` : versionHint!;
};
}
@@ -32,10 +32,11 @@
"@material-ui/core": "{{versionQuery '@material-ui/core' '4.12.2'}}",
"@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}",
"@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.57'}}",
"react": "{{versionQuery 'react' '16.13.1'}}",
"react-dom": "{{versionQuery 'react-dom' '16.13.1'}}",
"react-use": "{{versionQuery 'react-use' '17.2.4'}}"
},
"peerDependencies": {
"react": "{{versionQuery 'react' '^16.13.1 || ^17.0.0'}}"
},
"devDependencies": {
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
"@backstage/core-app-api": "{{versionQuery '@backstage/core-app-api'}}",
+18
View File
@@ -1,5 +1,23 @@
# @backstage/codemods
## 0.1.25
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.0
- @backstage/core-plugin-api@0.3.0
- @backstage/core-app-api@0.2.0
## 0.1.24
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.7.6
- @backstage/core-plugin-api@0.2.2
- @backstage/core-app-api@0.1.24
## 0.1.23
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/codemods",
"description": "A collection of codemods for Backstage projects",
"version": "0.1.23",
"version": "0.1.25",
"private": false,
"publishConfig": {
"access": "public",
+7
View File
@@ -1,5 +1,12 @@
# @backstage/config-loader
## 0.8.1
### Patch Changes
- b055a6addc: Align on usage of `cross-fetch` vs `node-fetch` in frontend vs backend packages, and remove some unnecessary imports of either one of them
- 4bea7b81d3: Uses key visibility as fallback in non-object arrays
## 0.8.0
### Minor Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config-loader",
"description": "Config loading functionality used by Backstage backend, and CLI",
"version": "0.8.0",
"version": "0.8.1",
"private": false,
"publishConfig": {
"access": "public",
@@ -20,6 +20,7 @@ import { filterByVisibility, filterErrorsByVisibility } from './filtering';
const data = {
arr: ['f', 'b', 's'],
arrU: ['f', 'b', 't'],
objArr: [
{ f: 1, b: 2, s: 3 },
{ f: 4, b: 5, s: 6 },
@@ -40,6 +41,8 @@ const data = {
const visibility = new Map<string, ConfigVisibility>(
Object.entries({
'/arrU': 'frontend',
'/arrU/2': 'backend',
'/arr/0': 'frontend',
'/arr/1': 'backend',
'/arr/2': 'secret',
@@ -71,6 +74,9 @@ describe('filterByVisibility', () => {
'arr[0]',
'arr[1]',
'arr[2]',
'arrU[0]',
'arrU[1]',
'arrU[2]',
'objArr[0].f',
'objArr[0].b',
'objArr[0].s',
@@ -97,10 +103,12 @@ describe('filterByVisibility', () => {
obj: { f: 'a' },
arrF: [],
objF: {},
arrU: ['f', 'b'],
},
filteredKeys: [
'arr[1]',
'arr[2]',
'arrU[2]',
'objArr[0].b',
'objArr[0].s',
'objArr[1].b',
@@ -120,6 +128,7 @@ describe('filterByVisibility', () => {
{
data: {
arr: ['b'],
arrU: ['t'],
objArr: [{ b: 2 }, { b: 5 }],
obj: { b: {} },
arrF: [{ never: 'here' }],
@@ -132,6 +141,8 @@ describe('filterByVisibility', () => {
filteredKeys: [
'arr[0]',
'arr[2]',
'arrU[0]',
'arrU[1]',
'objArr[0].f',
'objArr[0].s',
'objArr[1].f',
@@ -154,6 +165,9 @@ describe('filterByVisibility', () => {
filteredKeys: [
'arr[0]',
'arr[1]',
'arrU[0]',
'arrU[1]',
'arrU[2]',
'objArr[0].f',
'objArr[0].b',
'objArr[1].f',
@@ -61,11 +61,17 @@ export function filterByVisibility(
const arr = new Array<JsonValue>();
for (const [index, value] of jsonVal.entries()) {
const out = transform(
value,
let path = visibilityPath;
const hasVisibilityInIndex = visibilityByDataPath.get(
`${visibilityPath}/${index}`,
`${filterPath}[${index}]`,
);
if (hasVisibilityInIndex || typeof value === 'object') {
path = `${visibilityPath}/${index}`;
}
const out = transform(value, path, `${filterPath}[${index}]`);
if (out !== undefined) {
arr.push(out);
}
+56
View File
@@ -1,5 +1,61 @@
# @backstage/core-app-api
## 0.2.0
### Minor Changes
- a036b65c2f: **BREAKING CHANGE**
The app `SignInPage` component has been updated to switch out the `onResult` callback for a new `onSignInSuccess` callback. This is an immediate breaking change without any deprecation period, as it was deemed to be the way of making this change that had the lowest impact.
The new `onSignInSuccess` callback directly accepts an implementation of an `IdentityApi`, rather than a `SignInResult`. The `SignInPage` from `@backstage/core-component` has been updated to fit this new API, and as long as you pass on `props` directly you should not see any breakage.
However, if you implement your own custom `SignInPage`, then this will be a breaking change and you need to migrate over to using the new callback. While doing so you can take advantage of the `UserIdentity.fromLegacy` helper from `@backstage/core-components` to make the migration simpler by still using the `SignInResult` type. This helper is also deprecated though and is only provided for immediate migration. Long-term it will be necessary to build the `IdentityApi` using for example `UserIdentity.create` instead.
The following is an example of how you can migrate existing usage immediately using `UserIdentity.fromLegacy`:
```ts
onResult(signInResult);
// becomes
onSignInSuccess(UserIdentity.fromLegacy(signInResult));
```
The following is an example of how implement the new `onSignInSuccess` callback of the `SignInPage` using `UserIdentity.create`:
```ts
const identityResponse = await authApi.getBackstageIdentity();
// Profile is optional and will be removed, but allows the
// synchronous getProfile method of the IdentityApi to be used.
const profile = await authApi.getProfile();
onSignInSuccess(
UserIdentity.create({
identity: identityResponse.identity,
authApi,
profile,
}),
);
```
### Patch Changes
- cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used.
- dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly
- Updated dependencies
- @backstage/core-components@0.8.0
- @backstage/core-plugin-api@0.3.0
- @backstage/app-defaults@0.1.2
- @backstage/version-bridge@0.1.1
## 0.1.24
### Patch Changes
- 0e7f256034: Fixed a bug where `useRouteRef` would fail in situations where relative navigation was needed and the app was is mounted on a sub-path. This would typically show up as a failure to navigate to a tab on an entity page.
- Updated dependencies
- @backstage/core-components@0.7.6
- @backstage/theme@0.2.14
- @backstage/core-plugin-api@0.2.2
## 0.1.23
### Patch Changes
+16 -76
View File
@@ -39,6 +39,7 @@ import { FeatureFlagsSaveOptions } from '@backstage/core-plugin-api';
import { gitlabAuthApiRef } from '@backstage/core-plugin-api';
import { googleAuthApiRef } from '@backstage/core-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
import { IdentityApi } from '@backstage/core-plugin-api';
import { microsoftAuthApiRef } from '@backstage/core-plugin-api';
import { OAuthApi } from '@backstage/core-plugin-api';
import { OAuthRequestApi } from '@backstage/core-plugin-api';
@@ -250,24 +251,13 @@ export class AppThemeSelector implements AppThemeApi {
// @public
export class AtlassianAuth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
}: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T;
}
// @public
export class Auth0Auth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
}: OAuthApiCreateOptions): typeof auth0AuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T;
}
// @public
@@ -303,13 +293,7 @@ export type BackstagePluginWithAnyOutput = Omit<
// @public
export class BitbucketAuth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
}: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T;
}
// @public
@@ -402,13 +386,7 @@ export class GithubAuth implements OAuthApi, SessionApi {
// @deprecated
constructor(sessionManager: SessionManager<GithubSession>);
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
}: OAuthApiCreateOptions): GithubAuth;
static create(options: OAuthApiCreateOptions): GithubAuth;
// (undocumented)
getAccessToken(scope?: string, options?: AuthRequestOptions): Promise<string>;
// (undocumented)
@@ -441,25 +419,13 @@ export type GithubSession = {
// @public
export class GitlabAuth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
}: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T;
}
// @public
export class GoogleAuth {
// (undocumented)
static create({
discoveryApi,
oauthRequestApi,
environment,
provider,
defaultScopes,
}: OAuthApiCreateOptions): typeof googleAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T;
}
// @public
@@ -477,13 +443,7 @@ export class LocalStorageFeatureFlags implements FeatureFlagsApi {
// @public
export class MicrosoftAuth {
// (undocumented)
static create({
environment,
provider,
oauthRequestApi,
discoveryApi,
defaultScopes,
}: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T;
}
// @public
@@ -507,14 +467,7 @@ export class OAuth2
scopeTransform: (scopes: string[]) => string[];
});
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
scopeTransform,
}: OAuth2CreateOptions): OAuth2;
static create(options: OAuth2CreateOptions): OAuth2;
// (undocumented)
getAccessToken(
scope?: string | string[],
@@ -570,24 +523,15 @@ export class OAuthRequestManager implements OAuthRequestApi {
// @public
export class OktaAuth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
defaultScopes,
}: OAuthApiCreateOptions): typeof oktaAuthApiRef.T;
static create(options: OAuthApiCreateOptions): typeof oktaAuthApiRef.T;
}
// @public
export class OneLoginAuth {
// (undocumented)
static create({
discoveryApi,
environment,
provider,
oauthRequestApi,
}: OneLoginAuthCreateOptions): typeof oneloginAuthApiRef.T;
static create(
options: OneLoginAuthCreateOptions,
): typeof oneloginAuthApiRef.T;
}
// @public
@@ -607,11 +551,7 @@ export class SamlAuth
// @deprecated
constructor(sessionManager: SessionManager<SamlSession>);
// (undocumented)
static create({
discoveryApi,
environment,
provider,
}: AuthApiCreateOptions): SamlAuth;
static create(options: AuthApiCreateOptions): SamlAuth;
// (undocumented)
getBackstageIdentity(
options?: AuthRequestOptions,
@@ -635,10 +575,10 @@ export type SamlSession = {
// @public
export type SignInPageProps = {
onResult(result: SignInResult): void;
onSignInSuccess(identityApi: IdentityApi): void;
};
// @public
// @public @deprecated
export type SignInResult = {
userId: string;
profile: ProfileInfo;
+12 -10
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-app-api",
"description": "Core app API used by Backstage apps",
"version": "0.1.23",
"version": "0.2.0",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,26 +29,28 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/app-defaults": "^0.1.1",
"@backstage/core-components": "^0.7.5",
"@backstage/app-defaults": "^0.1.2",
"@backstage/core-components": "^0.8.0",
"@backstage/config": "^0.1.11",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/theme": "^0.2.13",
"@backstage/core-plugin-api": "^0.3.0",
"@backstage/theme": "^0.2.14",
"@backstage/types": "^0.1.1",
"@backstage/version-bridge": "^0.1.0",
"@backstage/version-bridge": "^0.1.1",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@types/react": "*",
"@types/prop-types": "^15.7.3",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^17.2.4",
"zen-observable": "^0.8.15"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0",
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.9.1",
"@backstage/test-utils": "^0.1.23",
"@backstage/cli": "^0.10.1",
"@backstage/test-utils": "^0.1.24",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
@@ -0,0 +1,90 @@
/*
* Copyright 2020 The Backstage Authors
*
* 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 {
IdentityApi,
ProfileInfo,
BackstageUserIdentity,
} from '@backstage/core-plugin-api';
function mkError(thing: string) {
return new Error(
`Tried to access IdentityApi ${thing} before app was loaded`,
);
}
/**
* Implementation of the connection between the App-wide IdentityApi
* and sign-in page.
*/
export class AppIdentityProxy implements IdentityApi {
private target?: IdentityApi;
// This is called by the app manager once the sign-in page provides us with an implementation
setTarget(identityApi: IdentityApi) {
this.target = identityApi;
}
getUserId(): string {
if (!this.target) {
throw mkError('getUserId');
}
return this.target.getUserId();
}
getProfile(): ProfileInfo {
if (!this.target) {
throw mkError('getProfile');
}
return this.target.getProfile();
}
async getProfileInfo(): Promise<ProfileInfo> {
if (!this.target) {
throw mkError('getProfileInfo');
}
return this.target.getProfileInfo();
}
async getBackstageIdentity(): Promise<BackstageUserIdentity> {
if (!this.target) {
throw mkError('getBackstageIdentity');
}
return this.target.getBackstageIdentity();
}
async getCredentials(): Promise<{ token?: string | undefined }> {
if (!this.target) {
throw mkError('getCredentials');
}
return this.target.getCredentials();
}
async getIdToken(): Promise<string | undefined> {
if (!this.target) {
throw mkError('getIdToken');
}
return this.target.getIdToken();
}
async signOut(): Promise<void> {
if (!this.target) {
throw mkError('signOut');
}
await this.target.signOut();
location.reload();
}
}
@@ -30,12 +30,14 @@ const DEFAULT_PROVIDER = {
* @public
*/
export default class AtlassianAuth {
static create({
discoveryApi,
environment = 'development',
provider = DEFAULT_PROVIDER,
oauthRequestApi,
}: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T {
static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T {
const {
discoveryApi,
environment = 'development',
provider = DEFAULT_PROVIDER,
oauthRequestApi,
} = options;
return OAuth2.create({
discoveryApi,
oauthRequestApi,
@@ -30,13 +30,15 @@ const DEFAULT_PROVIDER = {
* @public
*/
export default class Auth0Auth {
static create({
discoveryApi,
environment = 'development',
provider = DEFAULT_PROVIDER,
oauthRequestApi,
defaultScopes = ['openid', `email`, `profile`],
}: OAuthApiCreateOptions): typeof auth0AuthApiRef.T {
static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T {
const {
discoveryApi,
environment = 'development',
provider = DEFAULT_PROVIDER,
oauthRequestApi,
defaultScopes = ['openid', `email`, `profile`],
} = options;
return OAuth2.create({
discoveryApi,
oauthRequestApi,

Some files were not shown because too many files have changed in this diff Show More