Skip to content

Auto-bump patch version in publish workflow to prevent npm republish failures - #18

Merged
VrilLabs merged 7 commits into
mainfrom
copilot/auto-bump-patch-version
Jun 4, 2026
Merged

VrilLabs merged 7 commits into
mainfrom
copilot/auto-bump-patch-version

Conversation

Copilot AI commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Npm publishes fail with 403 Forbidden if they attempt to overwrite an already existing package version. To prevent these failures, the publish pipeline has been updated to automatically increment the patch (third segment) of the version prior to building and publishing.

Workflow Automation (.github/workflows/publish.yml)

  • Auto-bump version step: Inserted a Node.js-based version bump step before the package build step.
  • Metadata synchronization: Automatically updates version numbers in package.json, package-lock.json, and the compiled VRIL_VERSION constant in src/lib/vril/version.ts to ensure consistency.

Documentation Update (CLAUDE.md)

  • Process documentation: Added a Publishing & Versioning section outlining the automatic version bumping logic and synchronization during releases.

Example inline Node.js runner logic integrated into the GitHub Actions workflow:

const fs = require('fs');
const path = require('path');

// 1. Parse current version
const pkgPath = path.join(process.cwd(), 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
const currentVersion = pkg.version;

// 2. Increment patch segment
const parts = currentVersion.split('.');
parts[2] = String(parseInt(parts[2], 10) + 1);
const nextVersion = parts.join('.');

// 3. Update files
pkg.version = nextVersion;
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');

@vercel

vercel Bot commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vril-js Ready Ready Preview, Comment Jun 3, 2026 6:15pm

Copilot AI changed the title [WIP] Update publish workflow to auto-bump patch version before publishing Auto-bump patch version in publish workflow to prevent npm republish failures Jun 3, 2026
Copilot AI requested a review from VrilLabs June 3, 2026 17:59
@VrilLabs
VrilLabs marked this pull request as ready for review June 3, 2026 18:01
Copilot AI review requested due to automatic review settings June 3, 2026 18:01
Comment thread .github/workflows/publish.yml Outdated
Comment thread .github/workflows/publish.yml
vercel Bot and others added 2 commits June 3, 2026 18:05
…both main push and tag push), creating version conflicts and potential duplicate publishes without committing changes back to git.

This commit fixes the issue reported at .github/workflows/publish.yml:38

**Bug Explanation:**

The workflow is triggered on two distinct events:
1. Push to main branch
2. Push of tags matching 'v*'

The auto-bump version step (line 38) executes unconditionally on every trigger and performs these operations:
- Increments the patch version in package.json
- Updates package-lock.json
- Updates src/lib/vril/version.ts with the new version

However, these file changes are **never committed back to the git repository**. This creates a critical version management problem:

**Scenario of the bug:**
1. Developer pushes to main → workflow runs → version bumped from 2.2.1 to 2.2.2 → published to npm
2. Git repository still contains 2.2.1 in package.json
3. Developer pushes a tag (e.g., v2.2.2) → workflow runs again → version bumps from 2.2.1 to 2.2.2 again
4. This can cause:
   - The same version being published multiple times
   - Version conflicts during the publish step
   - Loss of version synchronization between npm and git

Additionally, the regex pattern used to update version.ts (`/export const VRIL_VERSION = '[^']+';/`) is fragile:
- Uses single quotes which may not match properly with different quote styles
- Doesn't properly escape the replacement string, risking escaping issues with special characters
- Uses `[^']+` which is too permissive and doesn't validate semantic versioning format

**Fix Applied:**

1. Added conditional execution: `if: github.ref == 'refs/heads/main'` to the auto-bump step
   - This ensures version bumping ONLY happens when pushing to the main branch
   - Tag pushes will skip this step, using the version from git as-is

2. Improved the regex pattern from `/export const VRIL_VERSION = '[^']+';/` to `/export const VRIL_VERSION = ['"]\d+.\d+.\d+['"];/`
   - Now matches both single and double quotes: `['"]`
   - Validates semantic versioning format: `\d+.\d+.\d+`
   - More precise and less prone to unintended matches
   - Properly escapes the replacement string with `\'` for correct quote insertion

