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

Add git node staging command #875

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

ruyadorno
Copy link
Member

@ruyadorno ruyadorno commented Nov 27, 2024

Add a new git node staging command that automates cherry-picking commits into staging branches.

It works by cherry-picking all commits that have no conflicts and stopping when finding commits that have conflicts so that the releaser can either manually fix that conflict to continue or skip.

Usage:

Fetches a commit list using branch-diff and automatically cherry-picks / skips commits based on whether or not they land cleanly:

  git node staging

By default the script will add backport-request labels to any skip commit, in order to run in a "dry-run" mode, avoiding the GH cli interactions, you can use the skipGH flag, e.g:

  git node staging --skipGH

After fixing up manual conflicts using git cherry-pick --continue the releaser can resume the cherry-pick queue:

  git node staging --continue

Similarly, after manually skipping a commit using git cherry-pick --skip the releaser can resume the cherry-pick queue using:

  git node staging --skip

If you want to run the script and automatically skip any commit that is unable to land cleanly you can use the --autoSkip flag:

  git node staging --autoSkip

Sets a custom reporter at the end of the automated operation:

  git node staging --reporter=json

Limits to 10 the number of commits to be cherry-picked:

  git node staging --pagination=10

Automates the backport request message, this won't run any of the branch-diff or cherry-pick routines. Useful for when you removed a faulty commit from the branch and want to signal to PR author and collaborators that commit now needs backporting, just use its PR#:

  git node staging --backport=12345

More:

The automate cherry-pick logic also includes local persistency of the ongoing commit list, in case a fatal error happens during the command execution, it's possible to resume after cleaning up the git repo state by running git node staging again.


Report

A report is generated at the end of operations listing information on the commits that were successfully cherry picked and commits that failed to be cherry-picked due to conflicts.

Important

Below is a short example of how these reports look like. The following report was generated for an operation that was limited using --pagination=10

Cherry-pick Report

6 successfully cherry-picked commits:

4 commits that failed to cherry-pick:

If no text is provided to `cli.stopSpinner` then it should allow for
non-persistent usage of the spinner.
@ruyadorno
Copy link
Member Author

ruyadorno commented Nov 27, 2024

When working on the v22 release, I did a progressive run of the automation using the --pagination option to ensure that the tooling was working as intended, as a result I ended up with multiple reports that I'm linking below for future reference:

  1. https://gist.github.com/ruyadorno/29d880a0029c50e6642f2dd1c4d09d1b
  2. https://gist.github.com/ruyadorno/d1813b10d473f1540e008c3ad5cf8769
  3. https://gist.github.com/ruyadorno/2f7d5ecb459f50c71f2e6ed027e942a3
  4. https://gist.github.com/ruyadorno/292b6bdf531e63078b7a5ce9b1d01253

These markdown format reports are way more useful when properly rendered on the GitHub UI or something similar. Right now the command is just printing this result to stdout but as you can imagine this opens the door to having a future GitHub action that either comments or stores this report somewhere, I'm very open to ideas on how to improve that next step of the automation.

