backstage / backstage/community-plugins

RFC: community-cli workspace fix pipeline

Open
#10,952 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
422
Forks
697
Avg merge
2d 6h
Merged PRs (30d)
286

Description

## Summary

This RFC proposes adding `community-cli workspace fix` to `@backstage-community/cli` — a community-plugins-specific extension of `backstage-cli repo fix` that runs a configurable pipeline of fixers (lint, prettier, markdownlint, knip, and others) from each workspace's `yarn fix` script.

The goal is to standardize local and CI fix workflows across ~100 independent plugin workspaces without duplicating standalone scripts at the repository root.

**Related work:** [PR #10939](https://github.com/backstage/community-plugins/pull/10939)

## Motivation

Community Plugins is not a single Yarn workspace. Each directory under `workspaces//` is an independent project with its own `yarn.lock`, `node_modules`, and release cycle. Contributors are expected to run `yarn fix` before opening a PR ([CONTRIBUTING.md](https://github.com/backstage/community-plugins/blob/main/CONTRIBUTING.md#yarn-fix)), and CI enforces this via `yarn fix --check` in [`.github/workflows/ci.yml`](https://github.com/backstage/community-plugins/blob/main/.github/workflows/ci.yml).

`backstage-cli repo fix` alone does not cover everything maintainers want fixed in one pass:

- ESLint auto-fix via `backstage-cli repo lint --fix`
- Prettier formatting
- Optional tools such as `sort-package-json`, `markdownlint`, and `knip --fix`
- Consistent `NODE_OPTIONS` for memory-heavy lint steps (matching CI's `--max-old-space-size=8192`)
- Per-workspace opt-in flags (e.g. `--publish` for dynamic plugin bundles)

An earlier approach used a root-level `scripts/workspace-fix.mjs` script invoked from each workspace. Review feedback on PR #10939 pointed out that a **custom CLI module living in this repository** is preferable to a standalone script duplicated across community-plugins and other forks (e.g. Red Hat's community-plugins fork).

## Proposal

Add `community-cli workspace fix` under `workspaces/repo-tools/packages/cli/`, following the same pattern as existing commands such as `community-cli workspace create`.

### Command

```bash
# From a workspace root (workspaces//)
yarn fix
# → node ../../node_modules/@backstage-community/cli/bin/community-cli workspace fix

yarn fix --check # CI mode: only backstage-cli repo fix --check
yarn fix --publish # Pass --publish to repo fix (e.g. kiali dynamic bundles)
yarn fix --knip # Opt in to knip --fix
yarn fix --plugin # Scope lint/prettier/markdownlint to one plugin
```

### Fix pipeline

When **not** in `--check` mode, the command runs these steps in order (skipping unavailable optional tools):

1. `backstage-cli repo fix` (required)
2. `sort-package-json` (optional; workspace root only)
3. `backstage-cli repo lint --fix` or `backstage-cli package lint --fix` (required)
4. `markdownlint --fix` (optional)
5. `prettier --write` (optional)
6. `knip --fix` (optional; opt-in via `--knip` or `workspaceFix.knip` in `package.json`)

When **`--check`** is passed (as CI does), only step 1 runs with `--check`. Lint, prettier, and other checks remain separate CI steps, matching today's workflow.

Implementation lives in `workspaces/repo-tools/packages/cli/src/lib/workspaceFix/` with unit tests.

### Workspace configuration

Workspaces can opt into behavior via `package.json`:

```json
{
"workspaceFix": {
"publish": true,
"knip": true,
"nodeOptions": "--max-old-space-size=16384"
}
}
```

### Wiring across workspaces

Each workspace's `package.json` `fix` script points at the community CLI:

```json
"fix": "node ../../node_modules/@backstage-community/cli/bin/community-cli workspace fix"
```

Most workspaces already have:

```json
"postinstall": "cd ../../ && yarn install"
```

This postinstall is required so the portal-linked `@backstage-community/cli` at the repository root is installed before `yarn fix` runs (including in CI, where only the workspace directory is installed by default). Workspaces without `postinstall` cannot resolve the CLI path.

The `noop` workspace remains a no-op exception.

## Alternatives considered

| Approach | Pros | Cons |
|----------|------|------|
| **Root `scripts/workspace-fix.mjs`** | Simple, no CLI changes | Duplicated across forks; harder to test and extend; reviewers preferred CLI module |
| **Upstream into `@backstage/cli`** | Single source of truth for all Backstage repos | Community-plugins-specific fixers (knip reports, publish validation, per-workspace config) are not generally applicable; slower to land and release |
| **Per-workspace shell scripts** | No shared infra | ~100 copies to maintain; drift guaranteed |
| **`community-cli workspace fix` (proposed)** | Testable, extensible, lives with existing `@backstage-community/cli`; clear default vs opt-in | Requires root `yarn install` (via postinstall) for CLI resolution; private package not published to npm |

## Benefits

- **One command for contributors:** `yarn fix` from any workspace runs the full community fix pipeline.
- **CI alignment:** `yarn fix --check` continues to gate `backstage-cli repo fix` drift; other checks stay as separate workflow steps.
- **Extensibility:** New fixers are added in one module (`workspaceFix/steps.ts`) rather than across 100+ workspaces.
- **Clear ownership:** Logic lives in `repo-tools`, alongside `community-cli workspace create` and other community tooling.

## Rollout

1. Land PR #10939 (or equivalent) with the CLI module, tests, and docs updates.
2. Update all workspace `fix` scripts (~106 workspaces) to invoke `community-cli workspace fix`.
3. Ensure workspaces without `postinstall` add it (e.g. `bookmarks` was missing this and failed CI).
4. Document the command in `CONTRIBUTING.md` and `README.md` (already drafted in the PR).

No breaking change for plugin consumers — this only affects contributor and CI workflows inside the monorepo-style collection of workspaces.

## Open questions

1. **Upstream path:** Should any subset of this pipeline eventually move into `@backstage/cli repo fix`, or is a community-only CLI command the long-term home? (@logonoff raised upstreaming on PR #10939; @awanlin suggested the in-repo CLI module approach.)

2. **CLI resolution without postinstall:** Is `postinstall: "cd ../../ && yarn install"` the right long-term pattern, or should workspaces declare `@backstage-community/cli` as a devDependency to avoid relying on root `node_modules`?

3. **Changesets:** `@backstage-community/cli` is private — should changes to it require a changeset, or is documentation-only versioning sufficient?

4. **Additional default fixers:** Should any currently optional fixers (e.g. `sort-package-json`) become required defaults for all workspaces?

5. **SIG process:** Should this RFC be discussed in the [Community Plugins Discord #general channel](https://discord.com/channels/687207715902193673/1211692810294788126) before or after merge?

## RFC timeline

- **RFC opens:** community feedback via this issue and Discord
- **~4 weeks:** Comment period
- **Decision:** Merge, revise, or defer based on maintainer and SIG feedback

## References

- PR: https://github.com/backstage/community-plugins/pull/10939
- Prior RFC example: #8982
- Implementation: `workspaces/repo-tools/packages/cli/src/lib/workspaceFix/`
- Contributing docs: `CONTRIBUTING.md#yarn-fix`

Contributor guide

Open the contributing guide

Research direction

Start with PR #10939 and the existing command pattern in workspaces/repo-tools/packages/cli/src/lib/workspaceFix/. Read the unit tests, .github/workflows/ci.yml, CONTRIBUTING.md, and the workspace package.json fix and postinstall scripts. Done means the RFC decision is reflected in the CLI, tests, workspace wiring, and contributor documentation.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, node.js, typescript
Domain
ci-cd, cli, developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.