Open sminnee opened 4 years ago
CC @emteknetnz as you asked in a comment "why would we ever delete the 4.6 branch?" ;) my thinking was lengthy enough for an RFC.
Yeah I think I'm generally on board with this because it moves in the direction of reducing the maintenance burden. It also aligns with our support timeline where we only fully support the latest minor and only touch the previous minors for critical/security bugfixes.
For pull-requests that target really old minors such as 4.3, I think this is usually just a really old pull-request and 4.3 was actually the latest minor at the time. However it may also be "My project still uses an old minor version" so I'll just target that. Either way I would prefer these pull-request to go straight into 4.6 rather than 4.3 for the reduced toil.
Also merging something into 4.5 for someone doesn't always feel great because old minors hardly gets a stable release and we are kind of setting a bad expectation. For instance in the last quarterly release we did not include the 4.5 recipes and dependent modules because there was nothing security related to release.
"Merge-ups" are more time-consuming and complex
Agree there, particularly with something like asset-admin javascript where you need to checkout the same admin module version in tandem and yarn install both and yarn build asset-admin at each merge-up step
If you just wanted to use the latest version of 4.2, but also stay on 4.2 after 4.3 has been a released, then what are you doing?
It is pretty normal for end-users to stay on fairly out of date versions because they don't have a robust minor upgrade process in place, or perhaps they are highly risk adverse and see upgrading minors as too risky since there may be regressions. Or maybe they just setup their composer.json with ~
instead of ^
back in the day, don't know any better and never updated it.
That said, a composer requirement that doesn't upgrade minors such as ~4.2.0 will still work even if the 4.2 branch is deleted because we're won't be removing the 4.2.n tags, only the 4.2 branch. People really should not be using 4.2.x-dev on production sites so I'm not fussed about loosing that functionality.
I'm not sure how hard this it to do in Cow, but hopefully it's relatively straightforward.
If we just created say the 4.5 branch manually when we needed it from the latest 4.5.n tag as you suggest, then we shouldn't need any changes in cow. You have provided data showing that it's an infrequent event so I don't think this fairly simple step is worth investing time to automate.
It is pretty normal for end-users to stay on fairly out of date versions because they don't have a robust minor upgrade process in place, or perhaps they are highly risk adverse and see upgrading minors as too risky since there may be regressions.
I think that's fine, but to be using an old version and be using the dev version of that minor release seem to be in conflict: I don't think a project can simultaneously be risk-averse and bleeding edge.
For the risk-averse folks, use ~4.2.0
rather than 4.2.x-dev
EDIT: I think we are using different words to agree 😆
@emteknetnz I think this
Or maybe they just setup their composer.json with ~ instead of ^ back in the day, don't know any better and never updated it.
might be sending a wrong message, suggesting the right way to do composer constraints is using ^
instead of ~
, allowing minor version updates (instead of just patches). It might be fine cross-requiring dependencies between SS modules, but from my experience so far I'd say it's reasonably fine to let patches in from SS modules to a project, but not always the case with new minor versions as they may require project code updates/changes to function properly.
Remember all the hassle going from 4.0 to 4.1 to 4.2 to .... and protected assets and file hash issues etc.?
It's probably offtopic in case of this RFC, just wanted to voice my concern if that ("people should use ^
") became a reason/supporting argument for some changes here.
The point was more that people shouldn't use 4.n.x-dev. Either ~ or ^ are better. You can pin to @dev, or reference a not-yet-released number (eg ^4.8 will check out 4.x-dev until 4.8.0 is released, which is great if you just got a PR merged into 4 and you're happy to use the dev branch until your PR makes its way into a stable tag)
What do we do if we want to delete minor-release branches but there is untagged content in them? Clearly, we should do a final 'merge-up' to future branches if one is needed.
However, is that sufficient? Imagine the scenario:
If someone is currently using 4.4.x-dev
, ~4.4.0@dev
, or ~4.4.0
with min-stability: dev, then there project will include BUGFIX-123.
If we just merge 4.4 into 4 or 4.5 and delete the branch, then they will lose this.
4.4.x-dev
I believe they will get a noisy error on composer update and so might go and switch to 4.5. But they might switch to ~4.4.0
and lose BUGFIX-123.Now it's an unreleased fix, but someone might have switched to dev stability precisely because they needed that fix.
My suggestion is that in such a case we tag 4.4.2-beta1 but made no attempt for a release beyond that. This will keep people's projects working but don't force us to go through the testing process required for an additional stable release. A dangling beta release is a little odd but seems like a fair reflection of the real-world situation.
cc @dnsl48 @chillu @maxime-rainville
In terms of approving this do we want to PR some branch management guidelines into the ope-source contributor docs?
If you're running a dev branch of an out-of-support release on something important, I'm inclined to be unsympathetic if deleting the branch ends up breaking your project.
I would try to merge up the fix on a "best effort" basis, but not much beyond that.
I'm inclined to be unsympathetic if deleting the branch ends up breaking your project.
Keep in mind that a lot of websites out in the wild were was once well resourced development projects several months or years ago, but when that project was finished the developers then moved on to the next thing, and the website barely have any sort of ongoing development resource / maintenance budget, so it has a prehistoric composer.json file that made perfect sense at the time.
If the site needs to be redeployed for whatever reason by their managed hosting provider, such as an infrastructure upgrade, then all of a sudden their code gets reverted to something pre-bugfix :'(
I think Sam's solution of tagging the very last thing on on the branch as an untested beta seems like a good idea.
Just went through a couple modules to get a better idea of how many repos have old branches with unreleased code. Most of the older modules have a couples. So most of them would need some of those fake beta tags.
My gut feeling at this stage is that adding beta tags to those branches before deleting them would transform this job from something that could be done in a couple hours to something that would take a couple days. Are we really willing to spend a week of dev time on this?
What work are you assuming is necessary beyond "git tag x && git push --tags"?
Can you avoid that work and still get a better result than throwing the code away?
If toil is a concern then this be a good candidate for automation?
A simple php cli script along these lines may be useful?
<?php
$branches = shell_exec('git fetch && git branch'); // just pretend this returns a php array
foreach ($branches as $branch) {
if (!preg_match('^[0-9]\.[0-9]$', $branch)) {
continue;
}
shell_exec("git checkout $branch");
$commitInGitTag = shell_exec("some git command that works out if the latest commit exists it at least 1 tag");
if (!$commitInGitTag) {
$tag = '1.2.3-beta'; // work out by incrementing the patch number on the latest tag that matches $branch
shell_exec("git tag $tag && git push --tags");
}
}
One issue we've hit when pruning old core branches in the past (and part of the reason we stopped doing this in the first place) is that all of our satellite modules have CI matrixes that cover a range of old minors, and dropping the branches therefore indirectly busts those builds. This could be resolved in a similar manner to what's being recommended for projects - using ~4.4.0@dev
instead of 4.4.x-dev
- but just worth noting that there's a bundle of toil waiting to be unleashed if/when we proceed with this.
(We've explored options for reducing this toil in #9174.)
Presumably we'd also want to drop a bunch of the older entries from the satellite modules matrix too? For instance just have a 4.6
entry and a --prefer-lowest
and call it a day?
We'd may also want to convert them to ~4.6.0@dev
notation at the same time to make them resilient for when 4.6
silverstripe/recipe-cms
gets pruned sometime in the distant future.
Another option may be to have a --prefer-highest
and a --prefer-lowest
and not denote minor versions at all to remove the need to update them going forward
Seems like at least one round of travis toil is pretty unavoidable here
Another option may be to have a --prefer-highest and a --prefer-lowest and not denote minor versions at all to remove the need to update them going forward
Yes I think that is the best way to have a general purpose build matrix, and covered in https://github.com/silverstripe/silverstripe-framework/issues/9174
We'd may also want to convert them to ~4.6.0@dev
Hit a problem with that approach. Most of our modules have prefer-stable: true, which makes it install only stable tags on CI (even when dev branches exists).
A potential workaround is to turn it off in CI (e.g. like that: composer config prefer-stable false
). However, that would make it install unstable 3rd party libraries too, not merely our own recipes (e.g. we don't want to test with dev-master branch of symfony components).
So far it looks like we may need to go with --prefer-lowest
and --prefer-highest
if we want to avoid the toil.
Yes fair enough. The use of travis templates referencing a .x-dev release (Steve's recent work) may also help.
There's four core committers involved in this discussion, and it sounds like there's agreement on the high level RFC, just some discussion on the technicalities - so I'm marking this as rfc/accepted
.
This does smell a bit like increased toil though, especially if we want to roll this out to all "supported" modules. Both as a one-off (review branches, dangling commits, tag beta releases), and as an ongoing effort when we create new minor branches. We could automate this on cow release
? Every time you make a stable release, it checks existing branches and offers to delete ones which would become unsupported. So when releasing 4.8.0
, it'd detect the presence of a 4.6
branch and delete it.
Alternatively we could do this via Github Actions, but an automated process deleting branches seems quite difficult to get right. Especially since you'd need to supply fixes to each individual module in the way that Github Actions is structured.
How often do we actually hit cases where PRs target the wrong branch, and a maintainer misses that and merges? Is it worth the upfront and ongoing effort?
We could automate this on cow release
I'd strongly prefer not to automate this step via cow, because as the recent issues with cow translate have shown, while computers may not mistakes, sometimes the humans programming them do
It would be worthwhile getting cow or a similar tool that pings the github api to list old branches to make it easier for a human to manually delete them
How often do we actually hit cases where PRs target the wrong branch, and a maintainer misses that and merges? Is it worth the upfront and ongoing effort?
Very infrequently. Probably more of an issue when merging very old PR's that originally targeted the correct branch. Generally branch targeting issues people have a targeting the master
branch or default 4
for simple bugfix that could be in the next patch release.
Regardless though this is still worth doing IMO because it makes it much clearer to everyone that critical fixes or even general fixes don't need to "target the oldest feasible branch and then merge it up 5 times"
I'd strongly prefer not to automate this step via cow,
There's different levels to this:
FYI We now have a view on our dashboard that list which branches have unrelease commits for all our module. This should hopefully make it easier to visualise which branches might need one last unstable release before we can delete the branch.
https://maxime-rainville.github.io/travis-dashboard/unreleases
9077 Problem
Right now, framework has (among others) the following branches:
This means that PRs can be made to any of these branches, having the following downsides:
In short, our code management is unnecessarily complex. I'd like to limit us to the necessary complexity. ;-)
Recommendation
My recommendation is that we retain only a single minor release line per major branch:
Other considerations
Security releases
l am not suggesting that we necessarily drop security support for earlier minor release lines as part of this change: just because the branch is deleted doesn't mean we're unable to produce a security patch.
If we need to create a security release on an older version (this happens about 3 times / year based on the last 2 years' data), then a release branch could be created using the latest stable tag as the starting point. This will mean that the security release will only contain the security fix, plus anything in the previous stable release, which seems superior.
I'm not sure how hard this it to do in Cow, but hopefully it's relatively straightforward.
Broken composer checkouts
If people are referencing
4.2.x-dev
, I believe this would fail on a composer update. I'd have to test whether it breaks on composer install.4.2.x-dev
might be to test the latest development version of the code. If you're still using4.2.x-dev
instead of4.6.x-dev
then you're not achieving this. So deleting the branch doesn't create a bug so much as expose the bug that was previously undetected.^4@dev
or~4.2.0@dev
based on what your needs actually are.Cleaning up dangling commits
If a branch due for deletion has any commits on it that haven't been tagged in a release, then they should be tagged in a beta release and may be left that way without an RC or stable release ever happening.
This ensures that people who have tied their project to the dev version of that minor release don't lose any changes in their next composer update.
Prior work
A couple of years ago I had raised #8189, which was effectively suggesting that we minimise the use of the minor release branches altogether. That was accepted, on the understanding that there's some professional judgement about what goes into minor releases.
The fact is that work still makes its way into older branches, so it's not effective in simplifying our branching strategy on its own.