Merge branch 'backstage:master' into master
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-node': minor
|
||||
---
|
||||
|
||||
Deprecated the `LocationSpec` type. It got moved from this package to the `@backstage/plugin-catalog-common` so make sure imports are updated.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': minor
|
||||
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch
|
||||
---
|
||||
|
||||
Bitbucket Cloud provider: Add option to configure schedule via `app-config.yaml` instead of in code.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Added back support for when no branch is provided for the Bitbucket Server `UrlReader`
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
---
|
||||
|
||||
Added `curve` prop to the `DependencyGraph` component to select the type of layout
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Make the `/next` scaffolder work end to end with the old `TaskPage` view
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Added a new method `addLocationAnalyzers` to the `CatalogBuilder`. With this you can add location analyzers to your catalog. These analyzers will be used by the /analyze-location endpoint to decide if the provided URL contains any catalog-info.yaml files already or not.
|
||||
|
||||
Moved the following types from this package to `@backstage/plugin-catalog-backend`.
|
||||
|
||||
- AnalyzeLocationResponse
|
||||
- AnalyzeLocationRequest
|
||||
- AnalyzeLocationExistingEntity
|
||||
- AnalyzeLocationGenerateEntity
|
||||
- AnalyzeLocationEntityField
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-node': patch
|
||||
---
|
||||
|
||||
Ensure `getIdentity` throws an `AuthenticationError` instead of a `NotAllowed` error when authentication fails
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-bazaar': patch
|
||||
---
|
||||
|
||||
Added a `Overview Card` for either latest or random projects. Changed `ProjectPreview.tsx` so it take `gridSize` and `useTablePagination` as props.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
`GitHubEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code.
|
||||
|
||||
Please find how to configure the schedule at the config at
|
||||
https://backstage.io/docs/integrations/github/discovery
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-common': patch
|
||||
---
|
||||
|
||||
Moved the following types from `@backstage/plugin-catalog-backend` to this package.
|
||||
|
||||
- AnalyzeLocationResponse
|
||||
- AnalyzeLocationRequest
|
||||
- AnalyzeLocationExistingEntity
|
||||
- AnalyzeLocationGenerateEntity
|
||||
- AnalyzeLocationEntityField
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-bitbucket': patch
|
||||
---
|
||||
|
||||
Deprecate `@backstage/plugin-catalog-backend-module-bitbucket`.
|
||||
|
||||
Please migrate to `@backstage/plugin-catalog-backend-module-bitbucket-cloud`
|
||||
or `@backstage/plugin-catalog-backend-module-bitbucket-server` instead.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': minor
|
||||
---
|
||||
|
||||
**Breaking**
|
||||
Moved the code search for the existing catalog-info.yaml files to the backend from the frontend. It means it will use the configured GitHub integration's credentials.
|
||||
|
||||
Add the following to your `CatalogBuilder` to have the repo URL ingestion working again.
|
||||
|
||||
```ts
|
||||
// catalog.ts
|
||||
import { GitHubLocationAnalyzer } from '@backstage/plugin-catalog-backend-module-github';
|
||||
...
|
||||
builder.addLocationAnalyzers(
|
||||
new GitHubLocationAnalyzer({
|
||||
discovery: env.discovery,
|
||||
config: env.config,
|
||||
}),
|
||||
);
|
||||
...
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
'@backstage/plugin-sonarqube-backend': patch
|
||||
'@backstage/plugin-vault-backend': patch
|
||||
---
|
||||
|
||||
Normalize on winston version ^3.2.1
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Fix BitBucket server integration
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
'@backstage/plugin-permission-common': minor
|
||||
'@backstage/plugin-permission-node': minor
|
||||
---
|
||||
|
||||
**BREAKING**: When defining permission rules, it's now necessary to provide a [ZodSchema](https://github.com/colinhacks/zod) that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed.
|
||||
|
||||
To help with this, we have also made a change to the API of permission rules. Before, the permission rules `toQuery` and `apply` signature expected parameters to be separate arguments, like so...
|
||||
|
||||
```ts
|
||||
createPermissionRule({
|
||||
apply: (resource, foo, bar) => true,
|
||||
toQuery: (foo, bar) => {},
|
||||
});
|
||||
```
|
||||
|
||||
The API has now changed to expect the parameters as a single object
|
||||
|
||||
```ts
|
||||
createPermissionRule({
|
||||
paramSchema: z.object({
|
||||
foo: z.string().describe('Foo value to match'),
|
||||
bar: z.string().describe('Bar value to match'),
|
||||
}),
|
||||
apply: (resource, { foo, bar }) => true,
|
||||
toQuery: ({ foo, bar }) => {},
|
||||
});
|
||||
```
|
||||
|
||||
One final change made is to limit the possible values for a parameter to primitives and arrays of primitives.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings-backend': patch
|
||||
---
|
||||
|
||||
Use `Response.status` instead of `.send(number)`
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Update the `github:publish` action to allow passing whether pull
|
||||
requests must be up to date with the default branch before merging.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend': patch
|
||||
---
|
||||
|
||||
The Tech Insights plugin supports running fact retrievers across multiple instances. Update the README to remove the stale instructions.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Bump to `react-jsonschema-form@v5-beta` for the `NextRouter` under `@alpha` exports
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Added `GitHubLocationAnalyzer`. This can be used to add to the `CatalogBuilder`. When added this will be used by `RepoLocationAnalyzer` to figure out if the given URL that you are trying to import from the /catalog-import page already contains catalog-info.yaml files.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Use schedule from config at backend module.
|
||||
|
||||
Also, it removes `GithubEntityProviderCatalogModuleOptions`
|
||||
in favor of config-only for the backend module setup
|
||||
like at other similar modules.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Fixed a bug where the `allowed*` values for the `RepoUrlPicker` would be reset on render.
|
||||
+31
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"mode": "pre",
|
||||
"mode": "exit",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"example-app": "0.2.75",
|
||||
@@ -177,47 +177,68 @@
|
||||
},
|
||||
"changesets": [
|
||||
"blue-lions-greet",
|
||||
"brave-goats-rush",
|
||||
"brave-peaches-brush",
|
||||
"breezy-pots-worry",
|
||||
"bright-rules-shout",
|
||||
"brown-grapes-battle",
|
||||
"calm-moose-fetch",
|
||||
"calm-pianos-burn",
|
||||
"clean-camels-sneeze",
|
||||
"clever-ties-burn",
|
||||
"cuddly-bikes-tease",
|
||||
"cuddly-ways-fail",
|
||||
"curly-rats-itch",
|
||||
"curvy-kiwis-fold",
|
||||
"curvy-lemons-change",
|
||||
"curvy-pets-wash",
|
||||
"dry-shirts-attack",
|
||||
"dull-rocks-warn",
|
||||
"early-rocks-smell",
|
||||
"eleven-apples-accept",
|
||||
"fair-tools-melt",
|
||||
"fifty-berries-learn",
|
||||
"five-tables-grow",
|
||||
"fresh-donuts-arrive",
|
||||
"fuzzy-dolls-give",
|
||||
"fuzzy-dolls-shake",
|
||||
"giant-pianos-repeat",
|
||||
"great-numbers-reply",
|
||||
"grumpy-pans-knock",
|
||||
"hot-geese-vanish",
|
||||
"itchy-schools-run",
|
||||
"kind-bees-suffer",
|
||||
"kind-penguins-report",
|
||||
"large-dingos-juggle",
|
||||
"large-jars-fry",
|
||||
"lazy-beds-pull",
|
||||
"lazy-eyes-switch",
|
||||
"lazy-fireants-check",
|
||||
"little-hats-yell",
|
||||
"little-roses-rule",
|
||||
"loud-dots-sit",
|
||||
"lovely-peaches-fold",
|
||||
"lucky-beans-bathe",
|
||||
"lucky-cows-boil",
|
||||
"mean-spiders-design",
|
||||
"mighty-lions-march",
|
||||
"moody-carrots-shout",
|
||||
"odd-pandas-suffer",
|
||||
"odd-singers-taste",
|
||||
"old-cobras-suffer",
|
||||
"old-melons-bathe",
|
||||
"old-needles-brake",
|
||||
"perfect-moose-drum",
|
||||
"plenty-kids-fetch",
|
||||
"plenty-laws-end",
|
||||
"poor-clouds-ring",
|
||||
"pretty-buttons-develop",
|
||||
"purple-masks-travel",
|
||||
"quick-meals-talk",
|
||||
"quiet-dancers-jog",
|
||||
"quiet-hats-kick",
|
||||
"quiet-ligers-draw",
|
||||
"rare-cougars-cross",
|
||||
"rare-hotels-cough",
|
||||
"red-dots-sleep",
|
||||
"red-pants-rush",
|
||||
@@ -225,6 +246,7 @@
|
||||
"renovate-a02d90b",
|
||||
"rich-carrots-reflect",
|
||||
"rude-bulldogs-sleep",
|
||||
"rude-tomatoes-behave",
|
||||
"search-bobcats-love",
|
||||
"search-cars-hide",
|
||||
"search-clouds-begin",
|
||||
@@ -232,10 +254,13 @@
|
||||
"search-dull-planes-prove",
|
||||
"search-rats-grin",
|
||||
"selfish-turkeys-exist",
|
||||
"seven-panthers-chew",
|
||||
"shaggy-books-smell",
|
||||
"short-plants-return",
|
||||
"silent-bees-repeat",
|
||||
"silly-rules-join",
|
||||
"sixty-items-nail",
|
||||
"slimy-suns-learn",
|
||||
"slow-mirrors-eat",
|
||||
"smooth-tables-pull",
|
||||
"soft-falcons-love",
|
||||
@@ -243,16 +268,20 @@
|
||||
"sweet-insects-camp",
|
||||
"swift-phones-cheat",
|
||||
"tall-baboons-deliver",
|
||||
"techdocs-olive-worms-yell",
|
||||
"tender-drinks-drive",
|
||||
"tender-parrots-peel",
|
||||
"thick-kings-destroy",
|
||||
"tiny-mails-bathe",
|
||||
"tough-hairs-sparkle",
|
||||
"tough-seahorses-learn",
|
||||
"twelve-melons-notice",
|
||||
"unlucky-seas-sip",
|
||||
"warm-days-watch",
|
||||
"wild-weeks-live",
|
||||
"wise-ligers-scream",
|
||||
"yellow-lemons-march",
|
||||
"young-bugs-remember"
|
||||
"young-bugs-remember",
|
||||
"young-olives-cheer"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Fixed layout for core-components docs where table was broken by splitting with code sample
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Add missing config schema for the `GitHubEntityProvider`.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
'@backstage/plugin-playlist-backend': minor
|
||||
---
|
||||
|
||||
**BREAKING** The exported permission rules have changed to reflect the breaking changes made to the PermissionRule type.
|
||||
|
||||
For example, the `playlistConditions.isOwner` API has changed from:
|
||||
|
||||
```ts
|
||||
playlistConditions.isOwner(['user:default/me', 'group:default/owner']);
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```ts
|
||||
playlistConditions.isOwner({
|
||||
owners: ['user:default/me', 'group:default/owner'],
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/cli': patch
|
||||
'@backstage/plugin-airbrake-backend': patch
|
||||
'@backstage/plugin-badges-backend': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-graphql-backend': patch
|
||||
'@backstage/plugin-periskop-backend': patch
|
||||
'@backstage/plugin-permission-backend': patch
|
||||
'@backstage/plugin-rollbar-backend': patch
|
||||
'@backstage/plugin-search-backend': patch
|
||||
'@backstage/plugin-tech-insights-backend': patch
|
||||
'@backstage/plugin-user-settings-backend': patch
|
||||
---
|
||||
|
||||
Use `response.json` rather than `response.send` where appropriate, as outlined in `SECURITY.md`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-bazaar-backend': patch
|
||||
---
|
||||
|
||||
Router now also has endpoint `getLatestProjects` that takes a limit of projects as prop.
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
'@backstage/plugin-search-react': minor
|
||||
---
|
||||
|
||||
A `<SearchPagination />` component was created for limiting the number of results shown per search page. Use this new component to give users options to select how many search results they want to display per page. The default options are 10, 25, 50, 100.
|
||||
|
||||
See examples below:
|
||||
|
||||
_Basic_
|
||||
|
||||
```jsx
|
||||
import React, { useState } from 'react';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { Page, Header, Content, Lifecycle } from '@backstage/core-components';
|
||||
import {
|
||||
SearchBarBase,
|
||||
SearchPaginationBase,
|
||||
SearchResultList,
|
||||
} from '@backstage/plugin-search-react';
|
||||
|
||||
const SearchPage = () => {
|
||||
const [term, setTerm] = useState('');
|
||||
const [pageLimit, setPageLimit] = useState(25);
|
||||
const [pageCursor, setPageCursor] = useState<string>();
|
||||
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header title="Search" subtitle={<Lifecycle alpha />} />
|
||||
<Content>
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={12}>
|
||||
<SearchBarBase value={term} onChange={setTerm} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SearchPaginationBase
|
||||
limit={pageLimit}
|
||||
onLimitChange={setPageLimit}
|
||||
cursor={pageCursor}
|
||||
onCursorChange={setPageCursor}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SearchResultList query={{ term, pageLimit }} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
_With context_
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { Page, Header, Content, Lifecycle } from '@backstage/core-components';
|
||||
import {
|
||||
SearchBar,
|
||||
SearchResult,
|
||||
SearchPagination,
|
||||
SearchResultListLayout,
|
||||
SearchContextProvider,
|
||||
DefaultResultListItem,
|
||||
} from '@backstage/plugin-search-react';
|
||||
|
||||
const SearchPage = () => (
|
||||
<SearchContextProvider>
|
||||
<Page themeId="home">
|
||||
<Header title="Search" subtitle={<Lifecycle alpha />} />
|
||||
<Content>
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={12}>
|
||||
<SearchBar />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SearchPagination />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<SearchResultListLayout
|
||||
resultItems={results}
|
||||
renderResultItem={({ document }) => (
|
||||
<DefaultResultListItem
|
||||
key={document.location}
|
||||
result={document}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</SearchResult>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
</SearchContextProvider>
|
||||
);
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/plugin-adr-backend': patch
|
||||
'@backstage/plugin-search-backend-module-elasticsearch': patch
|
||||
'@backstage/plugin-search-backend-node': patch
|
||||
'@backstage/plugin-stack-overflow-backend': patch
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
---
|
||||
|
||||
In order to improve the debuggability of the search indexing process, messages logged during indexing are now tagged with a `documentType` whose value corresponds to the `type` being indexed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
The exported permission rules and the API of `createCatalogConditionalDecision` have changed to reflect the breaking changes made to the `PermissionRule` type. Note that all involved types are exported from `@backstage/plugin-catalog-backend/alpha`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Leverage cache mounts in Dockerfile during `yarn install ...` and `apt-get ...` commands to speed up repeated builds.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Add the new search pagination component to the search page template.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Fixed setting default branch for Bitbucket Server
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-backend': minor
|
||||
---
|
||||
|
||||
Add optional `catalogClient` argument to `createRoute` parameters
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Added optional `sourcePath` parameter to `publish:gitlab:merge-request` action, `targetPath` is now optional and falls back to current workspace path.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-github-issues': patch
|
||||
---
|
||||
|
||||
Add filtering and ordering to the graphql query
|
||||
@@ -2,6 +2,7 @@ abc
|
||||
accessors
|
||||
addon
|
||||
addons
|
||||
ADRs
|
||||
Airbrake
|
||||
Airbrakes
|
||||
airbrake
|
||||
@@ -28,6 +29,7 @@ bool
|
||||
boolean
|
||||
builtins
|
||||
callout
|
||||
CDNs
|
||||
Chai
|
||||
changeset
|
||||
changesets
|
||||
@@ -68,6 +70,7 @@ dataflow
|
||||
dayjs
|
||||
debounce
|
||||
Debounce
|
||||
debuggability
|
||||
declaratively
|
||||
deduplicated
|
||||
deps
|
||||
@@ -129,6 +132,7 @@ hotspots
|
||||
http
|
||||
https
|
||||
Iain
|
||||
iLert
|
||||
img
|
||||
incentivised
|
||||
Indal
|
||||
@@ -139,6 +143,7 @@ JaCoCo
|
||||
JavaScript
|
||||
jenkins
|
||||
Jira
|
||||
JWTs
|
||||
jq
|
||||
js
|
||||
json
|
||||
@@ -147,6 +152,7 @@ jsx
|
||||
Kaewkasi
|
||||
Keyv
|
||||
Knex
|
||||
KPIs
|
||||
kubectl
|
||||
kubernetes
|
||||
kubernetes
|
||||
@@ -308,6 +314,7 @@ Superfences
|
||||
superset
|
||||
supertype
|
||||
storable
|
||||
SVGs
|
||||
talkdesk
|
||||
Talkdesk
|
||||
tasklist
|
||||
@@ -352,12 +359,15 @@ utils
|
||||
validator
|
||||
validators
|
||||
varchar
|
||||
VPCs
|
||||
VSCode
|
||||
Wayfair
|
||||
Weaveworks
|
||||
Webpack
|
||||
winston
|
||||
www
|
||||
WWW
|
||||
XCMetrics
|
||||
XML
|
||||
xyz
|
||||
yaml
|
||||
|
||||
@@ -13,6 +13,9 @@ jobs:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ jobs:
|
||||
--remote-repo-url=https://github.com/backstage/backstage
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
# Above we run the `monitor` command, this runs the `test` command which is
|
||||
# the one that generates the SARIF report that we can upload to GitHub.
|
||||
@@ -44,6 +45,7 @@ jobs:
|
||||
--sarif-file-output=snyk.sarif
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
- name: Upload Snyk report
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
# Adopters
|
||||
|
||||
_If you're using Backstage in your organization, please try to add your company name to this list. It really helps the project to gain momentum and credibility. It's a small contribution back to the project with a big impact._
|
||||
_You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKikB) or by editing this file after following the [CONTRIBUTING.md](./CONTRIBUTING.md)._
|
||||
_You can do this by using the [Adopter form](https://info.backstage.spotify.com/public-adopter-hand-raiser-form) or by editing this file after following the [CONTRIBUTING.md](./CONTRIBUTING.md)._
|
||||
|
||||
| Organization | Contact | Description of Use |
|
||||
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -22,7 +22,7 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
|
||||
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
|
||||
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
|
||||
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com), [@ajbw](https://github.com/ajbw) | EG Common Developer Toolkit |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [@gman0922](https://github.com/gman0922), [Sheena Sharma](mailto:shesharma@expediagroup.com), [Alekhya Karuturi](mailto:akaruturi@expediagroup.com) | EG Developer Front Door |
|
||||
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
|
||||
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
|
||||
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
|
||||
@@ -214,3 +214,4 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
|
||||
| [Vipps](https://vipps.no) | [Martin Ehrnst](https://github.com/ehrnst) | Vipps use backstage for our service catalog, documentation, and developer portal. Using templates we are able to simplify the developer experience when deploying new services to our platform. |
|
||||
| [Ferrovial](https://ferrovial.com) | [Jose Luis Rosado](mailto:jlrosado@ferrovial.com) | Backstage is helping us to improve and acelerate dev experience helping teams to quickly find technical documentation, infrastructure templates, pipelines, software components and quickstarters that have been developed by our squads in a inner source friendly environment. |
|
||||
| [Inter&Co](https://bancointer.com.br) | [Arnaud Lanna](https://github.com/arnaudlanna), [Adriano Silva](https://github.com/adrianovss), [Bruno Grossi](https://github.com/begrossi) | We're using Backstage as our internal Developer Portal to catalog and collect repositories and microservices pieces of information like ownership, deployment time, and documentation. |
|
||||
| [StatusNeo](https://statusneo.com/) | [Karan Nangru](mailto:nangru@statusneo.com), [@NishkarshRaj](https://github.com/NishkarshRaj), and [Gaurav Sarien](mailto:gaurav.sarien@statusneo.com) | Harnessing the power of central catalog inventory and self-serving software templates |
|
||||
|
||||
@@ -12,7 +12,7 @@ Using Cookiecutter extensions is a two-step process:
|
||||
This step depends on how the scaffolder is setup to use Cookiecutter:
|
||||
|
||||
- Using a local Cookiecutter, or
|
||||
- Using a Cookiecutter Docker image, e.g. [spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/37e35b91/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile).
|
||||
- Using a Cookiecutter Docker image, e.g. [spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile).
|
||||
|
||||
Say we want to install [`jinja2_custom_filters_extension`](https://pypi.org/project/jinja2-custom-filters-extension/) to use the `upper_case_first_letter` filter in a Cookiecutter template.
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,259 @@
|
||||
---
|
||||
id: oidc
|
||||
title: OIDC provider from scratch
|
||||
description: This section shows how to use an OIDC provider from scratch, same steps apply for custom providers.
|
||||
---
|
||||
|
||||
This section shows how to use an OIDC provider from scratch, same steps apply for custom
|
||||
providers. Please note these steps are for using a provider, not how to implement one,
|
||||
and Backstage recommends creating custom providers specific to the IDP, so we'll use a
|
||||
`azureOIDC` provider throughout this example, feel free to change any of those refs
|
||||
to your provider name.
|
||||
|
||||
## Summary
|
||||
|
||||
To add providers not enabled by default like OIDC, we need to follow some steps, we
|
||||
assume you already have a sign in page to which we'll add the provider so users can
|
||||
sign in through the provider. In simple steps here's how you enable the provider:
|
||||
|
||||
- Create an API reference to identify the provider.
|
||||
- Create the API factory that will handle the authentication.
|
||||
- Add or reuse an auth provider so you can authenticate.
|
||||
- Add or reuse a resolver to handle the result from the authentication.
|
||||
- Configure the provider to access your 3rd party auth solution.
|
||||
- Add the provider to sign in page so users can login with it.
|
||||
|
||||
We'll explain each step more in detail next.
|
||||
|
||||
### The API reference
|
||||
|
||||
An API reference exist for the sake of **Dependency Injection**, check [Utility APIs][4]
|
||||
for extended explanation.
|
||||
|
||||
In this OIDC example, we'll create the API reference directly in the
|
||||
`packages/app/src/apis.ts` file, it is not a requirement to put the reference in this
|
||||
file. Any location will do as long as it's available to be imported to where the API
|
||||
factory is, as well as easily accessible to the rest of the application so any package
|
||||
and plugin can inject the API instance when necessary.
|
||||
|
||||
An example of such would be when you use an auth provider from a library installed with
|
||||
NPM, or any other library repository, you would import the API ref from the library.
|
||||
|
||||
```ts
|
||||
export const azureOIDCAuthApiRef: ApiRef<
|
||||
OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
> = createApiRef({
|
||||
id: 'auth.my-custom-provider',
|
||||
});
|
||||
```
|
||||
|
||||
Please note a few things, the ID can be anything you want as long as it doesn't conflict
|
||||
with other refs, backstage recommends to use a custom name that references your custom
|
||||
provider, for example we are using OIDC protocol with Azure, so we could use something
|
||||
like `auth.azure.oidc` as well.
|
||||
|
||||
Also we're exporting this reference, as well as the `typings`, we need to
|
||||
be able to import this reference anywhere in the app, and the `typings` will tell typescript
|
||||
what instance we're getting from DI when injecting the API. In this case we are defining
|
||||
an API for authentication, so we tell TS that this instance complies with 4 API
|
||||
interfaces:
|
||||
|
||||
- The OICD API that will handle authentication.
|
||||
- Profile API for requesting user profile info from the auth provider in question.
|
||||
- Backstage identity API to handle and associate the user profile with backstage identity.
|
||||
- Session API, to handle the session the user will have while logged in.
|
||||
|
||||
### The API Factory
|
||||
|
||||
A factory is a function that can take some parameters or dependencies and return an
|
||||
instance of something, in our case it will be a function that requests some backstage
|
||||
APIs and use them to create an instance of an OIDC API provider.
|
||||
|
||||
Please note that this function only runs (creates the instance) when somewhere else in
|
||||
the app you request the DI to give you an instance of the OIDC provider using the API ref
|
||||
defined above, and the DI will only run this function the first time, from then on any
|
||||
other DI injection will just receive the same instance created the first time, basically
|
||||
the instance is cached by the DI library, a singleton.
|
||||
|
||||
Let's add our OIDC API factory to the APIs array in the `packages/app/src/apis.ts` file:
|
||||
|
||||
```diff
|
||||
+ import { OAuth2 } from '@backstage/core-app-api';
|
||||
|
||||
export const apis: AnyApiFactory[] = [
|
||||
+ createApiFactory({
|
||||
+ api: azureOIDCAuthApiRef,
|
||||
+ deps: {
|
||||
+ discoveryApi: discoveryApiRef,
|
||||
+ oauthRequestApi: oauthRequestApiRef,
|
||||
+ configApi: configApiRef,
|
||||
+ },
|
||||
+ factory: ({ discoveryApi, oauthRequestApi, configApi }) =>
|
||||
+ OAuth2.create({
|
||||
+ discoveryApi,
|
||||
+ oauthRequestApi,
|
||||
+ provider: {
|
||||
+ id: 'my-auth-provider',
|
||||
+ title: 'My custom auth provider',
|
||||
+ icon: () => null,
|
||||
+ },
|
||||
+ environment: configApi.getOptionalString('auth.environment'),
|
||||
+ defaultScopes: [
|
||||
+ 'openid',
|
||||
+ 'profile',
|
||||
+ 'email',
|
||||
+ ],
|
||||
+ }),
|
||||
+ }),
|
||||
|
||||
```
|
||||
|
||||
Please note we're importing the `OAuth2` class from `@backstage/core-app-api` effectively
|
||||
delegating the authentication to it. Also we're using the `my-auth-provider` ID to tell
|
||||
`OAuth2` to use the auth provider we'll define in the next section, and added the default
|
||||
scopes to request ID, profile, email and user read permissions.
|
||||
|
||||
## The Auth Provider
|
||||
|
||||
The Auth Provider is responsible for authenticating with the 3rd party service, and give
|
||||
us back the credentials, here's where you pick which protocol to use, be it Auth0, OAuth2,
|
||||
OIDC, SAML or any other that your 3rd party IDP provider supports.
|
||||
|
||||
For this example we'll use OIDC, we pass a factory to the `providerFactories` object with
|
||||
the ID you picked to represent the Auth provider, this ID has to match with the provider's
|
||||
`id` inside the API factory, the yaml config provider key under `auth.providers`, and the
|
||||
callback URI provider segment (you'll have to configure your IDP to handle the callback
|
||||
URI properly).
|
||||
|
||||
```diff
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
return await createRouter({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
providerFactories: {
|
||||
...defaultAuthProviderFactories,
|
||||
+ 'my-auth-provider': providers.oidc.create({
|
||||
+ }),
|
||||
}
|
||||
```
|
||||
|
||||
### The Resolver
|
||||
|
||||
Resolvers exist to map user identity from the 3rd party (in this case an azure IDP
|
||||
provider) to the backstage user identity, for a detailed explanation check the
|
||||
[Identity Resolver][1] page, it explains how to write a custom resolver as well as
|
||||
linking the built in resolvers of backstage.
|
||||
|
||||
The default OIDC provider does not support SignIn, we need to add such support by
|
||||
adding a resolver for a SignIn request.
|
||||
|
||||
The OIDC provider doesn't provide any build-in resolvers, so we'll need to define our own:
|
||||
|
||||
```diff
|
||||
import {
|
||||
DEFAULT_NAMESPACE,
|
||||
+ stringifyEntityRef,
|
||||
} from '@backstage/catalog-model';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
return await createRouter({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
providerFactories: {
|
||||
...defaultAuthProviderFactories,
|
||||
'my-auth-provider': providers.oidc.create({
|
||||
+ signIn: {
|
||||
+ resolver(info, ctx) {
|
||||
+ const userRef = stringifyEntityRef({
|
||||
+ kind: 'User',
|
||||
+ name: info.result.userinfo.sub,
|
||||
+ namespace: DEFAULT_NAMESPACE,
|
||||
+ });
|
||||
+ return ctx.issueToken({
|
||||
+ claims: {
|
||||
+ sub: userRef, // The user's own identity
|
||||
+ ent: [userRef], // A list of identities that the user claims ownership through
|
||||
+ },
|
||||
+ });
|
||||
+ },
|
||||
+ },
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
### The configuration
|
||||
|
||||
Since we are using our custom OIDC Auth Provider, we need to add a configuration based
|
||||
on the provider used, in this case based on OIDC protocol (remember the 3rd party has to
|
||||
support the protocol).
|
||||
|
||||
In this example we'll configure OIDC with `my-auth-provider`, to do so we need to
|
||||
[Create app registration][2] in the Azure console, the only difference is that the
|
||||
`http://localhost:7007/api/auth/microsoft/handler/frame` URL needs to change to
|
||||
`http://localhost:7007/api/auth/my-auth-provider/handler/frame`.
|
||||
|
||||
Then we need to configure the env variables for the provider, based on the provider's code
|
||||
in `plugins/auth-backend/src/providers/oidc/provider.ts` we need the following variables
|
||||
in the `app-config.yaml`:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
environment: development
|
||||
### Providing an auth.session.secret will enable session support in the auth-backend
|
||||
session:
|
||||
secret: ${SESSION_SECRET}
|
||||
providers:
|
||||
my-auth-provider:
|
||||
development:
|
||||
metadataUrl: https://example.com/.well-known/openid-configuration
|
||||
clientId: ${AUTH_MY_CLIENT_ID}
|
||||
clientSecret: ${AUTH_MY_CLIENT_SECRET}
|
||||
```
|
||||
|
||||
Anything enclosed in `${}` can be replaced directly in the yaml, or provided as
|
||||
environment variables, the way you obtain all these except `scope` and `prompt` is to
|
||||
check the App Registration you created:
|
||||
|
||||
- `clientId`: Grab from the Overview page.
|
||||
- `clientSecret`: Can only be seen when creating the secret, if you lose it you'll need a
|
||||
new secret.
|
||||
- `metadataUrl`: In Overview > Endpoints tab, grab OpenID Connect metadata document URL.
|
||||
- `authorizationUrl` and `tokenUrl`: Open the `metadataUrl` in a browser, that json will
|
||||
hold these 2 urls somewhere in there.
|
||||
- `tokenSignedResponseAlg`: Don't define it, use the default unless you know what it does.
|
||||
- `scope`: Only used if we didn't specify `defaultScopes` in the provider's factory,
|
||||
basically the same thing.
|
||||
- `prompt`: Recommended to use `auto` so the browser will request login to the IDP if the
|
||||
user has no active session.
|
||||
|
||||
Note that for the time being, any change in this yaml file requires a restart of the app,
|
||||
also you need to have the `session.secret` part to use OIDC (some other providers might
|
||||
need this as well) to support user sessions.
|
||||
|
||||
### The Sign In provider
|
||||
|
||||
The last step is to add the provider to the `SignInPage` so users can sign in with your
|
||||
new provider, please follow the [Sing In Configuration][3] docs, here's where you import
|
||||
and use the API ref we defined earlier.
|
||||
|
||||
## Note
|
||||
|
||||
These steps apply to most if not all the providers, including custom providers, the main
|
||||
difference between different providers will be the contents of the API factory, the code
|
||||
in the Auth Provider Factory, the resolver, and the different variables each provider
|
||||
needs in the YAML config or env variables.
|
||||
|
||||
[1]: https://backstage.io/docs/auth/identity-resolver
|
||||
[2]: https://backstage.io/docs/auth/microsoft/provider#create-an-app-registration-on-azure
|
||||
[3]: https://backstage.io/docs/auth/#sign-in-configuration
|
||||
[4]: https://backstage.io/docs/api/utility-apis
|
||||
@@ -23,6 +23,17 @@ Each package is searched for a schema at a single point of entry, a top-level
|
||||
inlined JSON schema, or a relative path to a schema file. Supported schema file
|
||||
formats are `.json` or `.d.ts`.
|
||||
|
||||
```jsonc title="package.json"
|
||||
{
|
||||
// ...
|
||||
"files": [
|
||||
// ...
|
||||
"config.d.ts"
|
||||
],
|
||||
"configSchema": "config.d.ts"
|
||||
}
|
||||
```
|
||||
|
||||
> When defining a schema file, be sure to include the file in your
|
||||
> `package.json` > `"files"` field as well!
|
||||
|
||||
|
||||
+33
-19
@@ -61,9 +61,10 @@ FROM node:16-bullseye-slim
|
||||
|
||||
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
|
||||
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
|
||||
RUN apt-get update && \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
yarn config set python /usr/bin/python3
|
||||
|
||||
# From here on we use the least-privileged `node` user to run the backend.
|
||||
@@ -79,7 +80,8 @@ ENV NODE_ENV production
|
||||
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
|
||||
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
|
||||
|
||||
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
|
||||
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
|
||||
yarn install --frozen-lockfile --production --network-timeout 300000
|
||||
|
||||
# Then copy the rest of the backend bundle, along with any other files we might want.
|
||||
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
|
||||
@@ -163,53 +165,64 @@ RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf {
|
||||
# Stage 2 - Install dependencies and build packages
|
||||
FROM node:16-bullseye-slim AS build
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=packages /app .
|
||||
|
||||
# install sqlite3 dependencies
|
||||
RUN apt-get update && \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
|
||||
yarn config set python /usr/bin/python3
|
||||
|
||||
RUN yarn install --frozen-lockfile --network-timeout 600000 && rm -rf "$(yarn cache dir)"
|
||||
USER node
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
COPY --from=packages --chown=node:node /app .
|
||||
|
||||
# Stop cypress from downloading it's massive binary.
|
||||
ENV CYPRESS_INSTALL_BINARY=0
|
||||
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
|
||||
yarn install --frozen-lockfile --network-timeout 600000
|
||||
|
||||
COPY --chown=node:node . .
|
||||
|
||||
RUN yarn tsc
|
||||
RUN yarn --cwd packages/backend build
|
||||
# If you have not yet migrated to package roles, use the following command instead:
|
||||
# RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies
|
||||
|
||||
RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \
|
||||
&& tar xzf packages/backend/dist/skeleton.tar.gz -C packages/backend/dist/skeleton \
|
||||
&& tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle
|
||||
|
||||
# Stage 3 - Build the actual backend image and install production dependencies
|
||||
FROM node:16-bullseye-slim
|
||||
|
||||
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
|
||||
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
|
||||
RUN apt-get update && \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
yarn config set python /usr/bin/python3
|
||||
|
||||
# From here on we use the least-privileged `node` user to run the backend.
|
||||
USER node
|
||||
WORKDIR /app
|
||||
|
||||
# This switches many Node.js dependencies to production mode.
|
||||
ENV NODE_ENV production
|
||||
|
||||
# Copy the install dependencies from the build stage and context
|
||||
COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton.tar.gz ./
|
||||
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
|
||||
COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./
|
||||
|
||||
RUN yarn install --frozen-lockfile --production --network-timeout 600000 && rm -rf "$(yarn cache dir)"
|
||||
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
|
||||
yarn install --frozen-lockfile --production --network-timeout 600000
|
||||
|
||||
# Copy the built packages from the build stage
|
||||
COPY --from=build --chown=node:node /app/packages/backend/dist/bundle.tar.gz .
|
||||
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
|
||||
COPY --from=build --chown=node:node /app/packages/backend/dist/bundle/ ./
|
||||
|
||||
# Copy any other files that we need at runtime
|
||||
COPY --chown=node:node app-config.yaml ./
|
||||
|
||||
# This switches many Node.js dependencies to production mode.
|
||||
ENV NODE_ENV production
|
||||
|
||||
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
|
||||
```
|
||||
|
||||
@@ -225,6 +238,7 @@ however ignore any existing build output or dependencies on the host. For our
|
||||
new `.dockerignore`, replace the contents of your existing one with this:
|
||||
|
||||
```text
|
||||
dist-types
|
||||
node_modules
|
||||
packages/*/dist
|
||||
packages/*/node_modules
|
||||
|
||||
@@ -62,7 +62,7 @@ This is an array used to determine where to retrieve cluster configuration from.
|
||||
Valid cluster locator methods are:
|
||||
|
||||
- [`catalog`](#catalog)
|
||||
- [`localKubectlProxy`](#localKubectlProxy)
|
||||
- [`localKubectlProxy`](#localkubectlproxy)
|
||||
- [`config`](#config)
|
||||
- [`gke`](#gke)
|
||||
- [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier)
|
||||
|
||||
@@ -110,7 +110,7 @@ metadata:
|
||||
backstage.io/edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet
|
||||
```
|
||||
|
||||
These annotations allow customising links from the catalog pages. The view URL
|
||||
These annotations allow customizing links from the catalog pages. The view URL
|
||||
should point to the canonical metadata YAML that governs this entity. The edit
|
||||
URL should point to the source file for the metadata. In the example above,
|
||||
`my-org` generates its catalog data from Jsonnet files in a monorepo, so the
|
||||
@@ -159,11 +159,11 @@ metadata:
|
||||
github.com/project-slug: backstage/backstage
|
||||
```
|
||||
|
||||
The value of this annotation is the so-called slug that identifies a project on
|
||||
The value of this annotation is the so-called slug that identifies a repository on
|
||||
[GitHub](https://github.com) (either the public one, or a private GitHub
|
||||
Enterprise installation) that is related to this entity. It is on the format
|
||||
`<organization>/<project>`, and is the same as can be seen in the URL location
|
||||
bar of the browser when viewing that project.
|
||||
`<organization or owner>/<repository>`, and is the same as can be seen in the URL location
|
||||
bar of the browser when viewing that repository.
|
||||
|
||||
Specifying this annotation will enable GitHub related features in Backstage for
|
||||
that entity.
|
||||
|
||||
@@ -123,7 +123,7 @@ will set the available actions that the scaffolder has access to.
|
||||
```ts
|
||||
import { createBuiltinActions } from '@backstage/plugin-scaffolder-backend';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { createNewFileAction } from './actions/custom';
|
||||
import { createNewFileAction } from './scaffolder/actions/custom';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
|
||||
@@ -51,14 +51,10 @@ create a subdirectory inside your current working directory.
|
||||
npx @backstage/create-app
|
||||
```
|
||||
|
||||
The wizard will ask you
|
||||
|
||||
- The name of the app, which will also be the name of the directory
|
||||
- The database type to use for the backend. For this guide, you'll be using the
|
||||
SQLite option.
|
||||
The wizard will ask you for the name of the app, which will also be the name of the directory
|
||||
|
||||
<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.' />
|
||||
</p>
|
||||
|
||||
### Run the Backstage app
|
||||
|
||||
@@ -12,7 +12,7 @@ The GitHub integration has a discovery provider for discovering catalog
|
||||
entities within a GitHub organization. The provider will crawl the GitHub
|
||||
organization and register entities matching the configured path. This can be
|
||||
useful as an alternative to static locations or manually adding things to the
|
||||
catalog. This is the prefered method for ingesting entities into the catalog.
|
||||
catalog. This is the preferred method for ingesting entities into the catalog.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -39,10 +39,13 @@ And then add the entity provider to your catalog builder:
|
||||
+ builder.addEntityProvider(
|
||||
+ GitHubEntityProvider.fromConfig(env.config, {
|
||||
+ logger: env.logger,
|
||||
+ // optional: alternatively, use scheduler with schedule defined in app-config.yaml
|
||||
+ schedule: env.scheduler.createScheduledTaskRunner({
|
||||
+ frequency: { minutes: 30 },
|
||||
+ timeout: { minutes: 3 },
|
||||
+ }),
|
||||
+ // optional: alternatively, use schedule
|
||||
+ scheduler: env.scheduler,
|
||||
+ }),
|
||||
+ );
|
||||
|
||||
@@ -55,7 +58,7 @@ And then add the entity provider to your catalog builder:
|
||||
To use the discovery provider, you'll need a GitHub integration
|
||||
[set up](locations.md) with either a [Personal Access Token](../../getting-started/configuration.md#setting-up-a-github-integration) or [GitHub Apps](./github-apps.md).
|
||||
|
||||
Then you can add a github config to the catalog providers configuration:
|
||||
Then you can add a `github` config to the catalog providers configuration:
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
@@ -68,6 +71,11 @@ catalog:
|
||||
filters:
|
||||
branch: 'main' # string
|
||||
repository: '.*' # Regex
|
||||
schedule: # optional; same options as in TaskScheduleDefinition
|
||||
# supports cron, ISO duration, "human duration" as used in code
|
||||
frequency: { minutes: 30 }
|
||||
# supports ISO duration, "human duration" as used in code
|
||||
timeout: { minutes: 3 }
|
||||
customProviderId:
|
||||
organization: 'new-org' # string
|
||||
catalogPath: '/custom/path/catalog-info.yaml' # string
|
||||
@@ -111,26 +119,35 @@ This provider supports multiple organizations via unique provider IDs.
|
||||
Default: `/catalog-info.yaml`.
|
||||
Path where to look for `catalog-info.yaml` files.
|
||||
You can use wildcards - `*` or `**` - to search the path and/or the filename
|
||||
- **filters** _(optional)_:
|
||||
- **branch** _(optional)_:
|
||||
- **`filters`** _(optional)_:
|
||||
- **`branch`** _(optional)_:
|
||||
String used to filter results based on the branch name.
|
||||
- **repository** _(optional)_:
|
||||
- **`repository`** _(optional)_:
|
||||
Regular expression used to filter results based on the repository name.
|
||||
- **topic** _(optional)_:
|
||||
- **`topic`** _(optional)_:
|
||||
Both of the filters below may be used at the same time but the exclusion filter has the highest priority.
|
||||
In the example above, a repository with the `backstage-include` topic would still be excluded
|
||||
if it were also carrying the `experiments` topic.
|
||||
- **include** _(optional)_:
|
||||
An array of strings used to filter in results based on their associated Github topics.
|
||||
- **`include`** _(optional)_:
|
||||
An array of strings used to filter in results based on their associated GitHub topics.
|
||||
If configured, only repositories with one (or more) topic(s) present in the inclusion filter will be ingested
|
||||
- **exclude** _(optional)_:
|
||||
An array of strings used to filter out results based on their associated Github topics.
|
||||
- **`exclude`** _(optional)_:
|
||||
An array of strings used to filter out results based on their associated GitHub topics.
|
||||
If configured, all repositories _except_ those with one (or more) topics(s) present in the exclusion filter will be ingested.
|
||||
- **organization**:
|
||||
- **`host`** _(optional)_:
|
||||
The hostname of your GitHub Enterprise instance. It must match a host defined in [integrations.github](locations.md).
|
||||
- **`organization`**:
|
||||
Name of your organization account/workspace.
|
||||
If you want to add multiple organizations, you need to add one provider config each.
|
||||
- **host** _(optional)_:
|
||||
The hostname of your GitHub Enterprise instance. It must match a host defined in [integrations.github](locations.md).
|
||||
- **`schedule`** _(optional)_:
|
||||
- **`frequency`**:
|
||||
How often you want the task to run. The system does its best to avoid overlapping invocations.
|
||||
- **`timeout`**:
|
||||
The maximum amount of time that a single task invocation can take.
|
||||
- **`initialDelay`** _(optional)_:
|
||||
The amount of time that should pass before the first invocation happens.
|
||||
- **`scope`** _(optional)_:
|
||||
`'global'` or `'local'`. Sets the scope of concurrency control.
|
||||
|
||||
## GitHub API Rate Limits
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export const isInSystemRule = createCatalogPermissionRule({
|
||||
},
|
||||
toQuery: (systemRef: string) => ({
|
||||
key: 'relations.partOf',
|
||||
value: systemRef,
|
||||
values: [systemRef],
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ router.use('/summary', async (req, res) => {
|
||||
]).then(async ([frobs, flerps, thunk]) => {
|
||||
return computeAggregate(await frobs.json(), await flerps.json(), thunk);
|
||||
});
|
||||
res.status(200).send(agg);
|
||||
res.status(200).json(agg);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -72,6 +72,12 @@ backend:
|
||||
+ port: ${POSTGRES_PORT}
|
||||
+ user: ${POSTGRES_USER}
|
||||
+ password: ${POSTGRES_PASSWORD}
|
||||
+ # https://node-postgres.com/features/ssl
|
||||
+ # you can set the sslmode configuration option via the `PGSSLMODE` environment variable
|
||||
+ # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
||||
+ # ssl:
|
||||
+ # ca: # if you have a CA file and want to verify it you can uncomment this section
|
||||
+ # $file: <file-path>/ca/server.crt
|
||||
+ # Refer to Tarn docs for default values on PostgreSQL pool configuration - https://github.com/Vincit/tarn.js
|
||||
+ knexConfig:
|
||||
+ pool:
|
||||
@@ -79,12 +85,6 @@ backend:
|
||||
+ max: 12
|
||||
+ acquireTimeoutMillis: 60000
|
||||
+ idleTimeoutMillis: 60000
|
||||
+ # https://node-postgres.com/features/ssl
|
||||
+ # you can set the sslmode configuration option via the `PGSSLMODE` environment variable
|
||||
+ # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
||||
+ # ssl:
|
||||
+ # ca: # if you have a CA file and want to verify it you can uncomment this section
|
||||
+ # $file: <file-path>/ca/server.crt
|
||||
```
|
||||
|
||||
### Using a single database
|
||||
|
||||
@@ -67,6 +67,13 @@ COPY .yarn ./.yarn
|
||||
COPY .yarnrc.yml ./
|
||||
```
|
||||
|
||||
In a multi-stage `Dockerfile`, each stage that runs a `yarn` command will also need the Yarn 3 installation. For example, in the final stage you may need to add the following:
|
||||
|
||||
```Dockerfile
|
||||
COPY --from=build --chown=node:node /app/.yarn ./.yarn
|
||||
COPY --from=build --chown=node:node /app/.yarnrc.yml ./
|
||||
```
|
||||
|
||||
The `--production` flag to `yarn install` has been removed in Yarn 3, instead you need to use `yarn workspaces focus --all --production` to avoid installing development dependencies in your production deployment. A tradeoff of this is that `yarn workspaces focus` does not support the `--immutable` flag.
|
||||
|
||||
```Dockerfile
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
---
|
||||
title: Adopters Community Sessions
|
||||
date: August 17, 2022
|
||||
category: Upcoming
|
||||
category: Meetup
|
||||
description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc.
|
||||
youtubeUrl: https://youtu.be/qYnvc8ge1kg
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com
|
||||
eventUrl: https://github.com/backstage/community/issues/54
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
---
|
||||
title: Contributor Community Sessions
|
||||
date: August 24, 2022
|
||||
category: Upcoming
|
||||
category: Meetup
|
||||
description: Join the maintainers and contributors for the Contributor Community Sessions
|
||||
youtubeUrl: https://youtu.be/qYnvc8ge1kg
|
||||
youtubeUrl: https://youtu.be/8ydEFFiuHAc
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com
|
||||
eventUrl: https://github.com/backstage/community/issues/54
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Contributor Community Sessions
|
||||
date: September 28, 2022
|
||||
category: Meetup
|
||||
description: Join the maintainers and contributors for the Contributor Community Sessions
|
||||
youtubeUrl: https://youtu.be/jmNT5x3mKaQ
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: System scoring
|
||||
author: Oriflame
|
||||
authorUrl: https://github.com/Oriflame
|
||||
category: Quality
|
||||
description: Visualization of maturity (and improving it) of services/systems thanks to a review process.
|
||||
documentation: https://github.com/Oriflame/backstage-plugins/tree/main/plugins/score-card
|
||||
iconUrl: img/score-card-plugin-logo.png
|
||||
npmPackageName: '@oriflame/backstage-plugin-score-card'
|
||||
@@ -226,6 +226,7 @@
|
||||
"plugins/composability",
|
||||
"plugins/customization",
|
||||
"plugins/analytics",
|
||||
"plugins/feature-flags",
|
||||
{
|
||||
"type": "subcategory",
|
||||
"label": "Backends and APIs",
|
||||
@@ -278,6 +279,7 @@
|
||||
},
|
||||
"auth/identity-resolver",
|
||||
"auth/oauth",
|
||||
"auth/oidc",
|
||||
"auth/add-auth-provider",
|
||||
"auth/service-to-service-auth",
|
||||
"auth/troubleshooting",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -163,6 +163,7 @@ nav:
|
||||
- Bitbucket: 'auth/bitbucket/provider.md'
|
||||
- Sign in resolvers: 'auth/identity-resolver.md'
|
||||
- OAuth and OpenID Connect: 'auth/oauth.md'
|
||||
- OIDC provider from scratch: 'auth/oidc.md'
|
||||
- Contributing New Providers: 'auth/add-auth-provider.md'
|
||||
- Service to Service Auth: 'auth/service-to-service-auth.md'
|
||||
- Troubleshooting Auth: 'auth/troubleshooting.md'
|
||||
|
||||
+3
-2
@@ -11,7 +11,7 @@
|
||||
"build": "backstage-cli repo build --all",
|
||||
"build:api-reports": "yarn build:api-reports:only --tsc",
|
||||
"build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts",
|
||||
"build:api-docs": "yarn build:api-reports --docs",
|
||||
"build:api-docs": "LANG=en_EN yarn build:api-reports --docs",
|
||||
"tsc": "tsc",
|
||||
"tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false",
|
||||
"clean": "backstage-cli repo clean",
|
||||
@@ -44,8 +44,9 @@
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17"
|
||||
},
|
||||
"version": "1.7.0-next.1",
|
||||
"version": "1.7.0-next.2",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@microsoft/api-documenter": "^7.17.11",
|
||||
"@microsoft/api-extractor": "^7.23.0",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.0.7-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-permission-react@0.4.6-next.2
|
||||
- @backstage/core-app-api@1.1.1-next.2
|
||||
- @backstage/core-components@0.11.2-next.2
|
||||
- @backstage/core-plugin-api@1.0.7-next.2
|
||||
- @backstage/theme@0.2.16
|
||||
|
||||
## 1.0.7-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"version": "1.0.7-next.1",
|
||||
"version": "1.0.7-next.2",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.76-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-scaffolder@1.7.0-next.2
|
||||
- @backstage/plugin-catalog-common@1.0.7-next.2
|
||||
- @backstage/plugin-catalog-import@0.9.0-next.2
|
||||
- @backstage/cli@0.20.0-next.2
|
||||
- @backstage/plugin-catalog-react@1.2.0-next.2
|
||||
- @backstage/plugin-playlist@0.1.1-next.2
|
||||
- @backstage/plugin-permission-react@0.4.6-next.2
|
||||
- @backstage/plugin-search-common@1.1.0-next.2
|
||||
- @backstage/app-defaults@1.0.7-next.2
|
||||
- @backstage/catalog-model@1.1.2-next.2
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/core-app-api@1.1.1-next.2
|
||||
- @backstage/core-components@0.11.2-next.2
|
||||
- @backstage/core-plugin-api@1.0.7-next.2
|
||||
- @backstage/integration-react@1.1.5-next.2
|
||||
- @backstage/theme@0.2.16
|
||||
- @backstage/plugin-airbrake@0.3.10-next.2
|
||||
- @backstage/plugin-apache-airflow@0.2.3-next.2
|
||||
- @backstage/plugin-api-docs@0.8.10-next.2
|
||||
- @backstage/plugin-azure-devops@0.2.1-next.2
|
||||
- @backstage/plugin-badges@0.2.34-next.2
|
||||
- @backstage/plugin-catalog-graph@0.2.22-next.2
|
||||
- @backstage/plugin-circleci@0.3.10-next.2
|
||||
- @backstage/plugin-cloudbuild@0.3.10-next.2
|
||||
- @backstage/plugin-code-coverage@0.2.3-next.2
|
||||
- @backstage/plugin-cost-insights@0.11.32-next.2
|
||||
- @backstage/plugin-dynatrace@1.0.0-next.2
|
||||
- @backstage/plugin-explore@0.3.41-next.2
|
||||
- @backstage/plugin-gcalendar@0.3.6-next.2
|
||||
- @backstage/plugin-gcp-projects@0.3.29-next.2
|
||||
- @backstage/plugin-github-actions@0.5.10-next.2
|
||||
- @backstage/plugin-gocd@0.1.16-next.2
|
||||
- @backstage/plugin-graphiql@0.2.42-next.2
|
||||
- @backstage/plugin-home@0.4.26-next.2
|
||||
- @backstage/plugin-jenkins@0.7.9-next.2
|
||||
- @backstage/plugin-kafka@0.3.10-next.2
|
||||
- @backstage/plugin-kubernetes@0.7.3-next.2
|
||||
- @backstage/plugin-lighthouse@0.3.10-next.2
|
||||
- @backstage/plugin-newrelic@0.3.28-next.2
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.3-next.2
|
||||
- @backstage/plugin-org@0.5.10-next.2
|
||||
- @backstage/plugin-pagerduty@0.5.3-next.2
|
||||
- @backstage/plugin-rollbar@0.4.10-next.2
|
||||
- @backstage/plugin-search@1.0.3-next.2
|
||||
- @backstage/plugin-search-react@1.2.0-next.2
|
||||
- @backstage/plugin-sentry@0.4.3-next.2
|
||||
- @backstage/plugin-shortcuts@0.3.2-next.2
|
||||
- @backstage/plugin-stack-overflow@0.1.6-next.2
|
||||
- @backstage/plugin-tech-insights@0.3.1-next.2
|
||||
- @backstage/plugin-tech-radar@0.5.17-next.2
|
||||
- @backstage/plugin-techdocs@1.3.3-next.2
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.0.5-next.2
|
||||
- @backstage/plugin-techdocs-react@1.0.5-next.2
|
||||
- @backstage/plugin-todo@0.2.12-next.2
|
||||
- @backstage/plugin-user-settings@0.5.0-next.2
|
||||
- @internal/plugin-catalog-customized@0.0.3-next.2
|
||||
|
||||
## 0.2.76-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.76-next.1",
|
||||
"version": "0.2.76-next.2",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
@@ -83,7 +83,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@rjsf/core": "^3.2.1",
|
||||
"@testing-library/cypress": "^8.0.2",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
SearchBar,
|
||||
SearchFilter,
|
||||
SearchResult,
|
||||
SearchPagination,
|
||||
SearchResultPager,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search-react';
|
||||
@@ -129,6 +130,7 @@ const SearchPage = () => {
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs>
|
||||
<SearchPagination />
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.2.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-tasks@0.3.6-next.2
|
||||
- @backstage/backend-common@0.15.2-next.2
|
||||
- @backstage/plugin-permission-node@0.7.0-next.2
|
||||
- @backstage/backend-plugin-api@0.1.3-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
|
||||
## 0.2.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.2.2-next.1",
|
||||
"version": "0.2.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.15.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c44cf412de: Fix BitBucket server integration
|
||||
- 2d3a5f09ab: Use `response.json` rather than `response.send` where appropriate, as outlined in `SECURITY.md`
|
||||
- Updated dependencies
|
||||
- @backstage/cli-common@0.1.10
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/config-loader@1.1.5-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
- @backstage/integration@1.3.2-next.2
|
||||
- @backstage/types@1.0.0
|
||||
|
||||
## 0.15.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.15.2-next.1",
|
||||
"version": "0.15.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { notFoundHandler } from './notFoundHandler';
|
||||
describe('notFoundHandler', () => {
|
||||
it('handles only missing routes', async () => {
|
||||
const app = express();
|
||||
app.use('/exists', (_, res) => res.status(200).send());
|
||||
app.use('/exists', (_, res) => res.status(200).end());
|
||||
app.use(notFoundHandler());
|
||||
|
||||
const existsResponse = await request(app).get('/exists');
|
||||
|
||||
@@ -28,6 +28,6 @@ import { NextFunction, Request, RequestHandler, Response } from 'express';
|
||||
export function notFoundHandler(): RequestHandler {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
return (_request: Request, response: Response, _next: NextFunction) => {
|
||||
response.status(404).send();
|
||||
response.status(404).end();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ describe('requestLoggingHandler', () => {
|
||||
|
||||
const app = express();
|
||||
app.use(requestLoggingHandler(logger));
|
||||
app.use('/exists1', (_, res) => res.status(200).send());
|
||||
app.use('/exists2', (_, res) => res.status(201).send());
|
||||
app.use('/exists1', (_, res) => res.status(200).end());
|
||||
app.use('/exists2', (_, res) => res.status(201).end());
|
||||
|
||||
const r = request(app);
|
||||
await r.get('/exists1');
|
||||
|
||||
@@ -55,7 +55,7 @@ export async function statusCheckHandler(
|
||||
return async (_request: Request, response: Response, next: NextFunction) => {
|
||||
try {
|
||||
const status = await statusCheck();
|
||||
response.status(200).header('').send(status);
|
||||
response.status(200).json(status);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
|
||||
@@ -83,13 +83,44 @@ describe('BitbucketServerUrlReader', () => {
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits/*',
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }),
|
||||
ctx.json({
|
||||
size: 2,
|
||||
values: [
|
||||
{
|
||||
displayId: 'some-branch-that-should-be-ignored',
|
||||
latestCommit: 'bogus hash',
|
||||
},
|
||||
{
|
||||
displayId: 'some-branch',
|
||||
latestCommit: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st',
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
id: 'refs/heads/master',
|
||||
displayId: 'master',
|
||||
type: 'BRANCH',
|
||||
latestCommit: '3bdd5457286abdf920db4b77bf2fef79a06190c2',
|
||||
latestChangeset: '3bdd5457286abdf920db4b77bf2fef79a06190c2',
|
||||
isDefault: true,
|
||||
}),
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/default-branch',
|
||||
(_, res, ctx) => res(ctx.status(404)),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -107,6 +138,14 @@ describe('BitbucketServerUrlReader', () => {
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('uses default branch when no branch is provided', async () => {
|
||||
const response = await reader.readTree(
|
||||
'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/src',
|
||||
);
|
||||
|
||||
expect(response.etag).toBe('3bdd5457286a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('readTree without branch', () => {
|
||||
@@ -130,12 +169,22 @@ describe('BitbucketServerUrlReader', () => {
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits/*',
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
values: [{ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }],
|
||||
size: 2,
|
||||
values: [
|
||||
{
|
||||
displayId: 'some-branch-that-should-be-ignored',
|
||||
latestCommit: 'bogus hash',
|
||||
},
|
||||
{
|
||||
displayId: 'some-branch',
|
||||
latestCommit: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st',
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
),
|
||||
@@ -179,11 +228,23 @@ describe('BitbucketServerUrlReader', () => {
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits/*',
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }),
|
||||
ctx.json({
|
||||
size: 2,
|
||||
values: [
|
||||
{
|
||||
displayId: 'master-of-none',
|
||||
latestCommit: 'bogus hash',
|
||||
},
|
||||
{
|
||||
displayId: 'master',
|
||||
latestCommit: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st',
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -188,38 +188,45 @@ export class BitbucketServerUrlReader implements UrlReader {
|
||||
private async getLastCommitShortHash(url: string): Promise<string> {
|
||||
const { name: repoName, owner: project, ref: branch } = parseGitUrl(url);
|
||||
|
||||
// Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp224
|
||||
const commitApiUrl = `${this.integration.config.apiBaseUrl}/projects/${project}/repos/${repoName}/commits/${branch}`;
|
||||
// If a branch is provided use that otherwise fall back to the default branch
|
||||
const branchParameter = branch
|
||||
? `?filterText=${encodeURIComponent(branch)}`
|
||||
: '/default';
|
||||
|
||||
const commitResponse = await fetch(
|
||||
commitApiUrl,
|
||||
// https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp211 (branches docs)
|
||||
const branchListUrl = `${this.integration.config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches${branchParameter}`;
|
||||
|
||||
const branchListResponse = await fetch(
|
||||
branchListUrl,
|
||||
getBitbucketServerRequestOptions(this.integration.config),
|
||||
);
|
||||
if (!commitResponse.ok) {
|
||||
const message = `Failed to retrieve commits from ${commitApiUrl}, ${commitResponse.status} ${commitResponse.statusText}`;
|
||||
if (commitResponse.status === 404) {
|
||||
if (!branchListResponse.ok) {
|
||||
const message = `Failed to retrieve branch list from ${branchListUrl}, ${branchListResponse.status} ${branchListResponse.statusText}`;
|
||||
if (branchListResponse.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
const commits = await commitResponse.json();
|
||||
const branchMatches = await branchListResponse.json();
|
||||
|
||||
// Handles case when a branch is provided in the URL
|
||||
if (commits && commits.id) {
|
||||
return commits.id.substring(0, 12);
|
||||
if (branchMatches && branchMatches.size > 0) {
|
||||
const exactBranchMatch = branchMatches.values.filter(
|
||||
(branchDetails: { displayId: string }) =>
|
||||
branchDetails.displayId === branch,
|
||||
)[0];
|
||||
return exactBranchMatch.latestCommit.substring(0, 12);
|
||||
}
|
||||
|
||||
// Handles case when no branch is provided in the URL
|
||||
if (
|
||||
commits &&
|
||||
commits.values &&
|
||||
commits.values.length > 0 &&
|
||||
commits.values[0].id
|
||||
) {
|
||||
return commits.values[0].id.substring(0, 12);
|
||||
// Handle when no branch is provided using the default as the fallback
|
||||
if (!branch && branchMatches) {
|
||||
return branchMatches.latestCommit.substring(0, 12);
|
||||
}
|
||||
|
||||
throw new Error(`Failed to read response from ${commitApiUrl}`);
|
||||
throw new Error(
|
||||
`Failed to find Last Commit using ${
|
||||
branch ? `branch "${branch}"` : 'default branch'
|
||||
} in response from ${branchListUrl}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.2.2-next.2
|
||||
- @backstage/backend-plugin-api@0.1.3-next.2
|
||||
|
||||
## 0.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.1.2-next.1",
|
||||
"version": "0.1.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.4-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-backend@1.5.0-next.2
|
||||
- @backstage/plugin-scaffolder-backend@1.7.0-next.2
|
||||
- @backstage/plugin-app-backend@0.3.37-next.2
|
||||
- @backstage/backend-defaults@0.1.2-next.2
|
||||
|
||||
## 0.0.4-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.4-next.1",
|
||||
"version": "0.0.4-next.2",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.1.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-tasks@0.3.6-next.2
|
||||
- @backstage/backend-common@0.15.2-next.2
|
||||
- @backstage/plugin-permission-common@0.7.0-next.2
|
||||
- @backstage/config@1.0.3-next.2
|
||||
|
||||
## 0.1.3-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"version": "0.1.3-next.1",
|
||||
"version": "0.1.3-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.3.6-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d4fea86ea3: Added new function `readTaskScheduleDefinitionFromConfig` to read `TaskScheduleDefinition` (aka. schedule) from the `Config`.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.15.2-next.2
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
- @backstage/types@1.0.0
|
||||
|
||||
## 0.3.6-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.3.6-next.1",
|
||||
"version": "0.3.6-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.1.29-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.15.2-next.2
|
||||
- @backstage/cli@0.20.0-next.2
|
||||
- @backstage/backend-app-api@0.2.2-next.2
|
||||
- @backstage/backend-plugin-api@0.1.3-next.2
|
||||
- @backstage/config@1.0.3-next.2
|
||||
|
||||
## 0.1.29-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.1.29-next.1",
|
||||
"version": "0.1.29-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.76-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-backend@1.5.0-next.2
|
||||
- @backstage/backend-tasks@0.3.6-next.2
|
||||
- @backstage/backend-common@0.15.2-next.2
|
||||
- @backstage/plugin-permission-common@0.7.0-next.2
|
||||
- @backstage/plugin-permission-node@0.7.0-next.2
|
||||
- @backstage/plugin-scaffolder-backend@1.7.0-next.2
|
||||
- @backstage/plugin-playlist-backend@0.2.0-next.2
|
||||
- @backstage/plugin-badges-backend@0.1.31-next.2
|
||||
- @backstage/plugin-graphql-backend@0.1.27-next.2
|
||||
- @backstage/plugin-permission-backend@0.5.12-next.2
|
||||
- @backstage/plugin-rollbar-backend@0.1.34-next.2
|
||||
- @backstage/plugin-search-backend@1.1.0-next.2
|
||||
- @backstage/plugin-tech-insights-backend@0.5.3-next.2
|
||||
- @backstage/plugin-techdocs-backend@1.4.0-next.2
|
||||
- example-app@0.2.76-next.2
|
||||
- @backstage/plugin-search-backend-node@1.0.3-next.2
|
||||
- @backstage/plugin-tech-insights-node@0.3.5-next.2
|
||||
- @backstage/plugin-app-backend@0.3.37-next.2
|
||||
- @backstage/plugin-auth-backend@0.17.0-next.2
|
||||
- @backstage/plugin-auth-node@0.2.6-next.2
|
||||
- @backstage/plugin-azure-devops-backend@0.3.16-next.2
|
||||
- @backstage/plugin-code-coverage-backend@0.2.3-next.2
|
||||
- @backstage/plugin-jenkins-backend@0.1.27-next.2
|
||||
- @backstage/plugin-kafka-backend@0.2.30-next.2
|
||||
- @backstage/plugin-kubernetes-backend@0.7.3-next.2
|
||||
- @backstage/plugin-proxy-backend@0.2.31-next.2
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.2
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.2
|
||||
- @backstage/plugin-search-backend-module-pg@0.4.1-next.2
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.2
|
||||
- @backstage/plugin-todo-backend@0.1.34-next.2
|
||||
- @backstage/plugin-search-common@1.1.0-next.2
|
||||
- @backstage/catalog-client@1.1.1-next.2
|
||||
- @backstage/catalog-model@1.1.2-next.2
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/integration@1.3.2-next.2
|
||||
|
||||
## 0.2.76-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -13,9 +13,10 @@ FROM node:16-bullseye-slim
|
||||
|
||||
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
|
||||
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
|
||||
RUN apt-get update && \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
yarn config set python /usr/bin/python3
|
||||
|
||||
# From here on we use the least-privileged `node` user to run the backend.
|
||||
@@ -38,7 +39,8 @@ COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar
|
||||
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
|
||||
|
||||
# Note that this install is not immutable, which is one of the reasons we don't recommend Yarn 3 yet
|
||||
RUN yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)"
|
||||
RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,sharing=locked,uid=1000,gid=1000 \
|
||||
yarn workspaces focus --all --production
|
||||
|
||||
# Then copy the rest of the backend bundle, along with any other files we might want.
|
||||
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.76-next.1",
|
||||
"version": "0.2.76-next.2",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 1.1.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.1.2-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
|
||||
## 1.1.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-client",
|
||||
"description": "An isomorphic client for the catalog backend",
|
||||
"version": "1.1.1-next.1",
|
||||
"version": "1.1.1-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 1.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
- @backstage/types@1.0.0
|
||||
|
||||
## 1.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"description": "Types and validators that help describe the model of a Backstage Catalog",
|
||||
"version": "1.1.2-next.1",
|
||||
"version": "1.1.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.20.0-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2d3a5f09ab: Use `response.json` rather than `response.send` where appropriate, as outlined in `SECURITY.md`
|
||||
- Updated dependencies
|
||||
- @backstage/cli-common@0.1.10
|
||||
- @backstage/config@1.0.3-next.2
|
||||
- @backstage/config-loader@1.1.5-next.2
|
||||
- @backstage/errors@1.1.2-next.2
|
||||
- @backstage/release-manifests@0.0.6
|
||||
- @backstage/types@1.0.0
|
||||
|
||||
## 0.20.0-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.20.0-next.1",
|
||||
"version": "0.20.0-next.2",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"@types/express": "{{versionQuery '@types/express' '4.17.13'}}",
|
||||
"express": "{{versionQuery 'express' '4.18.1'}}",
|
||||
"express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}",
|
||||
"winston": "{{versionQuery 'winston' '3.8.1'}}",
|
||||
"winston": "{{versionQuery 'winston' '3.2.1'}}",
|
||||
"node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}",
|
||||
"yn": "{{versionQuery 'yn' '4.0.0'}}"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user