@ruyadorno ruyadorno requested a review from aduh95 November 27, 2024 17:52
lib/staging.js Outdated
Comment on lines 96 to 129
if (this.isLTS) {
excludeLabels.push('baking-for-lts');
const res = await fetch('https://nodejs.org/dist/index.json');
if (!res.ok) throw new Error('Failed to fetch', { cause: res });
const [latest] = await res.json();
// Assume Current branch matches tag with highest semver value.
const latestReleaseLine = semver.coerce(latest.version).major;
if (!validNumber(latestReleaseLine)) {
throw new Error('Could not determine latest release line');
}
comparisonBranch = `v${latestReleaseLine}.x`;
Copy link
Member

@richardlau richardlau Nov 27, 2024

Choose a reason for hiding this comment

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

The latest current may not be the best thing to compare to. For example, if you were to take the latest v23.x today, that would be v23.3.0 which was only released one week ago and presumably commits would be identified that do not meet the usual "two weeks in a current release" (depending, of course, on when the planned date for the release being prepared is).

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, we need a better way to handle that 2-weeks delay for sure! That said, for now I think it might still be usable as long as we put enough guardrails in the release docs.

btw I'm def falling for that rn with my current release but given that I postponed it to next week I don't think it's worth going back to remove all the v23.3.0 commits but it goes to say that you're definitely right that this is a concern in the current implementation.

@targos
Copy link
Member

targos commented Nov 28, 2024

I understand why you are doing it but I'm afraid of the notification spamming that this generates when there are many conflicts. It's also actually not a good idea to ask for backports on most PRs because landing backports in the wrong order increases the risk of conflicts.

@RafaelGSS
Copy link
Member

I understand why you are doing it but I'm afraid of the notification spamming that this generates when there are many conflicts. It's also actually not a good idea to ask for backports on most PRs because landing backports in the wrong order increases the risk of conflicts.

I was afraid of it too. Maybe collapse all the messages into a single issue and add the backport-requested label to each one that might reduce the spamming?

@targos
Copy link
Member

targos commented Nov 28, 2024

I really like that! It would solve many problems:

  • No more spam
  • Single place to collaborate on backports
  • Encourage doing the backports in the correct order
  • More visibility, by having an open issue instead of comments on merged PRs

@ruyadorno
Copy link
Member Author

Right, I agree that having a single place to manage all the backports has many benefits, I think a simple way to tweak the implementation is to use thegh cli to open a new issue with that markdown report in which the commits that failed to cherry-pick section is the list of commits that need backporting in their expected order. Then the releasers and any other collaborator could work on that.

That said, I still believe that automatically placing the label is a fundamental step that needs to be part of the logic here but we can remove the automatic-commenting to avoid spamming.

@ruyadorno
Copy link
Member Author

@targos to reinforce on the idea here, my hope is that this is going to be a much more sane workflow for the releasers.

As anedoctal evidence, for the current release I'm working on I signed off for the day after running the script (which spammed a bunch of comments and added all the labels) and the next day when I woke up in the morning I noticed that @aduh95 jumped in and landed a dozen of the straightforward backports. This happened without any coordination but it does reinforces my believe that if we put a little bit more structure around the process we can have a workflow that is going to be way less demanding on a single releaser.

And of course this new workflow won't prevent the releaser themselves to go through the list of backport-requested commits on their own time and land the straighforward conflict resolutions.

@targos
Copy link
Member

targos commented Nov 28, 2024

I agree with everything you said.

@aduh95
Copy link
Contributor

aduh95 commented Dec 3, 2024

FWIW I'm trying to implement some automation in aduh95/node@38125cf, but it's failing atm

@ruyadorno
Copy link
Member Author

FWIW I'm trying to implement some automation in aduh95/node@38125cf, but it's failing atm

that's awesome as the end goal is to have it running in a GitHub action!

do you believe you can tweak it easily to use git node staging instead?

@RafaelGSS
Copy link
Member

What's missing to have this PR released? Can we land it and create an action to run this once per week to a specific release line? (I suggest v23.x)

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

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

Some nitpicks

components/git/staging.js Outdated Show resolved Hide resolved
components/git/staging.js Outdated Show resolved Hide resolved

const stagingOptions = {
backport: {
describe: 'The PR ID / number to backport, skip staging commits',
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why this option is on git node staging?

Copy link
Member Author

Choose a reason for hiding this comment

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

The idea is that this is a convenience helper for when, let's say, you end up having to remove a commit from the staging branch after figuring out it was breaking CI, then as a releaser you can just run git node staging --backport=<PR_ID> after rebasing / removing the offending commits from the staging branch.

It's part of git node staging more from an implementation convenience point of view since all the internal logic is already there.

Copy link
Member Author

@ruyadorno ruyadorno Dec 8, 2024

Choose a reason for hiding this comment

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

Also, it's worth noting that git node staging --backport=<PR_ID> should send an automated comment by default in the original PR, which it's not going to happen in the regular git node staging automation.


const validNumber = (n) => !Number.isNaN(n) && n > -1 && n < Infinity;

export class Staging extends Session {
Copy link
Member

Choose a reason for hiding this comment

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

Are we using Session functions somewhere?

Copy link
Member Author

@ruyadorno ruyadorno Dec 8, 2024

Choose a reason for hiding this comment

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

We're using warnForMissing & cherryPickInProgress that I remember from the top of my head but there might be some other internal that is used, and opportunities for reusing more of it in the future.

lib/staging.js Outdated Show resolved Hide resolved
@ruyadorno
Copy link
Member Author

ruyadorno commented Dec 4, 2024

What's missing to have this PR released? Can we land it and create an action to run this once per week to a specific release line? (I suggest v23.x)

I just had a quick chat offline with @aduh95 to make sure we're not duplicating the effort here 😊 but other than that I want to implement the feedback from @targos and tweak git node staging to submit a new issue with the Markdown report instead of posting comments to every single PR that needs backporting.

My stretch goal is to add tests for everything but I'd like to make sure we're committed to using it before putting in all that extra effort 😅

Copy link

codecov bot commented Dec 8, 2024

Codecov Report

Attention: Patch coverage is 52.38095% with 10 lines in your changes missing coverage. Please review.

Project coverage is 81.23%. Comparing base (e3e19b3) to head (6b1349f).
Report is 52 commits behind head on main.

Files with missing lines Patch % Lines
lib/run.js 56.25% 7 Missing ⚠️
lib/cli.js 40.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #875      +/-   ##
==========================================
- Coverage   83.08%   81.23%   -1.86%     
==========================================
  Files          37       39       +2     
  Lines        4251     4695     +444     
==========================================
+ Hits         3532     3814     +282     
- Misses        719      881     +162     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ruyadorno ruyadorno force-pushed the add-git-node-staging-cmd branch from ac8a9b8 to b7746a6 Compare December 8, 2024 21:26
@aduh95
Copy link
Contributor

aduh95 commented Dec 12, 2024

As we discussed in the Release meeting, I think that by default, the tool should ask before taking any non-local action (add a label, add a comment), and there should be CLI flags to disable those prompts if e.g. you know you only want to add label and no comment. It should also give the opportunity for the backporter to fix the conflict.
This is not a blocking concern for landing this PR, though it would be a blocking concern to document git node staging as the de facto tool for backporting.

Added a `captureStderr` option to `lib/run.js` `runAsyncBase` method
that allows for adding stderr information to thrown errors.
@ruyadorno ruyadorno force-pushed the add-git-node-staging-cmd branch 3 times, most recently from 4ac2739 to 24e8076 Compare December 19, 2024 23:04
@targos
Copy link
Member

targos commented Dec 20, 2024

Please tell me when this is ready for a deep review.

@ruyadorno ruyadorno force-pushed the add-git-node-staging-cmd branch 2 times, most recently from b909e67 to 639d5fa Compare December 21, 2024 03:15
@ruyadorno
Copy link
Member Author

Dropping a quick status update here since I just put in some time on this again over the weekend. It now includes many major changes we discussed here such as:

  • No longer automatically comments on PRs that were unable to land cleanly.
  • No longer automatically skips commits that were unable to land cleanly, by default the tool now works in an interactive mode that exits when finding a commit that is unable to land cleanly and allows you to manually fix it. In cases the releaser is able to fix a commit, running: git cherry-pick --continue & git node staging --continue will resume the cherry-pick to staging session. When the releaser is unable to fix it manually, running: git cherry-pick --skip followed by git node staging --skip will skip that & label that PR with the backport-requested label, optionally the command git node staging --backport <PR_ID> is available to automatically send a comment to that PR, letting the author know that the manual backport is necessary. (This new behavior is inspired by the feedback from @aduh95)
  • The behavior of automatically skipping commits that were unable to land cleanly is now an opt-in setting, it can be used with: git node staging --autoSkip
  • Reports can now be posted automatically to a GitHub issue at the end, the releaser can choose different destinations such as a file or stdout but by default a prompt will ask confirmation to open an issue on GitHub.

@ruyadorno
Copy link
Member Author

ruyadorno commented Dec 21, 2024

Please tell me when this is ready for a deep review.

@targos I just used it again to help me prepare nodejs/node#56329 and the new interactive behavior also worked great. The PR itself currently still lacks tests in order to land but it should be in a good enough state for review! As in, I don't plan to change anything drastically at this point.

Add a new `git node staging` command that automates cherry-picking
commits into staging branches.

It works by cherry-picking all commits that have no conflicts and
stopping when finding commits that have conflicts so that the
releaser can either manually fix that conflict to continue or skip.

Usage:

Fetches a commit list using `branch-diff` and automatically
cherry-picks / skips commits based on whether or not they land
cleanly:

  git node staging

By default the script will add `backport-request` labels to any
skip commit, in order to run in a "dry-run" mode, avoiding the GH
cli interactions, you can use the `skipGH` flag, e.g:

  git node staging --skipGH

After fixing up manual conflicts using `git cherry-pick --continue`
the releaser can resume the cherry-pick queue:

  git node staging --continue

Similarly, after manually skipping a commit using
`git cherry-pick --skip` the releaser can resume the cherry-pick
queue using:

  git node staging --skip

If you want to run the script and automatically skip any commit
that is unable to land cleanly you can use the `--autoSkip` flag:

  git node staging --autoSkip

Sets a custom reporter at the end of the automated operation:

  git node staging --reporter=json

Limits to 10 the number of commits to be cherry-picked:

  git node staging --pagination=10

Automates the backport request message, this won't run any of the
`branch-diff` or cherry-pick routines. Useful for when you removed
a faulty commit from the branch and want to signal to PR author and
collaborators that commit now needs backporting, just use its PR#:

  git node staging --backport=12345

More:

The automate cherry-pick logic also includes local persistency of
the ongoing commit list, in case a fatal error happens during the
command execution, it's possible to resume after cleaning up the
git repo state by running `git node staging` again.
@ruyadorno ruyadorno force-pushed the add-git-node-staging-cmd branch from 639d5fa to 6b1349f Compare December 21, 2024 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants