Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
fe3126c
feat: add Backstage 1.54 migration recipe (#155)
schultzp2020 Oct 12, 2026
013ec37
docs: use Yarn for v1.54 migration recipe commands
schultzp2020 Oct 12, 2026
ee197a4
docs: clarify v1.54 recipe AI provider blocker
schultzp2020 Oct 12, 2026
72fec75
docs: document conditional standalone AI step after recipe
schultzp2020 Oct 12, 2026
300ed71
fix: bind default-false nested recipe parameter
schultzp2020 Oct 13, 2026
3a1b4b3
Merge remote-tracking branch 'origin/main' into feat/v1.54.0/migratio…
schultzp2020 Oct 27, 2026
de65869
feat: bundle 1.54 codemod scripts into the migration recipe
schultzp2020 Oct 27, 2026
51b0ad0
test: keep every step's test suite inside the recipe
schultzp2020 Oct 27, 2026
bde7244
docs: describe the recipe as the go-forward codemod setup
schultzp2020 Oct 27, 2026
320956c
feat: repo-wide convention-based test runner for migration recipes
schultzp2020 Oct 27, 2026
42f0c8b
feat: move the recipe test runner into a private workspace package
schultzp2020 Oct 27, 2026
8e9a0c7
feat: move all repository scripts into a TypeScript scripts package
schultzp2020 Oct 27, 2026
49477a5
fix: sync-readme-pr staged check and hook regression setup
schultzp2020 Oct 27, 2026
782633a
fix: resolve the real lint-staged entry from its manifest in the hook…
schultzp2020 Oct 27, 2026
0f925e4
fix: keep CI under the job timeout
schultzp2020 Oct 27, 2026
c006a69
fix: make the fixture timeout actually fire on CI
schultzp2020 Oct 27, 2026
40cf915
fix: quote the OpenAPI shell step for sh compatibility
schultzp2020 Oct 27, 2026
cd07235
chore: restore the 15-minute Test job timeout
schultzp2020 Oct 27, 2026
c3770b3
fix: address review findings on the release path and fixture timeouts
schultzp2020 Oct 28, 2026
8f470fe
feat: validate recipe workflow structure in the shared runner
schultzp2020 Oct 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/early-sky-recipe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@backstage/v1-54-0-migration-recipe': minor
---

Bundle the five Backstage 1.54.0 codemod scripts as local steps in the recipe and remove the standalone packages, so the recipe is the only published 1.54.0 artifact and no nested registry codemod step is used.
12 changes: 4 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,12 @@ jobs:

- run: yarn install --immutable

- name: Test shell scripts
run: |
export LC_ALL=C
for script in scripts/test-*.sh; do
bash "$script" || exit $?
done
- name: Test scripts package
run: yarn test:scripts

# Shared with local husky pre-push (scripts/check-changed.sh) so gates cannot drift.
# Shared with local husky pre-push (yarn check:changed) so gates cannot drift.
- name: Check changed files
run: bash scripts/check-changed.sh origin/main
run: yarn check:changed origin/main

changeset-check:
name: Changeset Check
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: Tag released versions
if: steps.changesets.outputs['has-changesets'] == 'false'
id: tag
run: bash scripts/tag-and-publish.sh
run: yarn tag-and-publish

publish:
name: Publish ${{ matrix.dir }}
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/sync-readme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ jobs:
cmp README.md "$RUNNER_TEMP/generated-readme.md"
yarn format:check
yarn test
bash scripts/test-check-changed.sh
bash scripts/test-sync-readme-pr.sh

- name: Create or update review PR (no-op if README is current)
env:
GH_TOKEN: ${{ github.token }}
run: bash scripts/sync-readme-pr.sh
run: yarn sync-readme-pr
12 changes: 4 additions & 8 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#!/usr/bin/env sh
set -e
# Same gates as CI (.github/workflows/ci.yml → scripts/check-changed.sh).
if [ ! -f scripts/check-changed.sh ]; then
echo "error: scripts/check-changed.sh missing." >&2
# Same gates as CI (.github/workflows/ci.yml -> yarn check:changed).
if [ ! -x node_modules/.bin/check-changed ]; then
echo "error: check-changed bin not found. Run 'yarn install' in this worktree before pushing." >&2
exit 1
fi
if [ ! -d node_modules ]; then
echo "error: node_modules missing. Run 'yarn install' in this worktree before pushing." >&2
exit 1
fi
bash scripts/check-changed.sh origin/main
yarn check:changed origin/main
6 changes: 3 additions & 3 deletions .lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"*.{ts,tsx,js,jsx,mts,mjs}": ["bash scripts/format-staged.sh", "yarn lint"],
"*.{json,yaml,yml,md,css}": ["bash scripts/format-staged.sh"],
"codemods/**/scripts/*.{ts,tsx}": "bash scripts/test-staged.sh"
"*.{ts,tsx,js,jsx,mts,mjs}": ["format-staged", "yarn lint"],
"*.{json,yaml,yml,md,css}": ["format-staged"],
"codemods/**/scripts/*.{ts,tsx}": "test-staged"
}
35 changes: 29 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ yarn test

After `yarn install`, the `prepare` script runs `husky` and sets `core.hooksPath` to `.husky/_`. Hooks fail loudly if `node_modules` is missing (so worktrees cannot silently skip checks).

| Hook | What runs |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **pre-commit** | `yarn lint-staged` — format + lint staged files; package tests for staged `codemods/**/scripts/*` ([`.lintstagedrc.json`](./.lintstagedrc.json)) |
| **pre-push** | `yarn check:changed` → [`scripts/check-changed.sh`](./scripts/check-changed.sh) — the **same** format / lint / package-name / test gates as CI |
| Hook | What runs |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **pre-commit** | `yarn lint-staged` — format + lint staged files; package tests for staged `codemods/**/scripts/*` ([`.lintstagedrc.json`](./.lintstagedrc.json)) |
| **pre-push** | `yarn check:changed` (the `check-changed` bin from [`@backstage/scripts`](./packages/scripts)) — the **same** format / lint / package-name / test gates as CI |

CI (`.github/workflows/ci.yml`) calls that same script, so local and remote gates cannot drift. Run `yarn check:changed` anytime to reproduce CI locally. Codemod PRs do not regenerate or check the root README; leave it unchanged. After codemods land on `main`, run **Sync codemod README** from the Actions tab on `main` to generate a separate reviewable PR. A clean README is a no-op; reruns update the same bot branch/PR without force-pushing. The dispatch runs format, tests, script regressions, and README idempotence checks, but not repository-wide lint: PRs created with `GITHUB_TOKEN` do **not** trigger `pull_request` CI, so review the dispatch result before merging.

Expand Down Expand Up @@ -90,9 +90,32 @@ The `<group>` is either a Backstage release version (e.g. `v1.52.0`) for migrati

Conventions to follow:

- The two-level glob `codemods/*/*/` is assumed by `scripts/sync-codemod-versions.sh` and `scripts/tag-and-publish.sh`. Don't flatten or deepen this layout.
- The two-level glob `codemods/*/*/` is assumed by the `sync-codemod-versions` and `tag-and-publish` bins from [`@backstage/scripts`](./packages/scripts). Don't flatten or deepen this layout.
- The `package.json` `name` must be `@backstage/<codemod-name>`. The tagging and publishing scripts assume this scope.
- The `version` field in `codemod.yaml` is generated from `package.json` by `scripts/sync-codemod-versions.sh`. Don't edit it directly.
- The `version` field in `codemod.yaml` is generated from `package.json` by the `sync-codemod-versions` bin. Don't edit it directly.
- Use single-quoted scalars in `codemod.yaml` and `workflow.yaml` to match the oxfmt convention.

Use an existing codemod like `catalog-node-alpha-to-stable` as a reference when creating a new one.

## Adding a migration recipe

Each Backstage release publishes a single `migration-recipe` package under `codemods/<version>/migration-recipe/` — the recipe is the only published package for its version, and every workflow step runs a local script instead of a nested registry codemod:

```
codemods/<version>/migration-recipe/
scripts/<name>.ts # One script per codemod step, kept separately runnable
tests/<name>/ # Fixture suite matching scripts/<name>.ts
workflow.yaml # Steps reference the local scripts (js_file: scripts/<name>.ts)
codemod.yaml / package.json / README.md
```

Conventions:

- `package.json` `test` is `run-recipe-tests` (a bin from the private [`@backstage/scripts`](../../packages/scripts) workspace package, declared as a devDependency — no relative paths). The runner discovers suites by convention, so adding a step never changes a test command:
- `scripts/<name>.ts` + `tests/<name>/<case>/input.<ext>` fixtures run as `codemod jssg test`; the language is inferred from the fixture extension (`ts`/`tsx` → `tsx`, `json`, `yaml`/`yml`). Fixture roots without JSSG input files (e.g. `.sh` suites) are skipped there and covered by their `node --test` suites.
- `tests/<name>/assert-fixtures.ts` runs whole-app fixture trees through the recipe workflow (`run-recipe-tests --list` prints the plan without executing).
- Every `tests/**/tsconfig.json` is type-checked with `tsc`.
- Every `tests/**/*.test.mjs` runs under `node --test`.
- The workflow itself is structurally validated: every `js-ast-grep` step's `js_file` and every run step's `CODEMOD_SCRIPT` must exist locally, and registry `codemod:` steps are rejected. Recipe-specific concerns (step ordering, parameter bindings) stay in the recipe's own `tests/workflow.test.mjs`.
- Steps that share workflow state (an indexing step feeding a transform, or a shell step reading state set by another step) must run in the same workflow and in order — keep that coupling when reordering.
- Repository tooling (gates, generators, release helpers, the recipe runner) lives in [`packages/scripts`](../../packages/scripts) as TypeScript bins with `node:test` regression tests in `tests/`; run them with `yarn test:scripts`. Update them when changing discovery or gate rules.
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,27 @@ See the [Codemod docs](https://docs.codemod.com) for more on building and runnin

<!-- CODEMODS_START -->

### v1.54.0
### v1.55.0

Run the [`migration-recipe`](./codemods/v1.55.0/migration-recipe) to apply every codemod below in one pass, or run any individual codemod on its own.

| Codemod | Description |
| ----------------------------------------------------------------------------- | ----------------------------------------------------- |
| [rename-root-connection-auth](./codemods/v1.54.0/rename-root-connection-auth) | Rename RootConnectionAuth to ConfiguredConnectionAuth |
| Codemod | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [migration-recipe](./codemods/v1.55.0/migration-recipe) | Migration recipe that runs every @backstage v1.55.0 codemod from the registry in a safe order. |
| [move-connections-config-imports](./codemods/v1.55.0/move-connections-config-imports) | Move Connections configuration imports and re-exports to @backstage/connections/config |
| [remove-bui-anchor-render-props](./codemods/v1.55.0/remove-bui-anchor-render-props) | Remove obsolete BUI anchor render props |
| [remove-ignored-github-repo-create-inputs](./codemods/v1.55.0/remove-ignored-github-repo-create-inputs) | Remove ignored github:repo:create inputs from scaffolder templates |
| [remove-kubernetes-implicit-children](./codemods/v1.55.0/remove-kubernetes-implicit-children) | Remove unused Kubernetes component children |
| [remove-relations-compatibility-config](./codemods/v1.55.0/remove-relations-compatibility-config) | Remove deprecated catalog.enableRelationsCompatibility config |
| [rename-connections-public-api](./codemods/v1.55.0/rename-connections-public-api) | Rename Connections public symbols |

### v1.52.0
### v1.54.0

Run the [`migration-recipe`](./codemods/v1.52.0/migration-recipe) to apply every codemod below in one pass, or run any individual codemod on its own.
Run the [`migration-recipe`](./codemods/v1.54.0/migration-recipe) to apply every codemod below in one pass. Individual scripts can still be run on their own; see the recipe's README.

| Codemod | Description |
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [migrate-bui-props-to-intersection](./codemods/v1.52.0/migrate-bui-props-to-intersection) | Migrate ComboboxProps/SelectProps interface extends to type intersection |
| [migrate-select-combobox-props](./codemods/v1.52.0/migrate-select-combobox-props) | Migrate deprecated Select/Combobox search props and option value to id |
| [migration-recipe](./codemods/v1.52.0/migration-recipe) | Migration recipe that runs every @backstage v1.52.0 codemod from the registry in a safe order. |
| [remove-stitching-strategy-mode](./codemods/v1.52.0/remove-stitching-strategy-mode) | Remove deprecated catalog.stitchingStrategy.mode from app-config |
| [rename-bui-css-tokens-v1-52](./codemods/v1.52.0/rename-bui-css-tokens-v1-52) | Rename deprecated BUI semantic color tokens |
| Codemod | Description |
| ------------------------------------------------------- | --------------------------------------------------------------------------------- |
| [migration-recipe](./codemods/v1.54.0/migration-recipe) | Migration recipe that runs every Backstage 1.54.0 codemod script in a safe order. |

Older versions are available in the [`codemods/`](./codemods) directory.

Expand Down
7 changes: 0 additions & 7 deletions codemods/v1.54.0/migrate-connections-query/CHANGELOG.md

This file was deleted.

5 changes: 0 additions & 5 deletions codemods/v1.54.0/migrate-connections-query/README.md

This file was deleted.

20 changes: 0 additions & 20 deletions codemods/v1.54.0/migrate-connections-query/codemod.yaml

This file was deleted.

13 changes: 0 additions & 13 deletions codemods/v1.54.0/migrate-connections-query/package.json

This file was deleted.

20 changes: 0 additions & 20 deletions codemods/v1.54.0/migrate-connections-query/workflow.yaml

This file was deleted.

7 changes: 0 additions & 7 deletions codemods/v1.54.0/migrate-extension-config-schema/CHANGELOG.md

This file was deleted.

12 changes: 0 additions & 12 deletions codemods/v1.54.0/migrate-extension-config-schema/README.md

This file was deleted.

15 changes: 0 additions & 15 deletions codemods/v1.54.0/migrate-extension-config-schema/codemod.yaml

This file was deleted.

16 changes: 0 additions & 16 deletions codemods/v1.54.0/migrate-extension-config-schema/package.json

This file was deleted.

This file was deleted.

16 changes: 0 additions & 16 deletions codemods/v1.54.0/migrate-extension-config-schema/tsconfig.json

This file was deleted.

Loading
Loading