Skip to content

Discussion of the consistency checks #14897

Open

Description

@WilliamJamieson

Background

Currently, astropy maintains three primary branches:

  1. The main (development) branch.
  2. The current bugfix branch (currently 5.3.x).
  3. The LTS branch (currently 5.0.x); however, the acceptance of APE21 will end this soon.

For the vast majority of changes, they are PRs made against the main branch unless they are specific to an issue only present in the other two. We then mark these PRs in the following ways:

  • If those changes are determined to be relevant to the other branches, we attempt to use the meekseeks bot to "backport" them to those branches (and then manually backport them if the bot fails). Those backports are controlled via setting specific labels on the PR in question, which then tell meeseeks if/where to backport the PR. It does this by opening a PR against the backport branches.

  • Somewhat separately, we also try (and sometimes fail) to set milestones on the PRs. Those milestones are supposed to correspond to the oldest (lowest) version of astropy we expect the change to appear in. For example

    • if it is an LTS bugfix, it would currently get 5.0.7.
    • if it was only going to the bugfix branch it would currently get 5.3.1.
    • If it was a new feature and not a bugfixe it would currently get 6.0.0.

    Essentially, these milestones are used to track where/when a particular change will or has appeared in astropy.

Clearly, these to processes are related e.g.

  • If something has a backport-v5.0.x label, we would currently expect it to have a 5.0.7 milestone and vice versa.
  • If something only has a backport-v5.3.x label, we would expect it to have a 5.3.1 milestone and vice versa.
  • If something does not have a backport label, we would expect it to have a 6.0.0 milestone and vice versa.

However, they are currently two separate unlinked steps we expect (hope) our maintainers to perform sometime before merging a pull request. This tends to introduce human errors, which tend to undermine consistency the checks usefulness (assuming they are working).

Consistency Checks

It is my understanding that the consistency checks are intended to ensure that all the changes we intend to first appear in a given astropy version actually appear in that version. By this I mean:

  1. For "backport" versions, all the backport pull requests opened by the bot (or manually created when it fails) are merged.
  2. The backport bot has actually run on all PRs intended to be backported to the backport version in question. This is because the bot can sometimes be "down" and not get triggered; meaning, it does not create the backport PR nor does it mark the PR in question for manual backport.
  3. For all versions, the PRs marked with a given milestone have been merged. Note that the backport bot will set the milestone on its PR to be the same as the origin PR's.

I understand that the code supporting the consistency checks is both a bit flaky (sometimes it is just broken) and can be tricked by PRs not having the correct labels/milestones set. Both these issues tend to create "problems" for determining if a branch is ready to have its release made.

Possible PR Level Changes to Alleviate Consistency Check Issues

Most of my ideas revolve around preventing the "human" errors that will make it difficult for any consistency check solution to be completely accurate. That is making sure the backport labels and milestones are in some sort of agreement.

I propose that we add a required CI check to our current PR CI, which does two things:

  1. Requires a "backport" related label to be set. For the case that the change will not be backported, I propose a no-backport label be created to fill this purpose.
  2. Uses the label added by the maintainers to "compute" (determine) what the milestone for the PR should be.
  3. If a milestone is already present, check that the computed and listed milestones match (fail if they do not). If no milestone is present set the milestone on the PR. (Note in the failure case, in addition to updating the milestone to be correct, the maintainer will need to manually re-trigger the CI job).

This accomplishes the goal of having the right milestone set on PRs which is consistent with its backport status, and since it would be required this will "remind" maintainers to make and execute these decisions prior to merging the PR.

Known issues with this process

Human caused issues:

  1. GitHub currently does not have an event which can trigger CI if a milestone is set/changed. This is why I based all the CI on adding/modifying the backport label; however, this CI does not protect against the case were after the CI is run, someone updates only the milestone to something inconsistent with the currently specified label.
  2. It also doesn't protect against the case where we "change our minds" after a PR has been merged, as the CI will no-longer be triggered by any changes to labels (or milestones for that matter). However, one can manually trigger the backport bot using a comment on a PR without touching its current milestone; however, the backport PR generated will have whatever milestone was set at the time of the trigger. Again this can cause milestone-backport inconsistencies.

The only totally general solution I have for these issues is that we make it clear in the maintainer's merging guide/workflow that they do not touch the milestone prior to merging the PR. In theory this should lessen the burden on maintainers because

  1. They have only one (enforced) action they need to take in order to fit into the consistency process.
  2. They no longer have to figure out what the current milestones are active/relevant, the CI will be able to do this.

Hopefully this lessoning of burdens will convince the maintainers to adopt the proposed alteration to their workflow. However, it could still lead to some cases of human error that we cannot catch (due to the problem that CI cannot be triggered by a milestone change).

Many of the human caused inconsistencies from these two issues can be solved by:

  1. Ensuring the proposed CI is run on by the backport branches (the backport bot copies the labels and milestones of the originating PR).
  2. Adding a third step to the CI on backport branches which specifically checks the milestone computed from the label(s) matches what we would expect from computing that label based on the current backport branch instead. This part should cover most of the cases where one can run around the CI checks in the original PR, but it does not cover the main branch from this and it does not cover the backport PRs from the issues described above.

Note that if GitHub ever enables event triggers from updating milestones I can cover off all of the possible human caused inconsistencies.

Bot caused issues:

The other inconsistency which can appear is the case were the backport bot fails to even be triggered by merging a PR.

I believe it maybe possible to detect this by examining the PRs opened/merged on main with a given label and looking for a matching PR on the given backport branch. This would require that backport PRs have some identification linking them to the origin PR, such as having the PR number in the title or a commit message (both of which are done by the backport bot). Either of these facts can again be enforced on backport branches via CI (though it requires any human backports to mention the correct number).

Some Specific Details

Note that I have examples of getting/checking/setting the milestone from a CI job; however, it does require the pull_request_target trigger (so it has enough permissions to do so). This does have some security implications, but I can do it without any externally maintained actions.

The main detail will be "computing" the milestone from the label. This will require the branch names, label titles, and milestone titles to be entirely consistent with one-another and in formulation in order to do this. I believe we already do follow specific rules for this, and we will need to be extra vigilant about continuing to do this. In addition, to this consistency we will also need to very careful to close milestones when they are completed and close backport labels (add the 💤 to the beginning) as needed.

Note it is possible to handle the current three branch/milestone case even in the face of multiple backport labels (just have "order" the labels by the semantic version given and choose the first corresponding milestone). However, this should not be an issue once we begin following APE 21 (drop the LTS, meaning one backport branch and the main branch).

To actually compute the milestone from the label note:

  1. The labels in question are either like backport-v5.3.x or no-backport. This means we know the milstone is v5.3.something or the latest (in semantic version terms) milestone.
  2. If we are vigilant and close all completed milestones and don't add unrelated milestones which follow the PR milestone pattern (such as for issues or something), then we will only ever have one milestone beginning with v5.3 for example and so that one can be selected.

This strict adherence to milestones will make cases where we need to push changes into the "next" milestone, because they cannot make it into the current one a bit awkward. However, I believe we can add a future-va.b.c milestone and manually update those PRs to that milestone then once the "old" milestone is completed (an astropy release occurs), we can simply drop the future- prefix. Note that the fact that the future-va.b.c will not match the currently computed milestones will actually protect the branches from merging those PRs (if they are updated) because the milestone will not match the computed one, causing a failure in a required CI job (similar protection can be ensured using a label such as future, which will always fail the CI job).

The Actual Consistency Checks

The described PR level checks should (for the most part) ensure that we can reliably check the status of astropy with regards to the next release. Assuming, the backport bot has never had any issues, the constancy check itself is just pulling the milestone information and checking that all PRs with that milestone have been closed.

The issue with completely relying on this is the case when backports fail, this can happen in two ways:

  1. The backport bot cannot automatically generate the backport PR, in which case a Still Needs Manual Backport label is added to the origin PR.
  2. The backport bot fails to be triggered at all (possible but a rare occurrence).

Since we can "rely" on the milestones set on the main branch PRs and we are enforcing a title/commit pattern on the backport branches we can detect both cases, and provide a list of PRs that need attention. This can be done for a given milestone by looking at all the closed PRs against main that have the given milestone and then checking if a PR with following the enforced title/commit pattern has been opened on the given backport branch. If that is the case, the PR can be flagged/listed as being inconsistent.

When APE 21 is enforced, we can even set/remove the Still Needs Manual Backport label on merged PRs to main during this process. This can be done by removing the label if the backport PR is detected (a manual backport was create) or adding the label if it does not already exist on the PR (the backport bot failed to run entirely).

Conclusions

I think the above changes are all possible, I have (or had) CI proof of concepts implementing the majority of the required CI jobs. Though I have not put all the pieces together.

I also believe that this check "system" should detect virtually all the cases where a PR has not been merged to the correct branch prior to a release on that branch. The situations where it might be confused or fail would either need to be deliberately constructed or be a very complex and strange situation which the release managers should be made aware of.

Note that I may have missed key functions of the consistency checks as I have not actually used the current ones. The above conception evolved out of the consistency issues I explored automatically resolving in order to make managing some of the other projects I am involved with simpler (though I have not had time to fully implement it any where as of yet). Thus I maybe overlooking important astropy related details. Please comment below with anything I may have overlooked.

In any case, I would like to open discussions on how to tackle these issues.

Activity

  1. WilliamJamieson commented on Jun 1, 2023

    @WilliamJamieson
    ContributorAuthor

    @astrofrog and @saimn what are your thoughts on this? Would it help make things smoother easier for you?

    @pllim this would all be infrastructure, which I would be willing to (help) maintain, but it is more infrastructure and we are already spread kind of on that front. What do you think?

  2. WilliamJamieson commented on Jun 1, 2023

    @WilliamJamieson
    ContributorAuthor

    The TLDR:

    I propose 4 CI jobs/programs to help ensure consistency:

    1. A required CI check run on all PRs on all branches performing the following tasks:
      1. Check a backport label is set (or a no-backport label if no backport is needed).
      2. Checking the set milestone, when it exists, is consistent with this label otherwise automatically set it.
      3. If the PR is against a backport branch, check that its milestone is consistent with that branch.
    2. A required CI check on backport branches, which checks that the title begins with Backport PR #<a merged PR on main>.
    3. A scheduled check that all merged PRs on main for a given milestone have a "matching" PR on the correct backport branch excluding the development milestone.
    4. A scheduled check (after check 3) which checks that all the PRs under a given milestone are merged.

    If 3 and 4 are passing for a given milestone, theoretically a release corresponding to that milestone should be "consistent". Checks 1 and 2 should ensure checks 3 and 4 give accurate information (barring a few strange corner cases).

    This system will require us to continue our very strict naming pattern/relationship between backport branch names, milestone names, and backport labels. (We could even ensure this consistency with yet another CI job if it is a concern, and/or CI to update them upon a release).

  3. astrofrog commented on Jun 2, 2023

    @astrofrog
    Member

    I need to think about all this but a couple of thoughts after a first read:

    • Without LTS, why do we need milestones anymore? It's sufficient to know if the change is to be backported or not to the current release branch? Maybe we just don't need milestones?

    • Also without LTS, can we just have a simple 'backport' label that doesn't include a version number in it? That is, backport/no-backport is enough?

    • we should prevent PRs labelled 'enhancement' from being backported

  4. WilliamJamieson commented on Jun 2, 2023

    @WilliamJamieson
    ContributorAuthor

    I need to think about all this but a couple of thoughts after a first read:

    • Without LTS, why do we need milestones anymore? It's sufficient to know if the change is to be backported or not to the current release branch? Maybe we just don't need milestones?

    In chatting with @saimn and @pllim im in the infrastructure tag-up this week, they expressed a strong preference to keep milestones.

    • Also without LTS, can we just have a simple 'backport' label that doesn't include a version number in it? That is, backport/no-backport is enough?

    Yes that can work and it is a better idea. I originally wrote most of the code I had using the current astropy label, milestone, backport branch scheme. That is a vestige of that work. It will still require us to update the backport label every time we switch backport branches because the description of the label tells the backport bot where to backport the PR to.

    • we should prevent PRs labelled 'enhancement' from being backported

    The only way I can see to do this, is to have the label-checking job fail if both the enhancement and backport labels are present. As far as I am aware, this will not entirely prevent the possibility of automatic backports as the backport bot can be triggered via adding certain "magic" comments. However, it will block them under "normal" conditions.

    I'll see if I can put together a "test" version of all these CI jobs in a separate repository, which contains a complete clone of astropy in terms of the code, branches, necessary labels, and milestones. That way people can play with how this would all work in "realistic" circumstances. I probably won't have time to do this until the end of June; none the less, would this be a useful thing see?

  5. pllim commented on Jun 8, 2023

    @pllim
    Member

    I haven't read through all of this yet but I want to note that maybe there is some overlap with Scientific Python, see the following comment: scientific-python/pytest-doctestplus#203 (comment)


    jarrodmillman: We (mostly lagru and stefanv) are working on something similar (I think) for scikit-image and plan to use for release notes and ading milestones. We should coordinate!!

    This will be pulled out of scikit-image and made into a installable tool soonish:

    We are using it along with:

    The tentative plan to use it for a bunch of projects (networkx, scikit-image, napari) that are already basically using something like the new tool (due to copying from one another) and other projects I am releasing (pygraphviz, numpydoc, and a bunch of little tools living here.

  6. saimn commented on Jun 8, 2023

    @saimn
    Contributor

    I've been trying to think about it but with life and other tickets it's taking too much time, so just some random thoughts:

    • I like milestones, because it's the only way to find when something was merged. It's not perfect, and even not right with meeseeks PRs (since it copies to original milestone, which we don't systematically update), but it's the only way. And I don't think it would be better with labels.
    • With APE21 a good part of the original post is no longer relevant. Simplifying this process was also a reason for this APE. I'm struggling to transpose all the above thoughts to the new release process, so I will try another way, what do we need with the new process ?
      • By default PRs will go to the current major/minor version.
      • Bugfix PRs will need to be backported, but only to one branch and only if we plan to make a bugfix release before the next minor version. We used to backport many PRs to LTS, some of which were not really bugfix but to minimize potential conflicts with future PRs, so should be simpler now (i.e. we should only backport real bugfix PRs).
      • And we will need to milestone some PRs to the next major version.
      • Also there is the question of how to milestone bugfix PRs. We used to milestone to the oldest version, but maybe we can change ? (e.g. v5.0.7 milestone list both the original PR, and the backports to v5.2.x and to v5.0.x: https://github.com/astropy/astropy/milestone/108?closed=1).

    So in terms of CI jobs:

    • by default a PR should be milestoned to the current major/minor version, this could be done automatically.
    • if a backport label is set, meeseeks will backport it and it would be nice if a CI job could update the milestone.
    • also would be nice to have a scheduled job checking that PRs labelled as backport have actually been backported. No need to check if those are merged, that's the point of using milestones.
  7. pllim commented on Jun 27, 2023

    @pllim
    Member

    @WilliamJamieson has plan to open a proof-of-concept PR implementing the ideas here, though he is waiting for a resolution on #14473 first.

  8. pllim commented on Jul 13, 2023

    @pllim
  9. pllim commented on Aug 10, 2023

    @pllim
    Member

    We enabled squash-merge in #15100 . FYI.

  10. pllim commented on Feb 14, 2024

    @pllim
    Member

    2024-02-14

  11. pllim commented on Jul 11, 2024

    @pllim
    Member

    @astrofrog and @saimn , now that we don't have LTS, what from the original ideas are still needed here? Hope you can advise. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions