Repository navigation
Give each package its own version and release only the packages that changed - #37
Draft
jwrosewell wants to merge 8 commits into
Draft
jwrosewell wants to merge 8 commits into
jwrosewell wants to merge 8 commits into
Conversation
…changed Each package is now tagged here as <package>/<version>, such as fiftyone.pipeline.core/4.5.207, and the publish releases a package only when a file in its folder changed since its last tag, with every package that requires it. Only the patch number moves. The plan comes from common-ci's steps/release-plan.ps1, which reads the new ci/packages.json. - ci/packages.json lists the packages, what each requires and where each is published. ci/packages.ps1 reads it in place of its own table and keeps the build and test fields as before. - ci/get-next-package-version.ps1 gives the run the highest planned version as its label, and ci/package-update-required.ps1 prints the plan and the requirements each released package will be published with. - ci/check-version-bump.ps1 and ci/check-release-interval.ps1 check each planned package against its own tags with common-ci's shared steps. - ci/publish-package.ps1 tags each planned package, one tag a push, because GitHub starts no workflow for a push of more than three tags, and makes a GitHub release for each. - ci/mirror-tags.ps1 puts each released version on its package's mirror. A package that requires others is published with those requirements raised to the versions released with it, on a commit on top of the split that changes only them. mirror.yml runs it for every package tag, and did-publish.yml now starts from the tags of pipeline/did. - The README, AGENTS.md and the nightly pipeline describe the new scheme. Part of step 3.4 of 51Degrees/common-ci#306.
PowerShell names ignore case, so the loop variable $push in ci/mirror-tags.ps1 replaced the -Push switch, and the loop failed with "Cannot convert value PSCustomObject to type SwitchParameter" once a package was planned.
…lease plan common-ci's release plan now leaves out Markdown files, documentation, tests, examples and licences by default, and calls ci/release-plan-filter.ps1 with the files that are left. The filter here leaves out a composer.json whose only changes are to description, keywords, homepage, support, authors or license, so a change that only moves a link releases nothing, while a change to require, autoload, version or any other field still releases the package.
Each package's Ignore list in ci/packages.json leaves out its phpunit.xml, phpstan.neon.dist, .php-cs-fixer.php, .gitignore files, .github/workflows and ci/ folder, as James decided on 7 November 2026. pipeline/did keeps its ci/ folder counting, because ci/assemble-package.sh and ci/rewrite-composer-json.php build the published fiftyone.pipeline.did.
This was referenced Nov 7, 2026
Merged
Merged
…every pull request The weekly check's refusal tells the person to run this repository's Publish workflow with allow-early-release set, which common-ci's nightly-publish.yml now accepts. The Release plan workflow runs the release plan filter's tests and prints the plan a release of the commit would publish, and fails when the plan cannot be worked out, such as a composer.json requirement that DependsOn does not list.
…r already has mirror-tags.ps1 already refuses such a version, but only after publish-package.ps1 has tagged this repository and made the GitHub releases. It happens when a package's last release has no <package>/<version> tag here, as after the 4.5.207 release, which was tagged the old way.
This was referenced Nov 13, 2026
# Conflicts: # ci/packages.ps1
This was referenced Nov 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Step 3.4 of common-ci#306. On
rctoday,ci/get-next-package-version.ps1makes one plain tag for the whole repository, such as4.5.207, and the Tag job ofmirror.ymlputs it on every mirror, so every package is released with the same number whether it changed or not. Decisions 1 to 3 of common-ci#306 say each package has its own version, tagged<package>/<version>, and that a package is released when a file in its folder changed since its last tag, together with every package that depends on it.How the mirrors and Packagist work
fiftyone.pipeline.core,.engines,.cloudrequestengine,.did,fiftyone.devicedetectionandfiftyone.geolocation.fiftyone.pipeline.translation,fiftyone.ipintelligenceand the on-premise Device Detection package are not on Packagist.main, the Branch job ofmirror.ymlrunsgit subtree splitfor each mirrored folder, afterci/prepare-split.shhas cut the import merges, and pushes the result to the mirror'smain.composer.jsonand GitHub's archive of the tagged commit. The commit need not be on the mirror'smain.fiftyone.pipeline.core/4.5.208is not a version number, so it stays here, and the mirrors keep plain version tags.What changed
ci/packages.jsonlists the nine packages withName,Path,Ignore,DependsOnandPublish, which common-ci'ssteps/release-plan.ps1reads, and the fieldsci/packages.ps1already had (Mirror,Vendor,Ci,Assembled,Native).Nameis the Composer name without51degrees/. The six packages with a mirror are published and the other three are not, as today.ci/packages.ps1reads the list from there in place of its own table, so the build and test scripts see the same fields as before.ci/packages.ps1gainsGet-ReleasePlanScript, which finds common-ci'ssteps/release-plan.ps1,Get-PublishedComposerJson, which gives a package'scomposer.jsonwith each requirement on another package here set to^<version>and stops when the51degrees/requirements andDependsOndisagree, andGet-MirrorHighestVersion, which reads the highest version tag on a public mirror.ci/get-next-package-version.ps1gives the run the highest planned version as its label.ci/package-update-required.ps1prints the plan and the requirements each released package will be published with. It then stops the publish, before anything is tagged, when a planned version is not above the highest version already on that package's mirror (lines 54 to 69).ci/mirror-tags.ps1refuses such a version too, but only afterci/publish-package.ps1has tagged this repository and made the GitHub releases.ci/check-version-bump.ps1andci/check-release-interval.ps1run common-ci's shared checks with-TagPrefixfor every planned package. common-ci'snightly-publish.ymlruns them in place of its own, because 51degrees-php is in itsOWN_CHECKlist (line 142).ci/publish-package.ps1tags each planned package<package>/<version>in the order of the plan, pushes one tag at a time and makes a GitHub release for each, then setsSkipUpdateTagso no plain tag is made. GitHub creates no push event when more than three tags are pushed at once, so one push of every tag would start no workflow.ci/mirror-tags.ps1holds what the Tag job did. For every package tag on the checked out commit it splits the folder, and when the package requires others it makes a commit on top of the split that changes only those requirements, to the newest version of each tagged on or before that commit. That commit has fixed names and the tagged commit's date, so a second run makes the same commit. It checks every mirror before tagging any, then pushes<version>to each mirror in the order ofpackages.jsonand stops at the first failure. Without-Pushit only prints what it would push.mirror.ymlstarts on*/<version>tags in place of plain ones and runsci/mirror-tags.ps1, anddid-publish.ymlstarts onfiftyone.pipeline.did/<version>. A plain version tag no longer starts anything.ci/release-plan-filter.ps1leaves out acomposer.jsonwhose only changes are todescription,keywords,homepage,support,authorsorlicense, and each package'sIgnorelist leaves out its development files. See "The release rule" below.publish.ymlhas anallow-early-releaseinput and passes it to common-ci, which now accepts it (line 28 ofnightly-publish.yml). The weekly check's refusal tells the person to set it.mainandrc. It runs the 21 Pester tests ofci/release-plan-filter.Tests.ps1, which no workflow ran before, and prints the plan a release of the commit would publish. It fails when the plan cannot be worked out or gives a version a mirror already has, so that shows on the pull request and not at the publish.rcat a074012f is merged in with a merge commit (5fefc52). The one conflict wasci/packages.ps1, whererchad setCitrue forpipeline/translation. The branch keepspackages.jsonand sets that field there.AGENTS.mdand the header ofnightly-pipeline.ymldescribe the scheme.No package folder changes, and the
cxxsubmodule is not touched.The release rule
James Rosewell decided on 7 November 2026 that a package is not released when the only changes under its folders since its last tag are to documentation, tests, examples or manifest metadata such as links. common-ci's
steps/release-plan.ps1leaves out**/*.md,**/docs/**,**/tests/**,**/test/**,**/examples/**and**/LICENSE*, ignoring case, and then callsci/release-plan-filter.ps1here with the files of each package that are left. Each package'sIgnorelist leaves out<path>/.github/workflows/**,<path>/ci/**,<path>/**/.gitignore,<path>/.php-cs-fixer*.php,<path>/phpstan.neon.distand<path>/phpunit.xml.pipeline/didkeeps<path>/ci/**, becausepipeline/did/ci/assemble-package.shandpipeline/did/ci/rewrite-composer-json.phpbuild the published package.These scripts are unchanged since run 42417106471 on 798ff86, which asserted the plan for 25 single changes made on the 4.5.206 commit. A readme, a test, an example, a
docsfile, a licence,composer.jsonmetadata, or any of the seven development files of a package each planned nothing. Arequireadded topipeline/engines/composer.jsonplannedfiftyone.pipeline.enginesand its three dependants. A change tolocation/composer.json'sautoloadplannedfiftyone.geolocationalone.pipeline/core/src/Utils.phpplannedfiftyone.pipeline.coreand the four that depend on it.pipeline/did/ci/assemble-package.shplannedfiftyone.pipeline.did.The first release from these tags
Every published package last released 4.5.207, from 59bb0081, the head of
mainand the commit of the plain tag4.5.207. Each mirror's4.5.207tag holds the package folder at that commit. The tree of the tag equals the folder for the five plain splits, and for pipeline-php-did the assembled commit's parent b9395e0, the mirror'smain, has the tree ofpipeline/did. Packagist lists 4.5.207 for five packages and 4.5.203 forfiftyone.pipeline.did, whose hook is #32.The tags here are
<package>/4.5.206on 64fc91d, from before that release. So these six tags have to be pushed before this merges, or the first plan compares with 4.5.206 and plans 4.5.207 again.fiftyone.pipeline.core/4.5.207fiftyone.pipeline.engines/4.5.207fiftyone.pipeline.cloudrequestengine/4.5.207fiftyone.pipeline.did/4.5.207fiftyone.devicedetection/4.5.207fiftyone.geolocation/4.5.207Pushing them starts no workflow. At 59bb008,
mirror.ymlanddid-publish.ymlstart only on a plain version such as4.5.207, and six tags in one push make no push event. The nightly onmainstill uses the plain scheme, and 59bb008 already carries4.5.207, so its publish finds that version present and releases nothing. The 4.5.206 package tags have sat beside plain tags since 7 November, and the nightlies of 12 and 13 November and the 4.5.207 Publish (run 43331065748) passed.Checks
The guard against a version a mirror already has was shown red then green.
Two temporary branches checked the whole publish with the six 4.5.207 tags made in each job's own checkout by a temporary block in
ci/packages.ps1, as they are not pushed yet. Nothing was pushed from either.tmp/php-37-planis this head (d90ba55) with that block and a temporary workflow that lays out common-ci and this repository as the publish does, prints the plan, runsci/publish-package.ps1as a dry run and thenci/mirror-tags.ps1without-Pushagainst the real mirrors (run 43475747158). It printed "No package changed since its last release, so there is nothing to publish", asrcsince 4.5.207 changed onlyAGENTS.mdand thecxxandjavascript-templatessubmodules, which belong to no published package. A last step found no package tag above 4.5.207 here and 4.5.207 still the highest version on all six mirrors.tmp/php-37-publish-dryrunadds one comment line topipeline/cloudrequestengine/src/CloudRequestEngine.php, and setsPublishAnyBranchinci/install-package.ps1so common-ci's Package job runsci/publish-package.ps1offmain, as a dry run. The temporary workflow (run 43475746023) printed the plan below, andci/mirror-tags.ps1printed for each of the three the commit it would push, whosecomposer.jsondiffers from the split only in its51degrees/requirements, for example"51degrees/fiftyone.pipeline.engines": "4.*"to"^4.5.207"forfiftyone.pipeline.cloudrequestengine.Publish dry run. This repository's own Publish workflow, dispatched with
dryrunontmp/php-37-publish-dryrunat 63d6ab8 (run 43475792422), passed. All 30 jobs that ran passed, including the 13 Pre Build and 13 Test jobs on Ubuntu PHP 7.4 to 8.5, Windows PHP 8.3 and macOS PHP 8.1 to 8.5, and Report Compare Performance was skipped as Compare Performance passed. Its Configure job gave the label 4.5.208 and printed this plan.So the one changed package and the two that depend on it are released, and
fiftyone.pipeline.core,fiftyone.pipeline.enginesandfiftyone.pipeline.didare not. The version check passed each of the three with "Publishing 4.5.208, against 4.5.207 already released. The patch place, which needs no agreement." The weekly check named each one's last release as 12 November and said the next may go from 19 November, as a notice, becauseWEEKLY_RELEASES_FROMis not set. The Package job printed "Dry run - tagged '...' locally, not pushed, no release made" for the three tags in plan order, then "Tag update skipped", so no plain tag would be made.The quick checks on d90ba55 (environment variable names, only rc into main, UTM link lint) passed. No package code changes, so this has no full build of its own, under the 12 November decision for changes to CI scripts and their notes.
Before this merges
Weekly releases
Each package released 4.5.207 on 12 November, so the next release under the weekly rule may go from 19 November. James Rosewell asked on 13 November for a release of every repository on Monday 16 November, which is his permission for that early release, so the Monday Publish is dispatched with
allow-early-release.What remains
ci/publish-package.ps1pushes and releases one package at a time in plan order. If it stops after the first tag is pushed, by a failed push or a failedgh release create, the packages pushed so far are published and the rest of the plan is not. Running Publish again does not finish it, because common-ci'sGet-ReleasePlan(steps/release-plan.ps1lines 201 to 203 and 234 to 242 at 1c5c0e0b) leaves out a package tagged at HEAD and releases a dependant only with a package that changed, so it plans nothing. The fix belongs in that shared plan, which the other per-package languages read too, and common-ci#326 tracks that fix. Until then, finish a stopped release by hand from the plan the stopped run's Configure job printed. For each planned package with no<package>/<version>tag on the released commit, in plan order, rungit tag <package>/<version> <commit>, thengit push origin refs/tags/<package>/<version>on its own, so that each push startsmirror.yml, thengh release create <package>/<version> --verify-tag --title "<package> <version>" --notes "<package> <version>: a package it depends on is released.". Make the missing GitHub release of any package whose tag was pushed the same way. The checks inci/mirror-tags.ps1still apply to a tag pushed like this.fiftyone.pipeline.did4.5.204 to 4.5.207 are tagged on the mirror but not on Packagist.mirror.ymlwas not run with a real push, as that would publish. The dry runs run the sameci/mirror-tags.ps1without-Pushagainst the real mirrors.<path>/.github/workflows/**entries of eachIgnorelist match nothing. They stay, so a workflow added there by mistake still releases nothing.