Send Slack post when proposing issues (#30872)

This commit is contained in:
Felix Becker 2022-02-09 09:39:30 -08:00 committed by GitHub
parent 261515c28b
commit 927396537d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 131 deletions

View File

@ -3,7 +3,6 @@ name: Code Insights iteration stats Slack bot
on:
schedule:
# Every Friday 5pm PST (Saturday 1am UTC)
# Note: script will exit if there is no iteration ending that day (every 2 weeks, but cron doesn't support that)
- cron: 0 1 * * 6
jobs:
@ -18,12 +17,13 @@ jobs:
SLACK_WEBHOOK_URI: ${{ secrets.INSIGHTS_ITERATION_SLACKBOT_WEBHOOK_URI }}
with:
script: |
$global:InformationPreference = 'Continue'
$global:ProgressPreference = 'SilentlyContinue'
$InformationPreference = 'Continue'
$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 3.0
Install-Module PSGitHub -Force -ErrorAction Stop
Install-Module PSSlack -Force -ErrorAction Stop
Install-Module PSGitHub -Force
Install-Module PSSlack -Force
if (!$env:GITHUB_TOKEN) {
throw "No GITHUB_TOKEN env var provided"
@ -31,4 +31,4 @@ jobs:
$PSDefaultParameterValues['*GitHub*:Token'] = ConvertTo-SecureString -String $env:GITHUB_TOKEN -AsPlainText -Force
./.github/workflows/post-iteration-stats.ps1 -ProjectNodeId 'MDExOlByb2plY3ROZXh0MzI3Ng==' -SlackChannel '#code-insights-internal' -SlackWebhookUri $env:SLACK_WEBHOOK_URI
./.github/workflows/post-iteration-stats.ps1 -ProjectNodeId 'MDExOlByb2plY3ROZXh0MzI3Ng==' -SlackChannel '#code-insights-planning' -SlackWebhookUri $env:SLACK_WEBHOOK_URI

View File

@ -14,33 +14,6 @@ jobs:
# }
# }
# }' -F project=212
code-insights-board:
runs-on: ubuntu-latest
env:
PROJECT_ID: MDExOlByb2plY3ROZXh0MzI3Ng== # https://github.com/orgs/sourcegraph/projects/200
GITHUB_TOKEN: ${{ secrets.GH_PROJECTS_ACTION_TOKEN }}
steps:
- name: Get issue if relevant
if: ${{ contains(github.event.issue.labels.*.name, 'team/code-insights') }}
env:
NODE_ID: ${{ github.event.issue.node_id }}
run: echo 'NODE_ID='$NODE_ID >> $GITHUB_ENV
- name: Get pull request if relevant
if: ${{ contains(github.event.pull_request.labels.*.name, 'team/code-insights') }}
env:
NODE_ID: ${{ github.event.pull_request.node_id }}
run: echo 'NODE_ID='$NODE_ID >> $GITHUB_ENV
- name: Add to Code Insights board
if: ${{ env.NODE_ID != '' }}
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $node_id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $node_id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f node_id=$NODE_ID
code-intel-board:
runs-on: ubuntu-latest
env:

View File

@ -20,20 +20,19 @@ param(
$todayInPST = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId([DateTime]::Today, 'Pacific Standard Time').Date
$currentMilestone = Get-GitHubMilestone -Owner sourcegraph -RepositoryName sourcegraph -State open |
Where-Object { $_.Title -like 'Insights iteration*' -and $_.DueOn.Date -eq $todayInPST }
Where-Object { $_.Title -like 'Insights iteration*' -and $todayInPST -le $_.DueOn.Date -and $todayInPST -ge $_.DueOn.Date.AddDays(-11) }
if (!$currentMilestone) {
Write-Warning "No milestone found that ends today ($($todayInPST.ToLongDateString()))"
Write-Warning "No current milestone found for today ($($todayInPST.ToLongDateString()))"
return
}
$items = Get-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId | Where-Object { $_.Content -and $_.Content.Milestone }
Write-Information "Current milestone for today: $($currentMilestone.Title)"
Write-Information "$($items.Count) items in project"
$currentIterationItems = Find-GitHubIssue "org:sourcegraph is:issue milestone:`"$($currentMilestone.Title)`"" |
Get-GitHubBetaProjectItem |
Where-Object { $_.project.id -eq $ProjectNodeId }
$byIteration = $items | Group-Object -Property { $_.Content.Milestone.Title } -AsHashTable
$currentIterationItems = $byIteration[$currentMilestone.Title]
$finishedItems = $currentIterationItems | Where-Object { $_.Fields['Status'] -eq 'Done' }
$notSized = $currentIterationItems | Where-Object { !$_.Fields['Size 🔵'] }
@ -61,7 +60,7 @@ $notFinished = $currentIterationItems | Where-Object { $_.Fields['Status'] -ne '
$message = "
Beep bop, this is your friendly iteration bot, with some fresh stats to help with our next iteration planning! :spiral_calendar_pad:
*$($currentMilestone.Title) (ending today)*
*$($currentMilestone.Title) (current)*
Sum of finished issues: :large_blue_circle: *$($stats.Sum)* | :desktop_computer: Frontend: $($frontendStats.Sum) | :database: Backend: $($backendStats.Sum)
_$($stats.Count) issues, average size $($stats.Average.ToString('#.##')), smallest $($stats.Minimum), largest $($stats.Maximum)_

View File

@ -1,27 +1,31 @@
name: Code Insights GitHub project automation
name: "[OPTIONAL/DOESN'T BLOCK MERGING] Code Insights GitHub project automation"
on:
issues:
types: [closed, reopened]
types: [opened, closed, reopened, milestoned, labeled]
pull_request:
types: [opened, edited, synchronize, ready_for_review, converted_to_draft]
jobs:
update-status:
update-project-items:
name: Update project items
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Update status
- name: Update project items
uses: Amadevus/pwsh-script@v2
env:
GITHUB_TOKEN: ${{ secrets.GH_PROJECTS_ACTION_TOKEN }}
SLACK_WEBHOOK_URI: ${{ secrets.INSIGHTS_ITERATION_SLACKBOT_WEBHOOK_URI }}
with:
script: |
$global:InformationPreference = 'Continue'
$global:ProgressPreference = 'SilentlyContinue'
$InformationPreference = 'Continue'
$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 3.0
Install-Module PSGitHub -Force -ErrorAction Stop
Install-Module PSGitHub -Force
Install-Module PSSlack -Force
if (!$env:GITHUB_TOKEN) {
throw "No GITHUB_TOKEN env var provided"
@ -29,4 +33,4 @@ jobs:
$PSDefaultParameterValues['*GitHub*:Token'] = ConvertTo-SecureString -String $env:GITHUB_TOKEN -AsPlainText -Force
./.github/workflows/update-project-item-statuses.ps1 -ProjectNodeId 'MDExOlByb2plY3ROZXh0MzI3Ng==' -TeamLabel 'team/code-insights'
./.github/workflows/update-project-items.ps1 -ProjectNodeId 'MDExOlByb2plY3ROZXh0MzI3Ng==' -TeamLabel 'team/code-insights' -SlackChannel '#code-insights-planning' -SlackWebhookUri $env:SLACK_WEBHOOK_URI

View File

@ -1,82 +0,0 @@
# Script to run as a GitHub action on issue and PR updates that will update the associated GitHub Beta project items.
[CmdletBinding()]
param(
# GitHub GraphQL Node ID of the GitHub Beta project
[Parameter(Mandatory)]
[string] $ProjectNodeId,
# The team/* label to filter issues/PRs by. All issues/PRs that don't have this label will be ignored.
[Parameter(Mandatory)]
[string] $TeamLabel
)
# Regex for extracting the "Closes #1234" pattern in GitHub PR descriptions
$fixIssuePattern = "(?:close|fixe?|resolve)(?:[sd])? (?:#|(?<owner>[\w_-]+)/(?<repo>[\w_-]+)#|https://github\.com/(?<owner>[\w_-]+)/(?<repo>[\w_-]+)/issues/)(?<number>\d+)"
switch ($github.event_name) {
'issues' {
# Find project item for the issue
# THIS DOES NOT SCALE AS THE PROJECT GETS LARGE, but it's the only way possible afaict.
# One way this is mitigated is that this request is streamed/paginated in order of most-recent-first,
# which means we can hope the issue is usually found in the first page(s).
if (-not ($github.event.issue.labels | Where-Object { $_.name -eq $TeamLabel })) {
Write-Information "Issue does not have $TeamLabel label, exiting."
return
}
$status = if ($github.event.action -eq 'closed') { 'Done' } else { 'In Progress' }
Get-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId |
Where-Object { $_.content -and $_.content.number -eq $github.event.issue.number } |
Select-Object -First 1 |
Set-GitHubBetaProjectItemField -FieldName 'Status' -Value $status |
ForEach-Object { Write-Information "Updated `"Status`" field of project item for $($_.content.url) to `"$status`"" }
}
'pull_request' {
$pr = $github.event.pull_request
# Ignore merged and closed PRs
if ($pr.state -ne 'open') {
return
}
$status = if ($pr.draft) { 'In Progress' } else { 'In Review' }
# Get fixed issues from the PR description
$fixedIssues = [regex]::Matches($pr.body, $fixIssuePattern, [Text.RegularExpressions.RegexOptions]::IgnoreCase) |
ForEach-Object {
$owner = if ($_.Groups['owner'].Success) { $_.Groups['owner'].Value } else { $github.event.repository.owner.login }
$repo = if ($_.Groups['repo'].Success) { $_.Groups['repo'].Value } else { $github.event.repository.name }
$number = $_.Groups['number'].Value
Get-GitHubIssue -Owner $owner -Repository $repo -Number $number
} |
Where-Object { $_.labels | Where-Object { $_.name -eq $TeamLabel } }
if (!$fixedIssues) {
Write-Information "No fixed issues with $TeamLabel label referenced from PR description, exiting."
return
}
Write-Information "Fixed issues:"
$fixedIssues | ForEach-Object HtmlUrl | Write-Information
# Find project items for the issues the PR references
Get-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId |
Where-Object {
$item = $_
$fixedIssues | Where-Object {
$item.content -and
$_.Number -eq $item.content.number -and
$_.Owner -eq $item.content.repository.owner.login -and
$_.RepositoryName -eq $item.content.repository.name
}
} |
Select-Object -First $fixedIssues.Count |
Set-GitHubBetaProjectItemField -FieldName 'Status' -Value $status |
ForEach-Object { Write-Information "Updated `"Status`" field of project item for $($_.content.url) to `"$status`"" }
}
}

View File

@ -0,0 +1,108 @@
# Script to run as a GitHub action on issue and PR updates that will update the associated GitHub Beta project items.
[CmdletBinding()]
param(
# GitHub GraphQL Node ID of the GitHub Beta project
[Parameter(Mandatory)]
[string] $ProjectNodeId,
# The team/* label to filter issues/PRs by. All issues/PRs that don't have this label will be ignored.
[Parameter(Mandatory)]
[string] $TeamLabel,
# Previously set up webhook URI from https://sourcegraph.slack.com/apps/A0F7XDUAZ
[Parameter(Mandatory)]
[string] $SlackWebhookUri,
# Slack channel to post to
[Parameter(Mandatory)]
[string] $SlackChannel
)
# Regex for extracting the "Closes #1234" pattern in GitHub PR descriptions
$fixIssuePattern = "(?:close|fixe?|resolve)(?:[sd])? (?:#|(?<owner>[\w_-]+)/(?<repo>[\w_-]+)#|https://github\.com/(?<owner>[\w_-]+)/(?<repo>[\w_-]+)/issues/)(?<number>\d+)"
switch ($github.event_name) {
'issues' {
if (-not ($github.event.issue.labels | Where-Object { $_.name -eq $TeamLabel })) {
Write-Information "Issue does not have $TeamLabel label, exiting."
return
}
Write-Information "Issue was $($github.event.action)"
if ($github.event.action -in 'opened', 'labeled', 'milestoned') {
# If team label was added or issue was just opened, add to project board
# If added to an iteration, update status and set "proposed by" to the event actor
# Idempotent, will return the item if already exists in the board (this is fine because we checked for the team label)
$item = [pscustomobject]$github.event.issue | Add-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId
if ($item.content.milestone) {
$proposer = $github.event.sender.login
Write-Information "Updating issue as 'Proposed for iteration' by @$proposer"
$item |
Set-GitHubBetaProjectItemField -Name 'Status' -Value 'Proposed for iteration' |
Set-GitHubBetaProjectItemField -Name 'Proposed by' -Value $proposer
# Post Slack message
$size = $item.Fields['Size 🔵']
$iterationTitle = $item.content.milestone.title
$issueUrl = $item.content.url
$stats = Find-GitHubIssue "org:sourcegraph is:issue milestone:`"$($item.content.milestone.title)`"" |
Get-GitHubBetaProjectItem |
Where-Object { $_.project.id -eq $ProjectNodeId -and $_.Fields['Status'] -ne 'Done' } |
ForEach-Object { $_.Fields['Size 🔵'] ?? 1 } |
Measure-Object -AllStats
$message = "*$proposer* proposed a new issue $($size ? "of *size $size*" : "without a size") for iteration *$($iterationTitle)*:`n" +
"$issueUrl`n" +
"`n" +
"There are now $($stats.Sum) points of open issues in the iteration."
Write-Information "Sending Slack message:`n$message"
Send-SlackMessage -Text $message -Username 'Iteration Bot' -IconEmoji ':robot:' -Channel $SlackChannel -Uri $SlackWebhookUri -UnfurlLinks $true
}
} else {
# If issue was closed or reopened, update Status column
$status = if ($github.event.action -eq 'closed') { 'Done' } else { 'In Progress' }
[pscustomobject]$github.event.issue |
# Idempotent, will return the item if already exists
Add-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId |
Set-GitHubBetaProjectItemField -FieldName 'Status' -Value $status |
ForEach-Object { Write-Information "Updated `"Status`" field of project item for $($_.content.url) to `"$status`"" }
}
}
'pull_request' {
$pr = $github.event.pull_request
# Ignore merged and closed PRs
if ($pr.state -ne 'open') {
return
}
$status = if ($pr.draft) { 'In Progress' } else { 'In Review' }
# Get fixed issues from the PR description
[regex]::Matches($pr.body, $fixIssuePattern, [Text.RegularExpressions.RegexOptions]::IgnoreCase) |
ForEach-Object {
$owner = if ($_.Groups['owner'].Success) { $_.Groups['owner'].Value } else { $github.event.repository.owner.login }
$repo = if ($_.Groups['repo'].Success) { $_.Groups['repo'].Value } else { $github.event.repository.name }
$number = $_.Groups['number'].Value
Write-Information "Found fixed issue $owner/$repo#$number"
Get-GitHubIssue -Owner $owner -Repository $repo -Number $number
} |
Where-Object { $_.labels | Where-Object { $_.name -eq $TeamLabel } } |
# Idempotent, will return the item if already exists
Add-GitHubBetaProjectItem -ProjectNodeId $ProjectNodeId |
Set-GitHubBetaProjectItemField -FieldName 'Status' -Value $status |
ForEach-Object { Write-Information "Updated `"Status`" field of project item for $($_.content.url) to `"$status`"" }
}
}