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 create & close milestone and bind issue to milestone support (#37) #38

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/close.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Description:
# - Close a milestone by title or number.

name: Milestone Close@develop
on:
workflow_dispatch:
inputs:
milestone:
required: true
description: 'Title / Number'

# Fix GraphQL: Resource not accessible by integration (updatePullRequest)
permissions:
contents: write

jobs:
close-milestone:
runs-on: ubuntu-latest
name: Milestone Crete
steps:
- name: Close Milestone
uses: hustcer/milestone-action@develop
with:
action: close
github-token: ${{ secrets.PAT }}
milestone: ${{ github.event.inputs.milestone }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 changes: 36 additions & 0 deletions .github/workflows/create.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Description:
# - Create a milestone by title, description and due date.

name: Milestone Create@develop
on:
workflow_dispatch:
inputs:
title:
required: true
description: 'Milestone Title'
description:
required: false
description: 'Milestone Description'
due-on:
required: false
description: 'Milestone Due Date'

# Fix GraphQL: Resource not accessible by integration (updatePullRequest)
permissions:
contents: write

jobs:
create-milestone:
runs-on: ubuntu-latest
name: Milestone Crete
steps:
- name: Create Milestone
uses: hustcer/milestone-action@develop
with:
action: create
github-token: ${{ secrets.PAT }}
title: ${{ github.event.inputs.title }}
due-on: ${{ github.event.inputs.due-on }}
description: ${{ github.event.inputs.description }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 changes: 24 additions & 1 deletion action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ branding:
color: 'purple'

inputs:
action:
required: false
default: 'bind-pr'
description: 'The action to perform, should be bind-pr,bind-issue,create or close. Defaults to bind-pr.'
title:
required: false
default: '1.0.0'
description: 'The title of the milestone to create.'
description:
required: false
default: 'The first milestone.'
description: 'The description of the milestone to create.'
due-on:
required: false
default: ''
description: 'The due date of the milestone to create.'
force:
required: false
default: false
Expand All @@ -50,9 +66,16 @@ runs:
run: |
use ${{ github.action_path }}/nu/milestone.nu *
let repo = '${{ github.repository }}'
let action = '${{ inputs.action }}'
let title = '${{ inputs.title }}'
let description = '${{ inputs.description }}'
let due-on = '${{ inputs.due-on }}'
let token = '${{ inputs.github-token }}'
let issue = '${{ github.event.issue.number }}'
let pr = '${{ github.event.pull_request.number }}'
let force = '${{ inputs.force }}' | into bool
let milestone = '${{ inputs.milestone }}'
milestone-update $repo --gh-token $token --pr $pr --force=$force --milestone=$milestone
let commonArgs = [$action $repo --gh-token $token --force=$force]
let createArgs = [--title=$title --description=$description --due-on=$due-on]
milestone-action ...$commonArgs ...$createArgs --pr=$pr --issue=$issue --milestone=$milestone

79 changes: 70 additions & 9 deletions nu/milestone.nu
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
# [x] Support Windows, macOS, Linux
# [x] Should run on local machine or Github runners
# [x] Support dry run mode
# [ ] Create milestone by title, due_on, and description
# [ ] Close milestone by title or number
# [ ] Add milestone to issue that has been fixed by a PR
# [x] Create milestone by title, due_on, and description
# [x] Close milestone by title or number
# [x] Add milestone to issue that has been fixed by a PR
# Description: Scripts for Github milestone management.

use common.nu [ECODE, hr-line is-installed]
Expand All @@ -17,7 +17,8 @@ export-env {
$env.config.color_config.leading_trailing_space_bg = { attr: n }
}

export def 'milestone-update' [
# Bind milestone to a merged PR.
export def 'milestone-bind-for-pr' [
repo: string, # Github repository name
--gh-token(-t): string, # Github access token
--milestone(-m): string, # Milestone name
Expand All @@ -27,14 +28,14 @@ export def 'milestone-update' [
] {
check-gh
if ($gh_token | is-not-empty) { $env.GH_TOKEN = $gh_token }
let IGNORED_PR_STATUS = [CLOSED OPEN]
# Could be MERGED, OPEN, CLOSED.
let IGNORED_PR_STATUS = [CLOSED]
# PR state Could be MERGED, OPEN, CLOSED.
let prState = gh pr view $pr --repo $repo --json 'state' | from json | get state
if ($prState in $IGNORED_PR_STATUS) {
print $'PR (ansi p)($pr)(ansi reset) is in state (ansi p)($prState)(ansi reset), will be ignored.'
return
}
let selected = if ($milestone | is-empty) { guess-milestone $repo $pr } else { $milestone }
let selected = if ($milestone | is-empty) { guess-milestone-for-pr $repo $pr } else { $milestone }
if $force {
let prevMilestone = gh pr view $pr --repo $repo --json 'milestone' | from json | get milestone?.title? | default '-'
let shouldRemove = $prevMilestone != $selected
Expand All @@ -53,8 +54,47 @@ export def 'milestone-update' [
}
}

# Bind milestone to a completed issue.
export def 'milestone-bind-for-issue' [
repo: string, # Github repository name
--gh-token(-t): string, # Github access token
--milestone(-m): string, # Milestone name
--issue: string, # The Issue number that we want to add milestone.
--force(-f), # Force update milestone even if the milestone is already set.
--dry-run(-d), # Dry run, only print the milestone that would be set.
] {
check-gh
if ($gh_token | is-not-empty) { $env.GH_TOKEN = $gh_token }
let IGNORED_ISSUE_STATUS = [OPEN]
# Issue state Could be OPEN, CLOSED(with stateReasons: COMPLETED, NOT_PLANNED, REOPENED).
let issueState = gh issue view $issue --repo $repo --json 'state' | from json | get state
let stateReason = gh issue view $issue --repo $repo --json 'stateReason' | from json | get stateReason
let shouldIgnore = ($issueState in $IGNORED_ISSUE_STATUS) or ($stateReason == 'NOT_PLANNED')
if $shouldIgnore {
print $'Issue (ansi p)($issue)(ansi reset) is Not (ansi p)COMPLETED(ansi reset), will be ignored.'
return
}
let selected = if ($milestone | is-empty) { guess-milestone-for-issue $repo $issue } else { $milestone }
if $force {
let prevMilestone = gh issue view $issue --repo $repo --json 'milestone' | from json | get milestone?.title? | default '-'
let shouldRemove = $prevMilestone != $selected
if $dry_run and $shouldRemove {
print $'(char nl)Would remove milestone for Issue (ansi p)($issue)(ansi reset) in repository (ansi p)($repo)(ansi reset) ...'
} else if $shouldRemove {
gh issue edit $issue --repo $repo --remove-milestone
} else {
print $'(char nl)Milestone for Issue (ansi p)($issue)(ansi reset) in repo (ansi p)($repo)(ansi reset) was already set to (ansi p)($prevMilestone)(ansi reset), will be ignored.'
}
}
print $'(char nl)Setting milestone to (ansi p)($selected)(ansi reset) for Issue (ansi p)($issue)(ansi reset) in repository (ansi p)($repo)(ansi reset) ...'
# FIXME: GraphQL: Resource not accessible by integration (updatePullRequest)
if not $dry_run {
gh issue edit $issue --repo $repo --milestone $selected
}
}

# Guess milestone by the merged date of the PR and the infomation of open milestones.
def guess-milestone [repo: string, pr: string] {
def guess-milestone-for-pr [repo: string, pr: string] {
# Query github open milestone list by gh
let milestones = gh api -X GET $'/repos/($repo)/milestones' --paginate | from json
| select number title due_on created_at html_url
Expand Down Expand Up @@ -153,4 +193,25 @@ def check-gh [] {
}
}

alias main = milestone-update
# Milestone action entry point.
export def milestone-action [
action: string, # Action to perform, could be create, close, or bind-pr.
repo: string, # Github repository name
--gh-token(-t): string, # Github access token
--milestone(-m): string, # Milestone name
--title: string, # Milestone title to create or close
--due-on(-d): string, # Milestone due date, format: yyyy/mm/dd
--description(-D): string,# Milestone description
--pr: string, # The PR number/url/branch of the PR that we want to add milestone.
--force(-f), # Force update milestone even if the milestone is already set.
--dry-run(-d), # Dry run, only print the milestone that would be set.
] {
match $action {
close => { close-milestone $repo $milestone --gh-token $gh_token },
create => { create-milestone $repo $title --due-on $due_on -D $description -t $gh_token },
bind-pr => { milestone-bind-for-pr $repo -t $gh_token -m $milestone --pr $pr --force=$force --dry-run=$dry_run },
bind-issue => { milestone-bind-for-issue $repo -t $gh_token -m $milestone --issue $issue --force=$force --dry-run=$dry_run },
}
}

alias main = milestone-action
Loading