Merge branch 'backstage:master' into master

This commit is contained in:
Bogdan Nechyporenko
2022-07-08 10:58:44 +02:00
committed by GitHub
122 changed files with 148953 additions and 200705 deletions
+19
View File
@@ -0,0 +1,19 @@
---
'@backstage/plugin-catalog-backend': minor
---
Added an option to be able to trigger refreshes on entities based on a prestored arbitrary key.
The UrlReaderProcessor, FileReaderProcessor got updated to store the absolute URL of the catalog file as a refresh key. In the format of `<type>:<target>`
The PlaceholderProcessor got updated to store the resolverValues as refreshKeys for the entities.
The custom resolvers will need to be updated to pass in a `CatalogProcessorEmit` function as parameter and they should be updated to emit their refresh processingResults. You can see the updated resolvers in the `PlaceholderProcessor.ts`
```ts
// yamlPlaceholderResolver
...
const { content, url } = await readTextLocation(params);
params.emit(processingResult.refresh(`url:${url}`));
...
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Fixed that adding more than one `allowedOwner` or `allowedRepo` in the template config will now still set the first value as default in the initial form state of `RepoUrlPicker`.
+13
View File
@@ -0,0 +1,13 @@
---
'@backstage/plugin-kubernetes': minor
'@backstage/plugin-kubernetes-backend': minor
---
Add `localKubectlProxy` cluster locator method to make local development simpler to setup.
Consolidated no-op server side auth decorators.
The following Kubernetes auth decorators are now one class (`ServerSideKubernetesAuthProvider`):
- `AwsKubernetesAuthProvider`
- `AzureKubernetesAuthProvider`
- `ServiceAccountKubernetesAuthProvider`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-radar': patch
---
Update tech-radar documentation on how to use an external json data source with dates.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-newrelic-dashboard': minor
---
Fix bug where the default time window/snapshot duration was supposed to be 30 days, but ended up being 43 weeks
**BREAKING**: Add a select input to change the time window of the snapshot displayed. This removes the duration prop from the `DashboardSnapshot` component.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
contextMenu prop passed through to <ScaffolderPageContents /> from the <ScaffolderPage /> component
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
new setUserAsOwner flag for publish:gitlab action
The field default is `false`. When true it will use the token configured in the gitlab integration for the matching host, to try and set the user logged in via `repoUrlPicker` `requestUserCredentials` OAuth flow as owner of the repository created in GitLab.
+22
View File
@@ -0,0 +1,22 @@
---
'@backstage/plugin-sentry': minor
---
Added the possibility to specify organization per component, now the annotation `sentry.io/project-slug` can have the format of `[organization]/[project-slug]` or just `[project-slug]`.
**BREAKING**: The method `fetchIssue` changed the signature:
```diff
export interface SentryApi {
fetchIssues(
- project: string,
- statsFor: string,
- query?: string,
+ entity: Entity,
+ options: {
+ statsFor: string;
+ query?: string;
+ },
): Promise<SentryIssue[]>;
}
```
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-components': patch
'@backstage/plugin-gcp-projects': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-techdocs-module-addons-contrib': patch
---
Updated dependency `@react-hookz/web` to `^15.0.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Updated dependency `@octokit/request` to `^6.0.0`.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes-common': patch
'@backstage/plugin-kubernetes': patch
---
Updated dependency `@kubernetes/client-node` to `^0.17.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Updated dependency `@octokit/webhooks` to `^10.0.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/integration': patch
---
Updated dependency `@octokit/auth-app` to `^4.0.0`.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-tech-insights-backend': minor
---
**BREAKING**: Update FactRetrieverRegistry interface to be async so that db backed implementations can be passed through to the FactRetrieverEngine.
If you have existing custom `FactRetrieverRegistry` implementations, you'll need to remove the `retrievers` member and make all the methods async.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-tech-insights-node': patch
'@backstage/plugin-tech-insights-backend': patch
---
The `FactRetriever` model has been extended by adding optional title and description fields, allowing you to display them in the UI.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Add new config option for okta auth server and IDP
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-azure-devops-common': patch
---
Adding getProjects endpoint to list out all projects associated with the Azure DevOps organization.
It can be accessed by using this endpoint `{backendUrl}/api/azure-devops/projects`
+3 -3
View File
@@ -32,7 +32,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -61,7 +61,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -178,7 +178,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
cron:
runs-on: ubuntu-latest
steps:
- uses: backstage/actions/cron@v0.5.0
- uses: backstage/actions/cron@v0.5.3
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
+3 -3
View File
@@ -69,17 +69,17 @@ jobs:
working-directory: ./example-app
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: './example-app'
file: ./example-app/packages/backend/Dockerfile
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+2 -2
View File
@@ -67,7 +67,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -145,7 +145,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -10,4 +10,4 @@ jobs:
if: github.repository == 'backstage/backstage'
steps:
- name: Issue sync
uses: backstage/actions/issue-sync@v0.5.0
uses: backstage/actions/issue-sync@v0.5.3
@@ -16,4 +16,13 @@ jobs:
if: github.repository == 'backstage/backstage' && github.event.comment.user.id == github.event.pull_request.user.id
steps:
- run: echo "This PR needs another review"
- name: Save PR number
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
mkdir -p ./pr
echo $PR_NUMBER > ./pr/pr_number
- uses: actions/upload-artifact@v3
with:
name: pr_number-${{ github.event.pull_request.number }}
path: pr/
+22 -2
View File
@@ -15,10 +15,30 @@ jobs:
if: github.repository == 'backstage/backstage' && github.event.workflow_run.conclusion == 'success'
steps:
- uses: backstage/actions/re-review@v0.5.2
# Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow
- name: Read PR Number
id: pr-number
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
const [artifact] = allArtifacts.data.artifacts.filter(artifact => artifact.name.startsWith('pr_number-'))
if (!artifact) {
throw new Error('No PR Number artifact available')
}
const prNumber = artifact.name.slice('pr_number-'.length)
console.log(`::set-output name=pr-number::${prNumber}`);
- uses: backstage/actions/re-review@v0.5.3
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }}
project-id: PVT_kwDOBFKqdc02LQ
issue-number: ${{ github.event.workflow_run.pull_requests[0].number }}
issue-number: ${{ steps.pr-number.outputs.pr-number }}
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: PR sync
uses: backstage/actions/pr-sync@v0.5.0
uses: backstage/actions/pr-sync@v0.5.3
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -22,7 +22,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -46,7 +46,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@v0.5.0
uses: backstage/actions/yarn-install@v0.5.3
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
- name: storybook yarn install
-200078
View File
File diff suppressed because one or more lines are too long
+147529
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,5 +5,5 @@
registry "https://registry.npmjs.org/"
disable-self-update-check true
lastUpdateCheck 1580389148099
yarn-path ".yarn/releases/yarn-1.22.1.js"
yarn-path ".yarn/releases/yarn-1.22.19.js"
network-timeout 300000
+196 -187
View File
@@ -3,190 +3,199 @@
_If you're using Backstage in your organization, please try to add your company name to this list. It really helps the project to gain momentum and credibility. It's a small contribution back to the project with a big impact._
_You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKikB) or by editing this file after following the [CONTRIBUTING.md](./CONTRIBUTING.md)._
| Organization | Contact | Description of Use |
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Gamze Senturk](https://github.com/gmzsenturk), [Mert Can Bilgic](https://github.com/mertcb) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Matt Waldron](https://github.com/daftgopher) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. |
| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. |
| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. |
| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 |
| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes |
| [DAZN](https://dazn.com/) | [David Rubio Vidal](https://github.com/davidrv87), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com), [Kamil Wolny](https://github.com/mrwolny) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). |
| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. |
| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. |
| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. |
| [MavTek](https://www.mavtek.com/) | [@fgascon](https://github.com/fgascon) | Developer portal focused on standardizing practices, centralizing documentation and streamlining developer practices. |
| [QuintoAndar](https://www.quintoandar.com.br/) | [@quintoandar](https://github.com/quintoandar) | Developer portal, services catalog and centralization of service metrics. |
| [empathy.co](https://empathy.co/) | [@guillermotti](https://github.com/guillermotti) | Developer portal for tech docs, service catalog, plugin discovery and much more. |
| [creditas.com](https://creditas.com/) | [@aureliosaraiva](https://github.com/aureliosaraiva) [@Creditas](https://github.com/creditas) | Centralization of all services, standards, documentation, etc. We started the deployment process. |
| [Prisjakt](https://www.prisjakt.nu) / [PriceSpy](https://pricespy.co.uk) | [@kennylindahl](https://github.com/kennylindahl) | Internal developer portal - Documentation, scaffolding, software catalog, TechRadar, Gitlab org data integration |
| [Powerspike](https://powerspike.tv/) | [@trelore](https://github.com/trelore) | Developer portal for documentation of core libraries and repositories. |
| [2U](https://2u.com) | [@danielleEriksen](https://github.com/danielleEriksen), [@sbhatia](https://github.com/sbhatia) | Development team home-base, promoting service discoverability, resource dependencies, and tech radar |
| [Taxfix](https://taxfix.de/) | [Sami Ur Rehman](https://github.com/samiurrehman92) | Developer's portal with software catalog at it's core. Hosts API Specs, Tech Docs, Tech Radar and some custom plugins. |
| [Busuu](https://busuu.com/) | [Adam Tester](https://github.com/adamtester) | Developer portal with service catalog, API docs, Event docs, service templating, and cost insights. |
| [Loadsmart](https://loadsmart.com/) | [Loadsmart](https://github.com/loadsmart) | Improve services visibility and operations for service owners and developers. |
| [Monzo](https://monzo.com/) | [@WillSewell](https://github.com/WillSewell), [@joechrisellis](https://github.com/joechrisellis) | Developer portal showing metadata and docs for over 2000 microservices. We have built a number of plugins such as a UI for our system to measure [software excellence](https://monzo.com/blog/2021/09/15/how-we-measure-software-excellence), and a UI to show deployment and config change events. |
| [Vaimo](https://www.vaimo.com) | [@vaimo-magnus](https://github.com/vaimo-magnus) | Developer Portal for our developers at Vaimo, currently docs and self-service towards our internal PaaS based on k8s. Plans to extend the catalog into Projects, Environments etc |
| [Wayfair](https://www.wayfair.com) | [@fransan](https://github.com/fransan), [@errskipower](https://github.com/errskipower), [@hrrs](https://github.com/hrrs) | Developer portal for service catalog, technical documentation, and APIs. |
| [CircleHD](https://www.circlehd.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [CastDesk](https://castdesk.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [Santagostino](https://santagostino.it) | [@santagostino](https://github.com/santagostino) | Developer portal, gateway to our infrastructure, documentation, service catalog and internal tooling. |
| [Peak](https://peak.ai) | [Luke Beamish](https://github.com/lukebeamish-peak) | Developer portal for all internal engineers to access documentation and tooling. |
| [Gelato](https://gelato.com/) | [Dmitry Makarenko](https://github.com/dmitry-makarenko-gelato) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal and third-party systems🚀. |
| [GoCardless](https://gocardless.com/) | [James Turley](https://github.com/tragiclifestories) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal systems. |
| [Box](https://www.box.com) | [@kielosz](https://github.com/kielosz), [@jluk-box](https://github.com/jluk-box), [@ptychu](https://github.com/ptychu), [@alexrybch](https://github.com/alexrybch), [@szubster](https://github.com/szubster) | Developer portal for service catalog, integration with internal systems, new service onboarding. |
| [Bazaarvoice](https://www.bazaarvoice.com) | [@niallmccullagh](https://github.com/niallmccullagh) | Developer portal for service catalog and scaffolds, publishing Github docs and API documentation, visualising our internal tech radar and our product engineering org structure. |
| [Krateo PlatformOps](https://www.krateo.io) | [@projectkerberus](https://github.com/projectkerberus) | A multi-cloud control plane to create, manage and deploy any kind of resource easily and centrally via a Developer Portal that centralizes via a self-service catalog the templating and ownership of services, the available documentation, the overview of the components that compose an entire domain and all the data of the service lifecycle. |
| [Adevinta](https://www.adevinta.com) | [Ray Sinnema](https://github.com/RemonSinnema) | Showcase shared services to our internal customers. |
| [Splunk](https://www.splunk.com) | [@tonytamsf](https://github.com/tonytamsf) | Developer portal as a centralized place to find people, services, documentation, escalation policies and give bravos. This portal is also being used as a centralized search engine for engineering specific documentation. |
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc. |
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
| [Palo Alto Networks](https://www.paloaltonetworks.com) | [Jeremy Guarini](https://github.com/jeremyguarini), [Brian Lomeland](https://github.com/bbbmmmlll), [Palo Alto Networks](https://github.com/PaloAltoNetworks) | Developer portal, service catalog, documentation and tooling |
| [Signal Iduna Group](https://www.signal-iduna.de/) | [Jonas Thomsen](https://github.com/JoThomsen) | Developer Portal, documentation, monitoring, service catalog for our insurance ecosystem |
| [Tradeshift](https://www.tradeshift.com/) | [Soren Mathiasen](https://github.com/sorenmat) | Developer Portal: documentation, monitoring, service templates, service catalog for our micro services |
| [Unity](https://unity.com) | [Ted Cordery](https://github.com/TeddyBallGame) | A centralized service catalog with documentation for our service engineers. |
| [PicPay](https://www.picpay.com) | [Luis Baroni](https://github.com/lcsbaroni), [Renata Poluceno](https://github.com/renatapoluceno), [PicPay](https://github.com/picpay) | Developer portal for building services through templates, service catalog with ownership of services, documentation and metrics providing autonomy and visibility for all. |
| [Epic Games](https://www.epicgames.com) | [Brian Jung](https://github.com/brian-at-epic), [Jeff Goldian](https://github.com/jeffgoldian-Epic) | Developer Portal: Service Catalog, Documentation, Software Templates and more making our internal teams' lives easier! |
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
| [GoTo](https://www.goto.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. |
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 |
| [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. |
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [Rafał Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
| [Power Home Remodeling](https://www.techatpower.com) | [Ben Langfeld](https://github.com/benlangfeld) | Developer portal to our internal services, build on open-source software (including Kubernetes) in our own datacenters. Our Portal allows our team members to navigate inherant complexity and standardise. |
| [Livspace](https://www.livspace.com) | [Praveen Kumar](https://github.com/praveen-livspace) | Developer portal, service catalog, tech docs, API docs and plugins |
| [Just Eat Takeaway](https://www.justeattakeaway.com) | [Kim Wilson](https://github.com/kwilson541) | Our developer portal which centralises applications, reduces cognitive load and provides teams insights. |
| [Hopin](https://hopin.com) | [Vladimir Glafirov](https://github.com/vglafirov), [Chloe Lee](https://github.com/msfuko) | Developer portal to streamline the development practices. Integrated with service catalog, software templates, application monitoring, tech docs and plugins. |
| [HBO Max](https://hbomax.com) | [@mdb](https://github.com/mdb), [@nesta219](https://github.com/nesta219), [@nmische](https://github.com/nmische), [@hbomark](https://github.com/hbomark) | Developer portal hosting service catalog and API documentation, as well as cloud infrastructure details, operational visibility tools, and a custom plugin for browsing notable platform change events, such as deployments and configuration updates. |
| [RCHLO](https://www.riachuelo.com.br) & [MIDWAY](https://www.midway.com.br) | [@marcosborges](https://github.com/marcosborges), [@defaultbr](https://github.com/defaultbr) | Self-Service Platform |
| [HP Inc](https://www.hp.com) | [Damon Kaswell](https://github.com/dekoding) | DevEx engagement hub (dev portal: docs, standards, Q&A) and extensive assets catalog (APIs, services, code, data, etc.) for the pan-HP internal developer community. |
| [VMware](https://www.vmware.com) | [@mpriamo](https://github.com/mpriamo), [@krisapplegate](https://github.com/krisapplegate) | Part of [Tanzu Application Platform](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/index.html) offering; internal developer portal |
| [Ualá](https://www.uala.com.ar/) | [Santiago Bernal](https://github.com/sabernal) | Initial work being done to centralize documentation for all our microservices and APIs, as well as scaffolding new services and tracking code quality |
| [IKEA IT AB](https://www.ingka.com) | [@bjornramberg](https://github.com/bjornramberg), [@supriyachitale](https://github.com/supriyachitale) | Supporting engineers at scale with self serve access and connecting the dots of our engineering platform and services, enabling product teams to move faster and go further, and unleashing innovation, reuse and co-creation across the organisation. |
| [Invitae](https://www.invitae.com/en) | [@ryan-hanchett](https://github.com/ryan-hanchett), [@gmandler42](https://github.com/gmandler42) | Centralized Developer Experience portal, putting all of our tooling behind a single pane of glass and creating a living service catalog. |
| [Fortum](https://www.fortum.com/) | [@brunoamaroalmeida](https://github.com/brunoamaroalmeida), [@dhaval-vithalani](https://github.com/dhaval-vithalani), [@sunilkumarmohanty](https://github.com/sunilkumarmohanty) | A central portal containing information about our applications, services, processes and other software assets to be used by Fortum software engineering community. |
| [Procore](https://www.procore.com/jobs/engineering) | [@shayon](https://github.com/Shayon), [@jamesdabbs-procore](https://github.com/jamesdabbs-procore) | Developer portal - centralized software catalog and templates to enable self serve and reduce cognitive load. |
| [Bradesco](https://banco.bradesco/html/classic/sobre/index.shtm) | [@danilosoarescardoso](https://github.com/danilosoarescardoso) | Centralized developer portal with software catalog, software templates, techdocs and some plugins from community and by our own. |
| [SeatGeek](https://seatgeek.com) | [@zhammer](https://github.com/zhammer) | Software catalog and documentation platform |
| [Grupo Boticário](https://www.grupoboticario.com.br/) | [@chicoribas](https://github.com/chicoribas), [@fndiaz](https://github.com/fndiaz), [@digogid](https://github.com/digogid), [@manumbs](https://github.com/manumbs), [@haooliveira84](https://github.com/haooliveira84), [@Rhullyam](https://github.com/Rhullyam) | Centralized developer portal with catalog, documentation, and software templates to build a ready to go application, including pipelines (CI/CD) and cloud services provisioning |
| [Snyk](https://snyk.io/) | [@robcresswell](https://github.com/robcresswell) | Developer portal for software discovery, API documentation and templating |
| [Stilingue](https://www.stilingue.com.br/) | [@stilingue-inteligencia-artificial](https://github.com/Stilingue-IA), [@bbviana](https://github.com/bbviana) | Developer portal, services catalog and centralization of metrics from Grafana, Sentry and GCP. Furthermore, centralization of documentation and infra details like DNS, Network services, SSL and so on. |
| [TUI Group](https://www.tuigroup.com/) | [Simon Stamm](https://github.com/simonstamm), [Christian Rudolph](https://github.com/ChrisRu82) | Developer portal for all engineer to provide discoverability to all internal components, APIs, documentation and to scaffold templates with integrations to our internal tools extended by plugins from our community. |
| [Alliander](https://www.alliander.com/) | [@leon-vg](https://github.com/leon-vg), [@gieljl](https://github.com/gieljl), [@niekteg](https://github.com/niekteg) | Developer portal - software catalog, technical documentation, software templates, tech radar and exploration of used tools/services |
| [VIA](https://www.via.com.br) | [@vagnerguedes](https://github.com/vagnerguedes) | Centralized Developer Experience portal - Software catalog and documentation platform, software templates, techdocs, scaffolding, self-service infrastructure |
| [Surevine](https://www.surevine.com/) | [@DJDANNY123](https://github.com/djdanny123) | Developer portal for software catalog, discovery and a view of the technologies we are using across the organisation, we are looking to explore how we can enrich our entities in Backstage by integrating a software bill of materials. |
| [Bonial International GmbH](https://www.bonial.com/) | [@pjungermann](https://github.com/pjungermann) | Centralized developer portal with software catalog, tech docs, templates, and more. |
| [Beez Innovation Labs Pvt. Ltd](https://www.beezlabs.com/) | [Karthikeyan Venkatesan](https://github.com/karthikeyan23) | Developer portal with software catalog, scaffolding, tech docs, templates, and infra. |
| [Agorapulse](https://www.agorapulse.com/) | [@jvdrean](https://github.com/jvdrean) | Developer portal with software catalog, documentation, monitoring, runbooks, tech radar and more. |
| [Wistia](https://wistia.com/) | [@qrush](https://github.com/qrush), [@okize](https://github.com/okize) | Internal Developer Portal, service catalog, tech docs and more |
| [SIX](https://www.six-group.com/) | [@jbadeau](https://github.com/jbadeau), [@tomassatka](https://github.com/tomassatka) | Internal DevOps portal hosting our software and dataset catalog, as well as custom plugins for observability, service virtualization, deployments, incident managment and quality metrics. |
| [Raiffeisen Bank International](https://www.rbinternational.com/) | [Daniel Baumgartner](https://github.com/dabarbi) | From developers for developers: software catalog, techdocs and heavy use of scaffolder to drive reuse on engineering level forward. Part of inner source initiative. Multi national setup coming. |
| [Spread Group](https://www.spreadgroup.com/) | [Luna Stadler](https://github.com/heyLu), [Iván González](https://github.com/ivangonzalezacuna) | Internal Developer Portal, an overview of all running software, architecture documentation and more; replacing and unifying a variety of internal tools. |
| [RD Station](https://rdstation.com) | [Rogerio Angeliski](https://github.com/angeliski), [Paula Assis](https://github.com/paulassis), [Guilherme Eric](https://github.com/guilhermeeric), [Daniela Adamatti](https://github.com/daniadamatti), [Luana Negreiros](https://github.com/luananegreiros) | Developer portal, scaffolding, services catalog. We are looking to centralize automations and information for the whole engineering team . |
| [Resuelve Tu Deuda](https://resuelve.mx) | [Iván Álvarez](https://github.com/ivanhoe), [Jorge Medina](https://github.com/jorgearma1982) | Internal developer portal, service catalog, tech docs, api doc |
| [Pachama](https://pachama.com/) | [Aron Gates](https://github.com/agates4) | Internal Developer Portal, a catalog of all microservices, architecture documentation, and templates to generate developer resources. |
| [SEEK](https://www.seek.com.au) | [Jahred Hope](https://github.com/jahredhope) | Developer portal for developer tooling and technical documentation. |
| [Marks & Spencer](https://www.marksandspencer.com/) | [Kamal Cheriyath](https://github.com/kcheriyath) | Centralised discovery, adoption and devops automation hub for Engineering & Architecture. |
| [McKesson](https://www.mckesson.com/) | [Agnel Antony](https://github.com/aantony2) | Internal Developer Platform for developer gated CI/CD templates, technical documentation, cloud automation service catalog, etc. |
| [World Fuel Services](https://www.wfscorp.com/) | [Anirudh Kurapathi](https://github.com/anirudhkurapati), [Alex Kwon](https://github.com/alexkwon), [Lester Hernandez](https://github.com/lhernandez-wfscorp), [Avi Boru](https://github.com/aviboru), [Vardhan Annapureddy](https://github.com/harshaaws) | Internal Developer Portal, service catalog product, API's, Software Templates, tech docs and more. |
| [leboncoin](https://www.leboncoin.fr/) | [Andy Ladjadj](https://github.com/aladjadj) | Centralize our multiple UI in a single portal. Simplify onbording, new features and harmonize how people search information. Core features (catalog,api,docs,scafolder) are good to start the adoption. status: internal beta. |
| [Contentful](https://www.contentful.com) | [James Bourne](https://github.com/jamesmbourne) | Centralized documentation of service ownership, APIs, and documentation, and new service creation with a custom scaffolder - [full case study with Roadie](https://roadie.io/case-studies/maintaining-velocity-through-hypergrowth-contentful/). |
| [Back Market](https://www.backmarket.com) | [Sami Farhat](https://github.com/skfarhat) | Internal Developer Portal featuring catalog, tech-radar, ownership management, component creation (scaffolder) and centralized infrastructure management -- probably more to come. |
| [Avalia Systems](https://avalia.io) | [Olivier Liechti](https://github.com/wasadigi), [Fabio Velloso](https://github.com/fabiovelloso) | Innersource, software analytics, knowledge base for 360 software assessments, collaborative applications, hub for tracking and sharing IP assets. |
| [Albert Heijn](https://ah.technology) | [Joost Hofman](https://github.com/joosthofman), [Reindrich Geerman](https://github.com/reinst) | Single point of entry for all our engineers (Developer portal), Tech radar, catalog, templates (paved roads) and tech documentation. |
| [Wise, formerly TransferWise](https://wise.com) | [Andrew Beveridge](https://github.com/beveradb) | It's early days for us, we're trying to start small with catalog, tech docs and unified search. Future ambitious vision includes scaffolder for one-click component addition, building out integrations with CI/CD tooling, kubernetes clusters, monitoring/alerting tooling etc. and aiming for a frictionless "golden path" for engineers! 🚀 |
| [Happy Money](http://happymoney.com/) | [Akshit Lomash](mailto:alomash@happymoney.com) | We are moving from a monolith to microservices-based architecture. We are developing a developer portal based on Backstage to create a service catalog for our new services. All the services created are onboarded Backstage and engineering teams are using a cookie-cutter-based template from backstage to initiate a new service. |
| [Lightspeed](http://lightspeedhq.com/) | [Marcus Crane](mailto:marcus.crane@lightspeedhq.com) | We use it within our X-Series division (https://vendhq.com) to catalog ~100+ systems and ~350 components! |
| [Siemens](https://www.siemens.com/global/en.html) | [Nizar Chaouch](mailto:nizar.chaouch@siemens.com) | We are using Backstage as our Developer portal |
| [The Warehouse Group](https://www.thewarehouse.co.nz) | [Matt Law](mailto:matt.law@thewarehouse.co.nz) | Backstage enables us to bootstrap our middleware environment of new services for our Dev teams in a matter of seconds. CI, CD, testing, logging, deployments are all taken care of to get them up and running in less than 60 seconds. |
| [Tink](https://tink.com/) | [Sebastian Olsson](https://github.com/Sebelino), [Błażej Szum](https://github.com/blazejszumtink), [Anders Eurenius Runvald](https://github.com/anders-er-at-tink) | Internal developer portal which provides templates for creating new Java or Go microservices seamlessly. Also includes a tech radar and a visualization of our CD pipeline. |
| [Brandwatch](https://brandwatch.com) | [Stefan Buck](https://github.com/stefanbuck) | Our primary focus is on the service catalog. Backstage is replacing our homemade service catalog. The switch was quite simple due to the catalog processor API. |
| [Laybuy](https://www.laybuy.com) | [Chris Simmons](https://github.com/contrarianchris) | Backstage is the heart of Laybuys new centralised Development Platform, bringing disparate development tools and experiences into a single easy-to-use portal. It simplifies software and API discovery, project scaffolding, and technical documentation, enabling us to embrace golden path development and automate software standards. |
| [Sendinblue](https://engineering.sendinblue.com/) | [Tanguy Antoine](mailto:antoine.tanguy@sendinblue.com) | Helps us drive the change at scale. Puts light on services, resources, and dependencies. One tool that rules them all through plugins we created for that purpose. We are aiming to put Backstage at the center of every developer's work (Actionable items, Debugging, Monitoring, Provisioning, etc...) to improve their happiness |
| [SafetyCulture](https://safetyculture.com/) | [@R-cen](https://github.com/R-cen), [@lachlancooper](https://github.com/lachlancooper), [@hkf57](https://github.com/hkf57) | Internal developer portal to provide a centralized place for engineers to see an overview of their team's services and information related to the service from other systems. Initially focused on the software catalog, techdocs and search. |
| [Sana Life Science](https://sanalifescience.com) | [Joe Hillyard](mailto:joe@sanalifescience.com) | API Catalog, Tools Management & Control Hub |
| [Ndustrial](https://ndustrial.io) | [Jonathan Skubic](mailto:jonathan@ndustrial.io) | Software Project Catalog |
| [TUI Musement](https://www.musement.com/uk/) | [Simone Fumagalli](mailto:simone.fumagalli@musement.com) | We are importing our catalog into it to keep it under control. The next step is start using templates |
| [Kambi AB](https://www.kambi.com) | [Martin Norum](mailto:martin.norum@kambi.com) | We want to kick ass at speed, so we're currently building up a catalog of our existing software, and looking into how Backstage can support us in our journey towards autonomous product teams. Both to improve speed to market and operational awareness. |
| [ANZ](https://www.anz.com.au/personal/) | [Elliot Jackson](mailto:elliot.jackson@anz.com) | Catalog, tech docs and automation |
| [Genie Solutions](https://www.geniesolutionssoftware.com.au) | [Zainab Bagasrawala](mailto:zainabbagasrawala@geniesolutions.com.au) | Developer Portal to track our projects, documentation, observability tools and more |
| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [Paulo Eduardo Peixoto](mailto:paulo.peixoto@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. |
| [Sonatype](https://www.sonatype.com) | [Srikar Ananthula](mailto:sananthula@sonatype.com) | Centralize services used internally with many plugins |
| [CVS Health](https://www.cvshealth.com) | [Ari Ben-Elazar](mailto:abenelazar@gmail.com) | Cataloging and documenting our service offerings to offer our internal developers a better operational journey |
| [Yatra.com](https://www.yatra.com) | [Matiur Rahman Maitur](mailto:arifrahman4u@gmail.com) | Easy to find out Project details, ownership, dependent services, Documentation, it is very useful for developer. |
| [Yotpo](https://www.yotpo.com) | [Liran Yogev](mailto:lyogev@yotpo.com) | Services exploration, documentation and project generator |
| [Mainsail Industries](https://www.mainsailindustries.com) | [Brad Sollar](mailto:brad@mainsailindustries.com) | Internal tool management and docs |
| [Prisma](https://prismamp.com) | [Sebastian Gravina](mailto:sgravina@prismamp.com) | Is part of our IDP |
| [Syndetic](https://syndetic.io) | [John Feminella](mailto:robots+swag@syndetic.io) | We're working with multiple F100 clients for digital transformation and Backstage is a key part of our landing and acceleration strategy. |
| [Imagine Learning](https://www.imaginelearning.com/en/us) | [Jared Stehler](mailto:jared.stehler@imaginelearning.com) | Software catalog, product dependency visualization |
| [Alef Education](https://www.alefeducation.com) | [Belal Juma](mailto:belal.juma@alefeducation.com) | We use backstage as a Service Catalog and rely on the TechDocs feature |
| [Zego](https://www.zego.com) | [Sean Kenny](mailto:sean.kenny@zego.com) | Single pane of glass for organisational and operational information for all services across our systems. |
| [Absa Group Limited](https://www.absa.africa/absaafrica/) | [Chris Kieser](mailto:chris.kieser@absa.africa) | Developer portal for all development needs - security, AWS, k8s, build and deployment pipelines and more |
| [Nutrien Ag Solutions](https://www.nutrienagsolutions.com.au) | [Jan Quijano](mailto:jan.quijano@nutrien.com.au) | Software Project Catalog |
| [Lendingkart](https://www.lendingkart.com/) | [Dinesh Rajpoot](mailto:dinesh.rajpoot@lendingkart.com) | Service catalog, Software templates to enforce best practices and tech insights to track mandates & migrations. |
| [Meltwater](https://underthehood.meltwater.com) | [@spier](https://github.com/spier), [@remen](https://github.com/remen) | Improving developer experience by centralizing documentation and internal APIs. Goal: Foster InnerSource collaboration and speed up onboarding time in our 500+ people Product & Engineering org. |
| [Doctolib](https://doctolib.engineering/) | [@djiit](https://github.com/djiit) | Rails modularization effort awareness, tech organization discoverability. Improving the daily workflows and collaboration processes of our engineers. |
| [Twilio](https://www.twilio.com) | [Kyle Smith](https://github.com/knksmith57) | Developer portal, universal software catalog, and centralized taxonomy platform. |
| [OVHcloud](https://www.ovhcloud.com/fr/) | [Jean-Philippe Blary](https://github.com/blaryjp), [Arnaud Bauer](mailto:arnaud.bauer@ovhcloud.com), [Flavien Chantelot](https://github.com/Dorn-) | We're providing Backstage to our collaborators to ease their daily jobs, and let them extends it using plugins. |
| [Procter & Gamble](https://us.pg.com/) | [Binita Nayak](https://github.com/binitan), [Josh Rose](https://github.com/joshuarose), [RJ Winkler](https://github.com/rjwink) | P&G leverages Backstage to build internal developer portal to ensure developers' happiness. This developer portal shall act as single source of information needed by development teams to seamlessly create, find and maintain their software components/resources/documentation. |
| [SANS Institute](https://www.sans.org) | [Christopher Klewin](mailto:cklewin@sans.org) | Developer portal for centralized visibility, reporting, and tooling across multiple organizations. |
| [Okay](https://www.okayhq.com/) | [Tomas Barreto](mailto:tomas@okayhq.com) | Service catalog, developer portal, and technical documentation |
| [Kaluza](https://www.kaluza.com) | [James Condren](mailto:james.condron@kaluza.com) | To provide an automated golden path to developers, with a focus on discovery and documentation |
| [LinkedIn](https://linkedin.com) | [Joshua Lawrence](mailto:jlawrence@linkedin.com) | We are building a platform for internal web tools |
| [Forto](https://forto.com) | [Rodolfo Matos](mailto:rodolfo.matos@forto.com) | Still in a experimental phase/assessing the organisational fit. We will be using it mostly a developer portal -- pretty standard use case. |
| [BetterUp](https://betterup.com) | [Jordan Hochenbaum](mailto:jordan.hochenbaum@betterup.co) | We're starting to use Backstage as the central hub for service discovery, documentation, and develop experience. |
| [warung pintar](https://warungpintar.co.id/) | [Muhammad Rafly Andrianza](mailto:rafly.andrianza@warungpintar.co) | Initial Work Developer Portal with TechRadar, Service Catalogue, TechDocs, anything about platform & infrastructure resources. |
| [RD](https://rd.com.br/) | [Michael Silva](mailto:midsilva@rd.com.br) | We are building our developer portal. Software catalog, Tech Radar and Scaffolding are among the initial features. |
| [AEB](https://www.aeb.com/) | [David Fankhänel](mailto:dfl@aeb.com) | Central developer platform for creating new apps via templates, getting an overview via software catalog, etc |
| [SALTO Systems](https://saltosystems.com) | [Ian Cowley](mailto:i.cowley@saltosystems.com) | Currently using Backstage as an internal documentation portal. |
| [Lummo](https://lummo.com) | [Anjul Sahu](mailto:anjul@lummo.com) | We are building the internal developer portal using Backstage and bringing up all integrations and service information at one place. |
| [Frontside](https://frontside.com) | [Taras Mankovski](mailto:taras@frontside.com) | |
| [Stepstone](https://www.stepstone.com/en/) | [Neil Kennedy](mailto:neil.kennedy@stepstone.com) | StepStone is using Backstage to solve problems around ownership and visibility of our applications. We have thousands of repos, multiple legacy systems and a growing platform that is hard to maintain. Backstage is forming the centre of our push to embrace the chaos. |
| [idwall](https://idwall.co) | [Rodrigo Catão Araujo](mailto:rodrigo@idwall.co) | Developer Portal for internal engineers to access service catalog, documentation, observability, infrastructure and internal tooling. |
| [Jaguar Land Rover](https://www.jaguarlandrover.com) | [Josh Walker](mailto:jwalke18@jaguarlandrover.com) | Users can request a Gitlab user, which creates a commit with the Terraform code. |
| [Glovo](http://glovoapp.com/) | [Yaser Toutah](mailto:yaser.toutah@glovoapp.com) | Developer Portal to improve our Developer Experience, identify ownership and track metadata for our services and tools. It's our Service Catalog. In addition to that, we use it for Service Creation, and much more. |
| [Dixa](https://dixa.com) | [Jens Møller](https://github.com/jensamoller) | We are in early stages, but using it to get overview of our repositories and ownership of these. We want among many things to use it for compliance and easier access to key metrics for our repos. |
| [Notino](https://notino.com) | [Jan Remunda](mailto:jan.remunda@notino.com) | Backstage is our developer portal. We use it as service catalog and for technical documentation. |
| [Polarpoint](https://polarpoint.io/) | [Surj Bains](https://github.com/polarpoint-io) | We are using Backstage as our Developer portal as well as for hosting our DevOps portal for software catalog. |
| [Niche](https://niche.com) | [Zach Romitz](mailto:zach.romitz@niche.com) | We are using the Software Catalog, Software Templates, API documentation, and Techdocs to try and centralize service information. |
| [Mercedes-Benz.io](https://www.mercedes-benz.io/) | [Manuel Santos](https://github.com/manusant) | At Mercedes-Benz we use it as a developer portal with software catalog, TechDocs, Scaffolding and custom plugins. It provides an overview of our tech ecosystem to our product development teams. The portal also serves as a way to foster collaboration among the numerous companies of the Mercedes-Benz Group. |
| [Funding Circle](https://www.fundingcircle.com/) | [Ariel Pacciaroni](https://github.com/arielpacciaroni) | We are building the internal developer portal using Backstage project and centralizing all services information at one place. The portal helps us track down repositories ownership as well as direct access to key information on every component. |
| [Clarivate](https://www.clarivate.com) | [Gabriele Carteni](mailto:gabriele.carteni@clarivate.com) | We are building our Developer Portal using Backstage to have a better control over our software ecosystem, integrate SDLC tools and promote best practices |
| [Cho Tot](https://www.chotot.com) | [Chotot Team](mailto:sre@chotot.vn) | Internal developer portal, service catalog with CI/CD tools. |
| [William Hill](https://www.williamhillgroup.com/) | [Pat Mills](mailto:pat.mills@williamhill.com), [Nathan Flynn](mailto:nflynn@williamhill.co.uk), and [Nishkarsh Raj](mailto:nishkarsh.raj@williamhill.co.uk) | William Hill are leveraging Backstage to build our Engineering Portal. Our mission is to centralize the software catalog inventory to enable service discoverability, reduce the onboarding time for new Engineers, provide a single pane of glass to accelerate Developer Productivity and Save Engineers time. Our aspiration is to create an InnerSource community focussed on organization-wide patterns that are re-usable and can be self-served with the Scaffolder. |
| [Vodafone NewZealand Limited](https://vodafone.co.nz) | [Ankit Gupta](mailto:ankit.gupta@vodafone.nz), [DevOps COE](mailto:devopstooling@vodafone.nz) | Vodafone NZ are leveraging Backstage to build centralised and self service Engineering Portal. Our mission is to standardised Pipeline templates across the Engineering teams, One shop stop to create the pipelines and repository with a template approach which reduces creation part from days to minutes and no wait time for developers. A unified view for Azure DevOps pipeline, Azure Repo pull requests, Deployment status from Azure RedHat Openshift-ArgoCD and SonarQube Security and code quality scans report on a single pan to provide a streamlined view for all microservices across the app stack. |
| [Coamo](http://www.coamo.com.br) | [@holiiveira](https://github.com/holiiveira), [@gpxlnx](https://github.com/gpxlnx) | We're starting to use it as the main tool of a DevOps platform. Our goal is to provide software templates, centralize our software catalog enabling efficient service discovery, and make it easy to manage the entire software ecosystem in one place.
|
| Organization | Contact | Description of Use |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com), [@ajbw](https://github.com/ajbw) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Gamze Senturk](https://github.com/gmzsenturk), [Mert Can Bilgic](https://github.com/mertcb) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Matt Waldron](https://github.com/daftgopher) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. |
| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. |
| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. |
| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 |
| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes |
| [DAZN](https://dazn.com/) | [David Rubio Vidal](https://github.com/davidrv87), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com), [Kamil Wolny](https://github.com/mrwolny) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). |
| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. |
| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. |
| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. |
| [MavTek](https://www.mavtek.com/) | [@fgascon](https://github.com/fgascon) | Developer portal focused on standardizing practices, centralizing documentation and streamlining developer practices. |
| [QuintoAndar](https://www.quintoandar.com.br/) | [@quintoandar](https://github.com/quintoandar) | Developer portal, services catalog and centralization of service metrics. |
| [empathy.co](https://empathy.co/) | [@guillermotti](https://github.com/guillermotti) | Developer portal for tech docs, service catalog, plugin discovery and much more. |
| [creditas.com](https://creditas.com/) | [@aureliosaraiva](https://github.com/aureliosaraiva) [@Creditas](https://github.com/creditas) | Centralization of all services, standards, documentation, etc. We started the deployment process. |
| [Prisjakt](https://www.prisjakt.nu) / [PriceSpy](https://pricespy.co.uk) | [@kennylindahl](https://github.com/kennylindahl) | Internal developer portal - Documentation, scaffolding, software catalog, TechRadar, Gitlab org data integration |
| [Powerspike](https://powerspike.tv/) | [@trelore](https://github.com/trelore) | Developer portal for documentation of core libraries and repositories. |
| [2U](https://2u.com) | [@danielleEriksen](https://github.com/danielleEriksen), [@sbhatia](https://github.com/sbhatia) | Development team home-base, promoting service discoverability, resource dependencies, and tech radar |
| [Taxfix](https://taxfix.de/) | [Sami Ur Rehman](https://github.com/samiurrehman92) | Developer's portal with software catalog at it's core. Hosts API Specs, Tech Docs, Tech Radar and some custom plugins. |
| [Busuu](https://busuu.com/) | [Adam Tester](https://github.com/adamtester) | Developer portal with service catalog, API docs, Event docs, service templating, and cost insights. |
| [Loadsmart](https://loadsmart.com/) | [Loadsmart](https://github.com/loadsmart) | Improve services visibility and operations for service owners and developers. |
| [Monzo](https://monzo.com/) | [@WillSewell](https://github.com/WillSewell), [@joechrisellis](https://github.com/joechrisellis) | Developer portal showing metadata and docs for over 2000 microservices. We have built a number of plugins such as a UI for our system to measure [software excellence](https://monzo.com/blog/2021/09/15/how-we-measure-software-excellence), and a UI to show deployment and config change events. |
| [Vaimo](https://www.vaimo.com) | [@vaimo-magnus](https://github.com/vaimo-magnus) | Developer Portal for our developers at Vaimo, currently docs and self-service towards our internal PaaS based on k8s. Plans to extend the catalog into Projects, Environments etc |
| [Wayfair](https://www.wayfair.com) | [@fransan](https://github.com/fransan), [@errskipower](https://github.com/errskipower), [@hrrs](https://github.com/hrrs) | Developer portal for service catalog, technical documentation, and APIs. |
| [CircleHD](https://www.circlehd.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [CastDesk](https://castdesk.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [Santagostino](https://santagostino.it) | [@santagostino](https://github.com/santagostino) | Developer portal, gateway to our infrastructure, documentation, service catalog and internal tooling. |
| [Peak](https://peak.ai) | [Luke Beamish](https://github.com/lukebeamish-peak) | Developer portal for all internal engineers to access documentation and tooling. |
| [Gelato](https://gelato.com/) | [Dmitry Makarenko](https://github.com/dmitry-makarenko-gelato) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal and third-party systems🚀. |
| [GoCardless](https://gocardless.com/) | [James Turley](https://github.com/tragiclifestories) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal systems. |
| [Box](https://www.box.com) | [@kielosz](https://github.com/kielosz), [@jluk-box](https://github.com/jluk-box), [@ptychu](https://github.com/ptychu), [@alexrybch](https://github.com/alexrybch), [@szubster](https://github.com/szubster) | Developer portal for service catalog, integration with internal systems, new service onboarding. |
| [Bazaarvoice](https://www.bazaarvoice.com) | [@niallmccullagh](https://github.com/niallmccullagh) | Developer portal for service catalog and scaffolds, publishing Github docs and API documentation, visualising our internal tech radar and our product engineering org structure. |
| [Krateo PlatformOps](https://www.krateo.io) | [@projectkerberus](https://github.com/projectkerberus) | A multi-cloud control plane to create, manage and deploy any kind of resource easily and centrally via a Developer Portal that centralizes via a self-service catalog the templating and ownership of services, the available documentation, the overview of the components that compose an entire domain and all the data of the service lifecycle. |
| [Adevinta](https://www.adevinta.com) | [Ray Sinnema](https://github.com/RemonSinnema) | Showcase shared services to our internal customers. |
| [Splunk](https://www.splunk.com) | [@tonytamsf](https://github.com/tonytamsf) | Developer portal as a centralized place to find people, services, documentation, escalation policies and give bravos. This portal is also being used as a centralized search engine for engineering specific documentation. |
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc. |
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
| [Palo Alto Networks](https://www.paloaltonetworks.com) | [Jeremy Guarini](https://github.com/jeremyguarini), [Brian Lomeland](https://github.com/bbbmmmlll), [Palo Alto Networks](https://github.com/PaloAltoNetworks) | Developer portal, service catalog, documentation and tooling |
| [Signal Iduna Group](https://www.signal-iduna.de/) | [Jonas Thomsen](https://github.com/JoThomsen) | Developer Portal, documentation, monitoring, service catalog for our insurance ecosystem |
| [Tradeshift](https://www.tradeshift.com/) | [Soren Mathiasen](https://github.com/sorenmat) | Developer Portal: documentation, monitoring, service templates, service catalog for our micro services |
| [Unity](https://unity.com) | [Ted Cordery](https://github.com/TeddyBallGame) | A centralized service catalog with documentation for our service engineers. |
| [PicPay](https://www.picpay.com) | [Luis Baroni](https://github.com/lcsbaroni), [Renata Poluceno](https://github.com/renatapoluceno), [PicPay](https://github.com/picpay) | Developer portal for building services through templates, service catalog with ownership of services, documentation and metrics providing autonomy and visibility for all. |
| [Epic Games](https://www.epicgames.com) | [Brian Jung](https://github.com/brian-at-epic), [Jeff Goldian](https://github.com/jeffgoldian-Epic) | Developer Portal: Service Catalog, Documentation, Software Templates and more making our internal teams' lives easier! |
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
| [GoTo](https://www.goto.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. |
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 |
| [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. |
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [Rafał Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
| [Power Home Remodeling](https://www.techatpower.com) | [Ben Langfeld](https://github.com/benlangfeld) | Developer portal to our internal services, build on open-source software (including Kubernetes) in our own datacenters. Our Portal allows our team members to navigate inherant complexity and standardise. |
| [Livspace](https://www.livspace.com) | [Praveen Kumar](https://github.com/praveen-livspace) | Developer portal, service catalog, tech docs, API docs and plugins |
| [Just Eat Takeaway](https://www.justeattakeaway.com) | [Kim Wilson](https://github.com/kwilson541) | Our developer portal which centralises applications, reduces cognitive load and provides teams insights. |
| [Hopin](https://hopin.com) | [Vladimir Glafirov](https://github.com/vglafirov), [Chloe Lee](https://github.com/msfuko) | Developer portal to streamline the development practices. Integrated with service catalog, software templates, application monitoring, tech docs and plugins. |
| [HBO Max](https://hbomax.com) | [@mdb](https://github.com/mdb), [@nesta219](https://github.com/nesta219), [@nmische](https://github.com/nmische), [@hbomark](https://github.com/hbomark) | Developer portal hosting service catalog and API documentation, as well as cloud infrastructure details, operational visibility tools, and a custom plugin for browsing notable platform change events, such as deployments and configuration updates. |
| [RCHLO](https://www.riachuelo.com.br) & [MIDWAY](https://www.midway.com.br) | [@marcosborges](https://github.com/marcosborges), [@defaultbr](https://github.com/defaultbr) | Self-Service Platform |
| [HP Inc](https://www.hp.com) | [Damon Kaswell](https://github.com/dekoding) | DevEx engagement hub (dev portal: docs, standards, Q&A) and extensive assets catalog (APIs, services, code, data, etc.) for the pan-HP internal developer community. |
| [VMware](https://www.vmware.com) | [@mpriamo](https://github.com/mpriamo), [@krisapplegate](https://github.com/krisapplegate) | Part of [Tanzu Application Platform](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/index.html) offering; internal developer portal |
| [Ualá](https://www.uala.com.ar/) | [Santiago Bernal](https://github.com/sabernal) | Initial work being done to centralize documentation for all our microservices and APIs, as well as scaffolding new services and tracking code quality |
| [IKEA IT AB](https://www.ingka.com) | [@bjornramberg](https://github.com/bjornramberg), [@supriyachitale](https://github.com/supriyachitale) | Supporting engineers at scale with self serve access and connecting the dots of our engineering platform and services, enabling product teams to move faster and go further, and unleashing innovation, reuse and co-creation across the organisation. |
| [Invitae](https://www.invitae.com/en) | [@ryan-hanchett](https://github.com/ryan-hanchett), [@gmandler42](https://github.com/gmandler42) | Centralized Developer Experience portal, putting all of our tooling behind a single pane of glass and creating a living service catalog. |
| [Fortum](https://www.fortum.com/) | [@brunoamaroalmeida](https://github.com/brunoamaroalmeida), [@dhaval-vithalani](https://github.com/dhaval-vithalani), [@sunilkumarmohanty](https://github.com/sunilkumarmohanty) | A central portal containing information about our applications, services, processes and other software assets to be used by Fortum software engineering community. |
| [Procore](https://www.procore.com/jobs/engineering) | [@shayon](https://github.com/Shayon), [@jamesdabbs-procore](https://github.com/jamesdabbs-procore) | Developer portal - centralized software catalog and templates to enable self serve and reduce cognitive load. |
| [Bradesco](https://banco.bradesco/html/classic/sobre/index.shtm) | [@danilosoarescardoso](https://github.com/danilosoarescardoso) | Centralized developer portal with software catalog, software templates, techdocs and some plugins from community and by our own. |
| [SeatGeek](https://seatgeek.com) | [@zhammer](https://github.com/zhammer) | Software catalog and documentation platform |
| [Grupo Boticário](https://www.grupoboticario.com.br/) | [@chicoribas](https://github.com/chicoribas), [@fndiaz](https://github.com/fndiaz), [@digogid](https://github.com/digogid), [@manumbs](https://github.com/manumbs), [@haooliveira84](https://github.com/haooliveira84), [@Rhullyam](https://github.com/Rhullyam) | Centralized developer portal with catalog, documentation, and software templates to build a ready to go application, including pipelines (CI/CD) and cloud services provisioning |
| [Snyk](https://snyk.io/) | [@robcresswell](https://github.com/robcresswell) | Developer portal for software discovery, API documentation and templating |
| [Stilingue](https://www.stilingue.com.br/) | [@stilingue-inteligencia-artificial](https://github.com/Stilingue-IA), [@bbviana](https://github.com/bbviana) | Developer portal, services catalog and centralization of metrics from Grafana, Sentry and GCP. Furthermore, centralization of documentation and infra details like DNS, Network services, SSL and so on. |
| [TUI Group](https://www.tuigroup.com/) | [Simon Stamm](https://github.com/simonstamm), [Christian Rudolph](https://github.com/ChrisRu82) | Developer portal for all engineer to provide discoverability to all internal components, APIs, documentation and to scaffold templates with integrations to our internal tools extended by plugins from our community. |
| [Alliander](https://www.alliander.com/) | [@leon-vg](https://github.com/leon-vg), [@gieljl](https://github.com/gieljl), [@niekteg](https://github.com/niekteg) | Developer portal - software catalog, technical documentation, software templates, tech radar and exploration of used tools/services |
| [VIA](https://www.via.com.br) | [@vagnerguedes](https://github.com/vagnerguedes) | Centralized Developer Experience portal - Software catalog and documentation platform, software templates, techdocs, scaffolding, self-service infrastructure |
| [Surevine](https://www.surevine.com/) | [@DJDANNY123](https://github.com/djdanny123) | Developer portal for software catalog, discovery and a view of the technologies we are using across the organisation, we are looking to explore how we can enrich our entities in Backstage by integrating a software bill of materials. |
| [Bonial International GmbH](https://www.bonial.com/) | [@pjungermann](https://github.com/pjungermann) | Centralized developer portal with software catalog, tech docs, templates, and more. |
| [Beez Innovation Labs Pvt. Ltd](https://www.beezlabs.com/) | [Karthikeyan Venkatesan](https://github.com/karthikeyan23) | Developer portal with software catalog, scaffolding, tech docs, templates, and infra. |
| [Agorapulse](https://www.agorapulse.com/) | [@jvdrean](https://github.com/jvdrean) | Developer portal with software catalog, documentation, monitoring, runbooks, tech radar and more. |
| [Wistia](https://wistia.com/) | [@qrush](https://github.com/qrush), [@okize](https://github.com/okize) | Internal Developer Portal, service catalog, tech docs and more |
| [SIX](https://www.six-group.com/) | [@jbadeau](https://github.com/jbadeau), [@tomassatka](https://github.com/tomassatka) | Internal DevOps portal hosting our software and dataset catalog, as well as custom plugins for observability, service virtualization, deployments, incident managment and quality metrics. |
| [Raiffeisen Bank International](https://www.rbinternational.com/) | [Daniel Baumgartner](https://github.com/dabarbi) | From developers for developers: software catalog, techdocs and heavy use of scaffolder to drive reuse on engineering level forward. Part of inner source initiative. Multi national setup coming. |
| [Spread Group](https://www.spreadgroup.com/) | [Luna Stadler](https://github.com/heyLu), [Iván González](https://github.com/ivangonzalezacuna) | Internal Developer Portal, an overview of all running software, architecture documentation and more; replacing and unifying a variety of internal tools. |
| [RD Station](https://rdstation.com) | [Rogerio Angeliski](https://github.com/angeliski), [Paula Assis](https://github.com/paulassis), [Guilherme Eric](https://github.com/guilhermeeric), [Daniela Adamatti](https://github.com/daniadamatti), [Luana Negreiros](https://github.com/luananegreiros) | Developer portal, scaffolding, services catalog. We are looking to centralize automations and information for the whole engineering team . |
| [Resuelve Tu Deuda](https://resuelve.mx) | [Iván Álvarez](https://github.com/ivanhoe), [Jorge Medina](https://github.com/jorgearma1982) | Internal developer portal, service catalog, tech docs, api doc |
| [Pachama](https://pachama.com/) | [Aron Gates](https://github.com/agates4) | Internal Developer Portal, a catalog of all microservices, architecture documentation, and templates to generate developer resources. |
| [SEEK](https://www.seek.com.au) | [Jahred Hope](https://github.com/jahredhope) | Developer portal for developer tooling and technical documentation. |
| [Marks & Spencer](https://www.marksandspencer.com/) | [Kamal Cheriyath](https://github.com/kcheriyath) | Centralised discovery, adoption and devops automation hub for Engineering & Architecture. |
| [McKesson](https://www.mckesson.com/) | [Agnel Antony](https://github.com/aantony2) | Internal Developer Platform for developer gated CI/CD templates, technical documentation, cloud automation service catalog, etc. |
| [World Fuel Services](https://www.wfscorp.com/) | [Anirudh Kurapathi](https://github.com/anirudhkurapati), [Alex Kwon](https://github.com/alexkwon), [Lester Hernandez](https://github.com/lhernandez-wfscorp), [Avi Boru](https://github.com/aviboru), [Vardhan Annapureddy](https://github.com/harshaaws) | Internal Developer Portal, service catalog product, API's, Software Templates, tech docs and more. |
| [leboncoin](https://www.leboncoin.fr/) | [Andy Ladjadj](https://github.com/aladjadj) | Centralize our multiple UI in a single portal. Simplify onbording, new features and harmonize how people search information. Core features (catalog,api,docs,scafolder) are good to start the adoption. status: internal beta. |
| [Contentful](https://www.contentful.com) | [James Bourne](https://github.com/jamesmbourne) | Centralized documentation of service ownership, APIs, and documentation, and new service creation with a custom scaffolder - [full case study with Roadie](https://roadie.io/case-studies/maintaining-velocity-through-hypergrowth-contentful/). |
| [Back Market](https://www.backmarket.com) | [Sami Farhat](https://github.com/skfarhat) | Internal Developer Portal featuring catalog, tech-radar, ownership management, component creation (scaffolder) and centralized infrastructure management -- probably more to come. |
| [Avalia Systems](https://avalia.io) | [Olivier Liechti](https://github.com/wasadigi), [Fabio Velloso](https://github.com/fabiovelloso) | Innersource, software analytics, knowledge base for 360 software assessments, collaborative applications, hub for tracking and sharing IP assets. |
| [Albert Heijn](https://ah.technology) | [Joost Hofman](https://github.com/joosthofman), [Reindrich Geerman](https://github.com/reinst) | Single point of entry for all our engineers (Developer portal), Tech radar, catalog, templates (paved roads) and tech documentation. |
| [Wise, formerly TransferWise](https://wise.com) | [Andrew Beveridge](https://github.com/beveradb) | It's early days for us, we're trying to start small with catalog, tech docs and unified search. Future ambitious vision includes scaffolder for one-click component addition, building out integrations with CI/CD tooling, kubernetes clusters, monitoring/alerting tooling etc. and aiming for a frictionless "golden path" for engineers! 🚀 |
| [Happy Money](http://happymoney.com/) | [Akshit Lomash](mailto:alomash@happymoney.com) | We are moving from a monolith to microservices-based architecture. We are developing a developer portal based on Backstage to create a service catalog for our new services. All the services created are onboarded Backstage and engineering teams are using a cookie-cutter-based template from backstage to initiate a new service. |
| [Lightspeed](http://lightspeedhq.com/) | [Marcus Crane](mailto:marcus.crane@lightspeedhq.com) | We use it within our X-Series division (https://vendhq.com) to catalog ~100+ systems and ~350 components! |
| [Siemens](https://www.siemens.com/global/en.html) | [Nizar Chaouch](mailto:nizar.chaouch@siemens.com) | We are using Backstage as our Developer portal |
| [The Warehouse Group](https://www.thewarehouse.co.nz) | [Matt Law](mailto:matt.law@thewarehouse.co.nz) | Backstage enables us to bootstrap our middleware environment of new services for our Dev teams in a matter of seconds. CI, CD, testing, logging, deployments are all taken care of to get them up and running in less than 60 seconds. |
| [Tink](https://tink.com/) | [Sebastian Olsson](https://github.com/Sebelino), [Błażej Szum](https://github.com/blazejszumtink), [Anders Eurenius Runvald](https://github.com/anders-er-at-tink) | Internal developer portal which provides templates for creating new Java or Go microservices seamlessly. Also includes a tech radar and a visualization of our CD pipeline. |
| [Brandwatch](https://brandwatch.com) | [Stefan Buck](https://github.com/stefanbuck) | Our primary focus is on the service catalog. Backstage is replacing our homemade service catalog. The switch was quite simple due to the catalog processor API. |
| [Laybuy](https://www.laybuy.com) | [Chris Simmons](https://github.com/contrarianchris) | Backstage is the heart of Laybuys new centralised Development Platform, bringing disparate development tools and experiences into a single easy-to-use portal. It simplifies software and API discovery, project scaffolding, and technical documentation, enabling us to embrace golden path development and automate software standards. |
| [Sendinblue](https://engineering.sendinblue.com/) | [Tanguy Antoine](mailto:antoine.tanguy@sendinblue.com) | Helps us drive the change at scale. Puts light on services, resources, and dependencies. One tool that rules them all through plugins we created for that purpose. We are aiming to put Backstage at the center of every developer's work (Actionable items, Debugging, Monitoring, Provisioning, etc...) to improve their happiness |
| [SafetyCulture](https://safetyculture.com/) | [@R-cen](https://github.com/R-cen), [@lachlancooper](https://github.com/lachlancooper), [@hkf57](https://github.com/hkf57) | Internal developer portal to provide a centralized place for engineers to see an overview of their team's services and information related to the service from other systems. Initially focused on the software catalog, techdocs and search. |
| [Sana Life Science](https://sanalifescience.com) | [Joe Hillyard](mailto:joe@sanalifescience.com) | API Catalog, Tools Management & Control Hub |
| [Ndustrial](https://ndustrial.io) | [Jonathan Skubic](mailto:jonathan@ndustrial.io) | Software Project Catalog |
| [TUI Musement](https://www.musement.com/uk/) | [Simone Fumagalli](mailto:simone.fumagalli@musement.com) | We are importing our catalog into it to keep it under control. The next step is start using templates |
| [Kambi AB](https://www.kambi.com) | [Martin Norum](mailto:martin.norum@kambi.com) | We want to kick ass at speed, so we're currently building up a catalog of our existing software, and looking into how Backstage can support us in our journey towards autonomous product teams. Both to improve speed to market and operational awareness. |
| [ANZ](https://www.anz.com.au/personal/) | [Elliot Jackson](mailto:elliot.jackson@anz.com) | Catalog, tech docs and automation |
| [Genie Solutions](https://www.geniesolutionssoftware.com.au) | [Zainab Bagasrawala](mailto:zainabbagasrawala@geniesolutions.com.au) | Developer Portal to track our projects, documentation, observability tools and more |
| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [Paulo Eduardo Peixoto](mailto:paulo.peixoto@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. |
| [Sonatype](https://www.sonatype.com) | [Srikar Ananthula](mailto:sananthula@sonatype.com) | Centralize services used internally with many plugins |
| [CVS Health](https://www.cvshealth.com) | [Ari Ben-Elazar](mailto:abenelazar@gmail.com) | Cataloging and documenting our service offerings to offer our internal developers a better operational journey |
| [Yatra.com](https://www.yatra.com) | [Matiur Rahman Maitur](mailto:arifrahman4u@gmail.com) | Easy to find out Project details, ownership, dependent services, Documentation, it is very useful for developer. |
| [Yotpo](https://www.yotpo.com) | [Liran Yogev](mailto:lyogev@yotpo.com) | Services exploration, documentation and project generator |
| [Mainsail Industries](https://www.mainsailindustries.com) | [Brad Sollar](mailto:brad@mainsailindustries.com) | Internal tool management and docs |
| [Prisma](https://prismamp.com) | [Sebastian Gravina](mailto:sgravina@prismamp.com) | Is part of our IDP |
| [Syndetic](https://syndetic.io) | [John Feminella](mailto:robots+swag@syndetic.io) | We're working with multiple F100 clients for digital transformation and Backstage is a key part of our landing and acceleration strategy. |
| [Imagine Learning](https://www.imaginelearning.com/en/us) | [Jared Stehler](mailto:jared.stehler@imaginelearning.com) | Software catalog, product dependency visualization |
| [Alef Education](https://www.alefeducation.com) | [Belal Juma](mailto:belal.juma@alefeducation.com) | We use backstage as a Service Catalog and rely on the TechDocs feature |
| [Zego](https://www.zego.com) | [Sean Kenny](mailto:sean.kenny@zego.com) | Single pane of glass for organisational and operational information for all services across our systems. |
| [Absa Group Limited](https://www.absa.africa/absaafrica/) | [Chris Kieser](mailto:chris.kieser@absa.africa) | Developer portal for all development needs - security, AWS, k8s, build and deployment pipelines and more |
| [Nutrien Ag Solutions](https://www.nutrienagsolutions.com.au) | [Jan Quijano](mailto:jan.quijano@nutrien.com.au) | Software Project Catalog |
| [Lendingkart](https://www.lendingkart.com/) | [Dinesh Rajpoot](mailto:dinesh.rajpoot@lendingkart.com) | Service catalog, Software templates to enforce best practices and tech insights to track mandates & migrations. |
| [Meltwater](https://underthehood.meltwater.com) | [@spier](https://github.com/spier), [@remen](https://github.com/remen) | Improving developer experience by centralizing documentation and internal APIs. Goal: Foster InnerSource collaboration and speed up onboarding time in our 500+ people Product & Engineering org. |
| [Doctolib](https://doctolib.engineering/) | [@djiit](https://github.com/djiit) | Rails modularization effort awareness, tech organization discoverability. Improving the daily workflows and collaboration processes of our engineers. |
| [Twilio](https://www.twilio.com) | [Kyle Smith](https://github.com/knksmith57) | Developer portal, universal software catalog, and centralized taxonomy platform. |
| [OVHcloud](https://www.ovhcloud.com/fr/) | [Jean-Philippe Blary](https://github.com/blaryjp), [Arnaud Bauer](mailto:arnaud.bauer@ovhcloud.com), [Flavien Chantelot](https://github.com/Dorn-) | We're providing Backstage to our collaborators to ease their daily jobs, and let them extends it using plugins. |
| [Procter & Gamble](https://us.pg.com/) | [Binita Nayak](https://github.com/binitan), [Josh Rose](https://github.com/joshuarose), [RJ Winkler](https://github.com/rjwink) | P&G leverages Backstage to build internal developer portal to ensure developers' happiness. This developer portal shall act as single source of information needed by development teams to seamlessly create, find and maintain their software components/resources/documentation. |
| [SANS Institute](https://www.sans.org) | [Christopher Klewin](mailto:cklewin@sans.org) | Developer portal for centralized visibility, reporting, and tooling across multiple organizations. |
| [Okay](https://www.okayhq.com/) | [Tomas Barreto](mailto:tomas@okayhq.com) | Service catalog, developer portal, and technical documentation |
| [Kaluza](https://www.kaluza.com) | [James Condren](mailto:james.condron@kaluza.com) | To provide an automated golden path to developers, with a focus on discovery and documentation |
| [LinkedIn](https://linkedin.com) | [Joshua Lawrence](mailto:jlawrence@linkedin.com) | We are building a platform for internal web tools |
| [Forto](https://forto.com) | [Rodolfo Matos](mailto:rodolfo.matos@forto.com) | Still in a experimental phase/assessing the organisational fit. We will be using it mostly a developer portal -- pretty standard use case. |
| [BetterUp](https://betterup.com) | [Jordan Hochenbaum](mailto:jordan.hochenbaum@betterup.co) | We're starting to use Backstage as the central hub for service discovery, documentation, and develop experience. |
| [warung pintar](https://warungpintar.co.id/) | [Muhammad Rafly Andrianza](mailto:rafly.andrianza@warungpintar.co) | Initial Work Developer Portal with TechRadar, Service Catalogue, TechDocs, anything about platform & infrastructure resources. |
| [RD](https://rd.com.br/) | [Michael Silva](mailto:midsilva@rd.com.br) | We are building our developer portal. Software catalog, Tech Radar and Scaffolding are among the initial features. |
| [AEB](https://www.aeb.com/) | [David Fankhänel](mailto:dfl@aeb.com) | Central developer platform for creating new apps via templates, getting an overview via software catalog, etc |
| [SALTO Systems](https://saltosystems.com) | [Ian Cowley](mailto:i.cowley@saltosystems.com) | Currently using Backstage as an internal documentation portal. |
| [Lummo](https://lummo.com) | [Anjul Sahu](mailto:anjul@lummo.com) | We are building the internal developer portal using Backstage and bringing up all integrations and service information at one place. |
| [Frontside](https://frontside.com) | [Taras Mankovski](mailto:taras@frontside.com) | |
| [Stepstone](https://www.stepstone.com/en/) | [Neil Kennedy](mailto:neil.kennedy@stepstone.com) | StepStone is using Backstage to solve problems around ownership and visibility of our applications. We have thousands of repos, multiple legacy systems and a growing platform that is hard to maintain. Backstage is forming the centre of our push to embrace the chaos. |
| [idwall](https://idwall.co) | [Rodrigo Catão Araujo](mailto:rodrigo@idwall.co) | Developer Portal for internal engineers to access service catalog, documentation, observability, infrastructure and internal tooling. |
| [Jaguar Land Rover](https://www.jaguarlandrover.com) | [Josh Walker](mailto:jwalke18@jaguarlandrover.com) | Users can request a Gitlab user, which creates a commit with the Terraform code. |
| [Glovo](http://glovoapp.com/) | [Yaser Toutah](mailto:yaser.toutah@glovoapp.com) | Developer Portal to improve our Developer Experience, identify ownership and track metadata for our services and tools. It's our Service Catalog. In addition to that, we use it for Service Creation, and much more. |
| [Dixa](https://dixa.com) | [Jens Møller](https://github.com/jensamoller) | We are in early stages, but using it to get overview of our repositories and ownership of these. We want among many things to use it for compliance and easier access to key metrics for our repos. |
| [Notino](https://notino.com) | [Jan Remunda](mailto:jan.remunda@notino.com) | Backstage is our developer portal. We use it as service catalog and for technical documentation. |
| [Polarpoint](https://polarpoint.io/) | [Surj Bains](https://github.com/polarpoint-io) | We are using Backstage as our Developer portal as well as for hosting our DevOps portal for software catalog. |
| [Niche](https://niche.com) | [Zach Romitz](mailto:zach.romitz@niche.com) | We are using the Software Catalog, Software Templates, API documentation, and Techdocs to try and centralize service information. |
| [Mercedes-Benz.io](https://www.mercedes-benz.io/) | [Manuel Santos](https://github.com/manusant) | At Mercedes-Benz we use it as a developer portal with software catalog, TechDocs, Scaffolding and custom plugins. It provides an overview of our tech ecosystem to our product development teams. The portal also serves as a way to foster collaboration among the numerous companies of the Mercedes-Benz Group. |
| [Funding Circle](https://www.fundingcircle.com/) | [Ariel Pacciaroni](https://github.com/arielpacciaroni) | We are building the internal developer portal using Backstage project and centralizing all services information at one place. The portal helps us track down repositories ownership as well as direct access to key information on every component. |
| [Clarivate](https://www.clarivate.com) | [Gabriele Carteni](mailto:gabriele.carteni@clarivate.com) | We are building our Developer Portal using Backstage to have a better control over our software ecosystem, integrate SDLC tools and promote best practices |
| [Cho Tot](https://www.chotot.com) | [Chotot Team](mailto:sre@chotot.vn) | Internal developer portal, service catalog with CI/CD tools. |
| [William Hill](https://www.williamhillgroup.com/) | [Pat Mills](mailto:pat.mills@williamhill.com), [Nathan Flynn](mailto:nflynn@williamhill.co.uk), and [Nishkarsh Raj](mailto:nishkarsh.raj@williamhill.co.uk) | William Hill are leveraging Backstage to build our Engineering Portal. Our mission is to centralize the software catalog inventory to enable service discoverability, reduce the onboarding time for new Engineers, provide a single pane of glass to accelerate Developer Productivity and Save Engineers time. Our aspiration is to create an InnerSource community focussed on organization-wide patterns that are re-usable and can be self-served with the Scaffolder. |
| [Vodafone NewZealand Limited](https://vodafone.co.nz) | [Ankit Gupta](mailto:ankit.gupta@vodafone.nz), [DevOps COE](mailto:devopstooling@vodafone.nz) | Vodafone NZ are leveraging Backstage to build centralised and self service Engineering Portal. Our mission is to standardised Pipeline templates across the Engineering teams, One shop stop to create the pipelines and repository with a template approach which reduces creation part from days to minutes and no wait time for developers. A unified view for Azure DevOps pipeline, Azure Repo pull requests, Deployment status from Azure RedHat Openshift-ArgoCD and SonarQube Security and code quality scans report on a single pan to provide a streamlined view for all microservices across the app stack. |
| [Coamo](http://www.coamo.com.br) | [@holiiveira](https://github.com/holiiveira), [@gpxlnx](https://github.com/gpxlnx) | We're starting to use it as the main tool of a DevOps platform. Our goal is to provide software templates, centralize our software catalog enabling efficient service discovery, and make it easy to manage the entire software ecosystem in one place. |
| [Exclaimer](https://www.exclaimer.com/) | [Marley Powell](mailto:marley.powell@exclaimer.com) | Developer portal, service catalog and documentation |
| [Edge Consulting](https://egde.no/) | [Øyvind Brekkhus Sandåker](mailto:oyvindbs@egde.no) | Using it as a Software Catalog to get an overview of our systems, for ourselves and our customers. |
| [CRV](https://crv4all.com) | [Pepijn Schildkamp](mailto:pepijn.schildkamp@crv4all.com) |
| [uisee.com](https://uisee.com) | [Haili Zhang](mailto:haili.zhang@uisee.com) | In PoC stage, planning to land it for cloud platform dev team. |
| [Egencia](https://www.egencia.com) | [Micheal Gibbons](mailto:migibbons@egencia.com) | Developer Portal: Software Catalog, Software Templates and Techdocs. |
| [Adaptavist](https://adaptavist.com) | [Lilly Holden](mailto:lholden@adaptavist.com) | Developer portal, service catalog, documentation and self-service platform |
| [Shipshape](https://shipshape.io) | [Chuck Carpenter](mailto:chuck@shipshape.io) | We are a consultancy helping teams implement and customize Backstage. |
| [Backbase](https://backbase.com) | [Nicolas Torres](mailto:ntorres.dev@gmail.com) | To catalog components and teams |
| [https://www.clear.sale](https://www.clear.sale) | [Paulo Baima](mailto:paulo.filho@clear.sale) | Central Hub for all the company modules, enabling the track of ownership of components and resources and how they relate to each other. |
| [www.leroymerlin.com.br](https://www.leroymerlin.com.br) | [Rodrigo Franzoni](mailto:rfranzoni@leroymerlin.com.br) | Our engineers use the Backstage to solve problems around ownership and visibility of our applications, access service catalog, documentation, observability and infrastructure. |
| [Intility](https://intility.no/en/) | [@daniwk](https://github.com/daniwk) | We are creating a developer portal powered by Backstage, with software catalog, documentation, templates and integrations to our infrastructure and internal tools. |
+5 -1
View File
@@ -41,6 +41,8 @@ auth:
clientId: ${AUTH_OKTA_CLIENT_ID}
clientSecret: ${AUTH_OKTA_CLIENT_SECRET}
audience: ${AUTH_OKTA_DOMAIN}
authServerId: ${AUTH_OKTA_AUTH_SERVER_ID} # Optional
idp: ${AUTH_OKTA_IDP} # Optional
```
The values referenced are found on the Application page on your Okta site.
@@ -48,8 +50,10 @@ The values referenced are found on the Application page on your Okta site.
- `clientId`: The client ID that you generated on Okta, e.g.
`3abe134ejxzF21HU74c1`
- `clientSecret`: The client secret shown for the Application.
- `audience`: The Okta domain shown for your Application, e.g.
- `audience`: The Okta domain shown for the Application, e.g.
`https://company.okta.com`
- `authServerId`: The authorization server ID for the Application
- `idp`: The identity provider for the application, e.g. `0oaulob4BFVa4zQvt0g3`
## Adding the provider to the Backstage frontend
@@ -57,10 +57,17 @@ This is an array used to determine where to retrieve cluster configuration from.
Valid cluster locator methods are:
- [`localKubectlProxy`](#localKubectlProxy)
- [`config`](#config)
- [`gke`](#gke)
- [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier)
#### `localKubectlProxy`
This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001).
NOTE: This cluster locator method is for local development only and should not be used in production.
#### `config`
This cluster locator method will read cluster information from your app-config
@@ -242,13 +242,14 @@ that entity if the periskop plugin is installed.
# Example:
metadata:
annotations:
sentry.io/project-slug: pump-station
sentry.io/project-slug: backstage/pump-station
```
The value of this annotation is the so-called slug (or alternatively, the ID) of
a [Sentry](https://sentry.io) project within your organization. The organization
slug is currently not configurable on a per-entity basis, but is assumed to be
the same for all entities in the catalog.
a [Sentry](https://sentry.io) project within your organization. The value can
be the format of `[organization]/[project-slug]` or just `[project-slug]`. When
the organization slug is omitted the `app-config.yaml` will be used as a
fallback (`sentry.organization`).
Specifying this annotation may enable Sentry related features in Backstage for
that entity.
+1 -1
View File
@@ -79,7 +79,7 @@ privateKey: |
### Including in Integrations Config
Once the credentials are stored in a YAML file generated by `create-github-app`,
or manually by following the [GitHub Enterprise](#gitHub-enterprise)
or manually by following the [GitHub Enterprise](#github-enterprise)
instructions, they can be included in the `app-config.yaml` under the
`integrations` section.
+1 -1
View File
@@ -49,7 +49,7 @@ functionality, breaking changes, and bug fixes, according the
[versioning policy](#release-versioning-policy).
Patch versions will only be released to address critical bug fixes. They are not
bound to the regular cadence and are instead releases whenever needed.
bound to the regular cadence and are instead released whenever needed.
## Next Release Line
+1 -1
View File
@@ -40,7 +40,7 @@
"@hot-loader/react-dom-v16": "npm:@hot-loader/react-dom@^16.0.2",
"@hot-loader/react-dom-v17": "npm:@hot-loader/react-dom@^17.0.2",
"@manypkg/get-packages": "^1.1.3",
"@octokit/request": "^5.4.12",
"@octokit/request": "^6.0.0",
"@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.6",
+1 -1
View File
@@ -66,7 +66,7 @@
"react-syntax-highlighter": "^15.4.5",
"react-text-truncate": "^0.19.0",
"react-use": "^17.3.2",
"@react-hookz/web": "^14.0.0",
"@react-hookz/web": "^15.0.0",
"react-virtualized-auto-sizer": "^1.0.6",
"react-window": "^1.8.6",
"remark-gfm": "^3.0.1",
+1 -1
View File
@@ -38,7 +38,7 @@
"cross-fetch": "^3.1.5",
"git-url-parse": "^12.0.0",
"@octokit/rest": "^18.5.3",
"@octokit/auth-app": "^3.4.0",
"@octokit/auth-app": "^4.0.0",
"luxon": "^2.0.2",
"lodash": "^4.17.21"
},
+1 -1
View File
@@ -40,6 +40,7 @@
"@backstage/config": "^1.0.1",
"@backstage/errors": "^1.1.0-next.0",
"@backstage/types": "^1.0.0",
"@davidzemon/passport-okta-oauth": "^0.0.5",
"@google-cloud/firestore": "^5.0.2",
"@types/express": "^4.17.6",
"@types/passport": "^1.0.3",
@@ -68,7 +69,6 @@
"passport-google-oauth20": "^2.0.0",
"passport-microsoft": "^1.0.0",
"passport-oauth2": "^1.6.1",
"passport-okta-oauth": "^0.0.1",
"passport-onelogin-oauth": "^0.0.1",
"passport-saml": "^3.1.2",
"uuid": "^8.0.0",
@@ -26,7 +26,7 @@ import {
OAuthRefreshRequest,
OAuthResult,
} from '../../lib/oauth';
import { Strategy as OktaStrategy } from 'passport-okta-oauth';
import { Strategy as OktaStrategy } from '@davidzemon/passport-okta-oauth';
import passport from 'passport';
import {
executeFrameHandlerStrategy,
@@ -55,6 +55,8 @@ type PrivateInfo = {
export type OktaAuthProviderOptions = OAuthProviderOptions & {
audience: string;
authServerId?: string;
idp?: string;
signInResolver?: SignInResolver<OAuthResult>;
authHandler: AuthHandler<OAuthResult>;
resolverContext: AuthResolverContext;
@@ -94,6 +96,8 @@ export class OktaAuthProvider implements OAuthHandlers {
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
audience: options.audience,
authServerID: options.authServerId,
idp: options.idp,
passReqToCallback: false,
store: this.store,
response_type: 'code',
@@ -220,6 +224,8 @@ export const okta = createAuthProviderIntegration({
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const audience = envConfig.getString('audience');
const authServerId = envConfig.getOptionalString('authServerId');
const idp = envConfig.getOptionalString('idp');
const customCallbackUrl = envConfig.getOptionalString('callbackUrl');
const callbackUrl =
customCallbackUrl ||
@@ -240,6 +246,8 @@ export const okta = createAuthProviderIntegration({
const provider = new OktaAuthProvider({
audience,
authServerId,
idp,
clientId,
clientSecret,
callbackUrl,
@@ -12,6 +12,7 @@ import express from 'express';
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
import { GitTag } from '@backstage/plugin-azure-devops-common';
import { Logger } from 'winston';
import { Project } from '@backstage/plugin-azure-devops-common';
import { PullRequest } from '@backstage/plugin-azure-devops-common';
import { PullRequestOptions } from '@backstage/plugin-azure-devops-common';
import { RepoBuild } from '@backstage/plugin-azure-devops-common';
@@ -64,6 +65,8 @@ export class AzureDevOpsApi {
// (undocumented)
getGitTags(projectName: string, repoName: string): Promise<GitTag[]>;
// (undocumented)
getProjects(): Promise<Project[]>;
// (undocumented)
getPullRequests(
projectName: string,
repoName: string,
@@ -30,6 +30,7 @@ import {
RepoBuild,
Team,
TeamMember,
Project,
} from '@backstage/plugin-azure-devops-common';
import {
GitPullRequest,
@@ -47,7 +48,10 @@ import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/co
import { Logger } from 'winston';
import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces';
import { WebApi } from 'azure-devops-node-api';
import { WebApiTeam } from 'azure-devops-node-api/interfaces/CoreInterfaces';
import {
TeamProjectReference,
WebApiTeam,
} from 'azure-devops-node-api/interfaces/CoreInterfaces';
export class AzureDevOpsApi {
public constructor(
@@ -55,6 +59,20 @@ export class AzureDevOpsApi {
private readonly webApi: WebApi,
) {}
public async getProjects(): Promise<Project[]> {
const client = await this.webApi.getCoreApi();
const projectList: TeamProjectReference[] = await client.getProjects();
const projects: Project[] = projectList.map(project => ({
id: project.id,
name: project.name,
description: project.description,
}));
return projects.sort((a, b) =>
a.name && b.name ? a.name.localeCompare(b.name) : 0,
);
}
public async getGitRepository(
projectName: string,
repoName: string,
@@ -63,6 +63,11 @@ export async function createRouter(
res.status(200).json({ status: 'ok' });
});
router.get('/projects', async (_req, res) => {
const projects = await azureDevOpsApi.getProjects();
res.status(200).json(projects);
});
router.get('/repository/:projectName/:repoName', async (req, res) => {
const { projectName, repoName } = req.params;
const gitRepository = await azureDevOpsApi.getGitRepository(
@@ -168,6 +168,15 @@ export enum PolicyTypeId {
Status = 'cbdc66da-9728-4af8-aada-9a5a32e4a226',
}
// Warning: (ae-missing-release-tag) "Project" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type Project = {
id?: string;
name?: string;
description?: string;
};
// Warning: (ae-missing-release-tag) "PullRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
+6
View File
@@ -288,3 +288,9 @@ export type BuildRun = {
export type BuildRunOptions = {
top?: number;
};
export type Project = {
id?: string;
name?: string;
description?: string;
};
+15 -2
View File
@@ -268,6 +268,12 @@ export type CatalogProcessorParser = (options: {
location: LocationSpec;
}) => AsyncIterable<CatalogProcessorResult>;
// @public (undocumented)
export type CatalogProcessorRefreshKeysResult = {
type: 'refresh';
key: string;
};
// @public (undocumented)
export type CatalogProcessorRelationResult = {
type: 'relation';
@@ -279,7 +285,8 @@ export type CatalogProcessorResult =
| CatalogProcessorLocationResult
| CatalogProcessorEntityResult
| CatalogProcessorRelationResult
| CatalogProcessorErrorResult;
| CatalogProcessorErrorResult
| CatalogProcessorRefreshKeysResult;
// @public (undocumented)
export class CodeOwnersProcessor implements CatalogProcessor {
@@ -545,7 +552,11 @@ export class PlaceholderProcessor implements CatalogProcessor {
// (undocumented)
getProcessorName(): string;
// (undocumented)
preProcessEntity(entity: Entity, location: LocationSpec): Promise<Entity>;
preProcessEntity(
entity: Entity,
location: LocationSpec,
emit: CatalogProcessorEmit,
): Promise<Entity>;
}
// @public (undocumented)
@@ -567,6 +578,7 @@ export type PlaceholderResolverParams = {
baseUrl: string;
read: PlaceholderResolverRead;
resolveUrl: PlaceholderResolverResolveUrl;
emit: CatalogProcessorEmit;
};
// @public (undocumented)
@@ -601,6 +613,7 @@ export const processingResult: Readonly<{
newEntity: Entity,
) => CatalogProcessorResult;
readonly relation: (spec: EntityRelationSpec) => CatalogProcessorResult;
readonly refresh: (key: string) => CatalogProcessorResult;
}>;
// @public (undocumented)
@@ -0,0 +1,53 @@
/*
* 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.
*/
/**
* @param { import("knex").Knex } knex
*/
exports.up = async function up(knex) {
await knex.schema.createTable('refresh_keys', table => {
table.comment(
'This table contains relations between entities and keys to trigger refreshes with',
);
table
.text('entity_id')
.notNullable()
.references('entity_id')
.inTable('refresh_state')
.onDelete('CASCADE')
.comment('A reference to the entity that the refresh key is tied to');
table
.text('key')
.notNullable()
.comment(
'A reference to a key which should be used to trigger a refresh on this entity',
);
table.index('entity_id', 'refresh_keys_entity_id_idx');
table.index('key', 'refresh_keys_key_idx');
});
};
/**
* @param { import("knex").Knex } knex
*/
exports.down = async function down(knex) {
await knex.schema.alterTable('refresh_keys', table => {
table.dropIndex([], 'refresh_keys_entity_id_idx');
table.dropIndex([], 'refresh_keys_key_idx');
});
await knex.schema.dropTable('refresh_keys');
};
+1
View File
@@ -26,6 +26,7 @@ export type {
CatalogProcessorRelationResult,
CatalogProcessorErrorResult,
CatalogProcessorResult,
CatalogProcessorRefreshKeysResult,
} from './processor';
export type {
EntityProvider,
@@ -65,4 +65,8 @@ export const processingResult = Object.freeze({
relation(spec: EntityRelationSpec): CatalogProcessorResult {
return { type: 'relation', relation: spec };
},
refresh(key: string): CatalogProcessorResult {
return { type: 'refresh', key };
},
} as const);
+8 -1
View File
@@ -169,9 +169,16 @@ export type CatalogProcessorErrorResult = {
location: LocationSpec;
};
/** @public */
export type CatalogProcessorRefreshKeysResult = {
type: 'refresh';
key: string;
};
/** @public */
export type CatalogProcessorResult =
| CatalogProcessorLocationResult
| CatalogProcessorEntityResult
| CatalogProcessorRelationResult
| CatalogProcessorErrorResult;
| CatalogProcessorErrorResult
| CatalogProcessorRefreshKeysResult;
@@ -24,6 +24,7 @@ import { DateTime } from 'luxon';
import { applyDatabaseMigrations } from './migrations';
import { DefaultProcessingDatabase } from './DefaultProcessingDatabase';
import {
DbRefreshKeysRow,
DbRefreshStateReferencesRow,
DbRefreshStateRow,
DbRelationsRow,
@@ -98,6 +99,7 @@ describe('Default Processing Database', () => {
resultHash: '',
relations: [],
deferredEntities: [],
refreshKeys: [],
}),
).rejects.toThrow(
`Conflicting write of processing result for ${id} with location key 'undefined'`,
@@ -117,6 +119,7 @@ describe('Default Processing Database', () => {
relations: [],
deferredEntities: [],
locationKey: 'key',
refreshKeys: [],
errors: "['something broke']",
};
const { knex, db } = await createDatabase(databaseId);
@@ -143,6 +146,7 @@ describe('Default Processing Database', () => {
...options,
resultHash: '',
locationKey: 'fail',
refreshKeys: [],
}),
).rejects.toThrow(
`Conflicting write of processing result for ${id} with location key 'fail'`,
@@ -174,6 +178,7 @@ describe('Default Processing Database', () => {
relations: [],
deferredEntities: [],
locationKey: 'key',
refreshKeys: [],
errors: "['something broke']",
}),
);
@@ -228,6 +233,7 @@ describe('Default Processing Database', () => {
resultHash: '',
relations: relations,
deferredEntities: [],
refreshKeys: [],
}),
);
@@ -250,6 +256,7 @@ describe('Default Processing Database', () => {
resultHash: '',
relations: relations,
deferredEntities: [],
refreshKeys: [],
}),
);
@@ -309,6 +316,7 @@ describe('Default Processing Database', () => {
resultHash: '',
relations: [],
deferredEntities,
refreshKeys: [],
}),
);
@@ -400,6 +408,7 @@ describe('Default Processing Database', () => {
processedEntity,
resultHash: '',
relations: [],
refreshKeys: [],
deferredEntities: [
{
entity: {
@@ -465,6 +474,63 @@ describe('Default Processing Database', () => {
},
60_000,
);
it.each(databases.eachSupportedId())(
'stores the refresh keys for the entity',
async databaseId => {
const mockLogger = {
debug: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
};
const { knex, db } = await createDatabase(
databaseId,
mockLogger as unknown as Logger,
);
await insertRefreshStateRow(knex, {
entity_id: id,
entity_ref: 'location:default/fakelocation',
unprocessed_entity: '{}',
processed_entity: '{}',
errors: '[]',
next_update_at: '2021-04-01 13:37:00',
last_discovery_at: '2021-04-01 13:37:00',
});
const deferredEntities = [
{
entity: {
apiVersion: '1',
kind: 'Location',
metadata: {
name: 'next',
},
},
locationKey: 'mock',
},
];
await db.transaction(tx =>
db.updateProcessedEntity(tx, {
id,
processedEntity,
resultHash: '',
relations: [],
deferredEntities,
refreshKeys: [{ key: 'protocol:foo-bar.com' }],
}),
);
const refreshKeys = await knex<DbRefreshKeysRow>('refresh_keys')
.where({ entity_id: id })
.select();
expect(refreshKeys[0]).toEqual({
entity_id: id,
key: 'protocol:foo-bar.com',
});
},
);
});
describe('updateEntityCache', () => {
@@ -33,12 +33,14 @@ import {
UpdateEntityCacheOptions,
ListParentsOptions,
ListParentsResult,
RefreshByKeyOptions,
} from './types';
import { DeferredEntity } from '../processing/types';
import { ProcessingIntervalFunction } from '../processing/refresh';
import { rethrowError, timestampToDateTime } from './conversion';
import { initDatabaseMetrics } from './metrics';
import {
DbRefreshKeysRow,
DbRefreshStateReferencesRow,
DbRefreshStateRow,
DbRelationsRow,
@@ -77,6 +79,7 @@ export class DefaultProcessingDatabase implements ProcessingDatabase {
errors,
relations,
deferredEntities,
refreshKeys,
locationKey,
} = options;
const refreshResult = await tx<DbRefreshStateRow>('refresh_state')
@@ -100,11 +103,12 @@ export class DefaultProcessingDatabase implements ProcessingDatabase {
`Conflicting write of processing result for ${id} with location key '${locationKey}'`,
);
}
const sourceEntityRef = stringifyEntityRef(processedEntity);
// Schedule all deferred entities for future processing.
await this.addUnprocessedEntities(tx, {
entities: deferredEntities,
sourceEntityRef: stringifyEntityRef(processedEntity),
sourceEntityRef,
});
// Delete old relations
@@ -138,6 +142,21 @@ export class DefaultProcessingDatabase implements ProcessingDatabase {
BATCH_SIZE,
);
// Delete old refresh keys
await tx<DbRefreshKeysRow>('refresh_keys')
.where({ entity_id: id })
.delete();
// Insert the refresh keys for the processed entity
await tx.batchInsert(
'refresh_keys',
refreshKeys.map(k => ({
entity_id: id,
key: k.key,
})),
BATCH_SIZE,
);
return {
previous: {
relations: previousRelationRows,
@@ -516,6 +535,25 @@ export class DefaultProcessingDatabase implements ProcessingDatabase {
}
}
async refreshByRefreshKeys(
txOpaque: Transaction,
options: RefreshByKeyOptions,
) {
const tx = txOpaque as Knex.Transaction;
const { keys } = options;
await tx<DbRefreshStateRow>('refresh_state')
.whereIn('entity_id', function selectEntityRefs(tx2) {
tx2
.whereIn('key', keys)
.select({
entity_id: 'refresh_keys.entity_id',
})
.from('refresh_keys');
})
.update({ next_update_at: tx.fn.now() });
}
async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {
try {
let result: T | undefined = undefined;
@@ -43,6 +43,11 @@ export type DbRefreshStateRow = {
location_key?: string;
};
export type DbRefreshKeysRow = {
entity_id: string;
key: string;
};
export type DbRefreshStateReferencesRow = {
source_key?: string;
source_entity_ref?: string;
@@ -18,7 +18,7 @@ import { Entity } from '@backstage/catalog-model';
import { JsonObject } from '@backstage/types';
import { DateTime } from 'luxon';
import { EntityRelationSpec } from '../api';
import { DeferredEntity } from '../processing/types';
import { DeferredEntity, RefreshKeyData } from '../processing/types';
import { DbRelationsRow } from './tables';
/**
@@ -38,6 +38,7 @@ export type UpdateProcessedEntityOptions = {
relations: EntityRelationSpec[];
deferredEntities: DeferredEntity[];
locationKey?: string;
refreshKeys: RefreshKeyData[];
};
export type UpdateEntityCacheOptions = {
@@ -81,6 +82,10 @@ export type ReplaceUnprocessedEntitiesOptions =
type: 'delta';
};
export type RefreshByKeyOptions = {
keys: string[];
};
export type RefreshOptions = {
entityRef: string;
};
@@ -43,7 +43,10 @@ describe('FileReaderProcessor', () => {
expect(generated.type).toBe('entity');
expect(generated.location).toEqual(spec);
expect(generated.entity).toEqual({ kind: 'Component' });
expect(generated.entity).toEqual({
kind: 'Component',
metadata: { name: 'component-test' },
});
});
it('should fail load from file with error', async () => {
@@ -77,14 +80,24 @@ describe('FileReaderProcessor', () => {
defaultEntityDataParser,
);
expect(emit).toBeCalledTimes(2);
expect(emit.mock.calls[0][0].entity).toEqual({ kind: 'Component' });
expect(emit).toBeCalledTimes(4);
expect(emit.mock.calls[0][0].entity).toEqual({
kind: 'Component',
metadata: { name: 'component-test' },
});
expect(emit.mock.calls[0][0].location).toEqual({
type: 'file',
target: expect.stringMatching(/^[^*]*$/),
});
expect(emit.mock.calls[1][0].entity).toEqual({ kind: 'API' });
expect(emit.mock.calls[1][0].location).toEqual({
expect(emit.mock.calls[1][0].key).toContain('file:');
expect(emit.mock.calls[1][0].key).toContain(
'fileReaderProcessor/component.yaml',
);
expect(emit.mock.calls[2][0].entity).toEqual({
kind: 'API',
metadata: { name: 'api-test' },
});
expect(emit.mock.calls[2][0].location).toEqual({
type: 'file',
target: expect.stringMatching(/^[^*]*$/),
});
@@ -28,6 +28,8 @@ import {
const glob = promisify(g);
const LOCATION_TYPE = 'file';
/** @public */
export class FileReaderProcessor implements CatalogProcessor {
getProcessorName(): string {
@@ -40,7 +42,7 @@ export class FileReaderProcessor implements CatalogProcessor {
emit: CatalogProcessorEmit,
parser: CatalogProcessorParser,
): Promise<boolean> {
if (location.type !== 'file') {
if (location.type !== LOCATION_TYPE) {
return false;
}
@@ -50,17 +52,23 @@ export class FileReaderProcessor implements CatalogProcessor {
if (fileMatches.length > 0) {
for (const fileMatch of fileMatches) {
const data = await fs.readFile(fileMatch);
const normalizedFilePath = path.normalize(fileMatch);
// The normalize converts to native slashes; the glob library returns
// forward slashes even on windows
for await (const parseResult of parser({
data: data,
location: {
type: 'file',
target: path.normalize(fileMatch),
type: LOCATION_TYPE,
target: normalizedFilePath,
},
})) {
emit(parseResult);
emit(
processingResult.refresh(
`${LOCATION_TYPE}:${normalizedFilePath}`,
),
);
}
}
} else if (!optional) {
@@ -17,6 +17,7 @@ import { UrlReader } from '@backstage/backend-common';
import { Entity } from '@backstage/catalog-model';
import { ConfigReader } from '@backstage/config';
import { ScmIntegrations } from '@backstage/integration';
import { CatalogProcessorResult } from '../../api';
import {
jsonPlaceholderResolver,
PlaceholderProcessor,
@@ -51,7 +52,7 @@ describe('PlaceholderProcessor', () => {
integrations,
});
await expect(
processor.preProcessEntity(input, { type: 't', target: 'l' }),
processor.preProcessEntity(input, { type: 't', target: 'l' }, () => {}),
).resolves.toBe(input);
});
@@ -76,6 +77,7 @@ describe('PlaceholderProcessor', () => {
spec: { a: [{ b: { $upper: 'text' } }] },
},
{ type: 'fake', target: 'http://example.com' },
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -110,7 +112,7 @@ describe('PlaceholderProcessor', () => {
};
await expect(
processor.preProcessEntity(entity, { type: 'a', target: 'b' }),
processor.preProcessEntity(entity, { type: 'a', target: 'b' }, () => {}),
).resolves.toEqual(entity);
expect(read).not.toBeCalled();
@@ -131,7 +133,7 @@ describe('PlaceholderProcessor', () => {
};
await expect(
processor.preProcessEntity(entity, { type: 'a', target: 'b' }),
processor.preProcessEntity(entity, { type: 'a', target: 'b' }, () => {}),
).resolves.toEqual(entity);
expect(read).not.toBeCalled();
@@ -158,6 +160,7 @@ describe('PlaceholderProcessor', () => {
target:
'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
},
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -194,6 +197,7 @@ describe('PlaceholderProcessor', () => {
target:
'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
},
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -228,6 +232,7 @@ describe('PlaceholderProcessor', () => {
target:
'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
},
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -266,6 +271,7 @@ describe('PlaceholderProcessor', () => {
target:
'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
},
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -303,6 +309,7 @@ describe('PlaceholderProcessor', () => {
type: 'url',
target: './a/b/catalog-info.yaml',
},
() => {},
),
).resolves.toEqual({
apiVersion: 'a',
@@ -343,6 +350,7 @@ describe('PlaceholderProcessor', () => {
type: 'url',
target: './a/b/catalog-info.yaml',
},
() => {},
),
).rejects.toThrow(
/^Placeholder \$text could not form a URL out of \.\/a\/b\/catalog-info\.yaml and \.\.\/c\/catalog-info\.yaml, TypeError \[ERR_INVALID_URL\]/,
@@ -350,6 +358,35 @@ describe('PlaceholderProcessor', () => {
expect(read).not.toBeCalled();
});
it('should emit the resolverValue as a refreshKey', async () => {
read.mockResolvedValue(
Buffer.from(JSON.stringify({ a: ['b', 7] }), 'utf-8'),
);
const processor = new PlaceholderProcessor({
resolvers: {
json: jsonPlaceholderResolver,
},
reader,
integrations,
});
const emitted = new Array<CatalogProcessorResult>();
await processor.preProcessEntity(
{
apiVersion: 'a',
kind: 'k',
metadata: { name: 'n' },
spec: { a: [{ b: { $json: './path-to-file.json' } }] },
},
{ type: 'fake', target: 'http://example.com' },
result => emitted.push(result),
);
expect(emitted[0]).toEqual({
type: 'refresh',
key: 'url:http://example.com/path-to-file.json',
});
});
});
describe('yamlPlaceholderResolver', () => {
@@ -360,6 +397,7 @@ describe('yamlPlaceholderResolver', () => {
baseUrl: 'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
read,
resolveUrl: (url, base) => integrations.resolveUrl({ url, base }),
emit: () => {},
};
beforeEach(() => {
@@ -405,6 +443,7 @@ describe('jsonPlaceholderResolver', () => {
baseUrl: 'https://github.com/backstage/backstage/a/b/catalog-info.yaml',
read,
resolveUrl: (url, base) => integrations.resolveUrl({ url, base }),
emit: () => {},
};
beforeEach(() => {
@@ -19,7 +19,12 @@ import { Entity } from '@backstage/catalog-model';
import { JsonValue } from '@backstage/types';
import { ScmIntegrationRegistry } from '@backstage/integration';
import yaml from 'yaml';
import { CatalogProcessor, LocationSpec } from '../../api';
import {
CatalogProcessor,
CatalogProcessorEmit,
LocationSpec,
processingResult,
} from '../../api';
/** @public */
export type PlaceholderResolverRead = (url: string) => Promise<Buffer>;
@@ -37,6 +42,7 @@ export type PlaceholderResolverParams = {
baseUrl: string;
read: PlaceholderResolverRead;
resolveUrl: PlaceholderResolverResolveUrl;
emit: CatalogProcessorEmit;
};
/** @public */
@@ -66,6 +72,7 @@ export class PlaceholderProcessor implements CatalogProcessor {
async preProcessEntity(
entity: Entity,
location: LocationSpec,
emit: CatalogProcessorEmit,
): Promise<Entity> {
const process = async (data: any): Promise<[any, boolean]> => {
if (!data || !(data instanceof Object)) {
@@ -102,6 +109,7 @@ export class PlaceholderProcessor implements CatalogProcessor {
const resolverKey = keys[0].substr(1);
const resolverValue = data[keys[0]];
const resolver = this.options.resolvers[resolverKey];
if (!resolver || typeof resolverValue !== 'string') {
// If there was no such placeholder resolver or if the value was not a
@@ -134,6 +142,7 @@ export class PlaceholderProcessor implements CatalogProcessor {
baseUrl: location.target,
read,
resolveUrl,
emit,
}),
true,
];
@@ -151,11 +160,13 @@ export class PlaceholderProcessor implements CatalogProcessor {
export async function yamlPlaceholderResolver(
params: PlaceholderResolverParams,
): Promise<JsonValue> {
const text = await readTextLocation(params);
const { content, url } = await readTextLocation(params);
params.emit(processingResult.refresh(`url:${url}`));
let documents: yaml.Document.Parsed[];
try {
documents = yaml.parseAllDocuments(text).filter(d => d);
documents = yaml.parseAllDocuments(content).filter(d => d);
} catch (e) {
throw new Error(
`Placeholder \$${params.key} failed to parse YAML data at ${params.value}, ${e}`,
@@ -182,10 +193,12 @@ export async function yamlPlaceholderResolver(
export async function jsonPlaceholderResolver(
params: PlaceholderResolverParams,
): Promise<JsonValue> {
const text = await readTextLocation(params);
const { content, url } = await readTextLocation(params);
params.emit(processingResult.refresh(`url:${url}`));
try {
return JSON.parse(text);
return JSON.parse(content);
} catch (e) {
throw new Error(
`Placeholder \$${params.key} failed to parse JSON data at ${params.value}, ${e}`,
@@ -196,7 +209,11 @@ export async function jsonPlaceholderResolver(
export async function textPlaceholderResolver(
params: PlaceholderResolverParams,
): Promise<JsonValue> {
return await readTextLocation(params);
const { content, url } = await readTextLocation(params);
params.emit(processingResult.refresh(`url:${url}`));
return content;
}
/*
@@ -205,12 +222,12 @@ export async function textPlaceholderResolver(
async function readTextLocation(
params: PlaceholderResolverParams,
): Promise<string> {
): Promise<{ content: string; url: string }> {
const newUrl = relativeUrl(params);
try {
const data = await params.read(newUrl);
return data.toString('utf-8');
return { content: data.toString('utf-8'), url: newUrl };
} catch (e) {
throw new Error(
`Placeholder \$${params.key} could not read location ${params.value}, ${e}`,
@@ -61,7 +61,13 @@ describe('UrlReaderProcessor', () => {
server.use(
rest.get(`${mockApiOrigin}/component.yaml`, (_, res, ctx) =>
res(ctx.set({ ETag: 'my-etag' }), ctx.json({ mock: 'entity' })),
res(
ctx.set({ ETag: 'my-etag' }),
ctx.json({
kind: 'component',
metadata: { name: 'mock-url-entity' },
}),
),
),
);
@@ -74,15 +80,25 @@ describe('UrlReaderProcessor', () => {
mockCache,
);
expect(emitted.length).toBe(1);
expect(emitted.length).toBe(2);
expect(emitted[0]).toEqual({
type: 'entity',
location: spec,
entity: { mock: 'entity' },
entity: { kind: 'component', metadata: { name: 'mock-url-entity' } },
});
expect(emitted[1]).toEqual({
type: 'refresh',
key: 'url:http://localhost/component.yaml',
});
expect(mockCache.set).toBeCalledWith('v1', {
etag: 'my-etag',
value: [{ type: 'entity', location: spec, entity: { mock: 'entity' } }],
value: [
{
type: 'entity',
location: spec,
entity: { kind: 'component', metadata: { name: 'mock-url-entity' } },
},
],
});
expect(mockCache.set).toBeCalledTimes(1);
});
@@ -93,6 +93,8 @@ export class UrlReaderProcessor implements CatalogProcessor {
value: parseResults as CatalogProcessorEntityResult[],
});
}
emit(processingResult.refresh(`${location.type}:${location.target}`));
} catch (error) {
assertError(error);
const message = `Unable to read ${location.type}, ${error}`;
@@ -1 +1,3 @@
kind: Component
metadata:
name: component-test
@@ -1 +1,3 @@
kind: API
metadata:
name: api-test
@@ -30,6 +30,7 @@ describe('DefaultCatalogProcessingEngine', () => {
updateProcessedEntity: jest.fn(),
updateEntityCache: jest.fn(),
listParents: jest.fn(),
setRefreshKeys: jest.fn(),
} as unknown as jest.Mocked<DefaultProcessingDatabase>;
const orchestrator: jest.Mocked<CatalogProcessingOrchestrator> = {
process: jest.fn(),
@@ -58,6 +59,7 @@ describe('DefaultCatalogProcessingEngine', () => {
errors: [],
deferredEntities: [],
state: {},
refreshKeys: [],
});
const engine = new DefaultCatalogProcessingEngine(
getVoidLogger(),
@@ -123,6 +125,7 @@ describe('DefaultCatalogProcessingEngine', () => {
errors: [],
deferredEntities: [],
state: {},
refreshKeys: [],
});
const engine = new DefaultCatalogProcessingEngine(
getVoidLogger(),
@@ -203,6 +206,7 @@ describe('DefaultCatalogProcessingEngine', () => {
errors: [],
deferredEntities: [],
state: {},
refreshKeys: [],
});
const engine = new DefaultCatalogProcessingEngine(
@@ -413,6 +417,7 @@ describe('DefaultCatalogProcessingEngine', () => {
errors: [],
deferredEntities: [],
state: {},
refreshKeys: [],
})
.mockResolvedValueOnce({
ok: true,
@@ -432,6 +437,7 @@ describe('DefaultCatalogProcessingEngine', () => {
errors: [],
deferredEntities: [],
state: {},
refreshKeys: [],
});
await engine.start();
@@ -134,6 +134,7 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine {
.update(stableStringify({ ...result.completedEntity }))
.update(stableStringify([...result.deferredEntities]))
.update(stableStringify([...result.relations]))
.update(stableStringify([...result.refreshKeys]))
.update(stableStringify([...parents]));
}
@@ -180,6 +181,7 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine {
relations: result.relations,
deferredEntities: result.deferredEntities,
locationKey,
refreshKeys: result.refreshKeys,
});
oldRelationSources = new Set(
previous.relations.map(r => r.source_entity_ref),
@@ -102,6 +102,7 @@ describe('DefaultCatalogProcessingOrchestrator', () => {
ok: true,
completedEntity: entity,
deferredEntities: [],
refreshKeys: [],
errors: [],
relations: [],
state: {
@@ -119,6 +120,7 @@ describe('DefaultCatalogProcessingOrchestrator', () => {
).resolves.toEqual({
ok: true,
completedEntity: entity,
refreshKeys: [],
deferredEntities: [
{
locationKey: 'url:./new-place',
@@ -24,7 +24,7 @@ import { assertError } from '@backstage/errors';
import { Logger } from 'winston';
import { CatalogProcessorResult, EntityRelationSpec } from '../api';
import { locationSpecToLocationEntity } from '../util/conversion';
import { DeferredEntity } from './types';
import { DeferredEntity, RefreshKeyData } from './types';
import {
getEntityLocationRef,
getEntityOriginLocationRef,
@@ -38,6 +38,7 @@ export class ProcessorOutputCollector {
private readonly errors = new Array<Error>();
private readonly relations = new Array<EntityRelationSpec>();
private readonly deferredEntities = new Array<DeferredEntity>();
private readonly refreshKeys = new Array<RefreshKeyData>();
private done = false;
constructor(
@@ -54,6 +55,7 @@ export class ProcessorOutputCollector {
return {
errors: this.errors,
relations: this.relations,
refreshKeys: this.refreshKeys,
deferredEntities: this.deferredEntities,
};
}
@@ -116,6 +118,8 @@ export class ProcessorOutputCollector {
this.relations.push(i.relation);
} else if (i.type === 'error') {
this.errors.push(i.error);
} else if (i.type === 'refresh') {
this.refreshKeys.push({ key: i.key });
}
}
}
@@ -26,7 +26,6 @@ export type EntityProcessingRequest = {
entity: Entity;
state?: JsonObject; // Versions for multiple deployments etc
};
/**
* The result of processing an entity.
* @public
@@ -38,6 +37,7 @@ export type EntityProcessingResult =
completedEntity: Entity;
deferredEntities: DeferredEntity[];
relations: EntityRelationSpec[];
refreshKeys: RefreshKeyData[];
errors: Error[];
}
| {
@@ -45,6 +45,14 @@ export type EntityProcessingResult =
errors: Error[];
};
/**
* A string to associate to the entity itself.
* @public
*/
export type RefreshKeyData = {
key: string;
};
/**
* Responsible for executing the individual processing steps in order to fully process an entity.
* @public
@@ -48,6 +48,7 @@ describe('DefaultLocationServiceTest', () => {
name: 'foo',
},
},
refreshKeys: [],
deferredEntities: [
{
entity: {
@@ -75,6 +76,7 @@ describe('DefaultLocationServiceTest', () => {
},
},
deferredEntities: [],
refreshKeys: [],
relations: [],
errors: [],
});
@@ -134,6 +136,7 @@ describe('DefaultLocationServiceTest', () => {
},
},
deferredEntities: [],
refreshKeys: [],
relations: [],
errors: [],
});
@@ -161,6 +164,7 @@ describe('DefaultLocationServiceTest', () => {
name: 'foo',
},
},
refreshKeys: [],
deferredEntities: [
{
entity: {
@@ -188,6 +192,7 @@ describe('DefaultLocationServiceTest', () => {
},
},
deferredEntities: [],
refreshKeys: [],
relations: [],
errors: [],
});
@@ -211,6 +216,7 @@ describe('DefaultLocationServiceTest', () => {
name: 'bar',
},
},
refreshKeys: [],
deferredEntities: [],
relations: [],
errors: [],
@@ -138,6 +138,7 @@ describe('Refresh integration', () => {
errors: [],
deferredEntities,
state: {},
refreshKeys: [],
};
},
},
@@ -409,6 +409,7 @@ describe('createRouter readonly disabled', () => {
state: {},
completedEntity: entity,
deferredEntities: [],
refreshKeys: [],
relations: [],
errors: [],
});
+1 -1
View File
@@ -40,7 +40,7 @@
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@react-hookz/web": "^14.0.0",
"@react-hookz/web": "^15.0.0",
"react-router-dom": "6.0.0-beta.0"
},
"peerDependencies": {
@@ -2,48 +2,34 @@
This can be used to run the kubernetes plugin locally against a mock service.
# Viewing in local Minikube running Backstage locally
# Viewing in local Kind running Backstage locally
## Prerequisites
- kubectl installed
- Minikube installed, with the following addons
- metrics-server
- ingress
- jq installed
- [kubectl installed](https://kubernetes.io/docs/tasks/tools/#kubectl)
- [Kind installed](https://kind.sigs.k8s.io/docs/user/quick-start/)
- Backstage locally built and ready to run
## Steps
1. Start minikube
2. Get the Kubernetes master base URL `kubectl cluster-info`
3. Apply manifests `kubectl apply -f dice-roller-manifests.yaml`
4. Get service account token (see below)
5. Start Backstage UI and backend
6. Register existing component in Backstage
- https://github.com/mclarke47/dice-roller/blob/master/catalog-info.yaml
1. Start kind
2. Apply manifests `kubectl apply -f plugins/kubernetes-backend/examples/dice-roller/dice-roller-manifests.yaml`
3. Run `kubectl proxy`
4. In separate terminal windows start Backstage UI and backend
5. Register a test component ([example](https://github.com/mclarke47/dice-roller/blob/master/catalog-info.yaml))
6. Visit [kubernetes plugin page](http://localhost:3000/catalog/default/component/dice-roller/kubernetes)
Add or update `app-config.local.yaml` with the following:
### Example `app-config.local.yaml`
```yaml
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: <KUBERNETES MASTER BASE URL FROM STEP 2>
name: minikube
serviceAccountToken: <TOKEN FROM STEP 4>
authProvider: 'serviceAccount'
- type: 'localKubectlProxy'
catalog:
locations:
- type: url
target: https://github.com/mclarke47/dice-roller/blob/master/catalog-info.yaml
```
### Getting the service account token
Mac copy to clipboard:
```
kubectl get secret $(kubectl get sa dice-roller -o=json | jq -r '.secrets[0].name') -o=json | jq -r '.data["token"]' | base64 --decode | pbcopy
```
Paste into `app-config.local.yaml` `kubernetes.clusters[0].serviceAccountToken`
+1 -1
View File
@@ -44,7 +44,7 @@
"@backstage/plugin-auth-node": "^0.2.3-next.1",
"@backstage/plugin-kubernetes-common": "^0.4.0-next.0",
"@google-cloud/container": "^4.0.0",
"@kubernetes/client-node": "^0.16.0",
"@kubernetes/client-node": "^0.17.0",
"@types/express": "^4.17.6",
"@types/luxon": "^2.0.4",
"aws-sdk": "^2.840.0",
@@ -14,16 +14,25 @@
* limitations under the License.
*/
import { KubernetesAuthProvider } from './types';
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
import { ClusterDetails, KubernetesClustersSupplier } from '../types/types';
export class ServiceAccountKubernetesAuthProvider
implements KubernetesAuthProvider
export class LocalKubectlProxyClusterLocator
implements KubernetesClustersSupplier
{
async decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody> {
// No-op, with service account for auth, cluster config/details should already have serviceAccountToken
return requestBody;
private readonly clusterDetails: ClusterDetails[];
public constructor() {
this.clusterDetails = [
{
name: 'local',
url: 'http:/localhost:8001',
authProvider: 'localKubectlProxy',
skipMetricsLookup: true,
},
];
}
async getClusters(): Promise<ClusterDetails[]> {
return this.clusterDetails;
}
}
@@ -19,6 +19,7 @@ import { Duration } from 'luxon';
import { ClusterDetails, KubernetesClustersSupplier } from '../types/types';
import { ConfigClusterLocator } from './ConfigClusterLocator';
import { GkeClusterLocator } from './GkeClusterLocator';
import { LocalKubectlProxyClusterLocator } from './LocalKubectlProxyLocator';
class CombinedClustersSupplier implements KubernetesClustersSupplier {
constructor(readonly clusterSuppliers: KubernetesClustersSupplier[]) {}
@@ -45,6 +46,8 @@ export const getCombinedClusterSupplier = (
.map(clusterLocatorMethod => {
const type = clusterLocatorMethod.getString('type');
switch (type) {
case 'localKubectlProxy':
return new LocalKubectlProxyClusterLocator();
case 'config':
return ConfigClusterLocator.fromConfig(clusterLocatorMethod);
case 'gke':
@@ -49,6 +49,9 @@ export class KubernetesAuthTranslatorGenerator {
case 'oidc': {
return new OidcKubernetesAuthTranslator();
}
case 'localKubectlProxy': {
return new NoopKubernetesAuthTranslator();
}
default: {
throw new Error(
`authProvider "${authProvider}" has no KubernetesAuthTranslator associated with it`,
+2 -1
View File
@@ -38,8 +38,9 @@
"url": "https://github.com/backstage/backstage/issues"
},
"dependencies": {
"@backstage/catalog-model": "^1.1.0-next.1",
"@backstage/catalog-model": "^1.1.0-next.2",
"@kubernetes/client-node": "^0.16.0"
"@kubernetes/client-node": "^0.17.0"
},
"devDependencies": {
"@backstage/cli": "^0.18.0-next.2"
+3 -27
View File
@@ -32,17 +32,6 @@ import { V1ReplicaSet } from '@kubernetes/client-node';
import { V1Service } from '@kubernetes/client-node';
import { V1StatefulSet } from '@kubernetes/client-node';
// Warning: (ae-forgotten-export) The symbol "KubernetesAuthProvider" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "AwsKubernetesAuthProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export class AwsKubernetesAuthProvider implements KubernetesAuthProvider {
// (undocumented)
decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody>;
}
// Warning: (ae-forgotten-export) The symbol "ClusterProps" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "Cluster" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -147,6 +136,7 @@ export function formatClusterLink(
options: FormatClusterLinkOptions,
): string | undefined;
// Warning: (ae-forgotten-export) The symbol "KubernetesAuthProvider" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "GoogleKubernetesAuthProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -160,18 +150,6 @@ export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider {
): Promise<KubernetesRequestBody>;
}
// Warning: (ae-missing-release-tag) "GoogleServiceAccountAuthProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export class GoogleServiceAccountAuthProvider
implements KubernetesAuthProvider
{
// (undocumented)
decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody>;
}
// Warning: (ae-missing-release-tag) "GroupedResponses" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -386,10 +364,8 @@ export const PodsTable: ({
// @public (undocumented)
export const Router: (props: { refreshIntervalMs?: number }) => JSX.Element;
// Warning: (ae-missing-release-tag) "ServiceAccountKubernetesAuthProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export class ServiceAccountKubernetesAuthProvider
// @public
export class ServerSideKubernetesAuthProvider
implements KubernetesAuthProvider
{
// (undocumented)
+1 -1
View File
@@ -41,7 +41,7 @@
"@backstage/plugin-catalog-react": "^1.1.2-next.2",
"@backstage/plugin-kubernetes-common": "^0.4.0-next.1",
"@backstage/theme": "^0.2.16-next.1",
"@kubernetes/client-node": "^0.16.0",
"@kubernetes/client-node": "^0.17.0",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
@@ -1,27 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { KubernetesAuthProvider } from './types';
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
export class AwsKubernetesAuthProvider implements KubernetesAuthProvider {
async decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody> {
// No-op, with aws auth, server's AWS credentials are used for access
return requestBody;
}
}
@@ -1,27 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { KubernetesAuthProvider } from './types';
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
export class AzureKubernetesAuthProvider implements KubernetesAuthProvider {
async decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody> {
// No-op, with azure auth, server's Azure credentials are used for access
return requestBody;
}
}
@@ -17,11 +17,8 @@
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
import { KubernetesAuthProvider, KubernetesAuthProvidersApi } from './types';
import { GoogleKubernetesAuthProvider } from './GoogleKubernetesAuthProvider';
import { ServiceAccountKubernetesAuthProvider } from './ServiceAccountKubernetesAuthProvider';
import { AwsKubernetesAuthProvider } from './AwsKubernetesAuthProvider';
import { ServerSideKubernetesAuthProvider } from './ServerSideAuthProvider';
import { OAuthApi, OpenIdConnectApi } from '@backstage/core-plugin-api';
import { GoogleServiceAccountAuthProvider } from './GoogleServiceAccountAuthProvider';
import { AzureKubernetesAuthProvider } from './AzureKubernetesAuthProvider';
import { OidcKubernetesAuthProvider } from './OidcKubernetesAuthProvider';
export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
@@ -41,16 +38,23 @@ export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
);
this.kubernetesAuthProviderMap.set(
'serviceAccount',
new ServiceAccountKubernetesAuthProvider(),
new ServerSideKubernetesAuthProvider(),
);
this.kubernetesAuthProviderMap.set(
'googleServiceAccount',
new GoogleServiceAccountAuthProvider(),
new ServerSideKubernetesAuthProvider(),
);
this.kubernetesAuthProviderMap.set(
'aws',
new ServerSideKubernetesAuthProvider(),
);
this.kubernetesAuthProviderMap.set('aws', new AwsKubernetesAuthProvider());
this.kubernetesAuthProviderMap.set(
'azure',
new AzureKubernetesAuthProvider(),
new ServerSideKubernetesAuthProvider(),
);
this.kubernetesAuthProviderMap.set(
'localKubectlProxy',
new ServerSideKubernetesAuthProvider(),
);
if (options.oidcProviders) {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -17,13 +17,18 @@
import { KubernetesAuthProvider } from './types';
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
export class GoogleServiceAccountAuthProvider
/**
* No-op KubernetesAuthProvider, authorization will be handled in the kubernetes-backend plugin
*
* @public
*/
export class ServerSideKubernetesAuthProvider
implements KubernetesAuthProvider
{
async decorateRequestBodyForAuth(
requestBody: KubernetesRequestBody,
): Promise<KubernetesRequestBody> {
// No-op, with google service account auth, server's AWS credentials are used for access
// No-op, auth will be taken care of on the server-side
return requestBody;
}
}
@@ -17,7 +17,5 @@
export { kubernetesAuthProvidersApiRef } from './types';
export type { KubernetesAuthProvidersApi } from './types';
export { KubernetesAuthProviders } from './KubernetesAuthProviders';
export { AwsKubernetesAuthProvider } from './AwsKubernetesAuthProvider';
export { GoogleKubernetesAuthProvider } from './GoogleKubernetesAuthProvider';
export { GoogleServiceAccountAuthProvider } from './GoogleServiceAccountAuthProvider';
export { ServiceAccountKubernetesAuthProvider } from './ServiceAccountKubernetesAuthProvider';
export { ServerSideKubernetesAuthProvider } from './ServerSideAuthProvider';
+11
View File
@@ -14,3 +14,14 @@
* limitations under the License.
*/
import '@testing-library/jest-dom';
// eslint-disable-next-line no-restricted-imports
import { TextDecoder, TextEncoder } from 'util';
// These are missing from jest-node, so not available on global.
Object.defineProperty(global, 'TextEncoder', {
value: TextEncoder,
});
Object.defineProperty(global, 'TextDecoder', {
value: TextDecoder,
});
-2
View File
@@ -14,12 +14,10 @@ export const DashboardSnapshotComponent: ({
guid,
name,
permalink,
duration,
}: {
guid: string;
name: string;
permalink: string;
duration: number;
}) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityNewRelicDashboardCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+1 -1
View File
@@ -14,6 +14,6 @@
* limitations under the License.
*/
import { createDevApp } from '@backstage/dev-utils';
import { newRelicDashboardPlugin } from './../src/plugin';
import { newRelicDashboardPlugin } from '../src/plugin';
createDevApp().registerPlugin(newRelicDashboardPlugin).render();
@@ -28,7 +28,7 @@ import DesktopMac from '@material-ui/icons/DesktopMac';
import { DashboardEntitySummary } from '../../api/NewRelicDashboardApi';
import { ResultEntity } from '../../types/DashboardEntity';
import { useEntity } from '@backstage/plugin-catalog-react';
import { NEWRELIC_GUID_ANNOTATION } from './../../constants';
import { NEWRELIC_GUID_ANNOTATION } from '../../constants';
const useStyles = makeStyles({
svgIcon: {
@@ -14,8 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { Box, Grid } from '@material-ui/core';
import { useApi } from '@backstage/core-plugin-api';
import { Box, Grid, MenuItem, Select } from '@material-ui/core';
import { useApi, storageApiRef } from '@backstage/core-plugin-api';
import useAsync from 'react-use/lib/useAsync';
import {
InfoCard,
@@ -24,43 +24,72 @@ import {
Link,
} from '@backstage/core-components';
import { newRelicDashboardApiRef } from '../../../api';
import { DashboardSnapshotSummary } from './../../../api/NewRelicDashboardApi';
import { DashboardSnapshotSummary } from '../../../api/NewRelicDashboardApi';
import useObservable from 'react-use/lib/useObservable';
type Props = {
guid: string;
name: string;
permalink: string;
duration: number;
};
export const DashboardSnapshot = ({
guid,
name,
permalink,
duration,
}: Props) => {
export const DashboardSnapshot = ({ guid, name, permalink }: Props) => {
const newRelicDashboardAPI = useApi(newRelicDashboardApiRef);
const storageApi = useApi(storageApiRef).forBucket('newrelic-dashboard');
const setStorageValue = (value: number) => {
storageApi.set(guid, value);
};
const storageSnapshot = useObservable(
storageApi.observe$<number>(guid),
storageApi.snapshot(guid),
);
const { value, loading, error } = useAsync(async (): Promise<
DashboardSnapshotSummary | undefined
> => {
const dashboardObject: Promise<DashboardSnapshotSummary | undefined> =
newRelicDashboardAPI.getDashboardSnapshot(guid, duration);
newRelicDashboardAPI.getDashboardSnapshot(
guid,
storageSnapshot.value || 2592000000,
);
return dashboardObject;
}, [guid, duration]);
}, [guid, storageSnapshot.value]);
if (loading) {
return <Progress />;
}
if (error) {
return <ErrorPanel title={error.name} defaultExpanded error={error} />;
}
const url =
value?.getDashboardSnapshot?.data?.dashboardCreateSnapshotUrl?.replace(
/\pdf$/i,
'png',
);
return (
<Grid container style={{ marginTop: '30px' }}>
<InfoCard variant="gridItem" title={name}>
<Grid container>
<InfoCard
variant="gridItem"
title={name}
action={
<Select
style={{ margin: '15px 10px 0 0' }}
defaultValue={2592000000}
value={storageSnapshot.value}
onChange={event => {
setStorageValue(Number(event.target.value));
}}
>
<MenuItem value={3600000}>1 Hour</MenuItem>
<MenuItem value={43200000}>12 Hours</MenuItem>
<MenuItem value={86400000}>1 Day</MenuItem>
<MenuItem value={259200000}>3 Days</MenuItem>
<MenuItem value={604800000}>1 Week</MenuItem>
<MenuItem value={2592000000}>1 Month</MenuItem>
</Select>
}
>
<Box display="flex">
<Box flexGrow="1">
<Link to={permalink}>
@@ -137,7 +137,6 @@ export const DashboardSnapshotList = ({ guid }: Props) => {
name={Entity.name}
permalink={Entity.permalink}
guid={Entity.guid}
duration={26297430000}
/>
</TabPanel>
);
+1
View File
@@ -388,6 +388,7 @@ export function createPublishGitlabAction(options: {
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
setUserAsOwner?: boolean | undefined;
}>;
// @public
+1 -1
View File
@@ -45,7 +45,7 @@
"@backstage/types": "^1.0.0",
"@gitbeaker/core": "^35.6.0",
"@gitbeaker/node": "^35.1.0",
"@octokit/webhooks": "^9.14.1",
"@octokit/webhooks": "^10.0.0",
"@types/express": "^4.17.6",
"azure-devops-node-api": "^11.0.1",
"command-exists": "^1.2.9",
@@ -32,6 +32,9 @@ const mockGitlabClient = {
Users: {
current: jest.fn(),
},
ProjectMembers: {
add: jest.fn(),
},
};
jest.mock('@gitbeaker/node', () => ({
Gitlab: class {
@@ -113,6 +116,7 @@ describe('publish:gitlab', () => {
});
it('should work when there is a token provided through ctx.input', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -135,6 +139,7 @@ describe('publish:gitlab', () => {
});
it('should call the correct Gitlab APIs when the owner is an organization', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -168,6 +173,7 @@ describe('publish:gitlab', () => {
});
it('should call initRepoAndPush with the correct values', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -187,6 +193,7 @@ describe('publish:gitlab', () => {
});
it('should call initRepoAndPush with the correct default branch', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -241,6 +248,7 @@ describe('publish:gitlab', () => {
config: customAuthorConfig,
});
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -286,6 +294,7 @@ describe('publish:gitlab', () => {
config: customAuthorConfig,
});
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -305,6 +314,7 @@ describe('publish:gitlab', () => {
});
it('should call output with the remoteUrl and repoContentsUrl', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
@@ -321,4 +331,54 @@ describe('publish:gitlab', () => {
'http://mockurl/-/blob/master',
);
});
it('should call the correct Gitlab APIs when setUserAsOwner option is true and integration config has a token', async () => {
const customAuthorConfig = new ConfigReader({
integrations: {
gitlab: [
{
host: 'gitlab.com',
token: 'tokenlols',
apiBaseUrl: 'https://api.gitlab.com',
},
],
},
});
const customAuthorIntegrations =
ScmIntegrations.fromConfig(customAuthorConfig);
const customAuthorAction = createPublishGitlabAction({
integrations: customAuthorIntegrations,
config: customAuthorConfig,
});
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Projects.create.mockResolvedValue({
id: 123456,
http_url_to_repo: 'http://mockurl.git',
});
await customAuthorAction.handler({
...mockContext,
input: {
repoUrl: 'gitlab.com?repo=repo&owner=owner',
token: 'token',
setUserAsOwner: true,
},
});
expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner');
expect(mockGitlabClient.Users.current).toHaveBeenCalled();
expect(mockGitlabClient.ProjectMembers.add).toHaveBeenCalledWith(
123456,
12345,
50,
);
expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({
namespace_id: 1234,
name: 'repo',
visibility: 'private',
});
});
});
@@ -43,6 +43,7 @@ export function createPublishGitlabAction(options: {
gitCommitMessage?: string;
gitAuthorName?: string;
gitAuthorEmail?: string;
setUserAsOwner?: boolean;
}>({
id: 'publish:gitlab',
description:
@@ -92,6 +93,12 @@ export function createPublishGitlabAction(options: {
type: 'string',
description: 'The token to use for authorization to GitLab',
},
setUserAsOwner: {
title: 'Set User As Owner',
type: 'boolean',
description:
'Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host',
},
},
},
output: {
@@ -116,6 +123,7 @@ export function createPublishGitlabAction(options: {
gitCommitMessage = 'initial commit',
gitAuthorName,
gitAuthorEmail,
setUserAsOwner = false,
} = ctx.input;
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
@@ -149,19 +157,35 @@ export function createPublishGitlabAction(options: {
id: number;
};
const { id: userId } = (await client.Users.current()) as {
id: number;
};
if (!targetNamespace) {
const { id } = (await client.Users.current()) as {
id: number;
};
targetNamespace = id;
targetNamespace = userId;
}
const { http_url_to_repo } = await client.Projects.create({
const { id: projectId, http_url_to_repo } = await client.Projects.create({
namespace_id: targetNamespace,
name: repo,
visibility: repoVisibility,
});
// When setUserAsOwner is true the input token is expected to come from an unprivileged user GitLab
// OAuth flow. In this case GitLab works in a way that allows the unprivileged user to
// create the repository, but not to push the default protected branch (e.g. master).
// In order to set the user as owner of the newly created repository we need to check that the
// GitLab integration configuration for the matching host contains a token and use
// such token to bootstrap a new privileged client.
if (setUserAsOwner && integrationConfig.config.token) {
const adminClient = new Gitlab({
host: integrationConfig.config.baseUrl,
token: integrationConfig.config.token,
});
await adminClient.ProjectMembers.add(projectId, userId, 50);
}
const remoteUrl = (http_url_to_repo as string).replace(/\.git$/, '');
const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`;
+1 -1
View File
@@ -55,7 +55,7 @@
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@react-hookz/web": "^13.0.0",
"@react-hookz/web": "^15.0.0",
"@rjsf/core": "^3.2.1",
"@rjsf/material-ui": "^3.2.1",
"@types/json-schema": "^7.0.9",
@@ -133,11 +133,13 @@ export const ScaffolderPageContents = ({
export const ScaffolderPage = ({
TemplateCardComponent,
groups,
contextMenu,
}: ScaffolderPageProps) => (
<EntityListProvider>
<ScaffolderPageContents
TemplateCardComponent={TemplateCardComponent}
groups={groups}
contextMenu={contextMenu}
/>
</EntityListProvider>
);

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