Skip to content

[BRE-1932] Refactor dotnet extensions start-release.yml #280

Open
brandonbiete wants to merge 2 commits into
mainfrom
bre-1932/migrate-dotnet-extensions-release-workflows
Open

[BRE-1932] Refactor dotnet extensions start-release.yml #280
brandonbiete wants to merge 2 commits into
mainfrom
bre-1932/migrate-dotnet-extensions-release-workflows

Conversation

@brandonbiete
Copy link
Copy Markdown

@brandonbiete brandonbiete commented May 19, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/BRE-1932

📔 Objective

This PR changes how dotnet-extensions releases work. Previously, workflows in this repo would trigger the devops repo to publish releases. Now they trigger the locked down and BRE-owned deploy repo instead.

What happens when you trigger a release via prerelease and release workflows:

  1. pack-and-release.yml (this repo) builds the package and uploads artifacts
  2. It calls trigger-actions@main (composite action) with task name and data
  3. deploy repo's trigger-actions.yml receives the deployment event
  4. deploy repo's release-dotnet-extensions.yml workflow runs, which:
    • Downloads the artifacts from step 1 using the run_id
    • Checks out this repo at the release branch
    • Creates a GitHub release on this repo with the artifacts
    • Publishes the .nupkg to NuGet via OIDC
    • Triggers a version bump on the release branch

🚨 Breaking Changes

@brandonbiete brandonbiete requested review from a team as code owners May 19, 2026 19:23
@brandonbiete brandonbiete requested a review from dereknance May 19, 2026 19:23
@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.58%. Comparing base (53ebbb0) to head (74882b0).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #280   +/-   ##
=======================================
  Coverage   68.58%   68.58%           
=======================================
  Files          51       51           
  Lines        1184     1184           
  Branches      104      104           
=======================================
  Hits          812      812           
  Misses        325      325           
  Partials       47       47           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@withinfocus withinfocus requested a review from justindbaur May 19, 2026 19:26
@withinfocus
Copy link
Copy Markdown
Contributor

@justindbaur to review -- we need to be prepared for this workflow change.

dereknance
dereknance previously approved these changes May 19, 2026
@dereknance dereknance dismissed their stale review May 19, 2026 21:54

Didn't see that Justin was asked to review until after I approved, so I'm dismissing my review so that this PR can't be merged just yet, to give him time.

Copy link
Copy Markdown
Member

@justindbaur justindbaur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow doesn't actually do a release, this just starts a code freeze which uses the BW-GHAPP to create release/* branches and make a commit to main for vNext. The release branch action will fail if they can't do it with the Bitwarden bot. If any workflow needs to be updated it is probably pack-and-release.yml. But deploys already defer to the bitwarden/devops repo and requires approval to do the deploy. Right now the approving team has to be Platform or Arch but maybe we could just change the team to BRE.

@brandonbiete
Copy link
Copy Markdown
Author

This workflow doesn't actually do a release, this just starts a code freeze which uses the BW-GHAPP to create release/* branches and make a commit to main for vNext. The release branch action will fail if they can't do it with the Bitwarden bot. If any workflow needs to be updated it is probably pack-and-release.yml. But deploys already defer to the bitwarden/devops repo and requires approval to do the deploy. Right now the approving team has to be Platform or Arch but maybe we could just change the team to BRE.

Thank you for looking into this. I may have over-complicated this migration. Let me check with the team and see if what you've outlined aligns with the new deployment standards.

@brandonbiete brandonbiete marked this pull request as draft May 20, 2026 13:57
@brandonbiete
Copy link
Copy Markdown
Author

brandonbiete commented May 20, 2026

This workflow doesn't actually do a release, this just starts a code freeze which uses the BW-GHAPP to create release/* branches and make a commit to main for vNext. The release branch action will fail if they can't do it with the Bitwarden bot. If any workflow needs to be updated it is probably pack-and-release.yml. But deploys already defer to the bitwarden/devops repo and requires approval to do the deploy. Right now the approving team has to be Platform or Arch but maybe we could just change the team to BRE.

