Agent Skills: Release-Please Monorepo Configuration

|

UncategorizedID: laurigates/claude-plugins/release-please-configuration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/laurigates/claude-plugins/tree/HEAD/git-plugin/skills/release-please-configuration

Skill Files

Browse the full folder contents for release-please-configuration.

Download Skill

Loading file tree…

git-plugin/skills/release-please-configuration/SKILL.md

Skill Metadata

Name
release-please-configuration
Description
"release-please monorepo config — component tags, per-package extra-files, tag migration. Use when adding packages or fixing duplicate-tag / no-bump failures."

Release-Please Monorepo Configuration

Monorepo-specific release-please strategy: component tagging, per-package extra-files, linked versions, and the shared→component tag migration. For the single-repo workflow/manifest/config shape, the conventional-commit version-bump rules, and compliance auditing, use configure-plugin:configure-release-please.

When to Use This Skill

| Use this skill when... | Use the alternative when... | |---|---| | Configuring component/include-component-in-tag for a multi-package repo | Setting up a single-repo release-please (workflow, manifest, config shape) — use configure-plugin:configure-release-please | | Adding a new package to a monorepo's release-please config | Auditing an existing setup against documented conventions — use configure-plugin:configure-release-please | | Fixing duplicate-tag, multiple-paths, or per-package no-bump failures | Actually merging release-please PRs — use release-please-pr-workflow | | Migrating from shared v1.0.0 tags to component-v1.0.0 tags | Detecting manual edits to managed files — use release-please-protection | | Setting per-package extra-files (JSON/YAML/TOML/XML version locations) | Release-As: trailer-based one-off overrides — use git-commit-trailers |

Core Files

| File | Purpose | |------|---------| | release-please-config.json | Per-package config, changelog sections, extra-files | | .release-please-manifest.json | Current version for each package/component | | .github/workflows/release-please.yml | GitHub Actions workflow (see configure-plugin:configure-release-please REFERENCE.md for the shape) |

Monorepo Configuration

Critical Settings for Monorepos

{
  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
  "include-component-in-tag": true,
  "separate-pull-requests": true,
  "packages": {
    "package-a": {
      "component": "package-a",
      "release-type": "simple",
      "extra-files": ["package-a/version.json"]
    }
  }
}

Key Fields:

| Field | Required | Purpose | |-------|----------|---------| | include-component-in-tag | Yes (monorepo) | Creates package-a-v1.0.0 tags instead of v1.0.0 | | component | Yes (monorepo) | Unique identifier for each package; must be set for every package | | separate-pull-requests | Recommended | Creates per-package release PRs instead of combined |

Linked Versions

To keep a set of components on the same version, use the linked-versions plugin:

{
  "packages": {
    "packages/frontend": {"release-type": "node", "component": "frontend"},
    "packages/backend": {"release-type": "node", "component": "backend"}
  },
  "plugins": [
    "node-workspace",
    {
      "type": "linked-versions",
      "groupName": "workspace",
      "components": ["frontend", "backend"]
    }
  ]
}

Common Failure: Duplicate Release Tags

Symptom: Workflow fails with Duplicate release tag: v2.0.0

Cause: All packages try to create the same tag (e.g., v2.0.0) because:

  1. Missing include-component-in-tag: true at root level
  2. Missing component field in each package

Fix:

{
  "include-component-in-tag": true,
  "packages": {
    "my-package": {
      "component": "my-package",  // Add this to every package
      ...
    }
  }
}

Common Failure: Multiple Paths Warning

Symptom: Multiple paths for : package-a, package-b

Cause: Empty component field (the : with nothing after it indicates empty string)

Fix: Ensure every package has "component": "package-name" set

Common Failure: Merged Release PR Never Tagged

Symptom: Every run after a grouped release PR merges aborts with:

There are untagged, merged release PRs outstanding - aborting

The workflow log also carries the tell:

pullRequestTitlePattern miss the part of '${component}'
pullRequestTitlePattern miss the part of '${scope}'

Cause: A custom pull-request-title-pattern (or group-pull-request-title-pattern) containing ${version} — or ${component} / ${scope} — on a grouped release PR (separate-pull-requests: false). Because a grouped PR spans many packages, there is no single version/component to substitute, so the pattern renders a bare title (e.g. chore: release with nothing after it). On the tagging pass release-please re-parses the merged PR's title back through that same pattern to recover which releases it represents; the bare title no longer matches the pattern, so the PR is never tagged. It stays autorelease: pending, and every subsequent run refuses to proceed while an untagged merged release PR is outstanding.

Fix: Drop the custom title patterns. The release-please defaults round-trip correctly for grouped PRs — they render a parseable title and the tagging pass recovers the releases from it.

