Skip to content

feat: add version-file input#542

Closed
acouvreur wants to merge 5 commits into
goreleaser:masterfrom
acouvreur:add-version-file-input
Closed

feat: add version-file input#542
acouvreur wants to merge 5 commits into
goreleaser:masterfrom
acouvreur:add-version-file-input

Conversation

@acouvreur

@acouvreur acouvreur commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

You can now use .tool-versions file to specify GoReleaser version to download

Closes #541


Testing

With version-file referencing a non-existing file

Typo .tools-version instead of .tool-versions

image

sablierapp/sablier@0700179

With version-file referencing .tool-versions file

image

sablierapp/sablier@94739c4

No version specified

image

sablierapp/sablier@d5d4432

You can now use .tool-versions file to specify GoReleaser version to download
@acouvreur acouvreur marked this pull request as draft February 24, 2026 00:49
@acouvreur acouvreur marked this pull request as ready for review February 24, 2026 00:55

@caarlos0 caarlos0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks good - could you add tests as well? there's a bunch in there, you can follow their lead

@acouvreur

Copy link
Copy Markdown
Contributor Author

@caarlos0 just added a test file!

@codecov

codecov Bot commented Feb 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.78%. Comparing base (14707cd) to head (9307d0b).
⚠️ Report is 66 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #542      +/-   ##
==========================================
+ Coverage   66.92%   68.78%   +1.86%     
==========================================
  Files           3        4       +1     
  Lines         130      157      +27     
  Branches       23       43      +20     
==========================================
+ Hits           87      108      +21     
- Misses         27       49      +22     
+ Partials       16        0      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@acouvreur

Copy link
Copy Markdown
Contributor Author

Hey sorry about the missing unused imports, I will clean it up

@acouvreur

Copy link
Copy Markdown
Contributor Author

@caarlos0 I've updated the test file to remove the unused imports, tell me if that
s good for you!

