Skip to content

Commit c55961c

Browse files
authored
[repo] Release request issue template & automation (open-telemetry#2080)
1 parent 88de33c commit c55961c

File tree

4 files changed

+297
-1
lines changed

4 files changed

+297
-1
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Release request
2+
title: "[release request] "
3+
description: Request a release for a component
4+
labels: ["release"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Fill out this form to request a release of one of the components in this repository.
10+
11+
- type: dropdown
12+
id: component
13+
attributes:
14+
label: Component
15+
description: Which component does this release request concern?
16+
multiple: false
17+
options:
18+
- OpenTelemetry.Exporter.Geneva
19+
- OpenTelemetry.Exporter.InfluxDB
20+
- OpenTelemetry.Exporter.Instana
21+
- OpenTelemetry.Exporter.OneCollector
22+
- OpenTelemetry.Exporter.Stackdriver
23+
- OpenTelemetry.Extensions
24+
- OpenTelemetry.Extensions.AWS
25+
- OpenTelemetry.Extensions.Enrichment
26+
- OpenTelemetry.Instrumentation.AspNet
27+
- OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule
28+
- OpenTelemetry.Instrumentation.AspNetCore
29+
- OpenTelemetry.Instrumentation.AWS
30+
- OpenTelemetry.Instrumentation.AWSLambda
31+
- OpenTelemetry.Instrumentation.Cassandra
32+
- OpenTelemetry.Instrumentation.ConfluentKafka
33+
- OpenTelemetry.Instrumentation.ElasticsearchClient
34+
- OpenTelemetry.Instrumentation.EntityFrameworkCore
35+
- OpenTelemetry.Instrumentation.EventCounters
36+
- OpenTelemetry.Instrumentation.GrpcCore
37+
- OpenTelemetry.Instrumentation.GrpcNetClient
38+
- OpenTelemetry.Instrumentation.Hangfire
39+
- OpenTelemetry.Instrumentation.Http
40+
- OpenTelemetry.Instrumentation.MassTransit
41+
- OpenTelemetry.Instrumentation.MySqlData
42+
- OpenTelemetry.Instrumentation.Owin
43+
- OpenTelemetry.Instrumentation.Process
44+
- OpenTelemetry.Instrumentation.Quartz
45+
- OpenTelemetry.Instrumentation.Runtime
46+
- OpenTelemetry.Instrumentation.SqlClient
47+
- OpenTelemetry.Instrumentation.StackExchangeRedis
48+
- OpenTelemetry.Instrumentation.Wcf
49+
- OpenTelemetry.PersistentStorage.Abstractions
50+
- OpenTelemetry.PersistentStorage.FileSystem
51+
- OpenTelemetry.Resources.AWS
52+
- OpenTelemetry.Resources.Azure
53+
- OpenTelemetry.Resources.Container
54+
- OpenTelemetry.Resources.Gcp
55+
- OpenTelemetry.Resources.Host
56+
- OpenTelemetry.Resources.OperatingSystem
57+
- OpenTelemetry.Resources.Process
58+
- OpenTelemetry.Resources.ProcessRuntime
59+
- OpenTelemetry.Sampler.AWS
60+
- OpenTelemetry.SemanticConventions
61+
validations:
62+
required: true
63+
64+
- type: input
65+
attributes:
66+
label: Version
67+
description: |
68+
What is the requested version for the release?
69+
Version must specify [Major].[Minor].[Patch] and may also include prerelease information -[alpha|beta|rc].[Increment].
70+
Examples:
71+
* 1.9.0
72+
* 1.10.0-rc.1
73+
* 1.12.0-beta.2
74+
* 0.2.0-alpha.3
75+
validations:
76+
required: true
77+
78+
- type: textarea
79+
attributes:
80+
label: Additional context
81+
description: Any additional information you think may be relevant to this release request.

.github/workflows/prepare-release.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,20 @@ on:
5555
type: string
5656
description: 'Release version'
5757
required: true
58+
releaseIssue:
59+
type: string
60+
description: 'Release request issue'
61+
required: false
5862

5963
pull_request:
6064
types:
6165
- closed
6266

67+
issues:
68+
types:
69+
- opened
70+
- edited
71+
6372
issue_comment:
6473
types:
6574
- created
@@ -95,6 +104,7 @@ jobs:
95104
-component '${{ inputs.component }}' `
96105
-version '${{ inputs.version }}' `
97106
-requestedByUserName '${{ github.event.sender.login }}' `
107+
-releaseIssue '${{ inputs.releaseIssue }}' `
98108
-targetBranch '${{ github.ref_name }}' `
99109
-gitUserName '${{ needs.automation.outputs.username }}' `
100110
-gitUserEmail '${{ needs.automation.outputs.email }}'
@@ -209,3 +219,48 @@ jobs:
209219
-commentUserName '${{ github.event.comment.user.login }}' `
210220
-gitUserName '${{ needs.automation.outputs.username }}' `
211221
-gitUserEmail '${{ needs.automation.outputs.email }}'
222+
223+
process-release-request-issue:
224+
runs-on: ubuntu-latest
225+
226+
needs: automation
227+
228+
if: |
229+
startsWith(github.event.issue.title, '[release request] ')
230+
&& github.event.issue.pull_request == null
231+
&& needs.automation.outputs.enabled
232+
&& (
233+
(github.event_name == 'issues')
234+
||
235+
(github.event_name == 'issue_comment'
236+
&& github.event.issue.state == 'open'
237+
&& contains(github.event.comment.body, '/PrepareRelease')
238+
&& github.event.comment.user.login != needs.automation.outputs.username)
239+
)
240+
241+
env:
242+
GH_TOKEN: ${{ secrets[needs.automation.outputs.token-secret-name] }}
243+
244+
steps:
245+
- name: check out code
246+
uses: actions/checkout@v4
247+
with:
248+
token: ${{ secrets[needs.automation.outputs.token-secret-name] }}
249+
250+
- name: Process release request issue being opened or commented
251+
shell: pwsh
252+
run: |
253+
Import-Module .\build\scripts\prepare-release.psm1
254+
255+
TagCodeOwnersOnOrRunWorkflowForRequestReleaseIssue `
256+
-gitRepository '${{ github.repository }}' `
257+
-targetBranch '${{ github.event.repository.default_branch }}' `
258+
-triggeringEventName '${{ github.event_name }}' `
259+
-approvingGroups '@${{ github.repository_owner }}/dotnet-approvers @${{ github.repository_owner }}/dotnet-maintainers' `
260+
-requestedByUserName '${{ github.event.comment.user.login || github.event.sender.login }}' `
261+
-issueNumber '${{ github.event.issue.number }}' `
262+
-issueBody $env:ISSUE_BODY `
263+
-gitUserName '${{ needs.automation.outputs.username }}' `
264+
-gitUserEmail '${{ needs.automation.outputs.email }}'
265+
env:
266+
ISSUE_BODY: ${{ github.event.issue.body }}

build/scripts/prepare-release.psm1

Lines changed: 160 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ function CreatePullRequestToUpdateChangelogsAndPublicApis {
44
[Parameter(Mandatory=$true)][string]$component,
55
[Parameter(Mandatory=$true)][string]$version,
66
[Parameter(Mandatory=$true)][string]$requestedByUserName,
7+
[Parameter()][string]$releaseIssue,
78
[Parameter()][string]$targetBranch="main",
89
[Parameter()][string]$gitUserName,
910
[Parameter()][string]$gitUserEmail
@@ -42,10 +43,19 @@ function CreatePullRequestToUpdateChangelogsAndPublicApis {
4243
throw 'git switch failure'
4344
}
4445

46+
if ([string]::IsNullOrEmpty($releaseIssue) -eq $false)
47+
{
48+
$issueText =
49+
@"
50+
51+
Release request: #$releaseIssue
52+
"@
53+
}
54+
4555
$body =
4656
@"
4757
Note: This PR was opened automatically by the [prepare release workflow](https://github.com/$gitRepository/actions/workflows/prepare-release.yml).
48-
58+
$issueText
4959
Requested by: @$requestedByUserName
5060
5161
## Changes
@@ -304,3 +314,152 @@ Released $(Get-Date -UFormat '%Y-%b-%d')
304314
}
305315

306316
Export-ModuleMember -Function UpdateChangelogReleaseDatesAndPostNoticeOnPullRequest
317+
318+
function TagCodeOwnersOnOrRunWorkflowForRequestReleaseIssue {
319+
param(
320+
[Parameter(Mandatory=$true)][string]$gitRepository,
321+
[Parameter(Mandatory=$true)][string]$triggeringEventName,
322+
[Parameter(Mandatory=$true)][string]$approvingGroups,
323+
[Parameter(Mandatory=$true)][string]$requestedByUserName,
324+
[Parameter(Mandatory=$true)][string]$issueNumber,
325+
[Parameter(Mandatory=$true)][string]$issueBody,
326+
[Parameter()][string]$targetBranch="main",
327+
[Parameter()][string]$gitUserName,
328+
[Parameter()][string]$gitUserEmail
329+
)
330+
331+
$match = [regex]::Match($issueBody, '^[#]+ Component\s*(OpenTelemetry\.(?:.|\w+)+)$', [Text.RegularExpressions.RegexOptions]::Multiline)
332+
if ($match.Success -eq $false)
333+
{
334+
Write-Host 'Component could not be parsed from body'
335+
Return
336+
}
337+
338+
$component = $match.Groups[1].Value.Trim()
339+
340+
$match = [regex]::Match($issueBody, '^[#]+ Version\s*(.*)$', [Text.RegularExpressions.RegexOptions]::Multiline)
341+
if ($match.Success -eq $false)
342+
{
343+
Write-Host 'Version could not be parsed from body'
344+
Return
345+
}
346+
347+
$version = $match.Groups[1].Value.Trim()
348+
349+
$match = [regex]::Match($version, '^(\d+\.\d+\.\d+)(?:-((?:alpha)|(?:beta)|(?:rc))\.(\d+))?$')
350+
if ($match.Success -eq $false)
351+
{
352+
gh issue comment $issueNumber `
353+
--body "The version specified on the release request is invalid. Please create a new release request with a valid version or edit the description and set a valid version."
354+
Return
355+
}
356+
357+
$projectPath = "src/$component/$component.csproj"
358+
359+
if ((Test-Path -Path $projectPath) -eq $false)
360+
{
361+
gh issue comment $issueNumber `
362+
--body "I couldn't find the project file for the requested component. Please create a new release request and select a valid component or edit the description and set a valid component."
363+
Return
364+
}
365+
366+
$projectContent = Get-Content -Path $projectPath
367+
368+
$match = [regex]::Match($projectContent, '<MinVerTagPrefix>(.*)<\/MinVerTagPrefix>')
369+
if ($match.Success -eq $false)
370+
{
371+
gh issue comment $issueNumber `
372+
--body "I couldn't find ``MinVerTagPrefix`` in the project file for the requested component. Please create a new release request and select a valid component or edit the description and set a valid component."
373+
Return
374+
}
375+
376+
$minVerTagPrefix = $match.Groups[1].Value
377+
378+
$projectDirs = Get-ChildItem -Path src/**/*.csproj | Select-String "<MinVerTagPrefix>$minVerTagPrefix</MinVerTagPrefix>" -List | Select Path | Split-Path -Parent
379+
380+
$componentOwnersContent = Get-Content '.github/component_owners.yml' -Raw
381+
382+
$componentOwners = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
383+
384+
foreach ($projectDir in $projectDirs)
385+
{
386+
$projectName = [System.IO.Path]::GetFileName($projectDir)
387+
388+
$match = [regex]::Match($componentOwnersContent, "src\/$projectName\/:([\w\W\s]*?)src")
389+
if ($match.Success -eq $true)
390+
{
391+
$matches = [regex]::Matches($match.Groups[1].Value, "-\s*(.*)")
392+
foreach ($match in $matches)
393+
{
394+
$owner = $match.Groups[1].Value
395+
$_ = $componentOwners.Add($owner.Trim())
396+
}
397+
}
398+
}
399+
400+
$requestedByUserPermission = gh api "repos/$gitRepository/collaborators/$requestedByUserName/permission" | ConvertFrom-Json
401+
402+
$kickOffWorkflow = $false
403+
$kickOffWorkflowReason = ''
404+
405+
if ($requestedByUserPermission.permission -eq 'admin' -or $requestedByUserPermission.permission -eq 'write')
406+
{
407+
$kickOffWorkflow = $true
408+
$kickOffWorkflowReason = "@$requestedByUserName has collaborator or greater permission"
409+
}
410+
elseif ($componentOwners.Contains($requestedByUserName) -eq $true)
411+
{
412+
$kickOffWorkflow = $true
413+
$kickOffWorkflowReason = "@$requestedByUserName is a component owner"
414+
}
415+
416+
if ($kickOffWorkflow -eq $true)
417+
{
418+
CreatePullRequestToUpdateChangelogsAndPublicApis `
419+
-gitRepository $gitRepository `
420+
-component $component `
421+
-version $version `
422+
-requestedByUserName $requestedByUserName `
423+
-releaseIssue $issueNumber `
424+
-targetBranch $targetBranch `
425+
-gitUserName $gitUserName `
426+
-gitUserEmail $gitUserEmail
427+
428+
gh issue close $issueNumber `
429+
--comment "I executed the prepare release script for ``$component`` version ``$version``` because $kickOffWorkflowReason."
430+
431+
return
432+
}
433+
434+
if ($triggeringEventName -eq 'issues')
435+
{
436+
# Executed when issues are created or edited
437+
$componentOwnerApprovers = ''
438+
if ($componentOwners.Count -gt 0)
439+
{
440+
foreach ($componentOwner in $componentOwners)
441+
{
442+
$componentOwnerApprovers += "@$componentOwner "
443+
}
444+
}
445+
446+
$body =
447+
@"
448+
$componentOwnerApprovers$approvingGroups
449+
450+
Post a comment with "/PrepareRelease" in the body if you would like me to execute the prepare release script for the component and version listed in the description.
451+
"@
452+
453+
gh issue comment $issueNumber --body $body
454+
}
455+
else {
456+
# Executed when issues are commented with the /PrepareRelease command
457+
if ($kickOffWorkflow -eq $false)
458+
{
459+
gh issue comment $issueNumber `
460+
--body "I'm sorry @$requestedByUserName but you don't have permission to execute the prepare release script. Only maintainers, approvers, and/or owners of the component may use the `"/PrepareRelease`" command."
461+
}
462+
}
463+
}
464+
465+
Export-ModuleMember -Function TagCodeOwnersOnOrRunWorkflowForRequestReleaseIssue

opentelemetry-dotnet-contrib.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
382382
ProjectSection(SolutionItems) = preProject
383383
.github\ISSUE_TEMPLATE\bug_report.yml = .github\ISSUE_TEMPLATE\bug_report.yml
384384
.github\ISSUE_TEMPLATE\feature_request.yml = .github\ISSUE_TEMPLATE\feature_request.yml
385+
.github\ISSUE_TEMPLATE\release_request.yml = .github\ISSUE_TEMPLATE\release_request.yml
385386
EndProjectSection
386387
EndProject
387388
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.ConfluentKafka", "src\OpenTelemetry.Instrumentation.ConfluentKafka\OpenTelemetry.Instrumentation.ConfluentKafka.csproj", "{96341E23-990E-4144-A7E3-9EF0DAFF3232}"

0 commit comments

Comments
 (0)