Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ This action for [Changesets](https://github.com/changesets/changesets) creates a
- commit - The commit message to use. Default to `Version Packages`
- title - The pull request title. Default to `Version Packages`
- setupGitUser - Sets up the git user for commits as `"github-actions[bot]"`. Default to `true`
- createGithubReleases - A boolean value to indicate whether to create Github releases after `publish` or not. Default to `true`
- createGithubReleases - When `true` (default), after a successful publish the action pushes git tags and creates GitHub Releases from changelog entries. When `false`, the action skips **both** tag pushes and GitHub Release creation (your publish script must handle tags if you still need them).
- commitMode - Specifies the commit mode. Use `"git-cli"` to push changes using the Git CLI, or `"github-api"` to push changes via the GitHub API. When using `"github-api"`, all commits and tags are GPG-signed and attributed to the user or app who owns the `GITHUB_TOKEN`. Default to `git-cli`.
- cwd - Changes node's `process.cwd()` if the project is not located on the root. Default to `process.cwd()`
- cwd - Working directory passed to git operations and the `publish` script (resolved with `path.resolve`). Does **not** call `process.chdir`. The initial changeset read and the version path from the entrypoint still use the job’s `process.cwd()`, so keep `.changeset/` at the job working directory unless you only need `cwd` for publish/git scoping. Default: `process.cwd()`.
- branch - Branch the action treats as the release base (version PR targets this branch; version branch is `changeset-release/<branch>`). Defaults to the current branch from `github.context.ref` with the `refs/heads/` prefix removed.

### Outputs
Expand Down
5 changes: 4 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ inputs:
description: "The command to update version, edit CHANGELOG, read and delete changesets. Default to `changeset version` if not provided"
required: false
cwd:
description: Sets the cwd for the node process. Default to `process.cwd()`
description: >
Working directory for git operations and the publish script (path.resolve).
Does not change process.cwd(); the entrypoint's initial changeset read and
version path still use the job working directory. Default: process.cwd().
Comment on lines +18 to +21
required: false
commit:
description: |
Expand Down
9 changes: 4 additions & 5 deletions docs/action-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

Engineering notes for the Changesets Release Action control flow in `src/index.ts` and `src/run.ts`.

User-facing usage: [`README.md`](../README.md).
Auth / npm: [`auth-and-publishing.md`](./auth-and-publishing.md).
How version commits are pushed: [`push-changes-internals.md`](./push-changes-internals.md).
Related docs: [`README.md`](../README.md) (usage) · [`auth-and-publishing.md`](./auth-and-publishing.md) · [`push-changes-internals.md`](./push-changes-internals.md) · [`troubleshooting.md`](./troubleshooting.md).

---

Expand Down Expand Up @@ -140,11 +138,12 @@ Runs only from the dispatch publish case (no remaining changesets + `publish` in
- **Monorepo / non-root tool:** lines matching `New tag:\s+(@[^/]+\/[^@]+|[^/]+)@([^\s]+)`.
- **Root package:** first line matching `New tag:` → treat the single root package as released; GitHub tag name `v{version}`.
3. If `createGithubReleases` is true (default) and packages were detected:
- Push each tag via `git.pushTag`.
- Push each tag via `git.pushTag` (see [`push-changes-internals.md`](./push-changes-internals.md) §5 — github-api tags `github.context.sha`; failures only warn).
- `repos.createRelease` with body from that version’s changelog entry; `prerelease` when the version contains `-`.
- Missing changelog file → skip that release silently (`ENOENT`); missing entry for the version → throw.
4. If `createGithubReleases` is false → **no** `pushTag` and **no** GitHub Release, even when `New tag:` lines were parsed. `published` / `publishedPackages` still reflect stdout detection.

If stdout has no `New tag:` lines, result is `{ published: false }` and outputs stay at the startup defaults.
If stdout has no `New tag:` lines, result is `{ published: false }` and outputs stay at the startup defaults. Your publish script must print `New tag: …` (changeset publish does) or the action will not treat the run as published.

---

Expand Down
20 changes: 17 additions & 3 deletions docs/auth-and-publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

Engineering notes for token resolution and npm auth in `src/index.ts` / `src/run.ts` (behavior shipped for `@changesets/action@1.7.0`).

User-facing examples live in the root [`README.md`](../README.md).
Dispatch / version-PR / publish detection: [`action-runtime.md`](./action-runtime.md).
Related docs: [`README.md`](../README.md) (examples) · [`action-runtime.md`](./action-runtime.md) · [`troubleshooting.md`](./troubleshooting.md).

---

Expand Down Expand Up @@ -79,12 +78,27 @@ Auth-line detection matches npm CLI style: `/^\s*\/\/registry\.npmjs\.org\/:[_-]

---

## 4. Related codepaths
## 4. Octokit throttling (`src/octokit.ts`)

Every Octokit instance is created with `@octokit/plugin-throttling`:

| Event | Behavior |
|-------|----------|
| Primary rate limit | Warning; retry if `retryCount <= 2` after `retryAfter` seconds |
| Secondary rate limit | Same retry policy |

After three attempts the request fails. See [`troubleshooting.md`](./troubleshooting.md) §6.

---

## 5. Related codepaths

| Path | Role |
|------|------|
| `action.yml` → `github-token` | Default `${{ github.token }}` |
| `src/index.ts` | Token resolve, `.netrc`, `.npmrc` / OIDC branch, dispatch publish vs version |
| `src/octokit.ts` | Throttled Octokit factory |
| `src/run.ts` → `runPublish` / `runVersion` | Inject `GITHUB_TOKEN` into script env |
| `docs/action-runtime.md` | When the action publishes, opens a PR, or exits |
| `docs/push-changes-internals.md` | How commits are pushed after versioning |
| `docs/troubleshooting.md` | Consumer pitfall index |
28 changes: 25 additions & 3 deletions docs/push-changes-internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,28 @@ This is GitHub's official [Commits API](https://docs.github.com/en/graphql/refer

- **`pushChanges`** is called during `runVersion` to push the version-bump commit to the PR branch (`changeset-release/<branch>`).
- **Existing PR fetch before push** — `runVersion` lists open PRs for `head: owner:changeset-release/<branch>` **before** `pushChanges`. With `commitMode: github-api`, `@changesets/ghcommit` may reset the remote branch to the base SHA (which would otherwise close the PR); keeping the PR number and calling `pulls.update` with `state: "open"` reopens/updates it (#488). Full version-PR lifecycle: [`action-runtime.md`](./action-runtime.md) §5.
- **`pushTag`** is called during `runPublish` to tag releases after stdout `New tag:` detection:
- git-cli: `git push origin <tag>`
- github-api: `octokit.rest.git.createRef({ ref: "refs/tags/<tag>", sha: github.context.sha })`

---

## 5. `pushTag` — publish-time tags (`src/git.ts`)

Called from `runPublish` **only when** `createGithubReleases` is `true` (default). Setting `createGithubReleases: false` skips **both** tag creation/push by the action **and** `repos.createRelease`.

| Mode | Behavior |
|------|----------|
| **git-cli** | `git push origin <tag>` in `cwd`. Expects the publish script (e.g. `changeset publish` / `changeset tag`) to have created the local tag already. |
| **github-api** | `octokit.rest.git.createRef({ ref: "refs/tags/<tag>", sha: github.context.sha })`. The tag always points at the **workflow triggering commit** (`github.context.sha`), not at a commit the publish script may have created afterward. |

### Tag name conventions (chosen in `runPublish`, not in `pushTag`)

| Package layout (`@manypkg/get-packages` `tool`) | Tag name |
|------------------------------------------------|----------|
| Non-root (monorepo) | `{packageName}@{version}` |
| Root | `v{version}` |

### Pitfalls

1. **`createGithubReleases: false` disables action tag pushes** — if you rely on the action (not your script) to publish tags, leave it `true` or push tags in `publish`.
2. **github-api tags `github.context.sha`** — correct when publish does not create a new git commit; wrong if your publish script commits first and you expected the tag on that new commit.
3. **createRef failures are warnings** — `.catch` logs `Failed to create tag …` and continues (assumes a custom publish script already pushed the tag). `createRelease` still runs afterward.
4. **git-cli missing local tag** — `git push origin <tag>` fails the step if the tag was never created locally.
88 changes: 88 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Troubleshooting — consumer pitfalls

Scan-friendly fixes for common `@changesets/action` surprises. Behavior verified against `src/index.ts`, `src/run.ts`, `src/git.ts`, and `src/readChangesetState.ts`.

Deeper notes: [`action-runtime.md`](./action-runtime.md) · [`auth-and-publishing.md`](./auth-and-publishing.md) · [`push-changes-internals.md`](./push-changes-internals.md) · user examples in [`README.md`](../README.md).

---

## 1. Version Packages PR never opens

| Symptom | Likely cause | What to check |
|---------|--------------|---------------|
| Log: `All changesets are empty; not creating PR` | Every remaining changeset has `releases: []` | Remove or fill empty changesets. `hasChangesets` stays `"true"`. |
| Log: no changesets / no publish script | Merge cleared changesets and workflow omits `publish` | Expected no-op. Add `publish` if you want the publish path. |
| Changeset files exist but action says none | Pre mode already consumed those ids | `readChangesetState` filters ids listed in `preState.changesets` while `mode === "pre"`. |

---

## 2. Publish did not run / `published` is false

| Symptom | Likely cause | What to check |
|---------|--------------|---------------|
| Custom step `if: hasChangesets == 'false'` never runs | Empty-changeset skip left `hasChangesets=true` | See §1; empty changesets block both the Version PR and this pattern. |
| Action ran publish script but `published` is `false` | Stdout had no `New tag:` lines | Detection parses **stdout only**. Monorepo lines must match `New tag: name@version`; root needs any `New tag:` line. |
| npm 401 / auth errors | Token or OIDC misconfigured | [`auth-and-publishing.md`](./auth-and-publishing.md): `NPM_TOKEN` vs trusted publishing (`id-token: write`), custom registries need your own `.npmrc`. |

---

## 3. `cwd` input surprises

After #486 the action does **not** call `process.chdir`.

| Works with `cwd` | Still uses job `process.cwd()` |
|------------------|--------------------------------|
| `Git` (commit/push/tag via git-cli) | Initial `readChangesetState()` in `src/index.ts` |
| `runPublish({ cwd })` (publish script + package discovery) | `runVersion(...)` call from the entrypoint (omits `cwd`) |

**Practical rule:** keep the package root (and `.changeset/`) as the job working directory. Treat non-root `cwd` as best-effort for publish/git scoping only.

---

## 4. Tags and GitHub Releases

| Symptom | Likely cause | What to check |
|---------|--------------|---------------|
| No tags and no Releases after publish | `createGithubReleases: false` | That flag skips **both** `pushTag` and `repos.createRelease`. |
| Tag points at unexpected commit (`commitMode: github-api`) | `pushTag` uses `github.context.sha` | Tag is the workflow triggering SHA, not a commit your publish script created later. |
| Warning `Failed to create tag …` then Release still appears | Tag already existed remotely | createRef errors are swallowed as warnings; `createRelease` still runs. |
| git-cli: push tag failed | Local tag missing | Publish script must create the tag before the action pushes it. |
| Release creation throws | Changelog has no heading equal to the version | Missing `CHANGELOG.md` skips that release (`ENOENT`); missing **entry** throws. |

Tag names: monorepo `{name}@{version}`; root package `v{version}`. Details: [`push-changes-internals.md`](./push-changes-internals.md) §5.

---

## 5. `commitMode: github-api` issues

| Symptom | Likely cause | What to check |
|---------|--------------|---------------|
| Version PR closed then reopened / flicker | Branch reset to base SHA before new commit | Action lists open PRs **before** push and force-opens on update (#488). |
| Error about symlink or executable | Changed symlink/executable in the version commit | API cannot add/update those; use `git-cli` (default) or avoid changing them. |
| `setupGitUser: true` had no effect | github-api path | `Git.setupUser` is a no-op when Octokit is set; attribution follows the token owner. |

---

## 6. GitHub API rate limits

`setupOctokit` (`src/octokit.ts`) uses `@octokit/plugin-throttling`:

- On primary or secondary rate limit → warning log.
- Retries while `retryCount <= 2` (up to three attempts), waiting `retryAfter` seconds.
- Further limits fail the request.

Large monorepos with many Releases or frequent version-PR updates are the usual trigger.

---

## 7. Permissions quick checklist

Minimum for opening/updating the Version Packages PR with `github.token`:

```yaml
permissions:
contents: write
pull-requests: write
```

Add `id-token: write` when using npm trusted publishing (no `NPM_TOKEN`). Use a PAT / GitHub App token via `github-token` when the default token cannot trigger downstream workflows.
Loading