mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:51:43 +00:00
Send Slack post when proposing issues (#30872)
This commit is contained in:
parent
261515c28b
commit
927396537d
12
.github/workflows/iteration-stats-slackbot.yml
vendored
12
.github/workflows/iteration-stats-slackbot.yml
vendored
@ -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
|
||||
|
||||
27
.github/workflows/label-move.yml
vendored
27
.github/workflows/label-move.yml
vendored
@ -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:
|
||||
|
||||
15
.github/workflows/post-iteration-stats.ps1
vendored
15
.github/workflows/post-iteration-stats.ps1
vendored
@ -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)_
|
||||
|
||||
|
||||
20
.github/workflows/project-automation.yml
vendored
20
.github/workflows/project-automation.yml
vendored
@ -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
|
||||
|
||||
@ -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`"" }
|
||||
}
|
||||
}
|
||||
108
.github/workflows/update-project-items.ps1
vendored
Normal file
108
.github/workflows/update-project-items.ps1
vendored
Normal 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`"" }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user