Comment thread src/version.ts Outdated
Comment on lines +10 to +14
if (requestedVersion && versionFilePath) {
core.warning(
`Both version (${requestedVersion}) and version-file (${versionFilePath}) inputs are specified, only version will be used`
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i wonder if it would be better to simplify all this making version-file having precedence

so, if version-file is given, use it, or error

otherwise, use version, which would also mean we don't need to manually default to ~> v2

wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think it is a better solution indeed because then I can revert all the changes about how the default version is computed.

I've taken much inspiration from the current implementation in the goreleaser action, so I've essentially implemented the same behavior.

Let me change it with your suggestion.

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

Adds support for selecting the GoReleaser version via a version-file input (currently .tool-versions), with parsing logic and tests.

Changes:

  • Introduced getRequestedVersion() to resolve version from version or version-file.
  • Wired resolved version into the installation flow in src/main.ts.
  • Documented the new input and added Jest coverage for version resolution.

Reviewed changes

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

Show a summary per file
File Description
src/version.ts Adds logic to resolve GoReleaser version from .tool-versions (or fall back to version).
src/main.ts Uses resolved version when installing GoReleaser.
src/context.ts Adds versionFile input wiring.
action.yml Declares new version-file input.
tests/version.test.ts Adds Jest tests for version resolution behavior.
README.md Documents version-file and updates TOC / inputs list.

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

Comment thread src/version.ts
Comment on lines +11 to +18
const workingDirectory = inputs.workdir;
if (workingDirectory) {
versionFilePath = path.join(workingDirectory, versionFilePath);
}

if (!fs.existsSync(versionFilePath)) {
throw new Error(`The specified GoReleaser version file at: ${versionFilePath} does not exist`);
}

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

This always resolves version-file relative to workdir when workdir is set (including common monorepo setups where workdir is a subdirectory). That makes it impossible to reference a version file in the repo root while also using a non-root workdir, despite the docs saying the path can be relative to the root or workdir. Consider resolving relative paths by checking both candidates (repo root path first, then path.join(workdir, versionFile)), or updating the docs to state that version-file is interpreted relative to workdir when provided.

Copilot uses AI. Check for mistakes.
Comment thread src/version.ts
if (path.basename(versionFilePath) === '.tool-versions') {
// asdf/mise file.
const match = content.match(/^goreleaser\s+([^\n#]+)/m);
requestedVersion = match ? 'v' + match[1].trim().replace(/^v/gi, '') : '';

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

If .tool-versions doesn’t contain a goreleaser ... entry, this sets requestedVersion to an empty string, which will likely cause a confusing failure later during install. Prefer throwing a clear error when no matching entry is found (e.g., file exists but no goreleaser line), so users get an actionable message.

Suggested change
requestedVersion = match ? 'v' + match[1].trim().replace(/^v/gi, '') : '';
if (!match) {
throw new Error(
`No 'goreleaser' entry found in ${versionFilePath}. ` +
"Please add a line like 'goreleaser <version>' or specify the version input directly."
);
}
requestedVersion = 'v' + match[1].trim().replace(/^v/gi, '');

Copilot uses AI. Check for mistakes.
Comment thread src/version.ts

if (path.basename(versionFilePath) === '.tool-versions') {
// asdf/mise file.
const match = content.match(/^goreleaser\s+([^\n#]+)/m);

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

The parser requires goreleaser to start at column 0. .tool-versions files sometimes contain leading whitespace; allowing optional leading spaces (e.g., ^\\s*goreleaser\\s+... with the m flag) would make the parsing more robust without changing intended behavior.

Suggested change
const match = content.match(/^goreleaser\s+([^\n#]+)/m);
const match = content.match(/^\s*goreleaser\s+([^\n#]+)/m);

Copilot uses AI. Check for mistakes.
Comment thread __tests__/version.test.ts
expect(v).toBe('v1.2.3');
});

it('parses .tool-versions and returns v-prefixed version', () => {

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

There isn’t a test covering the case where .tool-versions exists but has no goreleaser entry (or has a malformed one). If getRequestedVersion() is updated to throw a specific error for that scenario (recommended), please add a Jest test asserting that behavior (ideally also asserting the error message).

Copilot uses AI. Check for mistakes.
Comment thread __tests__/version.test.ts
expect(v).toBe('v1.2.3');
});

it('when both version and version-file are provided, version-file takes precedence', () => {

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

There isn’t a test covering the case where .tool-versions exists but has no goreleaser entry (or has a malformed one). If getRequestedVersion() is updated to throw a specific error for that scenario (recommended), please add a Jest test asserting that behavior (ideally also asserting the error message).

Copilot uses AI. Check for mistakes.
Comment thread __tests__/version.test.ts
const v = getRequestedVersion(inputs);
expect(v).toBe('v1.2.3');
});

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

There isn’t a test covering the case where .tool-versions exists but has no goreleaser entry (or has a malformed one). If getRequestedVersion() is updated to throw a specific error for that scenario (recommended), please add a Jest test asserting that behavior (ideally also asserting the error message).

Suggested change
it('throws when .tool-versions exists but has no goreleaser entry', () => {
const toolVersionsPath = path.join(tmpDir, '.tool-versions');
fs.writeFileSync(toolVersionsPath, 'nodejs 20.0.0\n');
const inputs: Inputs = {
distribution: 'goreleaser',
version: '',
versionFile: '.tool-versions',
args: '',
workdir: tmpDir,
installOnly: false
};
expect(() => getRequestedVersion(inputs)).toThrow(/goreleaser/i);
});
it('throws when .tool-versions has a malformed goreleaser entry', () => {
const toolVersionsPath = path.join(tmpDir, '.tool-versions');
fs.writeFileSync(toolVersionsPath, 'goreleaser not-a-version\n');
const inputs: Inputs = {
distribution: 'goreleaser',
version: '',
versionFile: '.tool-versions',
args: '',
workdir: tmpDir,
installOnly: false
};
expect(() => getRequestedVersion(inputs)).toThrow(/goreleaser/i);
});

Copilot uses AI. Check for mistakes.
Comment thread __tests__/version.test.ts
expect(() => getRequestedVersion(inputs)).toThrow();
});

it('throws when version-file is an unsupported type', () => {

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

There isn’t a test covering the case where .tool-versions exists but has no goreleaser entry (or has a malformed one). If getRequestedVersion() is updated to throw a specific error for that scenario (recommended), please add a Jest test asserting that behavior (ideally also asserting the error message).

Copilot uses AI. Check for mistakes.
caarlos0 added a commit that referenced this pull request Apr 18, 2026
Resolves the GoReleaser version from a file. Currently supports the
asdf/mise `.tool-versions` format; resolved value takes precedence
over the `version` input.

  # .tool-versions
  goreleaser 2.13.0

  - uses: goreleaser/goreleaser-action@v7
    with:
      version-file: .tool-versions
      args: release --clean

Path is resolved relative to `workdir` unless absolute. Bare semvers
are auto-prefixed with `v`; constraint expressions and `latest` are
returned as-is. Multiple fallback versions per asdf convention are
accepted but only the first is used.

Refs #541
Closes #542

Co-authored-by: Anthony Couvreur <22034450+acouvreur@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@caarlos0

Copy link
Copy Markdown
Member

Hi @acouvreur — thanks a lot for this contribution! I'm taking the work over in #556 to add more test coverage and tighten parsing edge cases (inline comments, asdf fallback lists, error messages). The original feature design is preserved. Crediting you as co-author on the commit.

@caarlos0

Copy link
Copy Markdown
Member

merged in #556 - thanks!

pull Bot pushed a commit to Ausaci/goreleaser-action that referenced this pull request Apr 24, 2026
Resolves the GoReleaser version from a file. Currently supports the
asdf/mise `.tool-versions` format; resolved value takes precedence
over the `version` input.

  # .tool-versions
  goreleaser 2.13.0

  - uses: goreleaser/goreleaser-action@v7
    with:
      version-file: .tool-versions
      args: release --clean

Path is resolved relative to `workdir` unless absolute. Bare semvers
are auto-prefixed with `v`; constraint expressions and `latest` are
returned as-is. Multiple fallback versions per asdf convention are
accepted but only the first is used.

Refs goreleaser#541
Closes goreleaser#542

Co-authored-by: Anthony Couvreur <22034450+acouvreur@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Add a version file input

3 participants