WIP: Address various issues about milestones#143
WIP: Address various issues about milestones#143rimrul wants to merge 4 commits intogit-for-windows:mainfrom
Conversation
b5c2225 to
5936463
Compare
Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Matthias Aßhauer <mha1993@live.de>
8548d6e to
3201a44
Compare
This fixes git-for-windows#5 Signed-off-by: Matthias Aßhauer <mha1993@live.de>
… latest Git version This fixes git-for-windows#6 Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Matthias Aßhauer <mha1993@live.de>
This fixes git-for-windows#7 Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Matthias Aßhauer <mha1993@live.de>
3201a44 to
3e20881
Compare
|
You raise a lot of good points. I guess that my renaming of "Next release" to "v2.50.0" was premature, and I should have instead created an "After next release". In general, I am a big fan of automating everything, not only so that I cannot forget crucial steps by mistake, but also to implicitly document Git for Windows' workflow. As such, I think that we should settle on what you described:
|
dscho
left a comment
There was a problem hiding this comment.
Wow, great work!
I added a couple of suggestions, hopefully you agree with them?
| const getMilestoneByName = async (context, token, owner, repo, name) => { | ||
| const githubApiRequest = require('./github-api-request') | ||
| const milestones = await githubApiRequest(context, token, 'GET', `/repos/${owner}/${repo}/milestones?state=open`) | ||
| if (milestones.length === 2) { |
There was a problem hiding this comment.
We should probably be more lenient and test > 1 here (and then use .splice(0, milestones.length, filtered) below).
There was a problem hiding this comment.
I've meant to ask about that.
| const getToken = (() => { | ||
| let token | ||
|
|
||
| const get = async () => { | ||
| const getInstallationIdForRepo = require('./get-installation-id-for-repo') | ||
| const installationId = await getInstallationIdForRepo(context, owner, repo) | ||
| const getInstallationAccessToken = require('./get-installation-access-token') | ||
| return await getInstallationAccessToken(context, installationId) | ||
| } | ||
|
|
||
| return async () => token || (token = await get()) | ||
| })() | ||
|
|
||
| const isAllowed = async (login) => { | ||
| if (login === 'gitforwindowshelper[bot]') return true | ||
| const getCollaboratorPermissions = require('./get-collaborator-permissions') | ||
| const token = await getToken() | ||
| const permission = await getCollaboratorPermissions(context, token, owner, repo, login) | ||
| return ['ADMIN', 'MAINTAIN', 'WRITE'].includes(permission.toString()) | ||
| } | ||
|
|
||
| if (!await isAllowed(sender)) throw new Error(`${sender} is not allowed to do that`) |
There was a problem hiding this comment.
I guess it is about high time to move this (duplicated) logic into a central place instead, and maybe now would be as good a time as any to do that?
There was a problem hiding this comment.
That thought has crossed my mind as well.
| const candidates = req.body.pull_request.body.match(/(?:[Cc]loses|[Ff]ixes) (?:https:\/\/github\.com\/git-for-windows\/git\/issues\/|#)(\d+)/) | ||
|
|
||
| if (candidates.length !== 1) throw new Error(`Expected 1 candidate issue, got ${candidates.length}`) |
There was a problem hiding this comment.
I was looking for something more robust, and while there does not seem anything useful in GitHub's REST API, there is something in the GraphQL API. Try this, for example:
gh api graphql -f query='{
repository(owner: "git-for-windows", name: "MSYS2-packages") {
pullRequest(number: 236) {
closingIssuesReferences(first: 10) {
nodes {
number
repository {
owner {
login
}
name
}
title
url
}
}
}
}
}'
Over here, this returns this highly useful answer:
{
"data": { "repository": {
"pullRequest": {
"closingIssuesReferences": {
"nodes": [
{
"number": 5656,
"repository": {
"owner": {
"login": "git-for-windows"
},
"name": "git"
},
"title": "[New curl version] 8.14.1",
"url": "https://github.com/git-for-windows/git/issues/5656" }
]
}
}
}
}
}
We already have a precedent of a GraphQL call when looking for the "collaborator permission", so we could something similar here.
There was a problem hiding this comment.
That does look immensely more helpful than the REST API
| try { | ||
| const {renameCurrentAndCreateNextMilestone} = require('./update-milestones') | ||
| if (req.headers['x-github-event'] === 'pull_request' | ||
| && req.body.repository.full_name === 'git-for-windows/git' | ||
| && req.body.action === 'opened' | ||
| && req.body.pull_request.merged === 'true') return ok(await renameCurrentAndCreateNextMilestone(context, req)) | ||
| } catch (e) { | ||
| context.log(e) | ||
| return withStatus(500, undefined, e.message || JSON.stringify(e, null, 2)) | ||
| } | ||
|
|
There was a problem hiding this comment.
I'd rather do that when publishing the final release, i.e. at the same time as the current milestone is closed.
There was a problem hiding this comment.
That would prevent issues with late component updates.
There was a problem hiding this comment.
Isn't it the other way round? When a final rebase PR is opened, and /git-artifacts produces an installer that has issues that require a component-update ticket to be addressed, we'd still want that in the same milestone, right?
| if (req.headers['x-github-event'] === 'pull_request' | ||
| && req.body.repository.full_name === 'git-for-windows/git' | ||
| && req.body.action === 'closed' | ||
| && req.body.pull_request.merged === 'true') return ok(await closeReleaseMilestone(context, req)) |
There was a problem hiding this comment.
Alternatively, we could piggy-back onto the code that "pushes" the PR branch to main. That would cut out one extra round trip between GitHub and the GitForWindowsHelper, and simplify the mental model of the process.
There was a problem hiding this comment.
It does cut out a roundtrip, but it does require duplication of the "is this a pre-release" logic from https://github.com/git-for-windows/git-for-windows-automation/blob/main/.github/actions/github-release/action.yml and maybe some special handling of out of band releases, whereas the release.released approach would get that for free.
There was a problem hiding this comment.
Ah, I missed that. But wouldn't we want much more narrow conditions to be met before calling closeReleaseMilestone()?
I've just had the thought that we could always have an "After next release" milestone and have that automatically rotated into becoming the new "Next release" milestone and a new "After next release" created. We don't ususally need a milestone for the broad concept of "at some point in the future", but "the release after the next" is occasionally useful. |
I like it! |
I still need to add some tests for this.
This was originally supposed to be just a PR to address #5, but I've had a few realizations while working on this:
releasedaction of thereleasewebhookThe workflow that #5, #6 and #7 outline is as follows:
component-updateissues get added to the currentNext releasemilestone when the corresponding PR gets merged.Next releasemilestone gets renamed when a new Git version PR is created. A NewNext releasemilestone is created#67 outlines a different order of events
Next releasemilestone is closed and an newNext releasemilestone is created (at some point)What we currently have is also different.
Next releasemilestone has been renamed and a newNext releasemilestone has been created before the PR has been created.None of this is gonna be an issue, but the timing deviation in the current rename and recreate raises the question why we rename and recreate. And the answer is that we're sometimes close to a current release and already want to plan something (in this case git-for-windows/git#5671) for after this release.
But we also have reasons to wait with the name and recreate action until shortly before a release. One is that out-of-band releases also usually get their own milestone, but we don't usually know early on that a
Next releasemilestone will be for an out-of-band-release. Having a fixed name for the current milestone also makes automation (#5) easier.This leads to the discussion how we want to handle these edge cases in the future. Do we want to wait for the automation to rename and recreate in cases like git-for-windows/git#5671 or does the automation need to be aware that we might have manually renamed? And do we care about Situations like git-for-windows/git#5411 (comment) where a late component update would already be assigned to the new milestone?
How should the automation decide when it's time to close the milestone? I think the
releasedaction of thereleasewebhook fits our needs pretty exactly.When should the automation do the renaming and recreating for an out-of-band release? Do we just manually do it in that case? Or should the closing step detect that it hasn't happened yet and do it then?