Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update changelog/contributors/version bump in one script #19379

Merged
merged 26 commits into from
Jul 17, 2023

Conversation

huonw
Copy link
Contributor

@huonw huonw commented Jun 26, 2023

This evolves the changelog.py script into start_release.py, which does the first 4-ish steps of the release process:

  1. Update the changelog
  2. Update CONTRIBUTORS.md
  3. Bump the VERSION, on main
  4. Commit the above and open a PR

This is currently just meant for running locally, but a possible next step would be packaging it up to run in CI: a manually triggered workflow that takes the new version number as an input and then runs .../start_release.py --new $version_input --release-manager $sender_login --publish, to open the PR as @WorkerPants.

This is a step towards #19279, and in particular, does most of "1", other than having it run in CI.

This proposes a few conventions:

  • branches from automation are scoped under automation/, e.g. these branches are automation/release/2.34.56
  • labels for automation start with automation:, e.g. these release prep PRs would be created with label automation:release-prep

Thoughts? We could retrofit these conventions onto the cherry-picker, if they seem nice.

Next steps after this might be:

  1. run this in CI
  2. finish step 3, by automating the publishing of the docs site, PEX creation and even announcements
  3. finish step 2, by having automation that detects when the release PR is merged and cherry-picks, tags, creates branches and bumps versions (etc.), as appropriate

@huonw huonw added the category:internal CI, fixes for not-yet-released features, etc. label Jun 26, 2023
src/python/pants_release/start_release_test.py Outdated Show resolved Hide resolved
title=title,
body="\n\n".join([BASE_PR_BODY, formatted.internal]),
assignee=release_manager,
labels=["automation:release-prep"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note branch name and this label name, per the discussion of conventions in the PR description.

Comment on lines +88 to +89
# infer the changes since the most recent previous release on this branch
prior_tag = git("describe", "--tags", "--abbrev=0", release_ref)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes this script to not need the --prior argument, and instead just look for the most recent tag before the release ref.

Comment on lines +59 to +60
"--log-level",
default="WARNING",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For interactive use WARNING seems fine, but for running on CI, I was planning to set --log-level=DEBUG or something, to make it easier to understand what it's doing.

src/python/pants_release/git.py Outdated Show resolved Hide resolved
@huonw huonw requested review from benjyw and thejcannon June 26, 2023 11:19
Copy link
Member

@thejcannon thejcannon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some drive by comments before I review thoroughly

src/python/pants_release/start_release.py Show resolved Hide resolved

logger = logging.getLogger(__name__)

BASE_PR_BODY = softwrap(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this instead be a comment on PR? Making it the PR body feels weird

CONTRIBUTORS.md Show resolved Hide resolved
@kaos
Copy link
Member

kaos commented Jun 26, 2023

Another drive by observation without having looked at the code.

Given the number of steps done by this script, I think I would appreciate it if I were able to specify which ones to run. Say it gets halfway through and then aborts due to some error/issue or what not. If I'm able to address that and re-run I'd like it to be idempotent (either by detection, or perhaps more likely by me asking it to proceed at a certain step or something along those lines).

As long as the actions are local only, there's always the option to revert any changes to start over, but in case the issue is to manually tweak and then continue in order to get over a hump that could prove difficult. This is of course only a nice to have, but if it's easy enough to add.. perhaps worth having in the back of your mind at least :)

Sorry for the long rambling..

@thejcannon
Copy link
Member

Piggybacking off @kaos maybe we can expose one script per step, that can each be run independently (with assumptions, of course).
And then one script-runner (maybe just a bash script?) which fires them off.

@huonw
Copy link
Contributor Author

huonw commented Jun 26, 2023

Sounds good. I personally prefer calling Python functions in Python rather than arranging python subprocesses in bash, so I'll go with @kaos's original idea of being able to specify which action as args to the script.

@thejcannon
Copy link
Member

Generally, I see exposing each script's main as main and dealer's choice on how args are passed into it.

I can speak personally that my ability to reason about code goes down as line count goes up (I get easily distracted) so fewer, smaller, files makes me 😍

@benjyw
Copy link
Contributor

benjyw commented Jun 27, 2023

I think having it be idempotent would be best, and preferable to a bunch of one-function scripts.

But note that this is really start_dev_release.py. For RCs the process is a little different - e.g., we bump the VERSION only in the release branch.

@thejcannon
Copy link
Member

I think if the cherry pick script detects a CP with the proper label, it can do the version bump for the milestone branch.

@huonw
Copy link
Contributor Author

huonw commented Jun 28, 2023

I'll switch to idempotent. 👍

I think if the cherry pick script detects a CP with the proper label, it can do the version bump for the milestone branch.

I think we'll want dedicated automation for this, since it both does than the current auto cherry picker script:

  • more: it should also tag and potentially create a branch, see "The proposal" -> "2. Tag release" in Proposal: Smoother releases: 3 parts to have mostly-automated releases #19279 for my understanding of what it could do
  • less: AIUI, the release prep is only cherry picked to the specific relevant branch, not to all more recent ones, e.g. 2.16.0 release prep goes only to 2.16.x, not 2.17.x?

Of course, this non-cherrypicker automation can and should still do the version bump, if it needs to 👍

@benjyw
Copy link
Contributor

benjyw commented Jun 29, 2023

I think we'd always want a human to create the tag? Esp. since we sign the release tags. And we need some human-triggered action to kick off a release. But scripts can then act off the tag to automate everything else.

@thejcannon
Copy link
Member

@huonw what's the state of this PR? 😄

@huonw
Copy link
Contributor Author

huonw commented Jul 12, 2023

Updates:

  • the local changes are now idempotent (except for the external state like the date and PR labels for categorisation)
  • committing and opening a PR now only happens if --publish is explicitly specified
  • --publish uses PyGithub to open the PR and add comments etc. this requires adding a new dependency (Regenerate lockfiles for 3.9.* ICs #19454 will reduce the spurious/distracting lock file changes that happen in this PR)
  • change the release procedure to not use --publish, because setting up the token is a bit fiddly; the main purpose for that is running in CI

Example: huonw#6 (particularly huonw@894071b)

@huonw huonw requested a review from thejcannon July 12, 2023 23:02
@thejcannon
Copy link
Member

Can you comment a smidge on switching from gh wrapper to github? Is it code simplicity?

From the CI perspective, both are sufficient so that's unlikely the razor.

From the local perspective, I imagine it's much more likely a user has gh authenticated, and therefore can run the command without much headache. Versus having to make and use a token (although devil's advocate is that gh has gh auth token. So maybe the compromise is this code tries to use that if no token is configured?)

Comment on lines +51 to +52
# Only used for release management
PyGithub==2.0.0rc1
Copy link
Member

@kaos kaos Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can enforce this, by adding ("[PyGithub]", "src/python/pants_release/**", "!*"), to

__dependents_rules__(
( # Only the explorer server may depend on these libraries
(
"[fastapi]",
"[starlette]",
"[strawberry-graphql]",
"[uvicorn]",
),
"src/python/pants/explorer/server/**",
"!*",
),
# Free for all on the rest
("*", "*"),
)

Something like:

__dependents_rules__(
    (  # Only the explorer server may depend on these libraries
        (
            "[fastapi]",
            "[starlette]",
            "[strawberry-graphql]",
            "[uvicorn]",
        ),
        "src/python/pants/explorer/server/**",
        "!*",
    ),

    ("[PyGithub]", "src/python/pants_release/**", "!*"),

    # Free for all on the rest
    ("*", "*"),
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a slight aside, should we swap so the core pants package is includelisted, and everything else is free game?
Because it shouldn't matter if a release needs fastapi (I mean why, but you get the point) or some non-included plugin uses PyGitHub (what if its a GitHub plugin?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've filed #19458

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a slight aside, should we swap so the core pants package is includelisted, and everything else is free game? Because it shouldn't matter if a release needs fastapi (I mean why, but you get the point) or some non-included plugin uses PyGitHub (what if its a GitHub plugin?)

That works.

@huonw
Copy link
Contributor Author

huonw commented Jul 13, 2023

Can you comment a smidge on switching from gh wrapper to github? Is it code simplicity?

It was motivated by two things:

From the local perspective, I imagine it's much more likely a user has gh authenticated, and therefore can run the command without much headache. Versus having to make and use a token (although devil's advocate is that gh has gh auth token. So maybe the compromise is this code tries to use that if no token is configured?)

Good catch! Using gh auth token seems perfect, not a devil's-advocate position. I'll switch to using that unconditionally, because it'll even handle GH_TOKEN=... env var. If someone wants to avoid needing gh installed, we can implement the feature then.

Copy link
Member

@thejcannon thejcannon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM. I love me some more automation.

src/python/pants_release/git.py Outdated Show resolved Hide resolved
src/python/pants_release/start_release.py Outdated Show resolved Hide resolved
src/python/pants_release/start_release.py Show resolved Hide resolved
src/python/pants_release/start_release.py Outdated Show resolved Hide resolved
src/python/pants_release/start_release.py Show resolved Hide resolved
src/python/pants_release/start_release.py Outdated Show resolved Hide resolved
Comment on lines 14 to 16
cur_version_sha, prev_version_sha = git(
"log", "-2", "--pretty=format:%h", "src/python/pants/VERSION"
"log", "-2", "--pretty=format:%h", str(VERSION_PATH)
).splitlines(keepends=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to extract this into a method in git.py to keep all the git in one place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For one-off/specialised calls like this, I don't have a particular point of view. For me, I'd lean away from wrapping this sort of thing up into a "find_two_most_recent_commits_changing_version" function unless there were more locations that needed it! 🤷

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair. There's always a tension between keeping everything at the same abstraction level and having a pile of hyper-specific functions. I find that naming the function by why I would use it helps me determine if it's worth wrapping. (Put another way: the view of this interface by the consumer rather than the provider.) something like get_commit_filter_for_this_release would fit more naturally in a list of steps that this function performs, like:

  1. get git commit filter for this release
  2. get and sort all contributors from that range
  3. identify new contributors
  4. ...

You're right that this would make our git.py contain a lot of one-off functions.

Copy link
Member

@thejcannon thejcannon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this has been open long enough and I trust your judgement on fixing the comments. So I'll go ahead and approve, because it's good stuff.

@huonw huonw force-pushed the feature/release-start branch from 8af8b04 to f0e56b1 Compare July 17, 2023 00:16
@huonw
Copy link
Contributor Author

huonw commented Jul 17, 2023

Example/validation of the latest state of this (f0e56b1): huonw#8

@huonw
Copy link
Contributor Author

huonw commented Jul 17, 2023

I've created the automation:release-prep label. Merging based on @thejcannon's review and @kaos's 👍, but happy to iterate post-merge if there's further feedback.

@huonw huonw merged commit 38cb6de into pantsbuild:main Jul 17, 2023
@huonw huonw deleted the feature/release-start branch July 17, 2023 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category:internal CI, fixes for not-yet-released features, etc.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants