✨ We would love for you to contribute to Janus IDP collection of Backstage plugins and help make it even better than it is today! ✨
As a contributor, here are the guidelines we would like you to follow:
- Code of conduct
- How can I contribute?
- Using the issue tracker
- Submitting a Pull Request
- Coding rules
- Compatibility with Backstage Showcase
- Working with the code
We also recommend that you read How to Contribute to Open Source.
Help us keep Janus-IDP open and inclusive. Please read and follow our Code of Conduct.
Important
We encourage users to migrate their plugins to the backstage/community-plugins or redhat-developer/rhdh-plugins repos. For migrating plugins to redhat-developer/rhdh-plugins see: Migrating plugins to redhat-developer/rhdh-plugins instead of this guide.
Guide for Migrating Plugins from janus-idp/backstage-plugins to backstage/community-plugins
Note
After fully migrating plugins, remember to check for any updates that may have been made in the janus-idp/backstage-plugins repository. You may need to update the migrated plugins to pull in changes made to the janus-idp/backstage-plugins repo after migration. Additionally, any unmerged PRs should be closed and recreated against the new repo.
This guide will show you how to migrate plugins from janus-idp/backstage-plugins to backstage/community-plugins using the backstage/community-plugins cli.
- Have a janus-idp/backstage-plugins fork locally cloned
- Have a backstage/community-plugins fork locally cloned
-
In both repositories, create a new branch:
-
For
janus-idp/backstage-plugins:git checkout -b "deprecate-workspace-name" -
For
backstage/community-plugins:git checkout -b "migrate-workspace-name"
-
-
Update the community-cli to include the
janus-plugin migratecommand. In thebackstage/community-pluginsrepository, add thejanus-migration.tsfile into the following directory:workspaces/repo-tools/packages/cli/src/commands/pluginAdditionally, copy theindex.tsfile into:workspaces/repo-tools/packages/cli/src/commands/index.ts -
In the
backstage/community-pluginsrepository, execute the janus-plugin migrate command.- Usage:yarn community-cli janus-plugin migrate --monorepo-path [path_to_backstage_plugins]--workspace-name [workspace_name] --branch [branch_name] --maintainers [maintainer1],[maintainer2],[maintainer3],...-
The
path_to_backstage_pluginsis the path to thebackstage-pluginsproject where the plugin(s) you want to migrate live. -
The
workspace-nameis the name of the workspace you wish to create in thecommunity-pluginsproject. All plugins in thebackstage-pluginsthat either are exactly or start with@janus-idp/backstage-plugin-[workspace_name]will be migrated to this new workspace. -
The
branch_nameis the name of the branch in thebackstage-pluginsproject where the changes to add a deprecate note for the migrated plugins will be made. -
The
maintainersarray of arguments is the github usernames of those individuals that should be listed as the maintainers for the migrated plugins. Please separate each maintainer by a comma while supplying this value. -
example usage:
yarn community-cli janus-plugin migrate --monorepo-path ../backstage-plugins --workspace-name workspace-name --branch deprecate-workspace-name --maintainers @maintainer1,@maintainer2,@maintainer3
-
-
The script will generate changesets in both repositories. Be sure to commit these changes and open pull requests.
Important
This script updates metadata commonly found across all plugins. Please review your migrated plugins to ensure that all references to "janus" have been updated to point to "community-plugins."
Also make sure that you don't accidentally commit the workspaces/repo-tools/packages/cli/src/commands/plugin/janus-migration.ts or workspaces/repo-tools/packages/cli/src/commands/index.ts files.
-
If you run into CI issues in
community-pluginstake a look at this github gist which outlines the process taken to migrate argocd plugins in great detail. -
Check if the migrated plugins need to be added to janus-idp/backstage-showcase. If they do, create a wrapper for them following the steps below:
- In
dynamic-plugins> wrapperscreate a directory, name it based on your plugin (eg:backstage-community-plugin-3scale-backend) - Create a
srcdirectory within it - Add a
index.tsfile to this src directory and export from the plugin package here. Eg:export * from '@backstage-community/plugin-3scale-backend'; - In
dynamic-plugins> wrappers > backstage-community-plugin-3scale-backend(or whatever you named your wrapper directory), add apackage.jsonfile. Add your plugin package in dependencies. - run
yarn export-dynamicto generate dist-dynamic directory
For migrating plugins to redhat-developer/rhdh-plugins see: Migrating plugins to redhat-developer/rhdh-plugins
Once PRs are merged in the new repo, you should mark the old plugins deprecated, and delete the content - leaving only a README.md.
As only a single version will be migrated to the new repo, maintenance of older plugins for previous RHDH releases should continue to be done in the older repo, as the migrated versions will be aligned to newer versions of Backstage and may not be compatible.
As a Janus-IDP user, you are the perfect candidate to help us improve our documentation: typo corrections, clarifications, more examples, etc. Take a look at the documentation issues that need help.
Please follow the Documentation guidelines.
Issues that lack relevant information can be very difficult to track down and fix, please follow the Bug report guideline to help make them easier to resolve. Help make them easier to resolve by adding any relevant information.
Confirmed bugs and ready-to-implement features are marked with the help wanted label. Post a comment on an issue to indicate you would like to work on it and to request help from the @janus-idp/maintainers-plugins and the community.
Before opening an issue or a Pull Request, please use the GitHub issue search to make sure the bug or feature request hasn't been already reported or fixed.
A good bug report shouldn't leave others needing to chase you for more information. Please try to be as detailed as possible in your report and fill in the information requested in the bug report template.
Feature requests are welcome, but take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible and fill in the information requested in the feature request template.
Plugins are a great way to extend Backstage capabilities and are an integral part of this repository. Please provide as much detail and context as possible and fill the information requested in the plugin suggestion template.
Good pull requests, whether patches, improvements, or new features, are a fantastic help. They should remain focused in scope and avoid containing unrelated commits.
Please ask first before embarking on any significant pull requests (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that the project's maintainers might not want to merge into the project.
If you have never created a pull request before, welcome 🎉 😄. Here is a great tutorial on how to create one 🙂
Here is a summary of the steps to follow:
- Set up the workspace
- If you cloned a while ago, get the latest changes from upstream and update dependencies:
$ git checkout main
$ git pull upstream main
$ yarn install- Create a new topic branch (off the main project development branch) to contain your feature, change, or fix:
$ git checkout -b <topic-branch-name>- Make your code changes, following the Coding rules
- Push your topic branch up to your fork:
$ git push origin <topic-branch-name>- Open a Pull Request with a clear title and description.
Tips:
- For ambitious tasks, open a Pull Request as soon as possible with the
[WIP]prefix in the title, in order to get feedback and help from the community. - Allow Janus-IDP maintainers to make changes to your Pull Request branch. This way, we can rebase it and make some minor changes if necessary. All changes we make will be done in the new commit, and we'll ask for your approval before merging them.
To ensure consistency and quality throughout the source code, all code modifications must have:
- No linting errors
- A test for every possible case introduced by your code change
- 100% test coverage
- Valid commit message(s)
- Documentation for new features
- Updated documentation for modified features
Familiarize yourself with the Backstage ADRs for additional guidance on best practices.
Plugin authors are responsible for migrating their plugins to ensure they run on the latest Backstage Showcase version.
- Check the Backstage version you need to migrate to
- Follow the Keeping Backstage Updated instructions
While our linter configuration already cover most of the code styling, it is not always helpful when it comes how the code should be structured. Here's a list of few conventions we follow according to file names, and folder structure:
- Backstage plugins and supporting libraries live inside the
pluginsfolder. Each plugin has its own folder named after the plugin id. For example, the@janus-idp/backstage-plugin-topologyplugin lives inside theplugins/topologyfolder. packagesfolder contains all NPM packages that are notpluginrelated. For example, a local backstage instance lives inside thepackages/appandpackages/backendfolders. Additionally the@janus-idp/janus-clipackage lives inside thepackages/janus-clifolder since this is not a plugin.- Plugin names are always prefixed with
@janus-idp/backstage-plugin-and the plugin id. For example, the@janus-idp/backstage-plugin-topologyplugin has thetopologyid. Please always useyarn newwhen creating a new plugin. It will guide you through the process and ensure the plugin id is used consistently. - Each plugin contains a
devfolder. This is folder is used for development setup. Please try to make your plugin development self-contained so you don't have to rely on changes inpackagesfolder. This is not always possible, but we try to keep thepackagesfolder as clean as possible. - Each plugin contains a
README.md. This file contains the user facing documentation. Please follow the Documentation guidelines when writing documentation. - Each plugin contains a
CONTRIBUTING.md. This file contains the plugin contributor and developer documentation. Please follow the Documentation guidelines when writing documentation. - Within
srcfolder there are various additional folders depending on your plugin role. We follow following convention:apifolder contains API clients for third party servicescomponentsfolder contains React components exposed from the pluginhooksfolder contains React hookslibfolder contains all other code that is not exposed from the plugin, helper utilities etc.servicefolder contains the plugin backend service. This is most commonly a Backstage sub-router that is then exposed via the Backstage backend APIprovidersfolder contains the plugin's entity providers exposed from the pluginactionsfolder contains GPT/Scaffolder actions exposed from the plugin
To ensure consistency and quality, all documentation modifications must:
- Refer to brand in bold with proper capitalization, i.e. GitHub, Red Hat, Backstage, npm
- Prefer tables over lists when listing key values, i.e. List of options with their description
- Use links when you are referring to:
- a Janus-IDP concept described somewhere else in the documentation, i.e. How to contribute
- a third-party product/brand/service, i.e. Integrate with GitHub
- an external concept or feature, i.e. Create a GitHub release
- a package or module, i.e. The
@janus-idp/backstage-plugin-topologymodule
- Use the single backtick
codequoting for:- commands inside sentences, i.e. the
yarn newcommand - programming language keywords, i.e.
function,async,String - packages or modules, i.e. The
@janus-idp/backstage-plugin-topologymodule
- commands inside sentences, i.e. the
- Use the triple backtick
codeformatting for:- code examples
- configuration examples
- sequence of command lines
When adding a new plugin, provide a clear guide into how to use it. This includes:
- Installation instructions
- Development setup, including how to set up all necessary third party integrations
- Comprehensively describe all available configuration options
- Screenshots or Videos showcasing UI elements of the plugin
We do not enforce strict commit message guidelines, instead we resort to Atomic PRs and Squash and merge strategy to ensure that the commit history is clean and readable. However please keep in mind that your individual commit messages will be visible in the PR history and will be used to generate the commit message of the final merge commit. Therefore please keep the following guidelines in mind when writing commit messages and refrain from meaningless, non-descriptive commit messages like "update" or "fix issues", etc.
If possible, make atomic commits, which means:
- a commit should contain exactly one self-contained functional change
- a functional change should be contained in exactly one commit
- a commit should not create an inconsistent state (such as test errors, linting errors, partial fixes, feature with documentation, etc.)
A complex feature can be broken down into multiple commits as long as each one maintains a consistent state and consists of a self-contained change.
Following these guidelines for committing messages is optional but strongly encouraged.
Each commit message consists of a header and a body. The header has a special format that includes a type, a scope and a subject:
<type>(<scope>): <subject>
<BLANK LINE>
<body>The header is mandatory and the scope of the header is optional.
The body can contain a closing reference to an issue.
Each pull request consists of a title and a body
The title has a special format that includes a type, a scope and a subject:
<type>(<scope>): <subject>If the commit reverts a previous commit, it should begin with revert:, followed by the header of the reverted commit.
The body should say: This reverts commit <hash>., where the hash is the SHA of the commit being reverted.
The type must be one of the following:
| Type | Description |
|---|---|
| fix | A bug fix |
| feat | A new feature |
| chore | A change that doesn't affect package codebase but rather the tooling around |
| docs | Documentation only changes |
| style | Changes that do not affect the meaning of the code (white space, formatting, missing semicolons, etc.) |
| refactor | A code change that neither fixes a bug nor adds a feature |
| perf | A code change that improves performance |
| test | Adding missing tests or correcting existing tests |
| revert | Reverts a given commit |
Type can contain optional scope and ! to mark breaking changes. Please use scope to denote the affected plugin or package.
The subject contains a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
It should contain any information about Breaking Changes and is also the place to reference GitHub issues that this commit Closes.
Breaking Changes should start with the word BREAKING CHANGE: with a space or two newlines.
The rest of the commit message is then used for this.
fix(pencil): stop graphite breaking when too much pressure appliedfeat(pencil): add 'graphiteWidth' option
Fix #42perf(pencil)!: remove graphiteWidth option
BREAKING CHANGE: The graphiteWidth option has been removed.
The default graphite width of 10mm is always used for performance reasons.Fork the project, clone your fork, configure the remotes and install the dependencies:
# Clone your fork of the repo into the current directory
$ git clone git@github.com:$(gh config get user -h github.com)/backstage-plugins.git
# Navigate to the newly cloned directory
$ cd backstage-plugins
# Assign the original repo to a remote called "upstream"
$ git remote add upstream git@github.com:janus-idp/backstage-plugins.git
# Install the dependencies
$ yarn installThe Backstage has multiple dependencies. To pass through their installation, make sure to follow the isolated-vm requirements.
It's also recommended to install a pre-commit hook to prevent secrets from being accidentally exposed. If you don't already have one, you can choose from a few options here: https://pre-commit.com/hooks.html
The backstage-plugins repository use ESLint for linting and Prettier for formatting.
Formatting will be automatically verified and fixed by lint-staged on the commit.
Before pushing your code changes make sure there are no linting errors with yarn lint and yarn prettier:check.
Tips:
- Most linting errors can be automatically fixed with
yarn prettier:fix.
The backstage-plugins repository uses Jest for writing and running tests.
Before pushing your code changes make sure all tests pass and the coverage is 100%:
$ yarn testSome plugins (e.g. quay) also have playwright-based UI tests. When making changes to such plugin, make sure these tests pass.
To run the UI tests locally, take the following steps:
First, install playwright dependencies:
$ npx playwright install --with-deps chromiumFinally, launch the UI tests (headless):
$ yarn run ui-testTest results from the headless run will be available in plugins/${plugin}/playwright-report folder.
This guide outlines the process for contributing to our monorepo and publishing plugins using changesets. Changesets help us manage versioning and changelogs, especially with multiple packages.
- Make your changes: Develop and test your plugin within the monorepo.
- Add a changeset: Describe your changes and the desired version bump.
- Open a pull request: Submit your changes for review.
- Merge: Once approved, your changes will be merged.
- Versioning PR: A separate automated PR will be created to bump package versions based on your changeset.
- Publish: Once the Versioning PR is merged, the plugins are automatically published.
After making changes to a plugin, run the following command to add a changeset:
yarn changesetThis will prompt you to:
- Select the packages to be released: Choose the plugin(s) you modified.
- Specify the release type: Choose from
patch,minor, ormajorbased on the semantic versioning guidelines. - Summarize your changes: Provide a brief description of the changes included in the release.
-
Private plugins and CI changes: Even if your changes don't affect public packages, you should still create an empty changeset using:
yarn changeset add --empty
This helps us track all modifications and ensures consistent versioning across the monorepo.
-
Changeset format: Follow the conventional commit format for your changeset summaries. This improves readability and helps with automated changelog generation.
-
Review process: During the review process, ensure your changeset accurately reflects the modifications made in your pull request.
feat(my-plugin): add new feature X
This change introduces a new feature to the my-plugin package, allowing users to do Y.Changesets are enabled on release branches to facilitate backporting. However, there is a caveat:
- Manual Retagging: After a backported plugin is published, the publish action may overwrite the latest plugin version with the backported version. To fix this, you need to manually retag the latest plugin version on NPM.
-
Ensure you have the correct permissions on NPM. If you don't, please reach out to Nick Boldt or Kim Tsao.
-
Run the following command, replacing
<plugin name>and<latest plugin version>with the appropriate values:npm dist-tag add @janus-idp/<plugin name>@<latest plugin version e.g. 1.2.3> latest
This will update the npm tag to point to the latest version.
- Main Branch: The plugins team is responsible for merging the versioning PR to publish plugins.
- Release Branches: The security team is responsible for merging the versioning PR to publish plugins.
- Main Branch: The plugins team is responsible for ensuring RHDH uses the latest compatible plugin versions. Exception: Backstage version bumps are handled by the core platform team. Note: Plugins should not depend on a newer version of Backstage than what RHDH allows.
- Release Branches: The security team is responsible for ensuring RHDH uses the latest compatible plugin versions.
As of June 2024, new plugins should be contributed to the new Backstage Community Plugins repo.
The rest of this section is DEPRECATED and will be removed in future.
A particular case of contribution is implementing a new plugin. Before you start implementing a new one, please consult our issue tracker and make a New plugin request. Once you have a green light from the community, you can start implementing your plugin.
Start by running our plugin template wizard:
yarn newThis will lead you through plugin category selection and set up all the required boilerplate. By default, this will only create a new standalone plugin within the plugins folder and will not touch the packages folder where we host an empty Backstage instance. You can bypass this behavior by running janus-cli new directly instead, but we discourage it. We aim to enable a standalone, self-contained plugin development workspace, however this is not fully possible at this moment.
This interactive wizard will lead you through the process of creating a new plugin. It will ask you for the following information:
- Plugin type You are offered a choice from the following options:
| Option | Description | Package name | Folder name |
|---|---|---|---|
| plugin | A new frontend plugin. React-based frontend plugin. | @janus-idp/backstage-plugin-<ID> |
plugins/<ID> |
| backend-plugin | A new backend plugin. Plugin to the Node.js Express server. | @janus-idp/backstage-plugin-<ID>-backend |
plugins/<ID>-backend |
| scaffolder-module | An module exporting custom actions for @backstage/plugin-scaffolder-backend |
@janus-idp/backstage-plugin-scaffolder-backend-module-<ID> |
plugins/scaffolder-backend-module-<ID> |
| plugin-common | A new isomorphic common plugin package. Serves as an interface between other plugins. | @janus-idp/backstage-plugin-<ID>-common |
plugins/<ID>-common |
| backend-module | A new backend module | @janus-idp/backstage-plugin-<ID>-backend-module-<MODULE_ID> |
plugins/<ID>-backend-module-<MODULE_ID> |
| web-library | A new web-library package. Currently not used | @janus-idp/backstage-<ID> |
packages/<ID> |
| plugin-node | A new Node.js library plugin package. Currently not used | @janus-idp/backstage-plugin-<ID>-node |
plugins/<ID>-node |
| plugin-react | A new web library plugin package. Currently not used | @janus-idp/backstage-plugin-<ID>-react |
plugins/<ID>-react |
- Plugin id: This value is used in templating and determines the resulting package name and folder name. Please see the table above and look where the
<ID>is used. As you can see, you don't have to specify the plugin role within the ID value, the role is added to the package name automatically.
Once you finish bootstrapping your plugin folder, please look up the upstream documentation. For example:
- The structure of a plugin
- For frontend plugins, see the general plugin development guide and composability system.
- For backend plugins, see the backend specific plugin development guide.
Backstage's support for standalone plugin development is minimal (especially for backend plugins), therefore we include a minimal test instance within this repository.
-
Install the plugin via
yarn workspace [app|backend] add @janus-idp/<PLUGIN_NAME>@*- Example:
yarn workspace app add "@janus-idp/backstage-plugin-nexus-repository-manager@*" @*at the end ensures the package is always linked to the local package in thepluginsfolder
- Example:
-
Follow the plugin's install instructions
-
(Optional) Tell git to assume the modified files are unchanged, so that status/diff commands are representative of your current work:
# Example, list any dev app files where you don't want changes tracked git update-index --assume-unchanged \ app-config.yaml \ packages/app/package.json \ packages/app/src/components/catalog/EntityPage.tsx -
Run
yarn dev
In case your plugin supports standalone mode, you can use yarn start --filter=<PLUGIN_NAME> command in your plugin directory directly and you don't have to install the plugin as mentioned above.
If you want to start contributing to a plugin you're not yet familiar with, always consult its CONTRIBUTING.md file within its folder in plugins/. This file contains all the information you need to know about that particular plugin's development setup.
You can augment the configuration for a plugin by running yarn start --config <CONFIG_FILE>.
-
Error:
ERROR run failed: error preparing engine: Invalid persistent task configuration: You have <x - number> persistent tasks but `turbo` is configured for concurrency of 10. Set --concurrency to at least <x - number>
Solution: You need to run yarn start with a filter. e.g. yarn start --filter=<PLUGIN_NAME>