Skip to content

Backport Builder developer guide

Backport Builder is a release-engineering project. Treat source repositories as inputs, generated trees as outputs, and custom Rector rules as tested build logic.

Use this guide when you maintain downgrade rules, generated package metadata, target-runtime checks, or release automation for nextpdf/backport-builder.

LayerOwned byResponsibilityDo not put here
Source repositoriesProduct reposAuthoritative PHP source and tests.Generated downgrade edits.
Build scriptsnextpdf/backport-builderMerge source, run transformations, write metadata, and validate output.Runtime application logic.
Rector confignextpdf/backport-builderTarget-specific downgrade policy.Cross-target assumptions without tests.
Custom Rector rulesnextpdf/backport-builderProject-specific syntax transforms.Broad untested rewrites.
Generated packagesBuild outputInstallable artifacts for older runtimes.Manual source-of-truth patches.
StageBehaviorDeveloper action
Source checkoutThe release workflow checks out source repositories at the target tag.Keep source refs aligned across packages.
Contract validationValidateBuildContract::run() checks build assumptions.Treat a failed contract as release-blocking.
MergeMergeSources::run() assembles the target package tree.Verify target scope before running Rector.
TransformRector configurations and custom rules downgrade syntax.Add fixture tests for every rule change.
Composer adjustmentAdjustComposer writes generated package metadata and replace maps.Validate package names, versions, licenses, and constraints.
Runtime validationGenerated output is syntax-checked and tested on target PHP versions.Treat target-runtime failure as release-blocking.
ReleaseArchives are attached to a release.Do not patch generated output as the source of truth.
Work itemSource of truthGenerated output policy
PHP feature usageMain source repo.Backport rules adapt the feature.
Dependency constraintsSource composer.json metadata plus the adjustment script.Generated composer.json must be reproducible.
Syntax downgradeRector config and custom rules.Generated source should not be manually edited.
Runtime supportTarget branch and CI matrix.Build must pass on target PHP.
Release notesDocs and release automation.Generated artifacts should link back to source release.

Each custom rule should have a narrow purpose, metadata, and fixture coverage.

Rule methodPurposeQuality requirement
getRuleDefinition()Documents the transform for Rector tooling.Include a before/after sample that matches the actual downgrade.
getNodeTypes()Limits the AST nodes inspected by the rule.Keep the node list as small as possible.
refactor()Applies the transform or returns unchanged.Leave unrelated nodes unchanged and deterministic.
Fixture testVerifies before/after output.Cover the smallest valid input and at least one skip case.
<?php
final class ExampleDowngradeRector extends AbstractRector
{
public function getNodeTypes(): array
{
return [SomeNode::class];
}
public function refactor(Node $node): ?Node
{
if (!$node instanceof SomeNode) {
return null;
}
return $this->rewriteNode($node);
}
}

Use dry runs during development and release candidate validation. Write real output only when the source refs and target branch are known.

Terminal window
composer build:dry
php scripts/build.php --version=2.0.0 --target=php81 --dry-run
php scripts/build.php --version=2.0.0 --target=php74 --no-pro

Run generated package validation on the target runtime, not only on the modern build host.

Extension pointUse it forConstraint
Rector config filesTarget-specific downgrade policy.Keep PHP 8.1 and PHP 7.4 lanes separate.
Custom Rector rulesProject-specific syntax transforms.Must have metadata and fixture tests.
Composer adjustment scriptGenerated package identity.Must preserve SemVer-aligned versioning.
Merge scriptSelect and shape source package input.Must log source roots and output roots.
Build workflowRelease orchestration.Must validate generated output on target runtime.
  1. Reproduce the unsupported syntax in a minimal fixture.
  2. Add or update a custom Rector rule.
  3. Add before/after fixtures for the rule.
  4. Run the dry build.
  5. Validate generated output on the target PHP runtime.
  6. Apply the same logical change to each permanent target branch when required.
  7. Keep release artifacts reproducible from source tags and build scripts.
FailureWhere it should be handledRecommended response
Missing source repoContract validation or merge stage.Stop the build and fix checkout inputs.
Rector parse failureTransform stage.Reduce to a fixture and update the rule or config.
Generated composer.json mismatchComposer adjustment stage.Fix generation script, not generated metadata.
Target syntax failureRuntime validation.Block the release until the transform is corrected.
Pro source unavailableBuild configuration.Build public artifact only when that is the intended target.
ConcernDefaultWhen to override
Generated outputRead-only artifact.Never make it the source of truth.
Branch modelSeparate permanent target branches.Keep changes synchronized through independent pull requests.
Build hostModern PHP.Target runtime validation still decides release readiness.
Custom rulesSmall and fixture-backed.Avoid broad transforms without explicit before/after examples.
PHP 7.4 laneCore-only unless explicitly supported.Do not include Pro output without target-runtime validation.
  • Rector rule metadata tests instantiate every custom rule.
  • Fixture tests cover before and after code for each transform.
  • Dry build runs before release jobs.
  • Target runtime syntax checks and package tests run on generated output.
  • Composer metadata tests assert package name, version, constraints, replace map, and license.
  • Build logs include source paths, target path, target runtime, dry-run state, and Pro inclusion state.