This ensures that:
- Main branch pushes auto-bump and publish intermediate development versions
- Tag-based releases use the exact version specified in the tag/git (no duplicate bumping)
- Version.ts is updated with a more robust regex pattern
- No version conflicts or duplicate publishes occur

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: VrilLabs <vril@ik.me>
…tionally on all workflow triggers, including pushes to main branch, causing unintended releases and publications

This commit fixes the issue reported at .github/workflows/publish.yml:80

## Bug Details

The publish workflow is triggered by three events:
1. Push to `main` branch
2. Push of tags matching `v*`
3. Manual `workflow_dispatch` trigger

However, the "Create GitHub Release" step (line 80) and the "Publish to npm" step (line 88) execute unconditionally, without checking which trigger caused the workflow to run.

When the workflow is triggered by a push to the `main` branch, `github.ref_name` equals `'main'` and `github.ref_type` equals `'branch'`. This causes:
- The GitHub Release action to create a release with `tag_name='main'` and `name='Vril.js main'`, which is not a proper semantic version release
- The npm publish step to publish the package to npm even though this should only happen for tag-based releases

This is a logic bug because the workflow design (triggered on both branch and tag pushes) conflicts with the execution logic (unconditional release/publish operations), resulting in unintended releases and package publications on every main branch push.

## Fix Applied

Added conditional guards to three steps that should only execute during tag pushes or manual workflow dispatch:

```yaml
if: github.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
```

This condition ensures:
- When triggered by a tag push: `github.ref_type == 'tag'` is true → steps execute
- When triggered by main branch push: `github.ref_type == 'branch'` is false → steps are skipped
- When manually triggered: `github.event_name == 'workflow_dispatch'` is true → steps execute (allowing manual releases)

The condition was applied to:
1. "Create GitHub Release" step
2. "Verify npm auth" step (prerequisite for publishing)
3. "Publish to npm" step

This prevents unintended GitHub releases and npm publications from main branch pushes while preserving the intended behavior for tag-based releases and manual triggers.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: VrilLabs <vril@ik.me>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates the npm publish workflow to automatically bump the patch version prior to publishing, reducing the chance of 403 Forbidden republish failures, and documents the updated release/versioning behavior.

Changes:

  • Added a GitHub Actions step to increment the patch version and synchronize it across package.json, package-lock.json, and src/lib/vril/version.ts.
  • Documented the auto-bump behavior and file synchronization in CLAUDE.md.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
CLAUDE.md Adds documentation describing the publish workflow’s automatic patch bump and version synchronization.
.github/workflows/publish.yml Adds a Node-based patch version auto-bump step before build/publish.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/publish.yml Outdated
Comment on lines +51 to +56
// 2. Increment the patch component (the third segment) of the version by 1
const parts = currentVersion.split('.');
if (parts.length !== 3) {
throw new Error('Invalid version format: ' + currentVersion);
}
parts[2] = String(parseInt(parts[2], 10) + 1);
Comment on lines +75 to 93

// 5. Keep src/lib/vril/version.ts synchronized with the package version
const versionTsPath = path.join(process.cwd(), 'src/lib/vril/version.ts');
if (fs.existsSync(versionTsPath)) {
let content = fs.readFileSync(versionTsPath, 'utf8');
content = content.replace(/export const VRIL_VERSION = ['\"]\d+\.\d+\.\d+['\"];/, 'export const VRIL_VERSION = \\'' + nextVersion + '\\';');
fs.writeFileSync(versionTsPath, content, 'utf8');
console.log('Updated src/lib/vril/version.ts');
}
"

- name: Build
run: npm run build

- name: Create GitHub Release
if: github.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag || github.ref_name }}
Comment thread .github/workflows/publish.yml Outdated
Comment thread .github/workflows/publish.yml Outdated
vercel Bot and others added 2 commits June 3, 2026 18:15
…ue to missing regex verification and unhandled workflow_dispatch scenarios

This commit fixes the issue reported at .github/workflows/publish.yml:81

**Bug Details:**

The issue manifested in two ways:

1. **Missing regex verification (Line 81)**: When auto-bumping on main branch pushes, the workflow attempted to update `src/lib/vril/version.ts` using a regex replacement:
   ```javascript
   content = content.replace(/export const VRIL_VERSION = ['"]\d+.\d+.\d+['"];/, 'export const VRIL_VERSION = \'' + nextVersion + '\';');
   ```
   However, if the file format changed or the regex didn't match (e.g., different quote style, extra whitespace), the replacement would silently fail. The workflow would continue with an stale VRIL_VERSION while package.json was bumped, causing version inconsistency. The code wrote the content back without verifying it changed.

2. **Version drift on workflow_dispatch**: When manually triggering the workflow via `workflow_dispatch` with a custom tag input (e.g., `v3.0.0`):
   - The Auto-bump step would run (condition: `if: github.ref == 'refs/heads/main'` was TRUE)
   - This would bump package.json to the next patch version (e.g., `2.2.2`)
   - The Release step would use `inputs.tag = 'v3.0.0'` from the user input
   - Result: Released tag would be `v3.0.0` but published npm version would be `2.2.2`

**Impact:**
- Silent failure when file format changes could leave version.ts out of sync with package.json
- Manual workflow dispatches with custom tags would create version mismatches between release tags and published npm versions
- Users installing from npm would get different version than what the GitHub release indicates

**The Fix:**

1. **Added regex verification**: After replacement, the code now checks if the content actually changed. If the regex didn't match, it throws an error with the current content for debugging:
   ```javascript
   if (newContent === content) {
     throw new Error('Failed to update VRIL_VERSION in version.ts - regex did not match...');
   }
   ```

2. **Added workflow_dispatch condition to auto-bump**: Changed condition from `if: github.ref == 'refs/heads/main'` to `if: github.ref == 'refs/heads/main' && github.event_name == 'push'`, so auto-bump only runs on actual pushes, not manual dispatches.

3. **Added new "Sync version from tag input" step**: When workflow_dispatch is triggered, this step extracts the version from the provided tag input and synchronizes all version files (package.json, package-lock.json, version.ts) to match. It also includes the same regex verification to ensure the replacement succeeds.

These changes ensure:
- Workflow fails loudly if version files can't be updated (detecting format changes)
- Manual dispatches with custom tags update all version files to match the tag
- No silent version drift between release tags and published versions

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: VrilLabs <vril@ik.me>
…is a valid integer before incrementing, allowing parseInt() to produce NaN and create invalid semver

This commit fixes the issue reported at .github/workflows/publish.yml:56

## Bug Explanation

The original code at line 56 of `.github/workflows/publish.yml` performed:
```javascript
parts[2] = String(parseInt(parts[2], 10) + 1);
```

This has no validation that `parts[2]` is a valid integer. The `parseInt()` function behavior is:
- `parseInt("2", 10)` → `2` ✓
- `parseInt("2a", 10)` → `2` (parses prefix, unexpected behavior)
- `parseInt("a2", 10)` → `NaN` (can't parse any digits)
- `parseInt("", 10)` → `NaN` (empty string)

If `parts[2]` contains non-numeric characters or is empty, `parseInt()` returns `NaN`, and `String(NaN + 1)` becomes `"NaN"`, which creates an invalid semantic version in `package.json`. This would cause the publish step to fail with a confusing error during `npm publish` rather than failing fast with a clear validation error.

While the primary cause would be manual corruption of `package.json` (which shouldn't happen), this code should be defensive and fail fast with a clear message if the version format is invalid.

## Fix Applied

Added validation to ensure `parts[2]` is a valid integer before incrementing:

```javascript
const patchNum = parseInt(parts[2], 10);
if (isNaN(patchNum) || parts[2] !== String(patchNum)) {
  throw new Error('Invalid patch version (not a valid integer): ' + parts[2]);
}
parts[2] = String(patchNum + 1);
```

The validation:
1. Parses the patch segment to check if it's a valid number
2. Checks for `NaN` (unparseable content)
3. Checks that the string representation matches the original (catches cases like "2a" which partially parse)
4. Throws a clear, descriptive error if validation fails

This prevents silent creation of invalid semver versions and provides actionable error messages during the workflow.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: VrilLabs <vril@ik.me>

This branch was successfully deployed

1 active deployment
Preview — dbe975c5 Deployed Jun 3, 2026 by vercel[bot]
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.

Auto-bump patch version in publish workflow to prevent npm republish failures

3 participants