After the start-release workflow has ran which creates a new branch and bumps the version. The wrapper workflows, pre-release and release, are then ran manually. Those leverage the pack-and-release reusable workflow which creates a release in GitHub and then like like you said, kicks off the publish-nuget workflow that exists in the devops repo. I think our concern here is with the releases to GH, that also needs to be owned by BRE.

@brandonbiete brandonbiete requested a review from justindbaur May 20, 2026 15:47
@justindbaur
Copy link
Copy Markdown
Member

@brandonbiete If the concern is the GitHub release creation then honestly we can just delete that, it was largely just done to create a nice commit diff but I can work on something to fill that gap.

- name: Create GitHub Release
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
_PACKAGE: ${{ steps.parse-package.outputs.result }}
_CURRENT_VERSION: ${{ steps.current-version.outputs.VERSION }}
_EVENT_REF: ${{ github.event.ref }}
_INPUT_PRERELEASE: ${{ inputs.prerelease }}
with:
script: |
const package = process.env._PACKAGE;
const currentVersion = process.env._CURRENT_VERSION;
const eventRef = process.env._EVENT_REF;
const preRelease = process.env._INPUT_PRERELEASE === "true";
const currentRef = process.env.GITHUB_SHA;
// Configure Git
await exec.exec(`git config user.name "github-actions"`);
await exec.exec(`git config user.email "github-actions@github.com"`);
// List existing tags so that we could use them to link to the best full changelog
// Debug purposes only right now until there is enough data for me to make this command bullet proof
await exec.exec("git fetch --tags");
await exec.exec(`git --no-pager tag --list "${package}_v*" --no-contains "${currentRef}"`, [], {
listeners: {
stdout: function stdout(data) {
console.log(`Found tags:\n${data}`);
}
},
ignoreErrorCode: true // Just for research purposes right now, it's fine if this fails
});
// Create tag
const tag = `${package}_v${currentVersion}`;
console.log(`Creating tag & release: ${tag}`);
await exec.exec(`git tag "${tag}"`);
await exec.exec(`git push origin --tags`);
// Create release
const { data } = await github.rest.repos.createRelease({
owner: "bitwarden",
repo: "dotnet-extensions",
tag_name: tag,
target_commitish: eventRef,
name: tag,
body: "",
prerelease: preRelease,
generate_release_notes: false, // This creates a link between this and the last tag but that might not be our version
});
const templateMarker = data.upload_url.indexOf("{");
let url = data.upload_url;
if (templateMarker > -1) {
url = url.substring(0, templateMarker);
}
const globber = await glob.create("**/*.nupkg");
const files = await globber.glob();
const fs = require("fs");
const path = require("path");
if (files.length === 0) {
core.setFailed("No files found, cannot create release.");
return;
}
for (const file of files) {
const endpoint = new URL(url);
endpoint.searchParams.append("name", path.basename(file));
const endpointString = endpoint.toString();
console.log(`Uploading file: ${file} to ${endpointString}`);
// do the upload
const uploadResponse = await github.request({
method: "POST",
url: endpointString,
data: fs.readFileSync(file),
});
console.log(`Upload response: ${uploadResponse.status}`);
}
- name: Upload artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: packages
path: |
**/*.nupkg
**/*.snupkg

@brandonbiete
Copy link
Copy Markdown
Author

@brandonbiete If the concern is the GitHub release creation then honestly we can just delete that, it was largely just done to create a nice commit diff but I can work on something to fill that gap.

- name: Create GitHub Release
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
_PACKAGE: ${{ steps.parse-package.outputs.result }}
_CURRENT_VERSION: ${{ steps.current-version.outputs.VERSION }}
_EVENT_REF: ${{ github.event.ref }}
_INPUT_PRERELEASE: ${{ inputs.prerelease }}
with:
script: |
const package = process.env._PACKAGE;
const currentVersion = process.env._CURRENT_VERSION;
const eventRef = process.env._EVENT_REF;
const preRelease = process.env._INPUT_PRERELEASE === "true";
const currentRef = process.env.GITHUB_SHA;
// Configure Git
await exec.exec(`git config user.name "github-actions"`);
await exec.exec(`git config user.email "github-actions@github.com"`);
// List existing tags so that we could use them to link to the best full changelog
// Debug purposes only right now until there is enough data for me to make this command bullet proof
await exec.exec("git fetch --tags");
await exec.exec(`git --no-pager tag --list "${package}_v*" --no-contains "${currentRef}"`, [], {
listeners: {
stdout: function stdout(data) {
console.log(`Found tags:\n${data}`);
}
},
ignoreErrorCode: true // Just for research purposes right now, it's fine if this fails
});
// Create tag
const tag = `${package}_v${currentVersion}`;
console.log(`Creating tag & release: ${tag}`);
await exec.exec(`git tag "${tag}"`);
await exec.exec(`git push origin --tags`);
// Create release
const { data } = await github.rest.repos.createRelease({
owner: "bitwarden",
repo: "dotnet-extensions",
tag_name: tag,
target_commitish: eventRef,
name: tag,
body: "",
prerelease: preRelease,
generate_release_notes: false, // This creates a link between this and the last tag but that might not be our version
});
const templateMarker = data.upload_url.indexOf("{");
let url = data.upload_url;
if (templateMarker > -1) {
url = url.substring(0, templateMarker);
}
const globber = await glob.create("**/*.nupkg");
const files = await globber.glob();
const fs = require("fs");
const path = require("path");
if (files.length === 0) {
core.setFailed("No files found, cannot create release.");
return;
}
for (const file of files) {
const endpoint = new URL(url);
endpoint.searchParams.append("name", path.basename(file));
const endpointString = endpoint.toString();
console.log(`Uploading file: ${file} to ${endpointString}`);
// do the upload
const uploadResponse = await github.request({
method: "POST",
url: endpointString,
data: fs.readFileSync(file),
});
console.log(`Upload response: ${uploadResponse.status}`);
}
- name: Upload artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: packages
path: |
**/*.nupkg
**/*.snupkg

Just had a thorough discussion around this with @pixman20 and here's what we plan to do. We are going to pull the logic out from the workflows that handle version bumping and GH releases from this repo to the deploy repo. And also migrate the nuget publishing workflow from the devops repo to the deploy repo. Everything from a developer's perspective should work exactly the same as far as being able to trigger this logic from the dotnet-extensions repo. Let me know if you have any questions.

@withinfocus
Copy link
Copy Markdown
Contributor

For what it's worth, we've been enjoying GitHub Environments for a while now and it helps the team deploy what they need via the approval process built in there. Will that be moving to the repo as well? Would be cool to see Environments scaled out for other releases there too.

@brandonbiete
Copy link
Copy Markdown
Author

For what it's worth, we've been enjoying GitHub Environments for a while now and it helps the team deploy what they need via the approval process built in there. Will that be moving to the repo as well? Would be cool to see Environments scaled out for other releases there too.

Because the deploy repo is locked down to only BRE we are not currently using GH environments there as an approval gate. We do however use it as part of trust publishing for certain products such as this. So for dotnext-extensions anyone will be able to fire off a release just as before and we are planning to lock down the release* branches so that only our deploy bot can write to them.

Updates start-release and pack-and-release workflows to use trigger-actions
pattern instead of performing operations directly. This centralizes release
control in the deploy repo.

- Modify start-release.yml to trigger deploy repo via trigger-actions
- Modify pack-and-release.yml to trigger deploy repo for release + publish
- Remove GitHub release creation (moved to deploy repo)
- Remove devops dispatch (replaced with deploy repo trigger)
- Remove version bump job (now handled by deploy repo)
@brandonbiete brandonbiete force-pushed the bre-1932/migrate-dotnet-extensions-release-workflows branch from 125a540 to 74882b0 Compare May 21, 2026 15:49
@sonarqubecloud
Copy link
Copy Markdown

@brandonbiete brandonbiete marked this pull request as ready for review May 21, 2026 21:03
@brandonbiete brandonbiete requested a review from pixman20 May 21, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants