-
Notifications
You must be signed in to change notification settings - Fork 297
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
[repo] Automate release process #1841
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
name: Prepare for a release | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
component: | ||
type: choice | ||
options: | ||
- OpenTelemetry.Exporter.Geneva | ||
- OpenTelemetry.Exporter.InfluxDB | ||
- OpenTelemetry.Exporter.Instana | ||
- OpenTelemetry.Exporter.OneCollector | ||
- OpenTelemetry.Exporter.Stackdriver | ||
- OpenTelemetry.Extensions | ||
- OpenTelemetry.Extensions.AWS | ||
- OpenTelemetry.Extensions.Enrichment | ||
- OpenTelemetry.Instrumentation.AspNet | ||
- OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule | ||
- OpenTelemetry.Instrumentation.AspNetCore | ||
- OpenTelemetry.Instrumentation.AWS | ||
- OpenTelemetry.Instrumentation.AWSLambda | ||
- OpenTelemetry.Instrumentation.Cassandra | ||
- OpenTelemetry.Instrumentation.ElasticsearchClient | ||
- OpenTelemetry.Instrumentation.EntityFrameworkCore | ||
- OpenTelemetry.Instrumentation.EventCounters | ||
- OpenTelemetry.Instrumentation.GrpcCore | ||
- OpenTelemetry.Instrumentation.GrpcNetClient | ||
- OpenTelemetry.Instrumentation.Hangfire | ||
- OpenTelemetry.Instrumentation.Http | ||
- OpenTelemetry.Instrumentation.MassTransit | ||
- OpenTelemetry.Instrumentation.MySqlData | ||
- OpenTelemetry.Instrumentation.Owin | ||
- OpenTelemetry.Instrumentation.Process | ||
- OpenTelemetry.Instrumentation.Quartz | ||
- OpenTelemetry.Instrumentation.Runtime | ||
- OpenTelemetry.Instrumentation.SqlClient | ||
- OpenTelemetry.Instrumentation.StackExchangeRedis | ||
- OpenTelemetry.Instrumentation.Wcf | ||
- OpenTelemetry.PersistentStorage.Abstractions | ||
- OpenTelemetry.PersistentStorage.FileSystem | ||
- OpenTelemetry.Resources.AWS | ||
- OpenTelemetry.Resources.Azure | ||
- OpenTelemetry.Resources.Container | ||
- OpenTelemetry.Resources.Gcp | ||
- OpenTelemetry.Resources.Host | ||
- OpenTelemetry.Resources.Process | ||
- OpenTelemetry.Resources.ProcessRuntime | ||
Comment on lines
+41
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just FYI I went with |
||
- OpenTelemetry.Sampler.AWS | ||
- OpenTelemetry.SemanticConventions | ||
description: 'Release component' | ||
required: true | ||
version: | ||
type: string | ||
description: 'Release version' | ||
required: true | ||
|
||
pull_request: | ||
types: | ||
- closed | ||
|
||
issue_comment: | ||
types: | ||
- created | ||
|
||
permissions: | ||
contents: write | ||
pull-requests: write | ||
|
||
jobs: | ||
prepare-release-pr: | ||
if: github.event_name == 'workflow_dispatch' | ||
|
||
runs-on: windows-latest | ||
|
||
steps: | ||
- name: check out code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Create GitHub Pull Request to prepare release | ||
shell: pwsh | ||
run: | | ||
Import-Module .\build\scripts\prepare-release.psm1 | ||
|
||
CreatePullRequestToUpdateChangelogsAndPublicApis ` | ||
-component '${{ inputs.component }}' ` | ||
-version '${{ inputs.version }}' ` | ||
-targetBranch '${{ github.ref_name }}' | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
|
||
lock-pr-and-post-notice-to-create-release-tag: | ||
if: | | ||
github.event_name == 'pull_request' | ||
&& github.event.action == 'closed' | ||
&& github.event.pull_request.user.login == 'github-actions[bot]' | ||
&& github.event.pull_request.merged == true | ||
&& startsWith(github.event.pull_request.title, '[repo] Prepare release ') | ||
|
||
runs-on: windows-latest | ||
|
||
steps: | ||
- name: check out code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Lock GitHub Pull Request to prepare release | ||
shell: pwsh | ||
run: | | ||
Import-Module .\build\scripts\prepare-release.psm1 | ||
|
||
LockPullRequestAndPostNoticeToCreateReleaseTag ` | ||
-pullRequestNumber '${{ github.event.pull_request.number }}' | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
|
||
create-release-tag-unlock-pr-post-notice: | ||
if: | | ||
github.event_name == 'issue_comment' | ||
&& github.event.issue.pull_request | ||
&& github.event.issue.locked == true | ||
&& contains(github.event.comment.body, '/CreateReleaseTag') | ||
&& startsWith(github.event.issue.title, '[repo] Prepare release ') | ||
&& github.event.issue.pull_request.merged_at | ||
|
||
runs-on: windows-latest | ||
|
||
outputs: | ||
tag: ${{ steps.create-tag.outputs.tag }} | ||
|
||
steps: | ||
- name: check out code | ||
uses: actions/checkout@v4 | ||
with: | ||
# Note: By default GitHub only fetches 1 commit which fails the git tag operation below | ||
fetch-depth: 0 | ||
|
||
- name: Create release tag | ||
id: create-tag | ||
shell: pwsh | ||
run: | | ||
Import-Module .\build\scripts\prepare-release.psm1 | ||
|
||
$tag = '' | ||
|
||
CreateReleaseTag ` | ||
-pullRequestNumber '${{ github.event.issue.number }}' ` | ||
-actionRunId '${{ github.run_id }}' ` | ||
-tag ([ref]$tag) | ||
|
||
echo "tag=$tag" >> $env:GITHUB_OUTPUT | ||
env: | ||
GH_TOKEN: ${{ github.token }} | ||
|
||
invoke-package-workflow: | ||
needs: create-release-tag-unlock-pr-post-notice | ||
uses: ./.github/workflows/publish-packages.yml | ||
with: | ||
tag: ${{ needs.create-release-tag-unlock-pr-post-notice.outputs.tag }} | ||
secrets: inherit | ||
|
||
post-packages-ready-notice: | ||
needs: | ||
- create-release-tag-unlock-pr-post-notice | ||
- invoke-package-workflow | ||
runs-on: windows-latest | ||
steps: | ||
- name: check out code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Post notice when packages are ready | ||
shell: pwsh | ||
run: | | ||
Import-Module .\build\scripts\prepare-release.psm1 | ||
|
||
PostPackagesReadyNotice ` | ||
-pullRequestNumber '${{ github.event.issue.number }}' ` | ||
-tag '${{ needs.create-release-tag-unlock-pr-post-notice.outputs.tag }}' ` | ||
-packagesUrl '${{ needs.invoke-package-workflow.outputs.artifact-url }}' | ||
env: | ||
GH_TOKEN: ${{ github.token }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
$gitHubBotUserName="github-actions[bot]" | ||
$gitHubBotEmail="41898282+github-actions[bot]@users.noreply.github.com" | ||
|
||
$repoViewResponse = gh repo view --json nameWithOwner | ConvertFrom-Json | ||
|
||
$gitRepository = $repoViewResponse.nameWithOwner | ||
|
||
function CreatePullRequestToUpdateChangelogsAndPublicApis { | ||
param( | ||
[Parameter(Mandatory=$true)][string]$component, | ||
[Parameter(Mandatory=$true)][string]$version, | ||
[Parameter()][string]$gitUserName=$gitHubBotUserName, | ||
[Parameter()][string]$gitUserEmail=$gitHubBotEmail, | ||
[Parameter()][string]$targetBranch="main" | ||
) | ||
|
||
$projectContent = Get-Content -Path src/$component/$component.csproj | ||
|
||
$match = [regex]::Match($projectContent, '<MinVerTagPrefix>(.*)<\/MinVerTagPrefix>') | ||
if ($match.Success -eq $false) | ||
{ | ||
throw 'Could not parse MinVerTagPrefix from project file' | ||
} | ||
|
||
$minVerTagPrefix = $match.Groups[1].Value | ||
$tag="${minVerTagPrefix}${version}" | ||
$branch="release/prepare-${tag}-release" | ||
|
||
git config user.name $gitUserName | ||
git config user.email $gitUserEmail | ||
|
||
git switch --create $branch 2>&1 | % ToString | ||
if ($LASTEXITCODE -gt 0) | ||
{ | ||
throw 'git switch failure' | ||
} | ||
|
||
$body = | ||
@" | ||
Note: This PR was opened automatically by the [prepare release workflow](https://github.com/$gitRepository/actions/workflows/prepare-release.yml). | ||
|
||
## Changes | ||
|
||
* CHANGELOG files updated for projects being released. | ||
"@ | ||
|
||
# Update CHANGELOGs | ||
& ./build/scripts/update-changelogs.ps1 -minVerTagPrefix $minVerTagPrefix -version $version | ||
|
||
# Update publicApi files for stable releases | ||
if ($version -notlike "*-alpha*" -and $version -notlike "*-beta*" -and $version -notlike "*-rc*") | ||
{ | ||
& ./build/scripts/finalize-publicapi.ps1 -minVerTagPrefix $minVerTagPrefix | ||
|
||
$body += "`r`n* Public API files updated for projects being released (only performed for stable releases)." | ||
} | ||
|
||
git commit -a -m "Prepare repo to release $tag." 2>&1 | % ToString | ||
if ($LASTEXITCODE -gt 0) | ||
{ | ||
throw 'git commit failure' | ||
} | ||
|
||
git push -u origin $branch 2>&1 | % ToString | ||
if ($LASTEXITCODE -gt 0) | ||
{ | ||
throw 'git push failure' | ||
} | ||
|
||
gh pr create ` | ||
--title "[repo] Prepare release $tag" ` | ||
--body $body ` | ||
--base $targetBranch ` | ||
--head $branch ` | ||
--label infra | ||
} | ||
|
||
Export-ModuleMember -Function CreatePullRequestToUpdateChangelogsAndPublicApis | ||
|
||
function LockPullRequestAndPostNoticeToCreateReleaseTag { | ||
param( | ||
[Parameter(Mandatory=$true)][string]$pullRequestNumber, | ||
[Parameter()][string]$gitUserName=$gitHubBotUserName, | ||
[Parameter()][string]$gitUserEmail=$gitHubBotEmail | ||
) | ||
|
||
git config user.name $gitUserName | ||
git config user.email $gitUserEmail | ||
|
||
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json | ||
|
||
if ($prViewResponse.author.is_bot -eq $false -or $prViewResponse.author.login -ne 'app/github-actions') | ||
{ | ||
throw 'PR author was unexpected' | ||
} | ||
|
||
$match = [regex]::Match($prViewResponse.title, '^\[repo\] Prepare release (.*)$') | ||
if ($match.Success -eq $false) | ||
{ | ||
throw 'Could not parse tag from PR title' | ||
} | ||
|
||
$tag = $match.Groups[1].Value | ||
|
||
$commit = $prViewResponse.mergeCommit.oid | ||
if ([string]::IsNullOrEmpty($commit) -eq $true) | ||
{ | ||
throw 'Could not find merge commit' | ||
} | ||
|
||
$body = | ||
@" | ||
I noticed this PR was merged. | ||
|
||
Post a comment with "/CreateReleaseTag" in the body if you would like me to create the release tag ``$tag`` for [the merge commit](https://github.com/$gitRepository/commit/$commit) and then trigger the package workflow. | ||
"@ | ||
|
||
gh pr comment $pullRequestNumber --body $body | ||
|
||
gh pr lock $pullRequestNumber | ||
} | ||
|
||
Export-ModuleMember -Function LockPullRequestAndPostNoticeToCreateReleaseTag | ||
|
||
function CreateReleaseTag { | ||
param( | ||
[Parameter(Mandatory=$true)][string]$pullRequestNumber, | ||
[Parameter(Mandatory=$true)][string]$actionRunId, | ||
[Parameter()][string]$gitUserName=$gitHubBotUserName, | ||
[Parameter()][string]$gitUserEmail=$gitHubBotEmail, | ||
[Parameter()][ref]$tag | ||
) | ||
|
||
git config user.name $gitUserName | ||
git config user.email $gitUserEmail | ||
|
||
$prViewResponse = gh pr view $pullRequestNumber --json mergeCommit,author,title | ConvertFrom-Json | ||
|
||
if ($prViewResponse.author.is_bot -eq $false -or $prViewResponse.author.login -ne 'app/github-actions') | ||
{ | ||
throw 'PR author was unexpected' | ||
} | ||
|
||
$match = [regex]::Match($prViewResponse.title, '^\[repo\] Prepare release (.*)$') | ||
if ($match.Success -eq $false) | ||
{ | ||
throw 'Could not parse tag from PR title' | ||
} | ||
|
||
$tagValue = $match.Groups[1].Value | ||
|
||
$commit = $prViewResponse.mergeCommit.oid | ||
if ([string]::IsNullOrEmpty($commit) -eq $true) | ||
{ | ||
throw 'Could not find merge commit' | ||
} | ||
|
||
git tag -a $tagValue -m "$tagValue" $commit 2>&1 | % ToString | ||
if ($LASTEXITCODE -gt 0) | ||
{ | ||
throw 'git tag failure' | ||
} | ||
|
||
git push origin $tagValue 2>&1 | % ToString | ||
if ($LASTEXITCODE -gt 0) | ||
{ | ||
throw 'git push failure' | ||
} | ||
|
||
gh pr unlock $pullRequestNumber | ||
|
||
$body = | ||
@" | ||
I just pushed the [$tagValue](https://github.com/$gitRepository/releases/tag/$tagValue) tag. | ||
|
||
The [package workflow](https://github.com/$gitRepository/actions/runs/$actionRunId) should begin momentarily. | ||
"@ | ||
|
||
gh pr comment $pullRequestNumber --body $body | ||
|
||
$tag.value = $tagValue | ||
} | ||
|
||
Export-ModuleMember -Function CreateReleaseTag | ||
|
||
function PostPackagesReadyNotice { | ||
param( | ||
[Parameter(Mandatory=$true)][string]$pullRequestNumber, | ||
[Parameter(Mandatory=$true)][string]$tag, | ||
[Parameter(Mandatory=$true)][string]$packagesUrl | ||
) | ||
|
||
$body = | ||
@" | ||
The [packages]($packagesUrl) for [$tag](https://github.com/$gitRepository/releases/tag/$tag) should be available on NuGet shortly. | ||
|
||
Have a nice day! | ||
"@ | ||
|
||
gh pr comment $pullRequestNumber --body $body | ||
} | ||
|
||
Export-ModuleMember -Function PostPackagesReadyNotice |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kid of misleading. This packages are released always together.
Similar thing for
OpenTelemetry.PersistentStorage.*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Really this list should be the tag prefixes not components. I decided to go with components though because a) in most cases that is what users will be looking for (probably?) and b) it makes it easy to keep this list in sync with the other places it is mirrored (issue templates). I was hoping there was a way in yaml to pull in a list of items from another file so we could have a single source of truth for the set of known components but it doesn't seem possible 😢
How it works is you pick a component. The workflow will look for a csproj for that component. Then it will find the
MinVerTagPrefix
for that project. The release is then performed for thatMinVerTagPrefix
. So when it comes toOpenTelemetry.Instrumentation.AspNet*
andOpenTelemetry.PersistentStorage*
you have to kick off the job for one of the components in the set (doesn't matter which) and the job will release both. It is a bit odd, but I think the benefits outweigh the quirk(s)?Let me respond to some of the other comments on here...
Not true! When you kick off the job a PR will be opened to update CHANGELOGs and public api files (for stable releases). Someone has to merge that. Then the bot will ask you if you want it to create the tag. If you choose to not have the bot create the tag, you can do everything the manual way. Probably easier to let the bot do it, but it isn't forced 😄
Agree with this. To kick off this new job you need to be a collaborator in the repo (write access). This will help maintainers but it won't be widely useful. What I am thinking is add an issue template for "Request release" end users may use to request a release be done. I'm hoping the flow will be users select a component, and then the bot can look for code owners for the selected component to approve before kicking off the job. That would give us a nice flow/mechanism. Going to look at that as a follow-up.
I think this is already covered by: https://github.com/open-telemetry/opentelemetry-dotnet-contrib/actions/workflows/core-version-update.yml
Maintainers can kick that workflow off anytime a core release happens and it will generate the PR to bump all the components. My goal is to have the main repo automatically call this but that isn't in place yet.