Skip to content

fix: publish one combined GitHub release - #1503

Open
ArekChr wants to merge 5 commits into
callstack:mainfrom
ArekChr:fix/single-github-release
Open

ArekChr wants to merge 5 commits into
callstack:mainfrom
ArekChr:fix/single-github-release

Conversation

@ArekChr

@ArekChr ArekChr commented Oct 19, 2026 •

Copy link
Copy Markdown

Changesets currently creates a GitHub release for every published package. This creates one combined release on the existing main package tag (for example, @callstack/repack@5.4.2), titled with the shared version.

The notes list the fixed release group and merge its changelog entries by change type, remove dependency update bullets, and deduplicate shared entries. The generator prints Markdown to stdout; the workflow uses gh release create --verify-tag only after Changesets publishes packages and leaves existing releases untouched. Changesets still manages npm publishing and package tags.

The remaining generator tests run in the existing CI test job. CONTRIBUTING.md documents previewing notes and manually creating a missing GitHub release after npm publication. Canary publishing is unchanged.

Validation:

  • Four generator tests passed: actual 5.4.2 notes, shared fix(repack): support flow-parser in React Native 0.88 #1476 entry in 5.4.1, grouped multiline notes, and missing-version handling.
  • CLI preview against the repository's 5.4.2 changelogs passed.
  • Biome 2.5.6 for .github/scripts and package.json, actionlint 1.7.7 for both changed workflows, and git diff --check passed.
  • No live npm publication or GitHub release was created. Package build, typecheck, and full monorepo tests were not run locally.

@vercel

vercel Bot commented Oct 19, 2026

Copy link
Copy Markdown

@ArekChr is attempting to deploy a commit to the Callstack Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot

changeset-bot Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5d7d2cb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@ArekChr
ArekChr marked this pull request as ready for review October 19, 2026 08:10

@dannyhw dannyhw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I tested the branch locally: all 18 tests pass, and --dry-run produces a single release on @callstack/repack@5.4.2, titled 5.4.2. The output looks good.

I have a few suggestions to make this lighter to maintain, since we only touch release tooling every now and then:

  • Keep the changesets config as it is. create-github-releases: false with push-git-tags: true looks right to me.
  • Have release-notes.mjs print the notes to stdout. The workflow could then create the release with gh, which is already authenticated on the runner. That could let us drop create-release.mjs. Something like:
      - name: Create GitHub release
        if: steps.changesets.outputs.published == 'true'
        run: |
          version=$(node -p "require('./packages/repack/package.json').version")
          tag="@callstack/repack@${version}"
          node .github/scripts/release-notes.mjs > release-notes.md
          gh release view "$tag" >/dev/null 2>&1 || gh release create "$tag" \
            --verify-tag \
            --title "$version" \
            --notes-file release-notes.md \
            $([[ "$version" == *-* ]] && echo --prerelease)
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  • Trim the tests. A couple of tests for the CHANGELOG extraction against the 5.4.2 fixture would give us good coverage. Then we wouldn't need the separate CI job or the test step before publishing.

On retries: if you'd like to keep the automatic retry after a failed release step, the "main tag points at GITHUB_SHA" check could be a single gh api repos/$GITHUB_REPOSITORY/commits/$tag --jq .sha comparison in the same step. I'm also happy to just create the release manually in that rare case, whichever you prefer.

Comment thread .github/workflows/release.yml Outdated
run: pnpm test

- name: Test release automation
run: pnpm test:release

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we leave this out of the release job? If these tests ever fail, for example after a package is added to the fixed group, npm publishing would be held up too. Running them in regular CI should be enough.

Comment thread .github/workflows/release.yml Outdated
# Retry GitHub release creation after all package tags have been pushed.
# Changesets can report published=false when npm is already up to date.
- name: Create combined GitHub release
if: steps.changesets.outputs.has-changesets == 'false'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What do you think about steps.changesets.outputs.published == 'true' here? Then the step only runs when something was actually published, and we wouldn't need the SHA check on every push to main.

Comment thread .github/workflows/test.yml Outdated
- name: Run tests
run: pnpm test

release-automation:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If the scripts get smaller, we could probably run the remaining tests as part of the existing test job instead of adding a separate one.

Comment thread .github/scripts/create-release.mjs Outdated
}
}

async function api(endpoint, body) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since gh is available on the runner with GH_TOKEN, we could use gh release view / gh release create --verify-tag here instead. That would also let us drop the request mocks in the tests.

Comment thread .github/scripts/create-release.mjs Outdated
throw new Error('GITHUB_REPOSITORY, GITHUB_SHA and GH_TOKEN are required');
}

for (const published of publishedPackages) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This check runs after publishing, so if it ever triggers, the packages are already on npm. I think it'd be fine to leave it out for now and add a policy when we have independently versioned packages.

Comment thread .github/scripts/release-notes.mjs Outdated
} catch (error) {
throw new Error(`${pkg.name}: ${error.message}`, { cause: error });
}
if (entry) sections.push(`## ${pkg.name}@${pkg.version}\n\n${entry}`);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Small idea on the format: could we merge the entries into one list (grouped by change type), skip the Updated dependencies bullets, and de-duplicate changesets that touch several packages? Right now a changeset like #1476 in 5.4.1 would show up under both repack and plugin-reanimated. The single merged list would also match how the 5.4.x releases look today.

@ArekChr

ArekChr commented Oct 26, 2026

Copy link
Copy Markdown
Author

@dannyhw Thanks for testing this! I’ve addressed your suggestions, the workflow now uses gh, and the notes are merged by change type, without duplicates or dependency updates. I also reduced the tests and moved them into the existing CI job. For failed release creation, I kept manual recovery and documented the steps. All four tests pass locally, along with Biome and actionlint.

This branch has not been deployed

No deployments
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