// WRONG - ${version} on a grouped PR renders a bare, unparseable title
{
  "separate-pull-requests": false,
  "pull-request-title-pattern": "chore: release ${version}"
}

// CORRECT - omit the custom pattern; the default round-trips
{
  "separate-pull-requests": false
}

Recovery: Unwedge an Already-Merged Untagged PR

Once a grouped release PR has merged with a bare title, dropping the config fixes future runs but the already-merged PR is still stuck at autorelease: pending, so runs keep aborting. Relabel it to autorelease: tagged so release-please stops treating it as outstanding, then dispatch a fresh run to cut the releases:

# Create the label first if the repo lacks it — release-please only
# auto-creates `autorelease: tagged` when it successfully tags a PR.
gh label create "autorelease: tagged" --color 2A7A2A --description "release-please tagged"

# Relabel the stuck merged PR
gh pr edit $PR_NUMBER --add-label "autorelease: tagged" --remove-label "autorelease: pending"

# Dispatch a fresh run — with no tags cut, it recomputes the same releases
# into a new, parseable release PR (or tags directly on the next merge).
gh workflow run release-please.yml

No tags were cut for the wedged PR, so release-please recomputes the identical set of releases on the next run; the relabel only removes the "outstanding" blocker.

Per-Package extra-files for Custom Version Locations

For JSON files, you must use the object format with type, path, and jsonpath:

{
  "packages": {
    "my-plugin": {
      "release-type": "simple",
      "extra-files": [
        {"type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version"}
      ]
    }
  }
}

Key insight: For monorepo packages, extra-files paths are relative to the package directory, NOT the repo root. Release-please automatically prepends the package path.

Common Mistakes:

  1. Using a simple string path for JSON files:
// WRONG - won't update the version field
"extra-files": [".claude-plugin/plugin.json"]

// CORRECT - uses JSON updater with jsonpath
"extra-files": [
  {"type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version"}
]
  1. Prepending the package path yourself (it gets doubled):
// WRONG - path becomes my-plugin/my-plugin/.claude-plugin/...
"extra-files": [
  {"type": "json", "path": "my-plugin/.claude-plugin/plugin.json", "jsonpath": "$.version"}
]

// CORRECT - path is relative to the package directory
"extra-files": [
  {"type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version"}
]

File Type Formats:

| File Type | Format | |-----------|--------| | JSON | {"type": "json", "path": "...", "jsonpath": "$.version"} | | YAML | {"type": "yaml", "path": "...", "jsonpath": "$.version"} | | TOML | {"type": "toml", "path": "...", "jsonpath": "$.version"} | | XML | {"type": "xml", "path": "...", "xpath": "//version"} | | Plain text | "path/to/version.txt" (string is fine) |

Adding a New Package to a Monorepo

  1. Update release-please-config.json:
{
  "packages": {
    "new-package": {
      "component": "new-package",
      "release-type": "simple",
      "extra-files": [
        {"type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version"}
      ],
      "changelog-sections": [...]
    }
  }
}
  1. Update .release-please-manifest.json:
{
  "new-package": "1.0.0"
}
  1. Create the initial version file in the package if needed.

For the standard changelog-sections set and release-type table, see configure-plugin:configure-release-please.

Migrating from Shared Tags to Component Tags

When transitioning from v1.0.0 style tags to component-v1.0.0:

  1. Add "include-component-in-tag": true to config
  2. Add "component": "package-name" to each package
  3. Old tags (v1.0.0) will be ignored
  4. New releases will create component-specific tags
  5. Close any pending combined release PRs

Note: Release-please scans for component-specific tags. The first run after migration creates release PRs for all packages with changes since the manifest version.

Monorepo Troubleshooting

One Package's PR Not Created (others fine)

Check:

  1. Are there releasable commits scoped to that package path since its last component tag?
  2. Does the commit scope match the package path?
  3. Is the package's component set and unique?

Wrong Version in a Package's Extra File

Ensure the package's extra-files paths are relative to the package directory, not the repo root (release-please prepends the package path):

// Correct (package path is "my-package")
"extra-files": [{"type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version"}]

For single-repo troubleshooting (no PR created at all, version not bumping, CI not running on the release PR), see configure-plugin:configure-release-please.

Quick Reference

# Check latest release-please-action version
curl -s https://api.github.com/repos/googleapis/release-please-action/releases/latest | jq -r '.tag_name'

# List pending release PRs (per-component in a monorepo)
gh pr list --label "autorelease: pending"

# View recent workflow runs
gh run list --workflow=release-please.yml --limit=5

# Inspect a package's current version in the manifest
jq -r '."my-package"' .release-please-manifest.json

Resources