Merge branch 'master' of github.com:backstage/backstage into RoadieHQ-add-export-for-in-memory-broker
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Make identity valid if subject of token is a backstage server-2-server auth token
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Button labels in the sidebar (previously displayed in uppercase) will be displayed in the case that is provided without any transformations.
|
||||
For example, a sidebar button with the label "Search" will appear as Search, "search" will appear as search, "SEARCH" will appear as SEARCH etc.
|
||||
This can potentially affect any overriding styles previously applied to change the appearance of Button labels in the Sidebar.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Make scaffolder adhere to page themes by using page `fontColor` consistently. If your theme overwrites template list or card headers, review those styles.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Bumped create-app version.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Update `EntityPicker` to use the fully qualified entity ref instead of the humanized version.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search-react': patch
|
||||
---
|
||||
|
||||
Correctly disable next button in `SearchPagination` on last page
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-puppetdb': minor
|
||||
---
|
||||
|
||||
Initial version of the plugin.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-tasks': minor
|
||||
---
|
||||
|
||||
add functionality to get descriptions from the scheduler for triggering
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Fixed msgraph catalog backend to use user.select option when fetching user from AzureAD
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
catalog write action should allow any shape of object
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
GitLab can now be used as an `oidcTokenProvider` for Kubernetes clusters
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-adr-backend': patch
|
||||
---
|
||||
|
||||
Support MADR v3 format
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Adds config option `backend.database.role` to set ownership for newly created schemas and tables in Postgres
|
||||
|
||||
The example config below connects to the database as user `v-backstage-123` but sets the ownership of
|
||||
the create schemas and tables to `backstage`
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
database:
|
||||
client: pg
|
||||
pluginDivisionMode: schema
|
||||
role: backstage
|
||||
connection:
|
||||
user: v-backstage-123
|
||||
...
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
|
||||
---
|
||||
|
||||
allow container runner to be undefined in cookiecutter plugin
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Fix dark theme Swagger's clear button font color.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-linguist-backend': patch
|
||||
---
|
||||
|
||||
Added support for linguist-js options using the linguistJSOptions in the plugin, the available config can be found [here](https://www.npmjs.com/package/linguist-js#API).
|
||||
+29
-2
@@ -210,44 +210,63 @@
|
||||
"@backstage/plugin-vault-backend": "0.2.8",
|
||||
"@backstage/plugin-xcmetrics": "0.2.35",
|
||||
"@backstage/plugin-octopus-deploy": "0.0.0",
|
||||
"@backstage/plugin-stackstorm": "0.0.0"
|
||||
"@backstage/plugin-stackstorm": "0.0.0",
|
||||
"@backstage/plugin-catalog-backend-module-puppetdb": "0.0.1"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-trees-stare",
|
||||
"backend-token-authentication",
|
||||
"breezy-bees-care",
|
||||
"bright-kids-raise",
|
||||
"clean-lemons-jump",
|
||||
"clean-planes-join",
|
||||
"clever-dogs-cheat",
|
||||
"cool-clocks-prove",
|
||||
"cool-feet-speak",
|
||||
"create-app-1676993958",
|
||||
"create-app-1678209629",
|
||||
"curvy-pets-hang",
|
||||
"eight-radios-bake",
|
||||
"eighty-chairs-roll",
|
||||
"eighty-geese-return",
|
||||
"empty-books-occur",
|
||||
"famous-sloths-tie",
|
||||
"fifty-beds-dress",
|
||||
"flat-kids-occur",
|
||||
"flat-peaches-act",
|
||||
"forty-snails-clap",
|
||||
"four-lizards-grin",
|
||||
"fresh-hairs-switch",
|
||||
"fuzzy-trains-search",
|
||||
"gentle-bears-love",
|
||||
"gentle-pears-clean",
|
||||
"great-trains-jam",
|
||||
"grumpy-bikes-begin",
|
||||
"happy-boxes-arrive",
|
||||
"honest-clouds-shout",
|
||||
"honest-nails-bake",
|
||||
"khaki-poems-run",
|
||||
"light-bees-end",
|
||||
"light-sheep-trade",
|
||||
"long-nails-pump",
|
||||
"long-wolves-drive",
|
||||
"lovely-tigers-look",
|
||||
"mean-toys-itch",
|
||||
"metal-suns-rhyme",
|
||||
"mighty-games-turn",
|
||||
"mighty-years-own",
|
||||
"new-jobs-deny",
|
||||
"nice-planets-wave",
|
||||
"nine-bikes-applaud",
|
||||
"ninety-turtles-wait",
|
||||
"odd-fireants-bathe",
|
||||
"odd-oranges-tease",
|
||||
"odd-waves-rescue",
|
||||
"old-foxes-shave",
|
||||
"olive-berries-poke",
|
||||
"orange-experts-hug",
|
||||
"perfect-mayflies-greet",
|
||||
"pink-dolls-unite",
|
||||
"polite-chicken-do",
|
||||
"polite-falcons-jump",
|
||||
"polite-wombats-smash",
|
||||
@@ -267,8 +286,13 @@
|
||||
"renovate-fb85ae7",
|
||||
"rich-clocks-approve",
|
||||
"rich-wombats-rescue",
|
||||
"rotten-cats-matter",
|
||||
"rotten-panthers-share",
|
||||
"selfish-hats-wait",
|
||||
"short-mayflies-fix",
|
||||
"silent-dryers-end",
|
||||
"silly-suits-run",
|
||||
"silver-bikes-breathe",
|
||||
"silver-lies-rest",
|
||||
"six-melons-rhyme",
|
||||
"slimy-lobsters-kneel",
|
||||
@@ -282,6 +306,7 @@
|
||||
"tall-hats-talk",
|
||||
"ten-tigers-marry",
|
||||
"thin-candles-wait",
|
||||
"tiny-llamas-jump",
|
||||
"tricky-jars-film",
|
||||
"twelve-cars-push",
|
||||
"twenty-jeans-speak",
|
||||
@@ -292,9 +317,11 @@
|
||||
"wicked-lions-repeat",
|
||||
"wicked-spoons-call",
|
||||
"wild-ads-pull",
|
||||
"wild-bulldogs-suffer",
|
||||
"witty-geckos-design",
|
||||
"yellow-bananas-yawn",
|
||||
"young-schools-double",
|
||||
"young-scissors-cough"
|
||||
"young-scissors-cough",
|
||||
"young-walls-prove"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
'@backstage/core-app-api': minor
|
||||
---
|
||||
|
||||
`OAuth2` now gets ID tokens from a session with the `openid` scope explicitly
|
||||
requested.
|
||||
|
||||
This should not be considered a breaking change, because spec-compliant OIDC
|
||||
providers will already be returning ID tokens if and only if the `openid` scope
|
||||
is granted.
|
||||
|
||||
This change makes the dependence explicit, and removes the burden on
|
||||
OAuth2-based providers which require an ID token (e.g. this is done by various
|
||||
default [auth
|
||||
handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add
|
||||
`openid` to their default scopes. _That_ could carry another indirect benefit:
|
||||
by removing `openid` from the default scopes for a provider, grants for
|
||||
resource-specific access tokens can avoid requesting excess ID token-related
|
||||
scopes.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/plugin-catalog-backend-module-aws': patch
|
||||
---
|
||||
|
||||
AwsS3UrlReader upgraded to use aws-sdk v3
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
Add styling to the `MembersListCard` and `ComponentsGrid` to handle overflow text.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Fix the scaffolder validator for arrays when the item is a field in the object
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': minor
|
||||
---
|
||||
|
||||
allow entity switch to render all cases that match the condition
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Use media queries to change layout instead of `isMobile` prop in `BackstagePage` component
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
filter gitlab groups by prefix
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-plugin-api': minor
|
||||
---
|
||||
|
||||
The GitLab auth provider can now be used to get OpenID tokens.
|
||||
@@ -30,6 +30,7 @@ yarn.lock @backstage/maintainers @back
|
||||
/plugins/catalog-backend-module-aws @backstage/maintainers @backstage/catalog-core @pjungermann
|
||||
/plugins/catalog-backend-module-bitbucket-cloud @backstage/maintainers @backstage/catalog-core @pjungermann
|
||||
/plugins/catalog-backend-module-msgraph @backstage/maintainers @backstage/catalog-core @pjungermann
|
||||
/plugins/catalog-backend-module-puppetdb @backstage/maintainers @backstage/catalog-core @tdabasinskas
|
||||
/plugins/catalog-graph @backstage/maintainers @backstage/catalog-core @backstage/sda-se-reviewers
|
||||
/plugins/circleci @backstage/maintainers @adamdmharvey
|
||||
/plugins/cloudbuild @backstage/maintainers @trivago/ebarrios
|
||||
|
||||
@@ -55,6 +55,7 @@ jobs:
|
||||
context: './example-app'
|
||||
file: ./example-app/packages/backend/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository_owner }}/backstage:latest
|
||||
ghcr.io/${{ github.repository_owner }}/backstage:${{ github.event.client_payload.version }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
env:
|
||||
CI: true
|
||||
NODE_OPTIONS: --max-old-space-size=7168
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
DOCUSAURUS_SSR_CONCURRENCY: 5
|
||||
|
||||
steps:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
env:
|
||||
CI: true
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
DOCUSAURUS_SSR_CONCURRENCY: 5
|
||||
|
||||
steps:
|
||||
|
||||
+5
-1
@@ -21,7 +21,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
|
||||
| [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) | [@gman0922](https://github.com/gman0922), [Sheena Sharma](mailto:shesharma@expediagroup.com), [Alekhya Karuturi](mailto:akaruturi@expediagroup.com) | EG Developer Front Door |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [Guillermo Manzo](mailto:gmanzo@expediagroup.com), [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) | [Bjørn Hald Sørensen](https://github.com/crevil) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
|
||||
@@ -230,3 +230,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
|
||||
| [OVO Energy](https://www.ovoenergy.com/) | [Michael Wizner](https://github.com/mwz), [Dan Laird](https://github.com/dlaird-ovo), [Samantha Betts](https://github.com/sammbetts) | Developer Experience Tool with an aim to to improve processes, boost productivity, finding of information/docs and building tech engagement throughout the business.
|
||||
| [MusicTribe](https://careers.musictribe.com/) | [Alex Ford](mailto:alex.j.ford@gmail.com), [Tiago Barbosa](https://github.com/t1agob) | We are starting to use Backstage as a developer portal to share API specifications and documentation, to quickly onboard new projects with the software templates, and to help developers discover software through the catalog.
|
||||
| [Cazoo](https://www.cazoo.co.uk/) | [Abz Mungul](https://www.linkedin.com/in/abzmungul/), [Scott Edwards](https://www.linkedin.com/in/scott-edwards-tech/) | We're assessing Backstage as our developer platform at Cazoo with a focus on reducing cognitive load for our engineers. We're currently aiming for 3 outcomes: creating visibility into service ownership across teams, improving the discoverability of event schemas and relationships, and improving the discoverability of technical documentation and best practices. |
|
||||
| [Gumtree](https://www.gumtree.com.au) | [Kumar Gaurav](https://www.linkedin.com/in/kumargaurav517) | We are starting to use it as a single place to find all component information in a distributed architecture. |
|
||||
| [N26](https://n26.com) | [Alexei Timofti](https://www.linkedin.com/in/alexeitimofti) | We use Backstage for our service catalog and are actively looking into adopting other plugins like TechDocs, TechInsights and Software Templates. |
|
||||
| [The LEGO Group](https://www.lego.com) | [Waqas Ali](https://www.linkedin.com/in/waqasali47) | We are building our internal develper portal on top of Backstage. |
|
||||
|
||||
|
||||
+1
-59
@@ -8,65 +8,7 @@ Contributions are welcome, and they are greatly appreciated! Every little bit he
|
||||
|
||||
Backstage is released under the Apache 2.0 License, and original creations contributed to this repo are accepted under the same license.
|
||||
|
||||
## Types of Contributions
|
||||
|
||||
### Report bugs
|
||||
|
||||
No one likes bugs. Report bugs as an issue [here](https://github.com/backstage/backstage/issues/new?template=bug_template.md).
|
||||
|
||||
### Fix bugs or build new features
|
||||
|
||||
Look through the GitHub issues for [bugs](https://github.com/backstage/backstage/labels/bug), [good first issues](https://github.com/backstage/backstage/labels/good%20first%20issue) or [help wanted](https://github.com/backstage/backstage/labels/help%20wanted).
|
||||
|
||||
### Build a plugin
|
||||
|
||||
The value of Backstage grows with every new plugin that gets added. Wouldn't it be fantastic if there was a plugin for every infrastructure project out there? We think so. And we would love your help.
|
||||
|
||||
A great reference example of a plugin can be found on [our blog](https://backstage.io/blog/2020/04/06/lighthouse-plugin) (thanks [@fastfrwrd](https://github.com/fastfrwrd)!)
|
||||
|
||||
What kind of plugins should/could be created? Some inspiration from the 120+ plugins that we have developed inside Spotify can be found [here](https://backstage.io/demos), but we will keep a running list of suggestions labeled with [[plugin]](https://github.com/backstage/backstage/labels/plugin).
|
||||
|
||||
### Suggesting a plugin
|
||||
|
||||
If you start developing a plugin that you aim to release as open source, we suggest that you create a [new Issue](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). This helps the community know what plugins are in development.
|
||||
|
||||
You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work.
|
||||
|
||||
### Adding Non-code Contributions
|
||||
|
||||
Since there is such a large landscape of possible development, build, and deployment environments, we welcome community contributions in these areas in the [`/contrib`](https://github.com/backstage/backstage/tree/master/contrib) folder of the project. This is an excellent place to put things that help out the community at large, but which may not fit within the scope of the core product to support natively. Here, you will find Helm charts, alternative Docker images, and much more.
|
||||
|
||||
### Write Documentation or improve the website
|
||||
|
||||
The current documentation is very limited. Help us make the `/docs` folder come alive.
|
||||
|
||||
Docs are published to [backstage.io/docs](https://backstage.io/docs). If you
|
||||
contribute to the documentation, you might want to preview your changes before
|
||||
submitting them. You'll find the website sources under [/microsite](/microsite)
|
||||
with instructions for building and locally serving the website in the
|
||||
[README](/microsite#readme).
|
||||
|
||||
### Contribute to Storybook
|
||||
|
||||
We think the best way to ensure different plugins provide a consistent experience is through a solid set of reusable UI/UX components. Backstage uses [Storybook](http://backstage.io/storybook).
|
||||
|
||||
Either help us [create new components](https://github.com/backstage/backstage/labels/help%20wanted) or improve stories for the existing ones (look for files with `*.stories.tsx`).
|
||||
|
||||
### Submit Feedback
|
||||
|
||||
The best way to send feedback is to file [an issue](https://github.com/backstage/backstage/issues).
|
||||
|
||||
If you are proposing a feature:
|
||||
|
||||
- Explain in detail how it would work.
|
||||
- Keep the scope as narrow as possible, to make it easier to implement.
|
||||
- Use appropriate labels
|
||||
- Remember that this is a volunteer-driven project, and that contributions
|
||||
are welcome :)
|
||||
|
||||
### Add your company to `ADOPTERS`
|
||||
|
||||
Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md) really helps the project, you can do this by filling out this [Adopter form](https://form.typeform.com/to/zcOaKikB).
|
||||
You can find out more about the types of contributions over at [getting involved](https://backstage.io/docs/getting-started/getting-involved)!
|
||||
|
||||
## Get Started!
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
Backstage unifies all your infrastructure tooling, services, and documentation to create a streamlined development environment from end to end.
|
||||
|
||||

|
||||

|
||||
|
||||
Out of the box, Backstage includes:
|
||||
|
||||
- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview) for managing all your software (microservices, libraries, data pipelines, websites, ML models, etc.)
|
||||
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index) for quickly spinning up new projects and standardizing your tooling with your organization’s best practices
|
||||
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview) for making it easy to create, maintain, find, and use technical documentation, using a "docs like code" approach
|
||||
- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) for managing all your software (microservices, libraries, data pipelines, websites, ML models, etc.)
|
||||
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) for quickly spinning up new projects and standardizing your tooling with your organization’s best practices
|
||||
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) for making it easy to create, maintain, find, and use technical documentation, using a "docs like code" approach
|
||||
- Plus, a growing ecosystem of [open source plugins](https://github.com/backstage/backstage/tree/master/plugins) that further expand Backstage’s customizability and functionality
|
||||
|
||||
Backstage was created by Spotify but is now hosted by the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io) as an Incubation level project. Read the announcement [here](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation).
|
||||
@@ -38,8 +38,8 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
|
||||
## Documentation
|
||||
|
||||
- [Main documentation](https://backstage.io/docs)
|
||||
- [Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview)
|
||||
- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview))
|
||||
- [Software Catalog](https://backstage.io/docs/features/software-catalog/)
|
||||
- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/))
|
||||
- [Designing for Backstage](https://backstage.io/docs/dls/design)
|
||||
- [Storybook - UI components](https://backstage.io/storybook)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Catalog Contrib
|
||||
|
||||
This directory contains various community contributions related to [the Backstage catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview).
|
||||
This directory contains various community contributions related to [the Backstage catalog](https://backstage.io/docs/features/software-catalog/).
|
||||
|
||||
There is no guarantee of correctness or fitness of purpose of these
|
||||
contributions, but we hope that they are helpful to someone!
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ By far, our most-used plugin is our TechDocs plugin, which we use for creating
|
||||
technical documentation. Our philosophy at Spotify is to treat "docs like code",
|
||||
where you write documentation using the same workflow as you write your code.
|
||||
This makes it easier to create, find, and update documentation.
|
||||
[TechDocs is now open source.](https://backstage.io/docs/features/techdocs/techdocs-overview)
|
||||
[TechDocs is now open source.](https://backstage.io/docs/features/techdocs/)
|
||||
(See also:
|
||||
"[Will Spotify's internal plugins be open sourced, too?](#will-spotifys-internal-plugins-be-open-sourced-too)"
|
||||
above)
|
||||
|
||||
@@ -18,7 +18,11 @@ Settings for local development:
|
||||
|
||||
- Name: Backstage (or your custom app name)
|
||||
- Redirect URI: `http://localhost:7007/api/auth/gitlab/handler/frame`
|
||||
- Scopes: `read_api` and `read_user`
|
||||
- Scopes: `read_user` for sign-in. If you also need ID tokens (e.g. if you are
|
||||
using the Kubernetes plugin and have clusters with `authProvider: oidc` and
|
||||
[`oidcTokenProvider:
|
||||
gitlab`](https://backstage.io/docs/features/kubernetes/configuration/#clustersoidctokenprovider-optional)),
|
||||
add the `openid` scope.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -168,7 +168,61 @@ Whenever you want to allow modules to configure your plugin dynamically, for
|
||||
example in the way that the catalog backend lets catalog modules inject
|
||||
additional entity providers, you can use the extension points mechanism. This is
|
||||
described in detail with code examples in [the extension points architecture
|
||||
article](../architecture/05-extension-points.md).
|
||||
article](../architecture/05-extension-points.md), while the following is a more
|
||||
slim example of how to implement an extension point for a plugin:
|
||||
|
||||
```ts
|
||||
import { createExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
|
||||
// This is the extension point interface, which is how modules interact with your plugin.
|
||||
export interface ExamplesExtensionPoint {
|
||||
addExample(example: Example): void;
|
||||
}
|
||||
|
||||
// This is the extension point reference that encapsulates the above interface.
|
||||
export const examplesExtensionPoint =
|
||||
createExtensionPoint<ExamplesExtensionPoint>({
|
||||
id: 'example.examples',
|
||||
});
|
||||
|
||||
// This is the implementation of the extension point, which is internal to your plugin.
|
||||
class ExamplesExtension implements ExamplesExtensionPoint {
|
||||
#examples: Example[] = [];
|
||||
|
||||
addExample(example: Example): void {
|
||||
this.#examples.push(example);
|
||||
}
|
||||
|
||||
// Note that this method is internal to this implementation
|
||||
getRegisteredExamples() {
|
||||
return this.#examples;
|
||||
}
|
||||
}
|
||||
|
||||
// The following shows how your plugin would register the extension point
|
||||
// and use the features that other modules have registered.
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
pluginId: 'example',
|
||||
register(env) {
|
||||
const examplesExtensions = new ExamplesExtension();
|
||||
env.registerExtensionPoint(examplesExtensionPoint, examplesExtensions);
|
||||
|
||||
env.registerInit({
|
||||
deps: { logger: coreServices.logger },
|
||||
async init({ logger }) {
|
||||
// We can access `examplesExtension` directly, giving us access to the internal interface.
|
||||
const examples = examplesExtension.getRegisteredExamples();
|
||||
|
||||
logger.info(`The following examples have been registered: ${examples}`);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This is a very common type of extension point, one where modules are given the opportunity to register features to be used by the plugin. In this case modules are able to register examples that are then used by our examples plugin.
|
||||
|
||||
Note that the public extension point interface only needs to expose the `addExample` method, while the `getRegisteredExamples()` method is kept internal to the plugin.
|
||||
|
||||
### Configuration
|
||||
|
||||
|
||||
@@ -160,8 +160,9 @@ auth:
|
||||
audience: ${AUTH_OKTA_AUDIENCE}
|
||||
```
|
||||
|
||||
The following values are supported out-of-the-box by the frontend: `google`, `microsoft`,
|
||||
`okta`, `onelogin`.
|
||||
The following values are supported out-of-the-box by the frontend: `gitlab` (the
|
||||
application whose `clientId` is used by the auth provider should be granted the
|
||||
`openid` scope), `google`, `microsoft`, `okta`, `onelogin`.
|
||||
|
||||
Take note that `oidcTokenProvider` is just the issuer for the token, you can use any
|
||||
of these with an OIDC enabled cluster, like using `microsoft` as the issuer for a EKS
|
||||
|
||||
@@ -14,7 +14,7 @@ websites, libraries, data pipelines, etc). The catalog is built around the
|
||||
concept of [metadata YAML files](descriptor-format.md) stored together with the
|
||||
code, which are then harvested and visualized in Backstage.
|
||||
|
||||

|
||||

|
||||
|
||||
## How it works
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ References for `createScaffolderFieldExtension` have an `/alpha` version of `cre
|
||||
|
||||
```diff
|
||||
-import { createScaffolderFieldExtension } from '@backstage/plugin-scaffolder';
|
||||
+import { createNextScaffolderFieldExtension } from '@backstage/plugin-scaffolder/alpha';
|
||||
+import { createNextScaffolderFieldExtension } from '@backstage/plugin-scaffolder-react/alpha';
|
||||
|
||||
export const EntityNamePickerFieldExtension = scaffolderPlugin.provide(
|
||||
- createScaffolderFieldExtension({
|
||||
|
||||
@@ -8,7 +8,7 @@ description: TechDocs CLI - a utility command line interface for managing TechDo
|
||||
Utility command line interface for managing TechDocs sites in
|
||||
[Backstage](https://github.com/backstage/backstage).
|
||||
|
||||
https://backstage.io/docs/features/techdocs/techdocs-overview
|
||||
https://backstage.io/docs/features/techdocs/
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ const app = createApp({
|
||||
|
||||
## How to add the documentation setup to your software templates
|
||||
|
||||
[Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index)
|
||||
[Software Templates](https://backstage.io/docs/features/software-templates/)
|
||||
in Backstage is a tool that can help your users to create new components out of
|
||||
already configured templates. It comes with a set of default templates to use,
|
||||
but you can also
|
||||
|
||||
@@ -71,9 +71,9 @@ app
|
||||
good starting point for you to get to know Backstage.
|
||||
- **packages/backend/**: We include a backend that helps power features such as
|
||||
[Authentication](https://backstage.io/docs/auth/),
|
||||
[Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview),
|
||||
[Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index)
|
||||
and [TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview)
|
||||
[Software Catalog](https://backstage.io/docs/features/software-catalog/),
|
||||
[Software Templates](https://backstage.io/docs/features/software-templates/)
|
||||
and [TechDocs](https://backstage.io/docs/features/techdocs/)
|
||||
amongst other things.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: getting-involved
|
||||
title: Getting Involved
|
||||
# prettier-ignore
|
||||
description: How can you help us build Backstage? We welcome contributions of all kinds, from documentation to code to design.
|
||||
---
|
||||
|
||||
We encourage contributions of all kinds, from documentation to code to design, here's some ideas on how you can help us build and improve Backstage!
|
||||
|
||||
### Report bugs
|
||||
|
||||
No one likes bugs. Report bugs as an issue [here](https://github.com/backstage/backstage/issues/new?template=bug_template.md).
|
||||
|
||||
### Fix bugs or build new features
|
||||
|
||||
Look through the GitHub issues for [bugs](https://github.com/backstage/backstage/labels/bug), [good first issues](https://github.com/backstage/backstage/labels/good%20first%20issue) or [help wanted](https://github.com/backstage/backstage/labels/help%20wanted).
|
||||
|
||||
### Build a plugin
|
||||
|
||||
The value of Backstage grows with every new plugin that gets added. Wouldn't it be fantastic if there was a plugin for every infrastructure project out there? We think so. And we would love your help.
|
||||
|
||||
A great reference example of a plugin can be found on [our blog](https://backstage.io/blog/2020/04/06/lighthouse-plugin) (thanks [@fastfrwrd](https://github.com/fastfrwrd)!)
|
||||
|
||||
What kind of plugins should/could be created? Some inspiration from the 120+ plugins that we have developed inside Spotify can be found [here](https://backstage.io/demos), but we will keep a running list of suggestions labeled with [[plugin]](https://github.com/backstage/backstage/labels/plugin).
|
||||
|
||||
### Suggesting a plugin
|
||||
|
||||
If you start developing a plugin that you aim to release as open source, we suggest that you create a [new Issue](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). This helps the community know what plugins are in development.
|
||||
|
||||
You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work.
|
||||
|
||||
### Adding non-code Contributions
|
||||
|
||||
Since there is such a large landscape of possible development, build, and deployment environments, we welcome community contributions in these areas in the [`/contrib`](https://github.com/backstage/backstage/tree/master/contrib) folder of the project. This is an excellent place to put things that help out the community at large, but which may not fit within the scope of the core product to support natively. Here, you will find Helm charts, alternative Docker images, and much more.
|
||||
|
||||
### Write documentation or improve the website
|
||||
|
||||
The current documentation is very limited. Help us make the `/docs` folder come alive.
|
||||
|
||||
Docs are published to [backstage.io/docs](https://backstage.io/docs). If you
|
||||
contribute to the documentation, you might want to preview your changes before
|
||||
submitting them. You'll find the website sources under [/microsite](https://github.com/backstage/backstage/tree/master/microsite)
|
||||
with instructions for building and locally serving the website in the
|
||||
[README](/microsite#readme).
|
||||
|
||||
### Contribute to Storybook
|
||||
|
||||
We think the best way to ensure different plugins provide a consistent experience is through a solid set of reusable UI/UX components. Backstage uses [Storybook](http://backstage.io/storybook).
|
||||
|
||||
Either help us [create new components](https://github.com/backstage/backstage/labels/help%20wanted) or improve stories for the existing ones (look for files with `*.stories.tsx`).
|
||||
|
||||
### Submit feedback
|
||||
|
||||
The best way to send feedback is to file [an issue](https://github.com/backstage/backstage/issues).
|
||||
|
||||
If you are proposing a feature:
|
||||
|
||||
- Explain in detail how it would work.
|
||||
- Keep the scope as narrow as possible, to make it easier to implement.
|
||||
- Use appropriate labels
|
||||
- Remember that this is a volunteer-driven project, and that contributions
|
||||
are welcome :)
|
||||
|
||||
### Add your company to `ADOPTERS`
|
||||
|
||||
Have you started using Backstage? Adding your company to [ADOPTERS](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) really helps the project, you can do this by filling out this [Adopter form](https://form.typeform.com/to/zcOaKikB).
|
||||
@@ -31,4 +31,10 @@ catalog:
|
||||
yourProviderId:
|
||||
host: gitlab.com
|
||||
orgEnabled: true
|
||||
group: org/teams # Optional. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
|
||||
groupPattern: '[\s\S]*' # Optional. Filters found groups based on provided pattern. Defaults to `[\s\S]*`, which means to not filter anything
|
||||
```
|
||||
|
||||
When the `group` parameter is provided, the corresponding path prefix will be stripped out from each matching group
|
||||
when computing the unique entity name. e.g. If `group` is `org/teams`, the name for `org/teams/avengers/gotg` will
|
||||
be `avengers-gotg`.
|
||||
|
||||
@@ -671,7 +671,7 @@ TypeScript support is currently handled though the `typesVersions` field, as the
|
||||
To add subpath exports to an existing package, simply add the desired `"exports"` fields and then run the following command:
|
||||
|
||||
```bash
|
||||
yarn backstage-cli package migrate package-exports
|
||||
yarn backstage-cli migrate package-exports
|
||||
```
|
||||
|
||||
## Experimental Type Build
|
||||
|
||||
@@ -146,7 +146,7 @@ Look at [DefaultTechDocsCollatorFactory test](https://github.com/backstage/backs
|
||||
|
||||
#### 6. Make your plugins collator discoverable for others
|
||||
|
||||
If you want to make your collator discoverable for other adopters, add it to the list of [plugins integrated to search](https://backstage.io/docs/features/search/search-overview#plugins-integrated-with-backstage-search).
|
||||
If you want to make your collator discoverable for other adopters, add it to the list of [plugins integrated to search](https://backstage.io/docs/features/search/#plugins-integrated-with-backstage-search).
|
||||
|
||||
## Building a search experience into your plugin
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,6 +104,22 @@ module.exports = {
|
||||
from: '/docs',
|
||||
to: '/docs/overview/what-is-backstage',
|
||||
},
|
||||
{
|
||||
from: '/docs/features/software-catalog/software-catalog-overview',
|
||||
to: '/docs/features/software-catalog/',
|
||||
},
|
||||
{
|
||||
from: '/docs/features/software-templates/software-templates-index',
|
||||
to: '/docs/features/software-templates/',
|
||||
},
|
||||
{
|
||||
from: '/docs/features/techdocs/techdocs-overview',
|
||||
to: '/docs/features/techdocs/',
|
||||
},
|
||||
{
|
||||
from: '/docs/features/search/search-overview',
|
||||
to: '/docs/features/search/',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -181,7 +197,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
label: 'Software Catalog',
|
||||
to: 'docs/features/software-catalog/software-catalog-overview',
|
||||
to: 'docs/features/software-catalog/',
|
||||
},
|
||||
{
|
||||
label: 'Create a Plugin',
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"getting-started/keeping-backstage-updated",
|
||||
"getting-started/concepts",
|
||||
"getting-started/contributors",
|
||||
"getting-started/getting-involved",
|
||||
"getting-started/project-structure"
|
||||
],
|
||||
"Local Development": [
|
||||
|
||||
@@ -188,7 +188,7 @@ const HomePage = () => {
|
||||
<h1>Learn more about the software catalog</h1>
|
||||
|
||||
<Link
|
||||
to="https://backstage.io/docs/features/software-catalog/software-catalog-overview"
|
||||
to="https://backstage.io/docs/features/software-catalog/"
|
||||
className="button button--secondary"
|
||||
>
|
||||
READ
|
||||
@@ -312,7 +312,7 @@ const HomePage = () => {
|
||||
<h1>Learn more about TechDocs</h1>
|
||||
|
||||
<Link
|
||||
to="https://backstage.io/docs/features/techdocs/techdocs-overview"
|
||||
to="https://backstage.io/docs/features/techdocs/"
|
||||
className="button button--secondary"
|
||||
>
|
||||
DOCS
|
||||
@@ -373,7 +373,7 @@ const HomePage = () => {
|
||||
<h1>Learn more about Backstage Search</h1>
|
||||
|
||||
<Link
|
||||
to="https://backstage.io/docs/features/search/search-overview"
|
||||
to="https://backstage.io/docs/features/search/"
|
||||
className="button button--secondary"
|
||||
>
|
||||
READ
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
|
||||
import nominateStyles from './nominate.module.scss';
|
||||
import Layout from '@theme/Layout';
|
||||
import clsx from 'clsx';
|
||||
import { BannerSection } from '@site/src/components/bannerSection/bannerSection';
|
||||
import { BannerSectionGrid } from '../../components/bannerSection/bannerSectionGrid';
|
||||
import { ContentBlock } from '@site/src/components/contentBlock/contentBlock';
|
||||
|
||||
const Nominate = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<div className={clsx(nominateStyles.nominatePage)}>
|
||||
<BannerSection greyBackground>
|
||||
<ContentBlock title={<h1>Contributor Spotlight nomination</h1>}>
|
||||
<iframe
|
||||
src="https://docs.google.com/forms/d/e/1FAIpQLSdiZ28O7vwHo6NrwirEzGSbuVyBANSv7ItHqRlgVvSz3Z5xqQ/viewform?embedded=true"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</ContentBlock>
|
||||
</BannerSection>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Nominate;
|
||||
@@ -0,0 +1,32 @@
|
||||
.nominatePage {
|
||||
font-size: 1.25rem;
|
||||
|
||||
&,
|
||||
& > section,
|
||||
& > section > div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
& > section > div > div {
|
||||
flex: 1;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 54px;
|
||||
line-height: 56px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
+43
-43
@@ -2623,90 +2623,90 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.36"
|
||||
"@swc/core-darwin-arm64@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.38"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.36"
|
||||
"@swc/core-darwin-x64@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.38"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.36"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.38"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.36"
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.38"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.36"
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.38"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.36"
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.38"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.36"
|
||||
"@swc/core-linux-x64-musl@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.38"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.36"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.38"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.36"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.38"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.36"
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.38":
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.38"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.36":
|
||||
version: 1.3.36
|
||||
resolution: "@swc/core@npm:1.3.36"
|
||||
version: 1.3.38
|
||||
resolution: "@swc/core@npm:1.3.38"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.3.36
|
||||
"@swc/core-darwin-x64": 1.3.36
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.36
|
||||
"@swc/core-linux-arm64-gnu": 1.3.36
|
||||
"@swc/core-linux-arm64-musl": 1.3.36
|
||||
"@swc/core-linux-x64-gnu": 1.3.36
|
||||
"@swc/core-linux-x64-musl": 1.3.36
|
||||
"@swc/core-win32-arm64-msvc": 1.3.36
|
||||
"@swc/core-win32-ia32-msvc": 1.3.36
|
||||
"@swc/core-win32-x64-msvc": 1.3.36
|
||||
"@swc/core-darwin-arm64": 1.3.38
|
||||
"@swc/core-darwin-x64": 1.3.38
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.38
|
||||
"@swc/core-linux-arm64-gnu": 1.3.38
|
||||
"@swc/core-linux-arm64-musl": 1.3.38
|
||||
"@swc/core-linux-x64-gnu": 1.3.38
|
||||
"@swc/core-linux-x64-musl": 1.3.38
|
||||
"@swc/core-win32-arm64-msvc": 1.3.38
|
||||
"@swc/core-win32-ia32-msvc": 1.3.38
|
||||
"@swc/core-win32-x64-msvc": 1.3.38
|
||||
dependenciesMeta:
|
||||
"@swc/core-darwin-arm64":
|
||||
optional: true
|
||||
@@ -2728,7 +2728,7 @@ __metadata:
|
||||
optional: true
|
||||
"@swc/core-win32-x64-msvc":
|
||||
optional: true
|
||||
checksum: 36e96e86d1ab8fd84eb51e7264a7ae781ee7e507d36b9ccc028d7f31a2ccf2949f074656e34139c970196774d24d55a54c3aa5c53d04eb6e3569c71cbfed0c0d
|
||||
checksum: c55d30e57638bcd21f788add8490c3f3e71bfe027aa5a8b153e1b1b9686ecddd6deeaaa6a6b17717c7eab4c1e2a232b465b6755b6c891506fc0d03139badfbf7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ New components, of course, get added automatically to the Backstage Service Cata
|
||||
|
||||
## Define your standards
|
||||
|
||||
Backstage ships with four example templates, but since these are likely not the (only) ones you want to promote inside your company, the next step is to add [your own templates](https://backstage.io/docs/features/software-templates/software-templates-index). Using Backstage’s Software Templates feature, it’s easy to help your engineers get started building software with your organization’s best practices built-in.
|
||||
Backstage ships with four example templates, but since these are likely not the (only) ones you want to promote inside your company, the next step is to add [your own templates](https://backstage.io/docs/features/software-templates/). Using Backstage’s Software Templates feature, it’s easy to help your engineers get started building software with your organization’s best practices built-in.
|
||||
|
||||
We have learned that one of the keys to getting these standards adopted is to keep an open process. Templates are code. By making it clear to your engineers that you are open to pull requests, and that teams with different needs can add their own templates, you are on the path of striking a good balance between autonomy and standardization.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ More specifically, with this first iteration, you can:
|
||||
- Choose your own storage solution for the documentation.
|
||||
- Define your own API to interface with your documentation solution.
|
||||
|
||||
For a full overview, including getting started instructions, check out our [TechDocs Documentation](https://backstage.io/docs/features/techdocs/techdocs-overview).
|
||||
For a full overview, including getting started instructions, check out our [TechDocs Documentation](https://backstage.io/docs/features/techdocs/).
|
||||
|
||||
But before you go there, let me tell you a bit about the TechDocs story — and why we believe TechDocs is such a powerful yet simple solution for great documentation.
|
||||
|
||||
|
||||
@@ -97,6 +97,6 @@ Whichever situation you’re in, we have you covered.
|
||||
|
||||
We’ve built the foundation for the Backstage Search platform, and we can't wait to see the exciting engines, collators, and components the community builds on the platform.
|
||||
|
||||
You can check out our [project roadmap](https://backstage.io/docs/features/search/search-overview#project-roadmap) in our search documentation or track the progress of our [Beta milestone](https://github.com/backstage/backstage/milestone/27) and [GA milestone](https://github.com/backstage/backstage/milestone/28).
|
||||
You can check out our [project roadmap](https://backstage.io/docs/features/search/#project-roadmap) in our search documentation or track the progress of our [Beta milestone](https://github.com/backstage/backstage/milestone/27) and [GA milestone](https://github.com/backstage/backstage/milestone/28).
|
||||
|
||||
For any questions, feedback or ideas about the Backstage Search platform, join us in the #search channel on [Discord](https://discord.gg/backstage-687207715902193673)!
|
||||
|
||||
@@ -25,11 +25,11 @@ To start, let’s define Backstage: it’s an open platform for building develop
|
||||
Our definition of Backstage 1.0 includes:
|
||||
|
||||
- Backstage Core 1.0 libraries as the set of libraries to make the platform work
|
||||
- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview) 1.0
|
||||
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index) 1.0
|
||||
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview) 1.0
|
||||
- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) 1.0
|
||||
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) 1.0
|
||||
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) 1.0
|
||||
|
||||
Coming soon: [Backstage Search](https://backstage.io/docs/features/search/search-overview) 1.0 will be included in the near future as part of the regular releases to the Backstage platform.
|
||||
Coming soon: [Backstage Search](https://backstage.io/docs/features/search/) 1.0 will be included in the near future as part of the regular releases to the Backstage platform.
|
||||
|
||||
In terms of features, the maintainers will not be shipping new stuff as part of the major release but instead:
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ _TL;DR:_ Introducing the TechDocs Addon Framework — a way for us all to contri
|
||||
|
||||
<!--truncate-->
|
||||
|
||||
[TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview) is a centralized platform for publishing, viewing, and discovering technical documentation across an entire organization. It's a solid foundation! But TechDocs doesn't solve higher order documentation needs on its own such as: How do you create and reinforce a culture of documentation? How do you build trust in the quality of technical documentation?
|
||||
[TechDocs](https://backstage.io/docs/features/techdocs/) is a centralized platform for publishing, viewing, and discovering technical documentation across an entire organization. It's a solid foundation! But TechDocs doesn't solve higher order documentation needs on its own such as: How do you create and reinforce a culture of documentation? How do you build trust in the quality of technical documentation?
|
||||
|
||||
To address this need, we’re proud to introduce the [TechDocs Addon Framework](https://github.com/backstage/backstage/issues/9636) — a way for us all to contribute and share additional features, TechDocs Addons, on top of the base docs-like-code experience. Using TechDocs Addons, you can customize the TechDocs experience to address some of these higher order needs.
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
# prettier-ignore
|
||||
title: Releasing Backstage Search 1.0
|
||||
title: Releasing Backstage Search 1.0
|
||||
author: Emma Indal, Spotify
|
||||
authorURL: https://www.linkedin.com/in/emma-indal
|
||||
---
|
||||
|
||||
**TL;DR** If you’ve been waiting for Backstage Search to come out of beta, we’re excited to announce that [Backstage Search 1.0](https://backstage.io/docs/features/search/search-overview#backstage-search-10) is here!
|
||||
**TL;DR** If you’ve been waiting for Backstage Search to come out of beta, we’re excited to announce that [Backstage Search 1.0](https://backstage.io/docs/features/search/#backstage-search-10) is here!
|
||||
|
||||
We first released the Backstage Search Platform over a year ago. Backstage Search Platform is a search experience built for you, by you.
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ author: Paul Cowan & Taras Mankovski
|
||||
authorURL: https://frontside.com/
|
||||
---
|
||||
|
||||
At the heart of [Backstage](https://backstage.io/) is the [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview), which is a data store that allows an organization to centralize and visualize its many software services and components. Backstage inspects and transforms an organization's disparate software services and parts into a centralized data store. This blog post introduces the concept of incremental entity providers, which allow Backstage to scale ingestion to even larger datasets.
|
||||
At the heart of [Backstage](https://backstage.io/) is the [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/), which is a data store that allows an organization to centralize and visualize its many software services and components. Backstage inspects and transforms an organization's disparate software services and parts into a centralized data store. This blog post introduces the concept of incremental entity providers, which allow Backstage to scale ingestion to even larger datasets.
|
||||
|
||||

|
||||
|
||||
<!--truncate-->
|
||||
|
||||
A common use case is for an organization to want to surface ownership and metadata about repositories. Backstage provides a mechanism for discovering and transforming repository information into a standard data structure and persisting it into the Backstage [Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview). This process is known as ingestion, where all data is transformed into a standard Backstage data structure known as an entity. Entities in the Catalog’s data store are accessible to the Backstage App via the REST API.
|
||||
A common use case is for an organization to want to surface ownership and metadata about repositories. Backstage provides a mechanism for discovering and transforming repository information into a standard data structure and persisting it into the Backstage [Catalog](https://backstage.io/docs/features/software-catalog/). This process is known as ingestion, where all data is transformed into a standard Backstage data structure known as an entity. Entities in the Catalog’s data store are accessible to the Backstage App via the REST API.
|
||||
|
||||
Data is transformed into entities via what is known as the ingestion and processing loop, which can be thought of as an [extract, transform and load (ETL) pipeline](https://en.wikipedia.org/wiki/Extract,_transform,_load), where raw data such as GitHub repositories are loaded from GitHub, transformed into entities and outputted to the Catalog.
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: PuppetDB Entity Provider
|
||||
author: TDabasinskas
|
||||
authorUrl: https://github.com/tdabasinskas
|
||||
category: Configuration Management
|
||||
description: Import nodes from PuppetDB into Backstage as Resource Entities
|
||||
documentation: https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-puppetdb/README.md
|
||||
iconUrl: https://avatars.githubusercontent.com/u/234268?s=200&v=4
|
||||
npmPackageName: '@backstage/plugin-catalog-backend-module-puppetdb'
|
||||
tags:
|
||||
- puppet
|
||||
- puppetdb
|
||||
addedDate: '2023-02-06'
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Harness Feature Flags
|
||||
author: harness.io
|
||||
authorUrl: https://github.com/harness/backstage-plugins
|
||||
category: Feature Flags
|
||||
description: This plugin lets you view Harness Feature Flags created in your project inside Backstage.
|
||||
documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/harness-feature-flags
|
||||
iconUrl: https://static.harness.io/ng-static/images/favicon.png
|
||||
npmPackageName: '@harnessio/backstage-plugin-feature-flags'
|
||||
tags:
|
||||
- feature-flags
|
||||
addedDate: '2023-03-01'
|
||||
@@ -5,7 +5,7 @@ authorUrl: https://github.com/mufaddal7
|
||||
category: Monitoring
|
||||
description: Easily view your New Relic Dashboards in Backstage, via real-time snapshots of your dashboards
|
||||
documentation: https://github.com/backstage/backstage/tree/master/plugins/newrelic-dashboard
|
||||
iconUrl: https://newrelic.com/themes/custom/curio/assets/mediakit/NR_logo_Horizontal_Rev.svg
|
||||
iconUrl: https://newrelic.com/themes/custom/erno/assets/mediakit/new_relic_logo_vertical_white.svg
|
||||
npmPackageName: '@backstage/plugin-newrelic-dashboard'
|
||||
tags:
|
||||
- performance
|
||||
|
||||
@@ -24,7 +24,7 @@ const truncate = text =>
|
||||
const newForDays = 100;
|
||||
|
||||
const addPluginDocsLink = '/docs/plugins/add-to-marketplace';
|
||||
const defaultIconUrl = 'img/logo-gradient-on-dark.svg';
|
||||
const defaultIconUrl = '/img/logo-gradient-on-dark.svg';
|
||||
|
||||
const Plugins = () => (
|
||||
<main className="MainContent">
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
<svg id="Logos" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 140"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M19.13 103.13c9.35-6 20.33-16.34 16.16-28.5C33 68 29.87 62.33 29.45 55.17a43.84 43.84 0 0 1 2.66-17.83C40.49 14.85 65.4 4.2 87.92 11c20.85 6.26 35.2 30.48 26.56 51.58-5 12.18-7.22 21.58 3.9 31.05 3 2.57 10.33 6.42 10.31 11 0 6-11.74-1.27-13-2.31 1.49 2.6 16.24 18 6.85 19.08-8.64 1-16.27-11.06-21.47-16.25-8.72-8.7-7.21 10.55-7.25 14.53-.06 6.28-4.5 19-12.46 10.72-6.58-6.84-4.09-17.76-8.66-25.36-5-8.33-13.34 8.33-15.42 11.37-2.33 3.4-14 19.89-18.59 11.1-3.76-7.13 2.25-18.3 5.2-24.75-1.08 2.34-8.71 5.8-10.94 6.93-5 2.54-10.15 4.05-15.82 3.65-11.73-.84-2.73-7.07 2-10.15z"/></svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 140 140" style="enable-background:new 0 0 140 140;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#0D80D8;}
|
||||
</style>
|
||||
<path class="st0" d="M19.1,102.1c9.4-6,20.3-16.3,16.2-28.5C33,67,29.9,61.3,29.5,54.2C29.1,48.1,30,42,32.1,36.3
|
||||
C40.5,13.8,65.4,3.2,87.9,10c20.8,6.3,35.2,30.5,26.6,51.6c-5,12.2-7.2,21.6,3.9,31c3,2.6,10.3,6.4,10.3,11c0,6-11.7-1.3-13-2.3
|
||||
c1.5,2.6,16.2,18,6.8,19.1c-8.6,1-16.3-11.1-21.5-16.2c-8.7-8.7-7.2,10.6-7.2,14.5c-0.1,6.3-4.5,19-12.5,10.7
|
||||
c-6.6-6.8-4.1-17.8-8.7-25.4c-5-8.3-13.3,8.3-15.4,11.4c-2.3,3.4-14,19.9-18.6,11.1c-3.8-7.1,2.2-18.3,5.2-24.8
|
||||
c-1.1,2.3-8.7,5.8-10.9,6.9c-5,2.5-10.1,4.1-15.8,3.7C5.4,111.5,14.4,105.3,19.1,102.1L19.1,102.1z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 962 B |
+1
-1
@@ -47,7 +47,7 @@
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17"
|
||||
},
|
||||
"version": "1.12.0-next.1",
|
||||
"version": "1.12.0-next.2",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3"
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.2.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.5-next.2
|
||||
- @backstage/core-app-api@1.6.0-next.2
|
||||
- @backstage/core-plugin-api@1.5.0-next.2
|
||||
- @backstage/plugin-permission-react@0.4.11-next.2
|
||||
|
||||
## 1.2.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"version": "1.2.1-next.1",
|
||||
"version": "1.2.1-next.2",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.81-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.5-next.2
|
||||
- @backstage/plugin-scaffolder-react@1.2.0-next.2
|
||||
- @backstage/plugin-techdocs-react@1.1.4-next.2
|
||||
- @backstage/plugin-catalog-react@1.4.0-next.2
|
||||
- @backstage/plugin-tech-insights@0.3.8-next.2
|
||||
- @backstage/plugin-search-react@1.5.1-next.2
|
||||
- @backstage/plugin-scaffolder@1.12.0-next.2
|
||||
- @backstage/plugin-techdocs@1.6.0-next.2
|
||||
- @backstage/plugin-explore@0.4.1-next.2
|
||||
- @backstage/plugin-search@1.1.1-next.2
|
||||
- @backstage/plugin-kubernetes@0.7.9-next.2
|
||||
- @backstage/plugin-api-docs@0.9.1-next.2
|
||||
- @backstage/core-app-api@1.6.0-next.2
|
||||
- @backstage/plugin-org@0.6.6-next.2
|
||||
- @backstage/core-plugin-api@1.5.0-next.2
|
||||
- @backstage/app-defaults@1.2.1-next.2
|
||||
- @backstage/cli@0.22.4-next.1
|
||||
- @backstage/integration-react@1.1.11-next.2
|
||||
- @backstage/plugin-airbrake@0.3.16-next.2
|
||||
- @backstage/plugin-apache-airflow@0.2.9-next.2
|
||||
- @backstage/plugin-azure-devops@0.2.7-next.2
|
||||
- @backstage/plugin-azure-sites@0.1.5-next.2
|
||||
- @backstage/plugin-badges@0.2.40-next.2
|
||||
- @backstage/plugin-catalog-graph@0.2.28-next.2
|
||||
- @backstage/plugin-catalog-import@0.9.6-next.2
|
||||
- @backstage/plugin-circleci@0.3.16-next.2
|
||||
- @backstage/plugin-cloudbuild@0.3.16-next.2
|
||||
- @backstage/plugin-code-coverage@0.2.9-next.2
|
||||
- @backstage/plugin-cost-insights@0.12.5-next.2
|
||||
- @backstage/plugin-dynatrace@3.0.0-next.2
|
||||
- @backstage/plugin-entity-feedback@0.1.1-next.2
|
||||
- @backstage/plugin-gcalendar@0.3.12-next.2
|
||||
- @backstage/plugin-gcp-projects@0.3.35-next.2
|
||||
- @backstage/plugin-github-actions@0.5.16-next.2
|
||||
- @backstage/plugin-gocd@0.1.22-next.2
|
||||
- @backstage/plugin-graphiql@0.2.48-next.2
|
||||
- @backstage/plugin-home@0.4.32-next.2
|
||||
- @backstage/plugin-jenkins@0.7.15-next.2
|
||||
- @backstage/plugin-kafka@0.3.16-next.2
|
||||
- @backstage/plugin-lighthouse@0.4.1-next.2
|
||||
- @backstage/plugin-linguist@0.1.1-next.2
|
||||
- @backstage/plugin-microsoft-calendar@0.1.1-next.2
|
||||
- @backstage/plugin-newrelic@0.3.34-next.2
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.9-next.2
|
||||
- @backstage/plugin-pagerduty@0.5.9-next.2
|
||||
- @backstage/plugin-playlist@0.1.7-next.2
|
||||
- @backstage/plugin-rollbar@0.4.16-next.2
|
||||
- @backstage/plugin-sentry@0.5.1-next.2
|
||||
- @backstage/plugin-shortcuts@0.3.8-next.2
|
||||
- @backstage/plugin-stack-overflow@0.1.12-next.2
|
||||
- @backstage/plugin-stackstorm@0.1.0-next.2
|
||||
- @backstage/plugin-tech-radar@0.6.2-next.2
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.0.11-next.2
|
||||
- @backstage/plugin-todo@0.2.18-next.2
|
||||
- @backstage/plugin-user-settings@0.7.1-next.2
|
||||
- @internal/plugin-catalog-customized@0.0.8-next.2
|
||||
- @backstage/plugin-permission-react@0.4.11-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
|
||||
## 0.2.81-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.81-next.1",
|
||||
"version": "0.2.81-next.2",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.4.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-auth-node@0.2.12-next.2
|
||||
- @backstage/backend-tasks@0.5.0-next.2
|
||||
- @backstage/backend-common@0.18.3-next.2
|
||||
- @backstage/backend-plugin-api@0.4.1-next.2
|
||||
- @backstage/plugin-permission-node@0.7.6-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
|
||||
## 0.4.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.4.1-next.1",
|
||||
"version": "0.4.1-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.18.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f75097868a7: Adds config option `backend.database.role` to set ownership for newly created schemas and tables in Postgres
|
||||
|
||||
The example config below connects to the database as user `v-backstage-123` but sets the ownership of
|
||||
the create schemas and tables to `backstage`
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
database:
|
||||
client: pg
|
||||
pluginDivisionMode: schema
|
||||
role: backstage
|
||||
connection:
|
||||
user: v-backstage-123
|
||||
...
|
||||
```
|
||||
|
||||
- 87f0bbec175: AwsS3UrlReader upgraded to use aws-sdk v3
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.4.1-next.2
|
||||
- @backstage/backend-plugin-api@0.4.1-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
- @backstage/integration@1.4.3-next.0
|
||||
- @backstage/integration-aws-node@0.1.2-next.0
|
||||
|
||||
## 0.18.3-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="webpack-env" />
|
||||
|
||||
import aws from 'aws-sdk';
|
||||
import { AwsCredentialsManager } from '@backstage/integration-aws-node';
|
||||
import { AwsS3Integration } from '@backstage/integration';
|
||||
import { AzureIntegration } from '@backstage/integration';
|
||||
import { BackendFeature } from '@backstage/backend-plugin-api';
|
||||
@@ -67,9 +67,9 @@ import { Writable } from 'stream';
|
||||
// @public
|
||||
export class AwsS3UrlReader implements UrlReader {
|
||||
constructor(
|
||||
credsManager: AwsCredentialsManager,
|
||||
integration: AwsS3Integration,
|
||||
deps: {
|
||||
s3: aws.S3;
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
},
|
||||
);
|
||||
|
||||
Vendored
+4
@@ -96,6 +96,8 @@ export interface Config {
|
||||
* @default database
|
||||
*/
|
||||
pluginDivisionMode?: 'database' | 'schema';
|
||||
/** Configures the ownership of newly created schemas in pg databases. */
|
||||
role?: string;
|
||||
/**
|
||||
* Arbitrary config object to pass to knex when initializing
|
||||
* (https://knexjs.org/#Installation-client). Most notable is the debug
|
||||
@@ -125,6 +127,8 @@ export interface Config {
|
||||
* This is merged recursively into the base knexConfig
|
||||
*/
|
||||
knexConfig?: object;
|
||||
/** Configures the ownership of newly created schemas in pg databases. */
|
||||
role?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.18.3-next.1",
|
||||
"version": "0.18.3-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
@@ -46,6 +46,10 @@
|
||||
"test:kubernetes": "backstage-cli package test -t KubernetesContainerRunner --no-watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/abort-controller": "^3.208.0",
|
||||
"@aws-sdk/client-s3": "^3.208.0",
|
||||
"@aws-sdk/credential-providers": "^3.208.0",
|
||||
"@aws-sdk/types": "^3.208.0",
|
||||
"@backstage/backend-app-api": "workspace:^",
|
||||
"@backstage/backend-dev-utils": "workspace:^",
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
@@ -54,6 +58,7 @@
|
||||
"@backstage/config-loader": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/integration": "workspace:^",
|
||||
"@backstage/integration-aws-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@google-cloud/storage": "^6.0.0",
|
||||
"@keyv/memcache": "^1.3.5",
|
||||
@@ -67,7 +72,6 @@
|
||||
"@types/luxon": "^3.0.0",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"archiver": "^5.0.2",
|
||||
"aws-sdk": "^2.840.0",
|
||||
"base64-stream": "^1.0.0",
|
||||
"compression": "^1.7.4",
|
||||
"concat-stream": "^2.0.0",
|
||||
@@ -90,6 +94,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-forge": "^1.3.1",
|
||||
"pg": "^8.3.0",
|
||||
"raw-body": "^2.4.1",
|
||||
"request": "^2.88.2",
|
||||
"selfsigned": "^2.0.0",
|
||||
@@ -110,6 +115,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/util-stream-node": "^3.208.0",
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/archiver": "^5.1.0",
|
||||
@@ -122,12 +128,14 @@
|
||||
"@types/mock-fs": "^4.13.0",
|
||||
"@types/morgan": "^1.9.0",
|
||||
"@types/node-forge": "^1.3.0",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/recursive-readdir": "^2.2.0",
|
||||
"@types/stoppable": "^1.1.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"@types/tar": "^6.1.1",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@types/yauzl": "^2.10.0",
|
||||
"aws-sdk-client-mock": "^2.0.0",
|
||||
"aws-sdk-mock": "^5.2.1",
|
||||
"better-sqlite3": "^8.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
|
||||
@@ -687,5 +687,59 @@ describe('DatabaseManager', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('sets the owner config for plugin using default config', async () => {
|
||||
const testManager = DatabaseManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
database: {
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host: 'localhost',
|
||||
database: 'foodb',
|
||||
},
|
||||
role: 'backstage',
|
||||
plugin: {
|
||||
testowner: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
await testManager.forPlugin('testowner').getClient();
|
||||
|
||||
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
|
||||
const [baseConfig] = mockCalls[0];
|
||||
|
||||
expect(baseConfig.data.role).toEqual('backstage');
|
||||
});
|
||||
|
||||
it('sets the owner config for plugin using plugin config', async () => {
|
||||
const testManager = DatabaseManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
database: {
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host: 'localhost',
|
||||
database: 'foodb',
|
||||
},
|
||||
role: 'backstage',
|
||||
plugin: {
|
||||
testowner: {
|
||||
role: 'backstage-plugin',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
await testManager.forPlugin('testowner').getClient();
|
||||
|
||||
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
|
||||
const [baseConfig] = mockCalls[0];
|
||||
|
||||
expect(baseConfig.data.role).toEqual('backstage-plugin');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,6 +186,13 @@ export class DatabaseManager {
|
||||
};
|
||||
}
|
||||
|
||||
private getRoleConfig(pluginId: string): string | undefined {
|
||||
return (
|
||||
this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??
|
||||
this.config.getOptionalString('role')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the knexConfig which should be used for a given plugin.
|
||||
*
|
||||
@@ -278,11 +285,13 @@ export class DatabaseManager {
|
||||
*/
|
||||
private getConfigForPlugin(pluginId: string): Knex.Config {
|
||||
const { client } = this.getClientType(pluginId);
|
||||
const role = this.getRoleConfig(pluginId);
|
||||
|
||||
return {
|
||||
...this.getAdditionalKnexConfig(pluginId),
|
||||
client,
|
||||
connection: this.getConnectionConfig(pluginId),
|
||||
...(role && { role }),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { mergeDatabaseConfig } from '../config';
|
||||
import { DatabaseConnector } from '../types';
|
||||
import defaultNameOverride from './defaultNameOverride';
|
||||
import defaultSchemaOverride from './defaultSchemaOverride';
|
||||
import { Client } from 'pg';
|
||||
|
||||
/**
|
||||
* Creates a knex postgres database connection
|
||||
@@ -35,6 +36,17 @@ export function createPgDatabaseClient(
|
||||
) {
|
||||
const knexConfig = buildPgDatabaseConfig(dbConfig, overrides);
|
||||
const database = knexFactory(knexConfig);
|
||||
|
||||
const role = dbConfig.getOptionalString('role');
|
||||
|
||||
if (role) {
|
||||
database.client.pool.on(
|
||||
'createSuccess',
|
||||
async (_event: number, pgClient: Client) => {
|
||||
await pgClient.query(`SET ROLE ${role}`);
|
||||
},
|
||||
);
|
||||
}
|
||||
return database;
|
||||
}
|
||||
|
||||
@@ -147,10 +159,18 @@ export async function ensurePgSchemaExists(
|
||||
...schemas: Array<string>
|
||||
): Promise<void> {
|
||||
const admin = createPgDatabaseClient(dbConfig);
|
||||
const role = dbConfig.getOptionalString('role');
|
||||
|
||||
try {
|
||||
const ensureSchema = async (database: string) => {
|
||||
await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);
|
||||
if (role) {
|
||||
await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [
|
||||
database,
|
||||
role,
|
||||
]);
|
||||
} else {
|
||||
await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(schemas.map(ensureSchema));
|
||||
|
||||
@@ -18,19 +18,25 @@ import { ConfigReader } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { getVoidLogger } from '../logging';
|
||||
import { DefaultReadTreeResponseFactory } from './tree';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { setupRequestMockHandlers } from '@backstage/backend-test-utils';
|
||||
import { AwsS3UrlReader, parseUrl } from './AwsS3UrlReader';
|
||||
import { DEFAULT_REGION, AwsS3UrlReader, parseUrl } from './AwsS3UrlReader';
|
||||
import {
|
||||
AwsS3Integration,
|
||||
readAwsS3IntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { DefaultAwsCredentialsManager } from '@backstage/integration-aws-node';
|
||||
import { UrlReaderPredicateTuple } from './types';
|
||||
import AWSMock from 'aws-sdk-mock';
|
||||
import aws from 'aws-sdk';
|
||||
import path from 'path';
|
||||
import { NotModifiedError } from '@backstage/errors';
|
||||
import { mockClient } from 'aws-sdk-client-mock';
|
||||
import {
|
||||
S3Client,
|
||||
ListObjectsV2Command,
|
||||
ListObjectsV2Output,
|
||||
GetObjectCommand,
|
||||
S3ServiceException,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { sdkStreamMixin } from '@aws-sdk/util-stream-node';
|
||||
import fs from 'fs';
|
||||
|
||||
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
|
||||
config: new ConfigReader({}),
|
||||
@@ -97,7 +103,7 @@ describe('parseUrl', () => {
|
||||
).toEqual({
|
||||
path: 'a/puppy.jpg',
|
||||
bucket: 'my.bucket-3',
|
||||
region: '',
|
||||
region: DEFAULT_REGION,
|
||||
});
|
||||
expect(
|
||||
parseUrl('https://my.bucket-3.my-host.com/a/puppy.jpg', {
|
||||
@@ -106,7 +112,7 @@ describe('parseUrl', () => {
|
||||
).toEqual({
|
||||
path: 'a/puppy.jpg',
|
||||
bucket: 'my.bucket-3',
|
||||
region: '',
|
||||
region: DEFAULT_REGION,
|
||||
});
|
||||
expect(
|
||||
parseUrl('https://ignored.my-host.com/my.bucket-3/a/puppy.jpg', {
|
||||
@@ -116,14 +122,13 @@ describe('parseUrl', () => {
|
||||
).toEqual({
|
||||
path: 'a/puppy.jpg',
|
||||
bucket: 'my.bucket-3',
|
||||
region: '',
|
||||
region: DEFAULT_REGION,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AwsS3UrlReader', () => {
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
const s3Client = mockClient(S3Client);
|
||||
|
||||
const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => {
|
||||
return AwsS3UrlReader.factory({
|
||||
@@ -232,17 +237,19 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('ETag', '123abc'),
|
||||
ctx.body('site_name: Test'),
|
||||
s3Client.reset();
|
||||
|
||||
s3Client.on(GetObjectCommand).resolves({
|
||||
Body: sdkStreamMixin(
|
||||
fs.createReadStream(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
ETag: '123abc',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
@@ -280,17 +287,19 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('ETag', '123abc'),
|
||||
ctx.body('site_name: Test'),
|
||||
s3Client.reset();
|
||||
|
||||
s3Client.on(GetObjectCommand).resolves({
|
||||
Body: sdkStreamMixin(
|
||||
fs.createReadStream(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
ETag: '123abc',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket via buffer', async () => {
|
||||
@@ -340,17 +349,17 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'http://localhost:4566/test-bucket/awsS3-mock-object.yaml',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('ETag', '123abc'),
|
||||
ctx.body('site_name: Test'),
|
||||
s3Client.on(GetObjectCommand).resolves({
|
||||
Body: sdkStreamMixin(
|
||||
fs.createReadStream(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
ETag: '123abc',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket via buffer', async () => {
|
||||
@@ -377,12 +386,13 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
|
||||
(_, res, ctx) => res(ctx.status(304)),
|
||||
),
|
||||
);
|
||||
s3Client.reset();
|
||||
const t = new S3ServiceException({
|
||||
name: '304',
|
||||
$fault: 'client',
|
||||
$metadata: { httpStatusCode: 304 },
|
||||
});
|
||||
s3Client.on(GetObjectCommand).rejects(t);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
@@ -400,44 +410,43 @@ describe('AwsS3UrlReader', () => {
|
||||
describe('readTree', () => {
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
beforeAll(() => {
|
||||
const object: aws.S3.Types.Object = {
|
||||
beforeEach(() => {
|
||||
s3Client.reset();
|
||||
|
||||
const object: Object = {
|
||||
Key: 'awsS3-mock-object.yaml',
|
||||
};
|
||||
|
||||
const objectList: aws.S3.ObjectList = [object];
|
||||
const output: aws.S3.Types.ListObjectsV2Output = {
|
||||
const objectList: Object[] = [object];
|
||||
const output: ListObjectsV2Output = {
|
||||
Contents: objectList,
|
||||
};
|
||||
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock('S3', 'listObjectsV2', output);
|
||||
s3Client.on(ListObjectsV2Command).resolves(output);
|
||||
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
s3Client.on(GetObjectCommand).resolves({
|
||||
Body: sdkStreamMixin(
|
||||
fs.createReadStream(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
const config = new ConfigReader({
|
||||
host: '.amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
});
|
||||
|
||||
const credsManager = DefaultAwsCredentialsManager.fromConfig(config);
|
||||
|
||||
const s3 = new aws.S3();
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: '.amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
credsManager,
|
||||
new AwsS3Integration(readAwsS3IntegrationConfig(config)),
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// note: We do the import like this so that we don't get issues destructuring
|
||||
// and it not being mocked by the aws-sdk-mock package which is unfortunate.
|
||||
import aws from 'aws-sdk';
|
||||
import { CredentialsOptions } from 'aws-sdk/lib/credentials';
|
||||
import {
|
||||
ReaderFactory,
|
||||
ReadTreeOptions,
|
||||
@@ -28,16 +24,29 @@ import {
|
||||
SearchResponse,
|
||||
UrlReader,
|
||||
} from './types';
|
||||
import {
|
||||
AwsCredentialsManager,
|
||||
DefaultAwsCredentialsManager,
|
||||
} from '@backstage/integration-aws-node';
|
||||
import {
|
||||
AwsS3Integration,
|
||||
ScmIntegrations,
|
||||
AwsS3IntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { ForwardedError, NotModifiedError } from '@backstage/errors';
|
||||
import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3';
|
||||
import { fromTemporaryCredentials } from '@aws-sdk/credential-providers';
|
||||
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
|
||||
import {
|
||||
S3Client,
|
||||
ListObjectsV2Command,
|
||||
ListObjectsV2CommandOutput,
|
||||
GetObjectCommand,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { AbortController } from '@aws-sdk/abort-controller';
|
||||
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
const DEFAULT_REGION = 'us-east-1';
|
||||
export const DEFAULT_REGION = 'us-east-1';
|
||||
|
||||
/**
|
||||
* Path style URLs: https://s3.(region).amazonaws.com/(bucket)/(key)
|
||||
@@ -105,14 +114,14 @@ export function parseUrl(
|
||||
return {
|
||||
path: pathname.substring(slashIndex + 1),
|
||||
bucket: pathname.substring(0, slashIndex),
|
||||
region: '',
|
||||
region: DEFAULT_REGION,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
path: pathname,
|
||||
bucket: host.substring(0, host.length - config.host.length - 1),
|
||||
region: '',
|
||||
region: DEFAULT_REGION,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -124,18 +133,10 @@ export function parseUrl(
|
||||
export class AwsS3UrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const credsManager = DefaultAwsCredentialsManager.fromConfig(config);
|
||||
|
||||
return integrations.awsS3.list().map(integration => {
|
||||
const credentials = AwsS3UrlReader.buildCredentials(integration);
|
||||
|
||||
const s3 = new aws.S3({
|
||||
apiVersion: '2006-03-01',
|
||||
credentials,
|
||||
endpoint: integration.config.endpoint,
|
||||
s3ForcePathStyle: integration.config.s3ForcePathStyle,
|
||||
});
|
||||
const reader = new AwsS3UrlReader(integration, {
|
||||
s3,
|
||||
const reader = new AwsS3UrlReader(credsManager, integration, {
|
||||
treeResponseFactory,
|
||||
});
|
||||
const predicate = (url: URL) =>
|
||||
@@ -145,9 +146,9 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
};
|
||||
|
||||
constructor(
|
||||
private readonly credsManager: AwsCredentialsManager,
|
||||
private readonly integration: AwsS3Integration,
|
||||
private readonly deps: {
|
||||
s3: aws.S3;
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
},
|
||||
) {}
|
||||
@@ -156,39 +157,93 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
* If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:
|
||||
* https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html
|
||||
*/
|
||||
private static buildCredentials(
|
||||
private static buildStaticCredentials(
|
||||
accessKeyId: string,
|
||||
secretAccessKey: string,
|
||||
): AwsCredentialIdentityProvider {
|
||||
return async () => {
|
||||
return {
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private static async buildCredentials(
|
||||
credsManager: AwsCredentialsManager,
|
||||
region: string,
|
||||
integration?: AwsS3Integration,
|
||||
): aws.Credentials | CredentialsOptions | undefined {
|
||||
): Promise<AwsCredentialIdentityProvider> {
|
||||
// Fall back to the default credential chain if neither account ID
|
||||
// nor explicit credentials are provided
|
||||
if (!integration) {
|
||||
return undefined;
|
||||
return (await credsManager.getCredentialProvider()).sdkCredentialProvider;
|
||||
}
|
||||
|
||||
const accessKeyId = integration.config.accessKeyId;
|
||||
const secretAccessKey = integration.config.secretAccessKey;
|
||||
let explicitCredentials: aws.Credentials | undefined;
|
||||
|
||||
let explicitCredentials: AwsCredentialIdentityProvider;
|
||||
if (accessKeyId && secretAccessKey) {
|
||||
explicitCredentials = new aws.Credentials({
|
||||
explicitCredentials = AwsS3UrlReader.buildStaticCredentials(
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
});
|
||||
);
|
||||
} else {
|
||||
explicitCredentials = (await credsManager.getCredentialProvider())
|
||||
.sdkCredentialProvider;
|
||||
}
|
||||
|
||||
const roleArn = integration.config.roleArn;
|
||||
if (roleArn) {
|
||||
return new aws.ChainableTemporaryCredentials({
|
||||
return fromTemporaryCredentials({
|
||||
masterCredentials: explicitCredentials,
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-s3-url-reader',
|
||||
RoleArn: roleArn,
|
||||
ExternalId: integration.config.externalId,
|
||||
},
|
||||
clientConfig: { region },
|
||||
});
|
||||
}
|
||||
|
||||
return explicitCredentials;
|
||||
}
|
||||
|
||||
private async buildS3Client(
|
||||
credsManager: AwsCredentialsManager,
|
||||
region: string,
|
||||
integration: AwsS3Integration,
|
||||
): Promise<S3Client> {
|
||||
const credentials = await AwsS3UrlReader.buildCredentials(
|
||||
credsManager,
|
||||
region,
|
||||
integration,
|
||||
);
|
||||
|
||||
const s3 = new S3Client({
|
||||
region: region,
|
||||
credentials: credentials,
|
||||
endpoint: integration.config.endpoint,
|
||||
forcePathStyle: integration.config.s3ForcePathStyle,
|
||||
});
|
||||
return s3;
|
||||
}
|
||||
|
||||
private async retrieveS3ObjectData(stream: Readable): Promise<Readable> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const chunks: any[] = [];
|
||||
stream.on('data', chunk => chunks.push(chunk));
|
||||
stream.on('error', (e: Error) =>
|
||||
reject(new ForwardedError('Unable to read stream', e)),
|
||||
);
|
||||
stream.on('end', () => resolve(Readable.from(Buffer.concat(chunks))));
|
||||
} catch (e) {
|
||||
throw new ForwardedError('Unable to parse the response data', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async read(url: string): Promise<Buffer> {
|
||||
const response = await this.readUrl(url);
|
||||
return response.buffer();
|
||||
@@ -200,7 +255,12 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
): Promise<ReadUrlResponse> {
|
||||
try {
|
||||
const { path, bucket, region } = parseUrl(url, this.integration.config);
|
||||
aws.config.update({ region: region });
|
||||
const s3Client = await this.buildS3Client(
|
||||
this.credsManager,
|
||||
region,
|
||||
this.integration,
|
||||
);
|
||||
const abortController = new AbortController();
|
||||
|
||||
let params;
|
||||
if (options?.etag) {
|
||||
@@ -215,44 +275,22 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
Key: path,
|
||||
};
|
||||
}
|
||||
|
||||
const request = this.deps.s3.getObject(params);
|
||||
options?.signal?.addEventListener('abort', () => request.abort());
|
||||
|
||||
// Since we're consuming the read stream we need to consume headers and errors via events.
|
||||
const etagPromise = new Promise<string | undefined>((resolve, reject) => {
|
||||
request.on('httpHeaders', (status, headers) => {
|
||||
if (status < 400) {
|
||||
if (status === 200) {
|
||||
resolve(headers.etag);
|
||||
} else if (status !== 304 /* not modified */) {
|
||||
reject(
|
||||
new Error(
|
||||
`S3 readUrl request received unexpected status '${status}' in response`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
request.on('error', error => reject(error));
|
||||
request.on('complete', () =>
|
||||
reject(
|
||||
new Error('S3 readUrl request completed without receiving headers'),
|
||||
),
|
||||
);
|
||||
options?.signal?.addEventListener('abort', () => abortController.abort());
|
||||
const getObjectCommand = new GetObjectCommand(params);
|
||||
const response = await s3Client.send(getObjectCommand, {
|
||||
abortSignal: abortController.signal,
|
||||
});
|
||||
|
||||
const stream = request.createReadStream();
|
||||
stream.on('error', () => {
|
||||
// The AWS SDK forwards request errors to the stream, so we need to
|
||||
// ignore those errors here or the process will crash.
|
||||
});
|
||||
const s3ObjectData = await this.retrieveS3ObjectData(
|
||||
response.Body as Readable,
|
||||
);
|
||||
const etag = response.ETag;
|
||||
|
||||
return ReadUrlResponseFactory.fromReadable(stream, {
|
||||
etag: await etagPromise,
|
||||
return ReadUrlResponseFactory.fromReadable(s3ObjectData, {
|
||||
etag: etag,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.statusCode === 304) {
|
||||
if (e.$metadata && e.$metadata.httpStatusCode === 304) {
|
||||
throw new NotModifiedError();
|
||||
}
|
||||
|
||||
@@ -266,35 +304,49 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
): Promise<ReadTreeResponse> {
|
||||
try {
|
||||
const { path, bucket, region } = parseUrl(url, this.integration.config);
|
||||
const allObjects: ObjectList = [];
|
||||
const s3Client = await this.buildS3Client(
|
||||
this.credsManager,
|
||||
region,
|
||||
this.integration,
|
||||
);
|
||||
const abortController = new AbortController();
|
||||
const allObjects: String[] = [];
|
||||
const responses = [];
|
||||
let continuationToken: string | undefined;
|
||||
let output: ListObjectsV2Output;
|
||||
let output: ListObjectsV2CommandOutput;
|
||||
do {
|
||||
aws.config.update({ region: region });
|
||||
const request = this.deps.s3.listObjectsV2({
|
||||
const listObjectsV2Command = new ListObjectsV2Command({
|
||||
Bucket: bucket,
|
||||
ContinuationToken: continuationToken,
|
||||
Prefix: path,
|
||||
});
|
||||
options?.signal?.addEventListener('abort', () => request.abort());
|
||||
output = await request.promise();
|
||||
options?.signal?.addEventListener('abort', () =>
|
||||
abortController.abort(),
|
||||
);
|
||||
output = await s3Client.send(listObjectsV2Command, {
|
||||
abortSignal: abortController.signal,
|
||||
});
|
||||
if (output.Contents) {
|
||||
output.Contents.forEach(contents => {
|
||||
allObjects.push(contents);
|
||||
allObjects.push(contents.Key!);
|
||||
});
|
||||
}
|
||||
continuationToken = output.NextContinuationToken;
|
||||
} while (continuationToken);
|
||||
|
||||
for (let i = 0; i < allObjects.length; i++) {
|
||||
const object = this.deps.s3.getObject({
|
||||
const getObjectCommand = new GetObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: String(allObjects[i].Key),
|
||||
Key: String(allObjects[i]),
|
||||
});
|
||||
const response = await s3Client.send(getObjectCommand);
|
||||
const s3ObjectData = await this.retrieveS3ObjectData(
|
||||
response.Body as Readable,
|
||||
);
|
||||
|
||||
responses.push({
|
||||
data: object.createReadStream(),
|
||||
path: String(allObjects[i].Key),
|
||||
data: s3ObjectData,
|
||||
path: String(allObjects[i]),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.1.8-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.3-next.2
|
||||
- @backstage/backend-app-api@0.4.1-next.2
|
||||
- @backstage/backend-plugin-api@0.4.1-next.2
|
||||
|
||||
## 0.1.8-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.1.8-next.1",
|
||||
"version": "0.1.8-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-scaffolder-backend@1.12.0-next.2
|
||||
- @backstage/backend-defaults@0.1.8-next.2
|
||||
- @backstage/plugin-app-backend@0.3.43-next.2
|
||||
- @backstage/plugin-catalog-backend@1.8.0-next.2
|
||||
- @backstage/plugin-todo-backend@0.1.40-next.2
|
||||
|
||||
## 0.0.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.9-next.1",
|
||||
"version": "0.0.9-next.2",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.4.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-auth-node@0.2.12-next.2
|
||||
- @backstage/backend-tasks@0.5.0-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
|
||||
## 0.4.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"version": "0.4.1-next.1",
|
||||
"version": "0.4.1-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.5.0-next.2
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 1578276708a: add functionality to get descriptions from the scheduler for triggering
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.3-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
|
||||
## 0.4.4-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Config } from '@backstage/config';
|
||||
import { DatabaseManager } from '@backstage/backend-common';
|
||||
import { Duration } from 'luxon';
|
||||
import { HumanDuration as HumanDuration_2 } from '@backstage/types';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { Logger } from 'winston';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
|
||||
@@ -16,6 +17,7 @@ export type HumanDuration = HumanDuration_2;
|
||||
// @public
|
||||
export interface PluginTaskScheduler {
|
||||
createScheduledTaskRunner(schedule: TaskScheduleDefinition): TaskRunner;
|
||||
getScheduledTasks(): Promise<TaskDescriptor[]>;
|
||||
scheduleTask(
|
||||
task: TaskScheduleDefinition & TaskInvocationDefinition,
|
||||
): Promise<void>;
|
||||
@@ -27,6 +29,15 @@ export function readTaskScheduleDefinitionFromConfig(
|
||||
config: Config,
|
||||
): TaskScheduleDefinition;
|
||||
|
||||
// @public
|
||||
export type TaskDescriptor = {
|
||||
id: string;
|
||||
scope: 'global' | 'local';
|
||||
settings: {
|
||||
version: number;
|
||||
} & JsonObject;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TaskFunction =
|
||||
| ((abortSignal: AbortSignal) => void | Promise<void>)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.4.4-next.1",
|
||||
"version": "0.5.0-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2022 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 { Knex } from 'knex';
|
||||
import { TestDatabases } from '@backstage/backend-test-utils';
|
||||
import fs from 'fs';
|
||||
|
||||
const migrationsDir = `${__dirname}/../migrations`;
|
||||
const migrationsFiles = fs.readdirSync(migrationsDir).sort();
|
||||
|
||||
async function migrateUpOnce(knex: Knex): Promise<void> {
|
||||
await knex.migrate.up({ directory: migrationsDir });
|
||||
}
|
||||
|
||||
async function migrateDownOnce(knex: Knex): Promise<void> {
|
||||
await knex.migrate.down({ directory: migrationsDir });
|
||||
}
|
||||
|
||||
async function migrateUntilBefore(knex: Knex, target: string): Promise<void> {
|
||||
const index = migrationsFiles.indexOf(target);
|
||||
if (index === -1) {
|
||||
throw new Error(`Migration ${target} not found`);
|
||||
}
|
||||
for (let i = 0; i < index; i++) {
|
||||
await migrateUpOnce(knex);
|
||||
}
|
||||
}
|
||||
|
||||
describe('migrations', () => {
|
||||
const databases = TestDatabases.create({
|
||||
ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'],
|
||||
});
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'20210928160613_init.js, %p',
|
||||
async databaseId => {
|
||||
const knex = await databases.init(databaseId);
|
||||
|
||||
await migrateUntilBefore(knex, '20210928160613_init.js');
|
||||
await migrateUpOnce(knex);
|
||||
|
||||
await knex('backstage_backend_tasks__tasks').insert({
|
||||
id: 'test',
|
||||
settings_json: '{}',
|
||||
next_run_start_at: knex.fn.now(),
|
||||
});
|
||||
|
||||
await expect(knex('backstage_backend_tasks__tasks')).resolves.toEqual([
|
||||
{
|
||||
id: 'test',
|
||||
settings_json: '{}',
|
||||
next_run_start_at: expect.anything(),
|
||||
current_run_ticket: null,
|
||||
current_run_started_at: null,
|
||||
current_run_expires_at: null,
|
||||
},
|
||||
]);
|
||||
|
||||
await migrateDownOnce(knex);
|
||||
|
||||
// This looks odd - you might expect a .toThrow at the end but that
|
||||
// actually is flaky for some reason specifically on sqlite when
|
||||
// performing multiple runs in sequence
|
||||
await expect(knex('backstage_backend_tasks__tasks')).rejects.toEqual(
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
await knex.destroy();
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
});
|
||||
@@ -39,8 +39,9 @@ export class LocalTaskWorker {
|
||||
this.logger.info(
|
||||
`Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`,
|
||||
);
|
||||
let attemptNum = 1;
|
||||
|
||||
(async () => {
|
||||
let attemptNum = 1;
|
||||
for (;;) {
|
||||
try {
|
||||
if (settings.initialDelayDuration) {
|
||||
@@ -60,6 +61,7 @@ export class LocalTaskWorker {
|
||||
options?.signal,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.info(`Task worker finished: ${this.taskId}`);
|
||||
attemptNum = 0;
|
||||
break;
|
||||
|
||||
@@ -304,6 +304,46 @@ describe('PluginTaskManagerImpl', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('can fetch task ids', () => {
|
||||
it.each(databases.eachSupportedId())(
|
||||
'can fetch both global and local task ids, %p',
|
||||
async databaseId => {
|
||||
const { manager } = await init(databaseId);
|
||||
const fn = jest.fn();
|
||||
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromMillis(5000),
|
||||
fn,
|
||||
scope: 'global',
|
||||
});
|
||||
|
||||
await manager.scheduleTask({
|
||||
id: 'task2',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromMillis(5000),
|
||||
fn,
|
||||
scope: 'local',
|
||||
});
|
||||
|
||||
await expect(manager.getScheduledTasks()).resolves.toEqual([
|
||||
{
|
||||
id: 'task1',
|
||||
scope: 'global',
|
||||
settings: expect.objectContaining({ cadence: 'PT5S' }),
|
||||
},
|
||||
{
|
||||
id: 'task2',
|
||||
scope: 'local',
|
||||
settings: expect.objectContaining({ cadence: 'PT5S' }),
|
||||
},
|
||||
]);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
});
|
||||
|
||||
describe('parseDuration', () => {
|
||||
it('should parse durations', () => {
|
||||
expect(parseDuration({ milliseconds: 5000 })).toEqual('PT5S');
|
||||
|
||||
@@ -21,9 +21,11 @@ import { LocalTaskWorker } from './LocalTaskWorker';
|
||||
import { TaskWorker } from './TaskWorker';
|
||||
import {
|
||||
PluginTaskScheduler,
|
||||
TaskDescriptor,
|
||||
TaskInvocationDefinition,
|
||||
TaskRunner,
|
||||
TaskScheduleDefinition,
|
||||
TaskSettingsV2,
|
||||
} from './types';
|
||||
import { validateId } from './util';
|
||||
|
||||
@@ -32,6 +34,7 @@ import { validateId } from './util';
|
||||
*/
|
||||
export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
private readonly localTasksById = new Map<string, LocalTaskWorker>();
|
||||
private readonly allScheduledTasks: TaskDescriptor[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly databaseFactory: () => Promise<Knex>,
|
||||
@@ -55,6 +58,14 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
validateId(task.id);
|
||||
const scope = task.scope ?? 'global';
|
||||
|
||||
const settings: TaskSettingsV2 = {
|
||||
version: 2,
|
||||
cadence: parseDuration(task.frequency),
|
||||
initialDelayDuration:
|
||||
task.initialDelay && parseDuration(task.initialDelay),
|
||||
timeoutAfterDuration: parseDuration(task.timeout),
|
||||
};
|
||||
|
||||
if (scope === 'global') {
|
||||
const knex = await this.databaseFactory();
|
||||
const worker = new TaskWorker(
|
||||
@@ -63,37 +74,22 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
knex,
|
||||
this.logger.child({ task: task.id }),
|
||||
);
|
||||
|
||||
await worker.start(
|
||||
{
|
||||
version: 2,
|
||||
cadence: parseDuration(task.frequency),
|
||||
initialDelayDuration:
|
||||
task.initialDelay && parseDuration(task.initialDelay),
|
||||
timeoutAfterDuration: parseDuration(task.timeout),
|
||||
},
|
||||
{
|
||||
signal: task.signal,
|
||||
},
|
||||
);
|
||||
await worker.start(settings, { signal: task.signal });
|
||||
} else {
|
||||
const worker = new LocalTaskWorker(task.id, task.fn, this.logger);
|
||||
|
||||
worker.start(
|
||||
{
|
||||
version: 2,
|
||||
cadence: parseDuration(task.frequency),
|
||||
initialDelayDuration:
|
||||
task.initialDelay && parseDuration(task.initialDelay),
|
||||
timeoutAfterDuration: parseDuration(task.timeout),
|
||||
},
|
||||
{
|
||||
signal: task.signal,
|
||||
},
|
||||
const worker = new LocalTaskWorker(
|
||||
task.id,
|
||||
task.fn,
|
||||
this.logger.child({ task: task.id }),
|
||||
);
|
||||
|
||||
worker.start(settings, { signal: task.signal });
|
||||
this.localTasksById.set(task.id, worker);
|
||||
}
|
||||
|
||||
this.allScheduledTasks.push({
|
||||
id: task.id,
|
||||
scope: scope,
|
||||
settings: settings,
|
||||
});
|
||||
}
|
||||
|
||||
createScheduledTaskRunner(schedule: TaskScheduleDefinition): TaskRunner {
|
||||
@@ -103,6 +99,10 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getScheduledTasks(): Promise<TaskDescriptor[]> {
|
||||
return this.allScheduledTasks;
|
||||
}
|
||||
}
|
||||
|
||||
export function parseDuration(
|
||||
|
||||
@@ -19,6 +19,7 @@ export { TaskScheduler } from './TaskScheduler';
|
||||
export type {
|
||||
PluginTaskScheduler,
|
||||
TaskFunction,
|
||||
TaskDescriptor,
|
||||
TaskInvocationDefinition,
|
||||
TaskRunner,
|
||||
TaskScheduleDefinition,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { HumanDuration, JsonObject } from '@backstage/types';
|
||||
import { CronTime } from 'cron';
|
||||
import { Duration } from 'luxon';
|
||||
import { z } from 'zod';
|
||||
@@ -31,6 +31,28 @@ export type TaskFunction =
|
||||
| ((abortSignal: AbortSignal) => void | Promise<void>)
|
||||
| (() => void | Promise<void>);
|
||||
|
||||
/**
|
||||
* A semi-opaque type to describe an actively scheduled task.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TaskDescriptor = {
|
||||
/**
|
||||
* The unique identifier of the task.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The scope of the task.
|
||||
*/
|
||||
scope: 'global' | 'local';
|
||||
/**
|
||||
* The settings that control the task flow. This is a semi-opaque structure
|
||||
* that is mainly there for debugging purposes. Do not make any assumptions
|
||||
* about the contents of this field.
|
||||
*/
|
||||
settings: { version: number } & JsonObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options that control the scheduling of a task.
|
||||
*
|
||||
@@ -307,6 +329,19 @@ export interface PluginTaskScheduler {
|
||||
* @param schedule - The task schedule
|
||||
*/
|
||||
createScheduledTaskRunner(schedule: TaskScheduleDefinition): TaskRunner;
|
||||
|
||||
/**
|
||||
* Returns all scheduled tasks registered to this scheduler.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This method is useful for triggering tasks manually using the triggerTask
|
||||
* functionality. Note that the returned tasks contain only tasks that have
|
||||
* been initialized in this instance of the scheduler.
|
||||
*
|
||||
* @returns Scheduled tasks
|
||||
*/
|
||||
getScheduledTasks(): Promise<TaskDescriptor[]>;
|
||||
}
|
||||
|
||||
function isValidOptionalDurationString(d: string | undefined): boolean {
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.1.35-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-auth-node@0.2.12-next.2
|
||||
- @backstage/backend-common@0.18.3-next.2
|
||||
- @backstage/backend-app-api@0.4.1-next.2
|
||||
- @backstage/backend-plugin-api@0.4.1-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
|
||||
## 0.1.35-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.1.35-next.1",
|
||||
"version": "0.1.35-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,52 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.81-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-scaffolder-backend@1.12.0-next.2
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.1.4-next.2
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.27-next.2
|
||||
- @backstage/plugin-auth-node@0.2.12-next.2
|
||||
- @backstage/backend-tasks@0.5.0-next.2
|
||||
- @backstage/plugin-adr-backend@0.3.1-next.2
|
||||
- @backstage/backend-common@0.18.3-next.2
|
||||
- @backstage/plugin-linguist-backend@0.2.0-next.2
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.11-next.2
|
||||
- example-app@0.2.81-next.2
|
||||
- @backstage/plugin-techdocs-backend@1.5.4-next.2
|
||||
- @backstage/plugin-auth-backend@0.18.1-next.2
|
||||
- @backstage/plugin-entity-feedback-backend@0.1.1-next.2
|
||||
- @backstage/plugin-jenkins-backend@0.1.33-next.2
|
||||
- @backstage/plugin-kubernetes-backend@0.9.4-next.2
|
||||
- @backstage/plugin-permission-backend@0.5.18-next.2
|
||||
- @backstage/plugin-permission-node@0.7.6-next.2
|
||||
- @backstage/plugin-playlist-backend@0.2.6-next.2
|
||||
- @backstage/plugin-search-backend@1.2.4-next.2
|
||||
- @backstage/plugin-lighthouse-backend@0.1.1-next.2
|
||||
- @backstage/plugin-search-backend-node@1.1.4-next.2
|
||||
- @backstage/plugin-tech-insights-backend@0.5.9-next.2
|
||||
- @backstage/plugin-tech-insights-node@0.4.1-next.2
|
||||
- @backstage/plugin-app-backend@0.3.43-next.2
|
||||
- @backstage/plugin-azure-devops-backend@0.3.22-next.2
|
||||
- @backstage/plugin-azure-sites-backend@0.1.5-next.2
|
||||
- @backstage/plugin-badges-backend@0.1.37-next.2
|
||||
- @backstage/plugin-catalog-backend@1.8.0-next.2
|
||||
- @backstage/plugin-catalog-node@1.3.4-next.2
|
||||
- @backstage/plugin-code-coverage-backend@0.2.9-next.2
|
||||
- @backstage/plugin-events-backend@0.2.4-next.2
|
||||
- @backstage/plugin-explore-backend@0.0.5-next.2
|
||||
- @backstage/plugin-graphql-backend@0.1.33-next.2
|
||||
- @backstage/plugin-kafka-backend@0.2.36-next.2
|
||||
- @backstage/plugin-proxy-backend@0.2.37-next.2
|
||||
- @backstage/plugin-rollbar-backend@0.1.40-next.2
|
||||
- @backstage/plugin-search-backend-module-pg@0.5.4-next.2
|
||||
- @backstage/plugin-todo-backend@0.1.40-next.2
|
||||
- @backstage/plugin-events-node@0.2.4-next.2
|
||||
- @backstage/config@1.0.7-next.0
|
||||
- @backstage/integration@1.4.3-next.0
|
||||
|
||||
## 0.2.81-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -44,7 +44,7 @@ To debug the backend in [Visual Studio Code](https://code.visualstudio.com/):
|
||||
If you want to use the catalog functionality, you need to add so called
|
||||
locations to the backend. These are places where the backend can find some
|
||||
entity descriptor data to consume and serve. For more information, see
|
||||
[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview#adding-components-to-the-catalog).
|
||||
[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog).
|
||||
|
||||
For convenience we already include some statically configured example locations
|
||||
in `app-config.yaml` under `catalog.locations`. For local development you can override these in your own `app-config.local.yaml`.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user