Skip to content

ci: move to changesets for releases#4003

Open
Saadnajmi wants to merge 19 commits intomicrosoft:mainfrom
Saadnajmi:changesets-hybrid-mirrornx-kit
Open

ci: move to changesets for releases#4003
Saadnajmi wants to merge 19 commits intomicrosoft:mainfrom
Saadnajmi:changesets-hybrid-mirrornx-kit

Conversation

@Saadnajmi
Copy link
Collaborator

@Saadnajmi Saadnajmi commented Feb 10, 2026

The current release uses beachball, which requires a CI workflow (in Azure Pipelines) that on every commit to main:

  • Deletes change files and bumps versions in the repo
  • Publish to NPM
  • Push the version bump back to Github.

This workflow has two main issues:

  • Azure Pipelines requires a long lived Github token with write permission to main. This is especially bad as long lived tokens are getting phased out with no auto-rotate tool.
  • If the NPM publish succeeds but not the push back to Github (or vice versa), then the repo is left in a bad state and subsequent publishes fail

The fix is to use the Changesets flow, as used by rnx-kit.

The new workflow is as follows:

  • Introduce a new Github Action that mirrors the changeset action: It creates a PR to commit the version bump to git, rather than writing to main
  • After the version bump merges, a separate Azure Pipelines workflow (for compliance) still does the NPM publish on every commit, with no changes to the repo.

Developers in FURN still use the familiar change files, but now:

  • We no longer need a Github Token as Github Actions can generate one that lives only as long as the workflow run
  • NPM publish (the hard, irreversible thing) runs after the git bump (the easy to revert thing). Therefore, if we end up in a bad state, it's much easier to revert a commit and recover. Consequently, NPM will just mirror whatever state the Github repo is in.

Note:

I tried replicating this flow in beachball to keep our existing tool, buuuut that was a lot of AI generated code to copy something that already works and is battle tested. And AI code also makes it easy to switch tools. And Github Actions > Azure Pipelines for open soure stuff, so I vastly prefer this flow.

Description of changes

  • Add a new Github Actions Workflow to use Changesets to create PRs
  • Add some scripts to bring back some features we used in beachball, like:
    • Disallowing major version bumps
    • Adding a post version hook to update our dependency profile
    • validate that PRs have a changeset (similar to beachball check-change)
  • Replace all the change files with one big changeset file.

Verification

I added some new checks, but as with all CI, got to merge and fix after bc it's hard to test.

Pull request checklist

This PR has considered (when applicable):

  • Automated Tests
  • Documentation and examples
  • Keyboard Accessibility
  • Voiceover
  • Internationalization and Right-to-left Layouts

@changeset-bot
Copy link

changeset-bot bot commented Feb 10, 2026

🦋 Changeset detected

Latest commit: c124629

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 76 packages
Name Type
@fluentui-react-native/adapters Patch
@fluentui-react-native/android-theme Patch
@fluentui-react-native/apple-theme Patch
@fluentui-react-native/avatar Patch
@fluentui-react-native/badge Patch
@fluentui-react-native/button Patch
@fluentui-react-native/callout Patch
@fluentui-react-native/checkbox Patch
@fluentui-react-native/chip Patch
@fluentui-react-native/codemods Patch
@fluentui-react-native/composition Patch
@fluentui-react-native/contextual-menu Patch
@fluentui-react-native/default-theme Patch
@fluentui-react-native/divider Patch
@fluentui-react-native/drawer Patch
@fluentui-react-native/dropdown Patch
@fluentui-react-native/experimental-activity-indicator Patch
@fluentui-react-native/experimental-appearance-additions Patch
@fluentui-react-native/experimental-avatar Patch
@fluentui-react-native/experimental-checkbox Patch
@fluentui-react-native/experimental-expander Patch
@fluentui-react-native/experimental-menu-button Patch
@fluentui-react-native/experimental-native-date-picker Patch
@fluentui-react-native/experimental-native-font-metrics Patch
@fluentui-react-native/experimental-shadow Patch
@fluentui-react-native/experimental-shimmer Patch
@fluentui-react-native/focus-trap-zone Patch
@fluentui-react-native/focus-zone Patch
@fluentui-react-native/framework Patch
@fluentui-react-native/framework-base Patch
@fluentui-react-native/icon Patch
@fluentui-react-native/immutable-merge Patch
@fluentui-react-native/input Patch
@fluentui-react-native/interactive-hooks Patch
@fluentui-react-native/link Patch
@fluentui-react-native/memo-cache Patch
@fluentui-react-native/menu Patch
@fluentui-react-native/menu-button Patch
@fluentui-react-native/merge-props Patch
@fluentui-react-native/notification Patch
@fluentui-react-native/overflow Patch
@fluentui-react-native/persona Patch
@fluentui-react-native/persona-coin Patch
@fluentui-react-native/popover Patch
@fluentui-react-native/pressable Patch
@fluentui-react-native/radio-group Patch
@fluentui-react-native/separator Patch
@fluentui-react-native/spinner Patch
@fluentui-react-native/stack Patch
@fluentui-react-native/styling-utils Patch
@fluentui-react-native/switch Patch
@fluentui-react-native/tablist Patch
@fluentui-react-native/text Patch
@fluentui-react-native/theme Patch
@fluentui-react-native/theme-tokens Patch
@fluentui-react-native/theme-types Patch
@fluentui-react-native/themed-stylesheet Patch
@fluentui-react-native/theming-utils Patch
@fluentui-react-native/tokens Patch
@fluentui-react-native/tooltip Patch
@fluentui-react-native/use-slot Patch
@fluentui-react-native/use-slots Patch
@fluentui-react-native/use-styling Patch
@fluentui-react-native/use-tokens Patch
@fluentui-react-native/vibrancy-view Patch
@fluentui-react-native/win32-theme Patch
@fluentui/react-native Patch
@uifabricshared/foundation-composable Patch
@uifabricshared/foundation-compose Patch
@uifabricshared/foundation-settings Patch
@uifabricshared/foundation-tokens Patch
@uifabricshared/theme-registry Patch
@uifabricshared/themed-settings Patch
@uifabricshared/theming-ramp Patch
@uifabricshared/theming-react-native Patch
@fluentui-react-native/experimental-stack Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Saadnajmi Saadnajmi force-pushed the changesets-hybrid-mirrornx-kit branch 2 times, most recently from 5bb59ff to 4766a83 Compare February 11, 2026 02:13
@Saadnajmi Saadnajmi changed the title feat: implement hybrid changesets workflow (mirror rnx-kit) ci: move to changesets for releases Feb 11, 2026
@Saadnajmi Saadnajmi marked this pull request as ready for review February 11, 2026 06:08
Saadnajmi and others added 13 commits February 12, 2026 00:11
This commit implements a hybrid approach that mirrors rnx-kit's changesets
workflow while keeping Azure Pipelines for NPM publishing.

Architecture:
- GitHub Actions: Version bump PR creation using @changesets/action
- Azure Pipelines: NPM publishing (compliance-friendly)
- GitHub App token: Bypasses org PR restrictions (like rnx-kit)

Changes:
- Add changesets dependencies (@changesets/cli, @changesets/changelog-github)
- Create .changeset/config.json (mirrors rnx-kit configuration)
- Create GitHub Actions workflow for version bumps
- Update Azure Pipelines to use 'changeset publish'
- Add comprehensive setup documentation

Key features:
- Uses official @changesets/action (battle-tested)
- Preserves dependency-profiles postbump hook
- Maintains Azure KeyVault integration for NPM token
- Keeps all 1ESPT compliance and security measures
- No prepublish hook needed (packages have proper exports field)

Setup required:
1. Configure GitHub App (react-native-sdk-bot or new app)
2. Add APP_ID variable and PRIVATE_KEY secret
3. See CHANGESETS_SETUP.md for detailed instructions

References:
- rnx-kit workflow pattern
- Plan: /Users/sanajmi/.claude/plans/stateless-jumping-unicorn.md

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add two layers of changeset validation:

1. Changeset Bot (already installed):
   - Automatically comments on PRs
   - Provides immediate visual feedback
   - Shows status: '⚠️ No Changeset' or '✅ Changeset detected'

2. GitHub Actions PR validation (new):
   - Enforces changesets in CI/CD
   - Fails PR checks if no changeset present
   - Automatically skips for version bump PRs
   - Shows helpful error message with instructions

Changes:
- Add .github/workflows/pr-validation.yml
- Add 'checkchange:changeset' script to package.json
- Update CHANGESETS_SETUP.md with validation details

Both mechanisms work together to ensure all PRs include changesets
while providing clear feedback to developers.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@Saadnajmi Saadnajmi force-pushed the changesets-hybrid-mirrornx-kit branch from c0f8466 to 6d00718 Compare February 12, 2026 08:15
Copy link
Member

Choose a reason for hiding this comment

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

Could this not have been a bash script? Seems simpler than having a JS script that just mimics it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It was originally one. I've been trying to write scripts in typescript as much as I can. Then I discovered zx and tried that. I can take it back to bash though

Copy link
Collaborator Author

@Saadnajmi Saadnajmi Feb 12, 2026

Choose a reason for hiding this comment

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

Actually, I see a bunch of other scripts are in our other scripts folder, like so:

"check-publishing": "node ./scripts/src/cli.mjs check-publishing",

I wonder if I should just move my scripts there and use our task runner that @JasonVMo introduced

Comment on lines +83 to +86
const files = fs.readdirSync(CHANGESETS_DIR);
const changesetFiles = files
.filter(file => file.endsWith('.md') && file !== 'README.md')
.map(file => path.join(CHANGESETS_DIR, file));
Copy link
Member

Choose a reason for hiding this comment

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

Can we parse the JSON output of changeset --since origin/main --output bumps.json instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a better idea

Comment on lines +50 to +51
commit: 'chore(release): version packages'
title: 'chore(release): version packages'
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need to set this. The default is already correct.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looking at their website:
https://github.com/changesets/action/tree/v1/

commit - The commit message to use. Default to Version Packages
title - The pull request title. Default to Version Packages

so I guess it's what format we want. We don't enforce conventional commits in the repo yet... but, I'd like to? I'll think about it

Copy link
Collaborator Author

@Saadnajmi Saadnajmi Feb 12, 2026

Choose a reason for hiding this comment

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

Related:

version - The command to update version, edit CHANGELOG, read and delete changesets. Default to changeset version if not provided

I could make a small script to run changeset version && update-dependency-profiles && yarn install --immutable. Right now the dep profile bump is handled as a separate step in CI. Do you haave opinions on what may be clearer? Use default param + extra CI step vs small script to run the version command + our post hook?

Copy link
Member

Choose a reason for hiding this comment

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

I think I like it better as part of the version command. More local.

Btw, this is the default commit message

image

Saadnajmi and others added 3 commits February 12, 2026 07:10
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.

2 participants