Compare commits

..

22 commits

Author SHA1 Message Date
Paul Hatcherian
b1025b26f2
Merge pull request #178 from PaulHatch/conventional-commits
feat!: Change default version patterns to follow Conventional Commits
2025-10-15 06:47:03 -04:00
Paul Hatcherian
6b919cc3ae
docs: Minor updates to guide 2025-10-15 06:46:25 -04:00
Paul Hatcherian
7b71828c01
docs: Update example for monorepo in guide
#182
2025-09-06 12:18:09 +01:00
Paul Hatcherian
bdf7908364 feat!: Change default version patterns to follow Conventional Commits 2025-07-19 07:50:19 +02:00
Paul Hatcherian
305899e7da Add changelog 2025-07-10 08:21:26 +02:00
Paul Hatcherian
c4f3793c16
Merge pull request #163 from jeremybower/update-versions-to-v5.4
Update examples to v5.4.0
2024-07-19 00:38:58 +02:00
Jeremy Bower
7adc5c502c
Update examples to v5.4.0
Update contributing.md
Update readme.md
2024-07-17 17:34:11 -04:00
Paul Hatcherian
c423ebb784
Update readme.md 2024-04-17 09:37:02 +03:00
Paul Hatcherian
a8f8f59fd7 Update node/package versions (MINOR) 2024-01-31 06:52:08 -06:00
Paul Hatcherian
8c0b779a80 Fix example config 2024-01-28 07:52:38 -06:00
Paul Hatcherian
4df56d00ce Update guide 2024-01-27 23:07:44 -06:00
Paul Hatcherian
e528d273e7 Update guide + readme 2023-10-30 21:11:34 -06:00
Paul Hatcherian
23baf5d553
Update readme.md with latest version 2023-10-24 18:27:54 -06:00
Paul Hatcherian
8d3552d384 Can't default to GITHUB_REF_NAME during testing 2023-09-30 09:27:44 -04:00
Paul Hatcherian
f53462a96e Update Jest config 2023-09-30 07:28:24 -04:00
Paul Hatcherian
fce0e75dfd Update dist 2023-09-30 05:52:00 -04:00
Paul Hatcherian
ec20cad99a Ignore non-version branches, reset diagnostics between tests 2023-09-30 04:51:49 -04:00
Paul Hatcherian
cfbfddabdd Fix for bump each commit not respecting prerelease mode 2023-09-27 20:36:33 -04:00
Paul Hatcherian
61963e734d Add new branch versioning (MINOR) 2023-09-27 20:17:26 -04:00
Paul Hatcherian
d3c0da227f Update readme 2023-09-13 22:13:14 -04:00
Paul Hatcherian
0995adf892 Update contributing guide, document diagnostics mode 2023-09-13 22:07:45 -04:00
Paul Hatcherian
270924986e Update "no tags" warning to indicate if tags were found. 2023-08-26 16:21:25 -04:00
36 changed files with 3464 additions and 1436 deletions

281
CHANGELOG.md Normal file
View file

@ -0,0 +1,281 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [5.4.0] - 2024-01-31
### Changed
- Updated to Node.js v20 runtime
- Updated all dependencies to latest versions
## [5.3.0] - 2023-09-30
### Added
- **Branch-based versioning mode** (`version_from_branch` input) - Major/minor versions can now be derived from branch names (e.g., `release/v1`, `release/1.2`). Only considers tags matching the branch version, useful for maintaining multiple release lines
- Enhanced diagnostics documentation in contributing guide
- Improved warning messages to clarify when no tags are found vs when tags exist but don't match criteria
### Fixed
- `GITHUB_REF_NAME` environment variable no longer causes failures during testing
- `bump_each_commit` now properly respects `enable_prerelease_mode` setting
- Non-version branches are properly ignored when using branch-based versioning
### Changed
- Updated Jest configuration for better test isolation
- Rebuilt distribution files with latest changes
### Deprecated
- `use_branches` input is deprecated and will be removed in v6.0.0 - use `version_from_branch` instead
## [5.2.1] - 2023-08-24
### Fixed
- Diagnostic mode output was not being properly included in the action's output, preventing debugging
## [5.2.0] - 2023-08-20
### Added
- **Debug/diagnostic mode** (`debug` input) - Captures and outputs diagnostic information for troubleshooting version calculations. Useful when the source repository isn't available for direct inspection
## [5.1.0] - 2023-08-09
### Added
- **Patch pattern filtering** (`bump_each_commit_patch_pattern` input) - When using `bump_each_commit`, patch version only increments if commit matches specified pattern. Supports JavaScript regex syntax with flags (e.g., `/fix\(.*\)/i`)
- **Pre-release mode** (`enable_prerelease_mode` input) - Prevents automatic major version bumps for 0.x.x versions. When enabled, "major" changes become "minor" and "minor" become "patch", preventing premature 1.0.0 releases
- `is_tagged` output - Boolean indicating if the current commit already has a version tag
- Previous version commit information outputs (`previous_commit`, `previous_version`) for better version tracking
### Fixed
- Corrected tag ordering when determining previous version (was using reverse order incorrectly)
- Increased test timeout for Windows environments to prevent CI failures
- Fixed test failures in environments with global GPG signing enabled
- Documentation typo: "version" output name was incorrectly documented
## [5.0.3] - 2023-01-10
### Fixed
- Pre-release tags on current commit were not being handled correctly when determining version increments
- Fixed incorrect parameter name mapping that was causing action failures
### Changed
- Updated dependencies to latest versions
## [5.0.2] - 2022-12-31
### Fixed
- Build output mapping was incorrect, causing the action to fail when generating outputs
## [5.0.1] - 2022-12-27
### Fixed
- Tag prefix and namespace values are now properly escaped when constructing regex patterns, preventing regex errors with special characters
- Fixed unescaped dots in regex patterns that could cause incorrect matching
- Test suite now consistently uses 'master' as branch name to avoid CI failures
### Added
- Syntax highlighting for code examples in documentation
- Contributing.md guide for developers
- Test coverage for namespaces containing forward slashes
### Changed
- Documentation updated to reflect correct input parameter names
- Version calculation no longer limits the number of tags retrieved, ensuring accurate version determination in repos with many tags
## [5.0.0] - 2022-12-20 - Major Rewrite
### Added
- **Complete TypeScript rewrite** - Action rewritten from JavaScript to TypeScript with modular architecture
- **Author tracking** - New `authors` output lists all commit authors since last release, formatted as CSV (JSON option available via `user_format_type`)
- **Commit body searching** - `search_commit_body` input allows searching commit message bodies for version patterns, not just the subject line
- **Branch support** - Can now use branch names instead of tags for versioning with `use_branches` input
- **Improved outputs** - Additional metadata including `version_type`, commit hashes, and more detailed version information
- **Namespace support without tags** - Namespaces now work even when no existing tags match the namespace
### Fixed
- Pre-release tags (alpha, beta, rc) are now properly excluded from version calculations unless explicitly included
- Fixed issue where current commit's tag wasn't properly considered when calculating previous version
- Tag ordering now uses git's version sort instead of author date, providing more accurate version ordering
### Changed
- Architecture completely redesigned with providers, resolvers, classifiers, and formatters for better extensibility
- Short tag support has been completely removed (was deprecated in v4)
- Updated to actions/core@1.10.0 and modernized all dependencies
- Node.js 16 compatibility
## [4.0.3] - 2021-10-29
### Changed
- Version output now properly uses the user-supplied version format template combined with namespace
- Updated dependencies and improved test coverage
- Documentation clarifications for better user understanding
## [4.0.2] - 2021-04-22
### Fixed
- Tag prefixes can now contain forward slashes (e.g., `releases/v`), enabling more flexible tagging schemes
## [4.0.1] - 2021-02-25
### Fixed
- Fixed regex pattern for matching full version tags when `short_tags` is disabled
## [4.0.0] - 2021-02-08
### Changed
- **Breaking**: Branch parameter now defaults to `HEAD` instead of requiring explicit branch name
- Branch names no longer include `origin/` prefix, simplifying branch-based versioning
- Reintroduced support for using `HEAD` as branch parameter (was removed in v3)
### Deprecated
- `branch` input is now deprecated in favor of automatic HEAD detection
## [3.3.1] - 2021-01-28
### Added
- `version_tag` output now includes namespace value, making it easier to identify versioned releases in multi-project repositories
### Changed
- Improved documentation clarity for namespace feature
- Enhanced readme formatting and examples
## [3.3.0] - 2021-01-23
### Added
- **Regular expression support** for `major_pattern` and `minor_pattern` - Wrap patterns in `/` to use regex (e.g., `/breaking:\s/i`)
### Fixed
- Fixed logic that prevented version tags from being properly matched when calculating increments
## [3.2.1] - 2021-01-16
### Fixed
- Tagged commits now properly preserve their increment value instead of resetting to 0
- SVG diagrams now have proper background color for better visibility
### Changed
- Updated dependencies
- Documentation improvements
## [3.2.0] - 2020-12-20
### Added
- **`bump_each_commit` mode** - Every commit creates a new patch version, useful for continuous deployment scenarios
- **`short_tags` toggle** - When set to `false`, only full semantic version tags (e.g., v1.2.3) are considered, ignoring short tags (e.g., v1)
### Changed
- Improved documentation with visual diagrams
- Removed deprecated parameters from documentation
- Enhanced readme clarity with better examples
## [3.1.2] - 2020-10-07
### Fixed
- **Full Windows support** - Fixed line ending issues and command execution on Windows
- Action now properly exits when current commit already has a version tag
- Current commit's tag is now used as the version when applicable
### Added
- Complete Windows support in test suite with OS-specific temp directories
- Windows runner added to CI pipeline alongside Linux
### Changed
- Commands now run silently to reduce log noise
- Improved error handling for command execution failures
- Added warning about actions/checkout@v2 shallow clone behavior that can affect version detection
## [3.1.1] - 2020-09-05
### Fixed
- Change detection now works correctly when no previous tags exist in the repository
## [3.1.0] - 2020-09-05
### Added
- **`version_tag` output** - Returns the complete version tag including prefix and namespace
### Changed
- Improved logging for change detection to help with debugging
- Command execution failures are now logged as info rather than errors (they're handled gracefully)
- Updated package dependencies
## [3.0.0] - 2020-09-02 - Multi-Project Support
### Added
- **Namespace support** (`namespace` input) - Enables multiple projects/components in same repo with isolated versioning
- **Improved mono-repo support** - Each namespace maintains its own version sequence
### Changed
- **Breaking**: `change_path` input now filters which paths trigger version changes rather than just detecting changes
- Removed verbose action output for cleaner logs
- Modernized codebase and dependencies for GitHub Actions runner compatibility
### Removed
- Deprecated action inputs from v2
## [2.1.1] - 2020-02-07
### Fixed
- Release link generation now uses correct branch name format
## [2.1.0] - 2020-01-25
### Added
- **Path-based change detection** (`change_path` input) - Specify paths to monitor for changes, useful for mono-repos where not all changes should trigger version bumps
### Changed
- Release link now uses branch name from action input rather than GitHub environment variable
- Release link is now output to action logs for visibility
## [2.0.0] - 2019-12-24
### Changed
- **Breaking**: Now uses `git describe` for more reliable tag detection instead of `git log`
- Added warning when repository has no tags, helping users understand why versioning starts at 0.0.0
## [1.0.1] - 2019-12-11
### Fixed
- Empty tag prefixes are now supported (useful for repos that use plain version numbers without 'v' prefix)
### Added
- Documentation for `version_format` input parameter
## [1.0.0] - 2019-12-11 - Initial Release
### Added
- Automatic semantic versioning based on git commit history
- Version bumping through commit message markers: `(MAJOR)` and `(MINOR)`
- Customizable version output format via `version_format` input
- Support for both short (v1) and full (v1.0.0) version tags
- Increment counter for commits since last version tag
- No manual version maintenance required - fully automated from git history
[5.4.0]: https://github.com/PaulHatch/semantic-version/compare/v5.3.0...v5.4.0
[5.3.0]: https://github.com/PaulHatch/semantic-version/compare/v5.2.1...v5.3.0
[5.2.1]: https://github.com/PaulHatch/semantic-version/compare/v5.2.0...v5.2.1
[5.2.0]: https://github.com/PaulHatch/semantic-version/compare/v5.1.0...v5.2.0
[5.1.0]: https://github.com/PaulHatch/semantic-version/compare/v5.0.3...v5.1.0
[5.0.3]: https://github.com/PaulHatch/semantic-version/compare/v5.0.2...v5.0.3
[5.0.2]: https://github.com/PaulHatch/semantic-version/compare/v5.0.1...v5.0.2
[5.0.1]: https://github.com/PaulHatch/semantic-version/compare/v5.0.0...v5.0.1
[5.0.0]: https://github.com/PaulHatch/semantic-version/compare/v4.0.3...v5.0.0
[4.0.3]: https://github.com/PaulHatch/semantic-version/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/PaulHatch/semantic-version/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/PaulHatch/semantic-version/compare/v4...v4.0.1
[4.0.0]: https://github.com/PaulHatch/semantic-version/compare/v3.3.1...v4
[3.3.1]: https://github.com/PaulHatch/semantic-version/compare/v3.3...v3.3.1
[3.3.0]: https://github.com/PaulHatch/semantic-version/compare/v3.2.1...v3.3
[3.2.1]: https://github.com/PaulHatch/semantic-version/compare/v3.2...v3.2.1
[3.2.0]: https://github.com/PaulHatch/semantic-version/compare/v3.1.2...v3.2
[3.1.2]: https://github.com/PaulHatch/semantic-version/compare/v3.1.1...v3.1.2
[3.1.1]: https://github.com/PaulHatch/semantic-version/compare/v3.1...v3.1.1
[3.1.0]: https://github.com/PaulHatch/semantic-version/compare/v3...v3.1
[3.0.0]: https://github.com/PaulHatch/semantic-version/compare/v2.1.1...v3
[2.1.1]: https://github.com/PaulHatch/semantic-version/compare/v2.1...v2.1.1
[2.1.0]: https://github.com/PaulHatch/semantic-version/compare/v2...v2.1
[2.0.0]: https://github.com/PaulHatch/semantic-version/compare/v1.0.1...v2
[1.0.1]: https://github.com/PaulHatch/semantic-version/compare/v1...v1.0.1
[1.0.0]: https://github.com/PaulHatch/semantic-version/releases/tag/v1

View file

@ -13,13 +13,17 @@ inputs:
required: false required: false
default: "v" default: "v"
use_branches: use_branches:
description: "Use branches instead of tags" description: "(Deprecated) Use branches instead of tags"
required: false
default: "false"
version_from_branch:
description: If true, the branch will be used to select the maximum version
required: false required: false
default: "false" default: "false"
major_pattern: major_pattern:
description: "A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression." description: "A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression."
required: true required: true
default: "(MAJOR)" default: "/!:|BREAKING CHANGE:/"
major_regexp_flags: major_regexp_flags:
description: "A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs" description: "A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs"
required: false required: false
@ -27,7 +31,7 @@ inputs:
minor_pattern: minor_pattern:
description: "A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression." description: "A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression."
required: true required: true
default: "(MINOR)" default: "/feat:/"
minor_regexp_flags: minor_regexp_flags:
description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs" description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs"
required: false required: false
@ -97,5 +101,5 @@ outputs:
description: "Diagnostic information, if debug is enabled" description: "Diagnostic information, if debug is enabled"
runs: runs:
using: "node16" using: "node20"
main: "dist/index.js" main: "dist/index.js"

View file

@ -10,9 +10,34 @@ Fixes and enhancements are welcome, but if you are planning to do a lot of work,
## Getting Help ## Getting Help
If you have found or believe you have found a bug please open a ticket. If you are having trouble using the action and need help please use the discussions page.
Since nearly all questions are related to a specific repository it can be difficult to diagnose issues from a description alone. There are a few ways to provide additional information that can help diagnose the problem.
### Creating Diagnostic Information
There is a debug option which produces diagnostic information. This information can be used to troubleshoot and even to rerun the action without access to the original repository, for example with a debugger attached. To enable this option set the `debug` input to `true` and then use the `debug_output` output to access the information. The following configuration will print the debug output to the console:
```
- name: Version
uses: paulhatch/semantic-version@v5.4.0
id: version
with:
tag_prefix: ""
version_format: "${major}.${minor}.${patch}.${increment}"
debug: true
- name: Print Diagnostic Output
run: echo "$DEBUG_OUTPUT"
env:
DEBUG_OUTPUT: ${{ steps.version.outputs.debug_output }}
```
Please review the information before posting it to avoid disclosing any sensitive information. In particular the output may contain names and email addresses of the committers, as well as commit messages for recent commits.
### Providing a Test Case ### Providing a Test Case
If you are planning to open a ticket, it is extremely helpful if you can provide a test case that demonstrates the problem. This project includes a test helper than makes it very easy to create new tests with just a few lines of code. If you are planning to open a ticket or post to discussions, it is extremely helpful if you can provide a test case that demonstrates the problem. This project includes a test helper than makes it very easy to create new tests with just a few lines of code.
To get started simply: To get started simply:

340
dist/index.js vendored
View file

@ -43,8 +43,8 @@ exports.cmd = void 0;
// Using require instead of import to support integration testing // Using require instead of import to support integration testing
const exec = __importStar(__nccwpck_require__(1514)); const exec = __importStar(__nccwpck_require__(1514));
const DebugManager_1 = __nccwpck_require__(1823); const DebugManager_1 = __nccwpck_require__(1823);
const debugManager = DebugManager_1.DebugManager.getInstance();
const cmd = (command, ...args) => __awaiter(void 0, void 0, void 0, function* () { const cmd = (command, ...args) => __awaiter(void 0, void 0, void 0, function* () {
const debugManager = DebugManager_1.DebugManager.getInstance();
if (debugManager.isReplayMode()) { if (debugManager.isReplayMode()) {
return debugManager.replayCommand(command, args); return debugManager.replayCommand(command, args);
} }
@ -81,6 +81,7 @@ exports.cmd = cmd;
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ConfigurationProvider = void 0; exports.ConfigurationProvider = void 0;
const CsvUserFormatter_1 = __nccwpck_require__(9105); const CsvUserFormatter_1 = __nccwpck_require__(9105);
const BranchVersioningTagFormatter_1 = __nccwpck_require__(807);
const DefaultTagFormatter_1 = __nccwpck_require__(4808); const DefaultTagFormatter_1 = __nccwpck_require__(4808);
const DefaultVersionFormatter_1 = __nccwpck_require__(8524); const DefaultVersionFormatter_1 = __nccwpck_require__(8524);
const JsonUserFormatter_1 = __nccwpck_require__(7892); const JsonUserFormatter_1 = __nccwpck_require__(7892);
@ -105,7 +106,12 @@ class ConfigurationProvider {
return new DefaultVersionClassifier_1.DefaultVersionClassifier(this.config); return new DefaultVersionClassifier_1.DefaultVersionClassifier(this.config);
} }
GetVersionFormatter() { return new DefaultVersionFormatter_1.DefaultVersionFormatter(this.config); } GetVersionFormatter() { return new DefaultVersionFormatter_1.DefaultVersionFormatter(this.config); }
GetTagFormatter() { return new DefaultTagFormatter_1.DefaultTagFormatter(this.config); } GetTagFormatter(branchName) {
if (this.config.versionFromBranch) {
return new BranchVersioningTagFormatter_1.BranchVersioningTagFormatter(this.config, branchName);
}
return new DefaultTagFormatter_1.DefaultTagFormatter(this.config);
}
GetUserFormatter() { GetUserFormatter() {
switch (this.config.userFormatType) { switch (this.config.userFormatType) {
case 'json': return new JsonUserFormatter_1.JsonUserFormatter(this.config); case 'json': return new JsonUserFormatter_1.JsonUserFormatter(this.config);
@ -141,6 +147,10 @@ class DebugManager {
} }
return DebugManager.instance; return DebugManager.instance;
} }
/** Clears the singleton instance of the DebugManager (used for testing) */
static clearState() {
DebugManager.instance = new DebugManager();
}
/** Returns true if debug mode is enabled */ /** Returns true if debug mode is enabled */
isDebugEnabled() { isDebugEnabled() {
return this.debugEnabled; return this.debugEnabled;
@ -300,12 +310,12 @@ function runAction(configurationProvider) {
const commitsProvider = configurationProvider.GetCommitsProvider(); const commitsProvider = configurationProvider.GetCommitsProvider();
const versionClassifier = configurationProvider.GetVersionClassifier(); const versionClassifier = configurationProvider.GetVersionClassifier();
const versionFormatter = configurationProvider.GetVersionFormatter(); const versionFormatter = configurationProvider.GetVersionFormatter();
const tagFormatter = configurationProvider.GetTagFormatter(); const tagFormatter = configurationProvider.GetTagFormatter(yield currentCommitResolver.ResolveBranchNameAsync());
const userFormatter = configurationProvider.GetUserFormatter(); const userFormatter = configurationProvider.GetUserFormatter();
const debugManager = DebugManager_1.DebugManager.getInstance(); const debugManager = DebugManager_1.DebugManager.getInstance();
if (yield currentCommitResolver.IsEmptyRepoAsync()) { if (yield currentCommitResolver.IsEmptyRepoAsync()) {
const versionInfo = new VersionInformation_1.VersionInformation(0, 0, 0, 0, VersionType_1.VersionType.None, [], false, false); const versionInfo = new VersionInformation_1.VersionInformation(0, 0, 0, 0, VersionType_1.VersionType.None, [], false, false);
return new VersionResult_1.VersionResult(versionInfo.major, versionInfo.minor, versionInfo.patch, versionInfo.increment, versionInfo.type, versionFormatter.Format(versionInfo), tagFormatter.Format(versionInfo), versionInfo.changed, versionInfo.isTagged, userFormatter.Format('author', []), '', '', '0.0.0', debugManager.getDebugOutput(true)); return new VersionResult_1.VersionResult(versionInfo.major, versionInfo.minor, versionInfo.patch, versionInfo.increment, versionInfo.type, versionFormatter.Format(versionInfo), tagFormatter.Format(versionInfo), versionInfo.changed, versionInfo.isTagged, userFormatter.Format('author', []), '', '', tagFormatter.Parse(tagFormatter.Format(versionInfo)).join('.'), debugManager.getDebugOutput(true));
} }
const currentCommit = yield currentCommitResolver.ResolveAsync(); const currentCommit = yield currentCommitResolver.ResolveAsync();
const lastRelease = yield lastReleaseResolver.ResolveAsync(currentCommit, tagFormatter); const lastRelease = yield lastReleaseResolver.ResolveAsync(currentCommit, tagFormatter);
@ -333,6 +343,101 @@ function runAction(configurationProvider) {
exports.runAction = runAction; exports.runAction = runAction;
/***/ }),
/***/ 807:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.BranchVersioningTagFormatter = void 0;
const DefaultTagFormatter_1 = __nccwpck_require__(4808);
/** Default tag formatter which allows a prefix to be specified */
class BranchVersioningTagFormatter extends DefaultTagFormatter_1.DefaultTagFormatter {
getRegex(pattern) {
if (/^\/.+\/[i]*$/.test(pattern)) {
const regexEnd = pattern.lastIndexOf('/');
const parsedFlags = pattern.slice(pattern.lastIndexOf('/') + 1);
return new RegExp(pattern.slice(1, regexEnd), parsedFlags);
}
return new RegExp(pattern);
}
constructor(config, branchName) {
super(config);
const pattern = config.versionFromBranch === true ?
new RegExp("[0-9]+.[0-9]+$|[0-9]+$") :
this.getRegex(config.versionFromBranch);
const result = pattern.exec(branchName);
if (result === null) {
this.major = NaN;
this.onVersionBranch = false;
return;
}
let branchVersion;
switch (result === null || result === void 0 ? void 0 : result.length) {
case 1:
branchVersion = result[0];
break;
case 2:
branchVersion = result[1];
break;
default:
throw new Error(`Unable to parse version from branch named '${branchName}' using pattern '${pattern}'`);
}
this.onVersionBranch = true;
const versionValues = branchVersion.split('.');
if (versionValues.length > 2) {
throw new Error(`The version string '${branchVersion}' parsed from branch '${branchName}' is invalid. It must be in the format 'major.minor' or 'major'`);
}
this.major = parseInt(versionValues[0]);
if (isNaN(this.major)) {
throw new Error(`The major version '${versionValues[0]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
if (versionValues.length > 1) {
this.minor = parseInt(versionValues[1]);
if (isNaN(this.minor)) {
throw new Error(`The minor version '${versionValues[1]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
}
}
GetPattern() {
let pattern = super.GetPattern();
if (!this.onVersionBranch) {
return pattern;
}
if (this.minor === undefined) {
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.*[0-9].*[0-9]`);
}
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.${this.minor}.*[0-9]`);
}
IsValid(tag) {
if (!this.onVersionBranch) {
return super.IsValid(tag);
}
if (!super.IsValid(tag)) {
return false;
}
const parsed = super.Parse(tag);
if (parsed[0] !== this.major) {
return false;
}
if (this.minor !== undefined && parsed[1] !== this.minor) {
return false;
}
return true;
}
Parse(tag) {
if (!this.onVersionBranch) {
return super.Parse(tag);
}
const parsed = super.Parse(tag);
return [this.major, this.minor || parsed[1], parsed[2]];
}
}
exports.BranchVersioningTagFormatter = BranchVersioningTagFormatter;
/***/ }), /***/ }),
/***/ 9105: /***/ 9105:
@ -383,6 +488,9 @@ class DefaultTagFormatter {
return `${this.tagPrefix}*[0-9].*[0-9].*[0-9]`; return `${this.tagPrefix}*[0-9].*[0-9].*[0-9]`;
} }
Parse(tag) { Parse(tag) {
if (tag === '') {
return [0, 0, 0];
}
let tagParts = tag let tagParts = tag
.replace(this.tagPrefix, '<--!PREFIX!-->') .replace(this.tagPrefix, '<--!PREFIX!-->')
.replace(this.namespace, '<--!NAMESPACE!-->') .replace(this.namespace, '<--!NAMESPACE!-->')
@ -534,10 +642,29 @@ function setOutput(versionResult) {
} }
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
function toBool(value) {
if (!value || value.toLowerCase() === 'false') {
return false;
}
else if (value.toLowerCase() === 'true') {
return true;
}
return false;
}
function toStringOrBool(value) {
if (!value || value === 'false') {
return false;
}
if (value === 'true') {
return true;
}
return value;
}
const config = { const config = {
branch: core.getInput('branch'), branch: core.getInput('branch'),
tagPrefix: core.getInput('tag_prefix'), tagPrefix: core.getInput('tag_prefix'),
useBranches: core.getInput('use_branches') === 'true', useBranches: toBool(core.getInput('use_branches')),
versionFromBranch: toStringOrBool(core.getInput('version_from_branch')),
majorPattern: core.getInput('major_pattern'), majorPattern: core.getInput('major_pattern'),
minorPattern: core.getInput('minor_pattern'), minorPattern: core.getInput('minor_pattern'),
majorFlags: core.getInput('major_regexp_flags'), majorFlags: core.getInput('major_regexp_flags'),
@ -545,14 +672,17 @@ function run() {
versionFormat: core.getInput('version_format'), versionFormat: core.getInput('version_format'),
changePath: core.getInput('change_path'), changePath: core.getInput('change_path'),
namespace: core.getInput('namespace'), namespace: core.getInput('namespace'),
bumpEachCommit: core.getInput('bump_each_commit') === 'true', bumpEachCommit: toBool(core.getInput('bump_each_commit')),
searchCommitBody: core.getInput('search_commit_body') === 'true', searchCommitBody: toBool(core.getInput('search_commit_body')),
userFormatType: core.getInput('user_format_type'), userFormatType: core.getInput('user_format_type'),
enablePrereleaseMode: core.getInput('enable_prerelease_mode') === 'true', enablePrereleaseMode: toBool(core.getInput('enable_prerelease_mode')),
bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'), bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'),
debug: core.getInput('debug') === 'true', debug: toBool(core.getInput('debug')),
replay: '' replay: ''
}; };
if (config.useBranches) {
core.warning(`The 'use_branches' input option is deprecated, please see the documentation for more information on how to use branches`);
}
if (config.versionFormat === '' && core.getInput('format') !== '') { if (config.versionFormat === '' && core.getInput('format') !== '') {
core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`); core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`);
config.versionFormat = core.getInput('format'); config.versionFormat = core.getInput('format');
@ -593,6 +723,7 @@ const VersionType_1 = __nccwpck_require__(895);
class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVersionClassifier { class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVersionClassifier {
constructor(config) { constructor(config) {
super(config); super(config);
this.enablePrereleaseMode = config.enablePrereleaseMode;
this.patchPattern = !config.bumpEachCommitPatchPattern ? this.patchPattern = !config.bumpEachCommitPatchPattern ?
_ => true : _ => true :
this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody); this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody);
@ -610,28 +741,54 @@ class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVers
} }
for (let commit of commitSet.commits.reverse()) { for (let commit of commitSet.commits.reverse()) {
if (this.majorPattern(commit)) { if (this.majorPattern(commit)) {
major += 1;
minor = 0;
patch = 0;
type = VersionType_1.VersionType.Major; type = VersionType_1.VersionType.Major;
increment = 0;
} }
else if (this.minorPattern(commit)) { else if (this.minorPattern(commit)) {
minor += 1;
patch = 0;
type = VersionType_1.VersionType.Minor; type = VersionType_1.VersionType.Minor;
increment = 0;
} }
else { else if (this.patchPattern(commit) ||
if (this.patchPattern(commit) ||
(major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) { (major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) {
patch += 1;
type = VersionType_1.VersionType.Patch; type = VersionType_1.VersionType.Patch;
increment = 0;
} }
else { else {
type = VersionType_1.VersionType.None; type = VersionType_1.VersionType.None;
}
if (this.enablePrereleaseMode && major === 0) {
switch (type) {
case VersionType_1.VersionType.Major:
case VersionType_1.VersionType.Minor:
minor += 1;
patch = 0;
increment = 0;
break;
case VersionType_1.VersionType.Patch:
patch += 1;
increment = 0;
break;
default:
increment++; increment++;
break;
}
}
else {
switch (type) {
case VersionType_1.VersionType.Major:
major += 1;
minor = 0;
patch = 0;
increment = 0;
break;
case VersionType_1.VersionType.Minor:
minor += 1;
patch = 0;
break;
case VersionType_1.VersionType.Patch:
patch += 1;
increment = 0;
break;
default:
increment++;
break;
} }
} }
} }
@ -825,6 +982,12 @@ class DefaultCurrentCommitResolver {
return lastCommitAll === ''; return lastCommitAll === '';
}); });
} }
ResolveBranchNameAsync() {
return __awaiter(this, void 0, void 0, function* () {
const branchName = this.branch == 'HEAD' ? yield (0, CommandRunner_1.cmd)('git', 'rev-parse', '--abbrev-ref', 'HEAD') : this.branch;
return branchName.trim();
});
}
} }
exports.DefaultCurrentCommitResolver = DefaultCurrentCommitResolver; exports.DefaultCurrentCommitResolver = DefaultCurrentCommitResolver;
@ -885,6 +1048,7 @@ class DefaultLastReleaseResolver {
currentTag = tagFormatter.IsValid(currentTag) ? currentTag : ''; currentTag = tagFormatter.IsValid(currentTag) ? currentTag : '';
const isTagged = currentTag !== ''; const isTagged = currentTag !== '';
const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null]; const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null];
let tagsCount = 0;
let tag = ''; let tag = '';
try { try {
const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/'; const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/';
@ -892,16 +1056,16 @@ class DefaultLastReleaseResolver {
// If we already have the current branch tagged, we are checking for the previous one // If we already have the current branch tagged, we are checking for the previous one
// so that we will have an accurate increment (assuming the new tag is the expected one) // so that we will have an accurate increment (assuming the new tag is the expected one)
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
tag = yield (0, CommandRunner_1.cmd)(command); const tags = (yield (0, CommandRunner_1.cmd)(command)).split('\n');
tag = tag tagsCount = tags.length;
.split('\n') tag = tags
.find(t => tagFormatter.IsValid(t) && t !== currentTag) || ''; .find(t => tagFormatter.IsValid(t) && t !== currentTag) || '';
} }
else { else {
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
let tags = yield (0, CommandRunner_1.cmd)(command); const tags = (yield (0, CommandRunner_1.cmd)(command)).split('\n');
tagsCount = tags.length;
tag = tags tag = tags
.split('\n')
.find(t => tagFormatter.IsValid(t)) || ''; .find(t => tagFormatter.IsValid(t)) || '';
} }
tag = tag.trim(); tag = tag.trim();
@ -914,10 +1078,16 @@ class DefaultLastReleaseResolver {
// Since there is no remote, we assume that there are no other tags to pull. In // Since there is no remote, we assume that there are no other tags to pull. In
// practice this isn't likely to happen, but it keeps the test output from being // practice this isn't likely to happen, but it keeps the test output from being
// polluted with a bunch of warnings. // polluted with a bunch of warnings.
if (tagsCount > 0) {
core.warning(`None of the ${tagsCount} tags(s) found were valid version tags for the present configuration. If this is unexpected, check to ensure that the configuration is correct and matches the tag format you are using.`);
}
else {
core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.'); core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.');
} }
}
const [major, minor, patch] = tagFormatter.Parse('');
// no release tags yet, use the initial commit as the root // no release tags yet, use the initial commit as the root
return new ReleaseInformation_1.ReleaseInformation(0, 0, 0, '', currentMajor, currentMinor, currentPatch, isTagged); return new ReleaseInformation_1.ReleaseInformation(major, minor, patch, '', currentMajor, currentMinor, currentPatch, isTagged);
} }
// parse the version tag // parse the version tag
const [major, minor, patch] = tagFormatter.Parse(tag); const [major, minor, patch] = tagFormatter.Parse(tag);
@ -1033,8 +1203,8 @@ class DefaultVersionClassifier {
// - commit 3 was tagged v2.0.0 - v2.0.0+0 // - commit 3 was tagged v2.0.0 - v2.0.0+0
// - commit 4 - v2.0.1+0 // - commit 4 - v2.0.1+0
const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch; const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch;
const currentIncremement = versionsMatch ? increment : 0; const currentIncrement = versionsMatch ? increment : 0;
return new VersionClassification_1.VersionClassification(VersionType_1.VersionType.None, currentIncremement, false, lastRelease.currentMajor, lastRelease.currentMinor, lastRelease.currentPatch); return new VersionClassification_1.VersionClassification(VersionType_1.VersionType.None, currentIncrement, false, lastRelease.currentMajor, lastRelease.currentMinor, lastRelease.currentPatch);
} }
return new VersionClassification_1.VersionClassification(type, increment, changed, major, minor, patch); return new VersionClassification_1.VersionClassification(type, increment, changed, major, minor, patch);
}); });
@ -1196,7 +1366,7 @@ var VersionType;
VersionType["Patch"] = "Patch"; VersionType["Patch"] = "Patch";
/** Indicates no change--generally this means that the current commit is already tagged with a version */ /** Indicates no change--generally this means that the current commit is already tagged with a version */
VersionType["None"] = "None"; VersionType["None"] = "None";
})(VersionType = exports.VersionType || (exports.VersionType = {})); })(VersionType || (exports.VersionType = VersionType = {}));
/***/ }), /***/ }),
@ -1758,7 +1928,7 @@ class OidcClient {
.catch(error => { .catch(error => {
throw new Error(`Failed to get ID Token. \n throw new Error(`Failed to get ID Token. \n
Error Code : ${error.statusCode}\n Error Code : ${error.statusCode}\n
Error Message: ${error.result.message}`); Error Message: ${error.message}`);
}); });
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
if (!id_token) { if (!id_token) {
@ -3146,6 +3316,19 @@ class HttpClientResponse {
})); }));
}); });
} }
readBodyBuffer() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
const chunks = [];
this.message.on('data', (chunk) => {
chunks.push(chunk);
});
this.message.on('end', () => {
resolve(Buffer.concat(chunks));
});
}));
});
}
} }
exports.HttpClientResponse = HttpClientResponse; exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) { function isHttps(requestUrl) {
@ -3650,8 +3833,14 @@ function getProxyUrl(reqUrl) {
} }
})(); })();
if (proxyVar) { if (proxyVar) {
try {
return new URL(proxyVar); return new URL(proxyVar);
} }
catch (_a) {
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
return new URL(`http://${proxyVar}`);
}
}
else { else {
return undefined; return undefined;
} }
@ -3661,6 +3850,10 @@ function checkBypass(reqUrl) {
if (!reqUrl.hostname) { if (!reqUrl.hostname) {
return false; return false;
} }
const reqHost = reqUrl.hostname;
if (isLoopbackAddress(reqHost)) {
return true;
}
const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) { if (!noProxy) {
return false; return false;
@ -3686,13 +3879,24 @@ function checkBypass(reqUrl) {
.split(',') .split(',')
.map(x => x.trim().toUpperCase()) .map(x => x.trim().toUpperCase())
.filter(x => x)) { .filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) { if (upperNoProxyItem === '*' ||
upperReqHosts.some(x => x === upperNoProxyItem ||
x.endsWith(`.${upperNoProxyItem}`) ||
(upperNoProxyItem.startsWith('.') &&
x.endsWith(`${upperNoProxyItem}`)))) {
return true; return true;
} }
} }
return false; return false;
} }
exports.checkBypass = checkBypass; exports.checkBypass = checkBypass;
function isLoopbackAddress(host) {
const hostLower = host.toLowerCase();
return (hostLower === 'localhost' ||
hostLower.startsWith('127.') ||
hostLower.startsWith('[::1]') ||
hostLower.startsWith('[0:0:0:0:0:0:0:1]'));
}
//# sourceMappingURL=proxy.js.map //# sourceMappingURL=proxy.js.map
/***/ }), /***/ }),
@ -3732,11 +3936,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}; };
var _a; var _a;
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rename = exports.readlink = exports.readdir = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0;
const fs = __importStar(__nccwpck_require__(7147)); const fs = __importStar(__nccwpck_require__(7147));
const path = __importStar(__nccwpck_require__(1017)); const path = __importStar(__nccwpck_require__(1017));
_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; _a = fs.promises
// export const {open} = 'fs'
, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
// export const {open} = 'fs'
exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_WINDOWS = process.platform === 'win32';
// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691
exports.UV_FS_O_EXLOCK = 0x10000000;
exports.READONLY = fs.constants.O_RDONLY;
function exists(fsPath) { function exists(fsPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
@ -3917,12 +4127,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
const assert_1 = __nccwpck_require__(9491); const assert_1 = __nccwpck_require__(9491);
const childProcess = __importStar(__nccwpck_require__(2081));
const path = __importStar(__nccwpck_require__(1017)); const path = __importStar(__nccwpck_require__(1017));
const util_1 = __nccwpck_require__(3837);
const ioUtil = __importStar(__nccwpck_require__(1962)); const ioUtil = __importStar(__nccwpck_require__(1962));
const exec = util_1.promisify(childProcess.exec);
const execFile = util_1.promisify(childProcess.execFile);
/** /**
* Copies a file or folder. * Copies a file or folder.
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
@ -4003,61 +4209,23 @@ exports.mv = mv;
function rmRF(inputPath) { function rmRF(inputPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (ioUtil.IS_WINDOWS) { if (ioUtil.IS_WINDOWS) {
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
// Check for invalid characters // Check for invalid characters
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
if (/[*"<>|]/.test(inputPath)) { if (/[*"<>|]/.test(inputPath)) {
throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows'); throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows');
} }
}
try { try {
const cmdPath = ioUtil.getCmdPath(); // note if path does not exist, error is silent
if (yield ioUtil.isDirectory(inputPath, true)) { yield ioUtil.rm(inputPath, {
yield exec(`${cmdPath} /s /c "rd /s /q "%inputPath%""`, { force: true,
env: { inputPath } maxRetries: 3,
recursive: true,
retryDelay: 300
}); });
} }
else {
yield exec(`${cmdPath} /s /c "del /f /a "%inputPath%""`, {
env: { inputPath }
});
}
}
catch (err) { catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved throw new Error(`File was unable to be removed ${err}`);
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
}
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
try {
yield ioUtil.unlink(inputPath);
}
catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
}
}
else {
let isDir = false;
try {
isDir = yield ioUtil.isDirectory(inputPath);
}
catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
return;
}
if (isDir) {
yield execFile(`rm`, [`-rf`, `${inputPath}`]);
}
else {
yield ioUtil.unlink(inputPath);
}
} }
}); });
} }
@ -4707,7 +4875,7 @@ exports["default"] = _default;
/***/ }), /***/ }),
/***/ 807: /***/ 8292:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
"use strict"; "use strict";
@ -4825,7 +4993,7 @@ Object.defineProperty(exports, "__esModule", ({
})); }));
exports["default"] = void 0; exports["default"] = void 0;
var _rng = _interopRequireDefault(__nccwpck_require__(807)); var _rng = _interopRequireDefault(__nccwpck_require__(8292));
var _stringify = _interopRequireDefault(__nccwpck_require__(8950)); var _stringify = _interopRequireDefault(__nccwpck_require__(8950));
@ -5047,7 +5215,7 @@ Object.defineProperty(exports, "__esModule", ({
})); }));
exports["default"] = void 0; exports["default"] = void 0;
var _rng = _interopRequireDefault(__nccwpck_require__(807)); var _rng = _interopRequireDefault(__nccwpck_require__(8292));
var _stringify = _interopRequireDefault(__nccwpck_require__(8950)); var _stringify = _interopRequireDefault(__nccwpck_require__(8950));

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -1,15 +1,21 @@
# Configuration Guide # Configuration Guide
WIP
## Choosing a Release Strategy ## Choosing a Release Strategy
This section is designed to help you choose a release strategy for your project and help you configure GitHub Workflow to use that strategy. It is organized starting from the most simple with each strategy supporting more complex needs, allowing you to start at the top and continue until you find the simplest strategy that meets your needs. This section is designed to help you choose a release strategy for your project and help you configure GitHub Workflow to use that strategy. It is organized starting from the most simple with each strategy supporting more complex needs, allowing you to start at the top and continue until you find the simplest strategy that meets your needs.
Note that in the examples given `latest` is used, but you will likely want to pin your version to a specific version.
### Increment Every Release ### Increment Every Release
If your project has no gating requirements and you want to release every time a commit is pushed to the default branch, you can use the _Increment Every Release_ strategy. This may be appropriate for documentation projects, very small projects, or in cases where "shipping" a broken version isn't a big deal. The key limitation of this strategy is that once you push a commit, the version is going to increments no matter what. If you push a version and your build or automated tests fail, you'll have a version that is broken and you'll have to increment the version again to fix it. If your project has no gating requirements and you want to release every time a commit is pushed to the default branch, you can use the _Increment Every Release_ strategy. This may be appropriate for documentation projects, very small projects, or in cases where "shipping" a broken version isn't a big deal. The key limitation of this strategy is that once you push a commit, the version is going to increments no matter what. If you push a version and your build or automated tests fail, you'll have a version that is broken and you'll have to increment the version again to fix it.
```yaml
- uses: paulhatch/semantic-version@latest
with:
bump_each_commit: true
```
### Increment from Commit Message ### Increment from Commit Message
Very similar to the strategy above, using the _Increment from Commit Message_ means that you are making the decision to increment the version at the time you commit the code, however by using the `bump_each_commit_patch_pattern` parameter introduced in v5.1.0, you can prevent the version from incrementing for a commit unless it matches one of the patters (major, minor, or patch). Very similar to the strategy above, using the _Increment from Commit Message_ means that you are making the decision to increment the version at the time you commit the code, however by using the `bump_each_commit_patch_pattern` parameter introduced in v5.1.0, you can prevent the version from incrementing for a commit unless it matches one of the patters (major, minor, or patch).
@ -18,24 +24,83 @@ Compared to the _Increment Every Release_ strategy, this strategy allows you to
On the other hand, if you have a fast deployment strategy, such as "every commit goes to prod" and don't mind versions being created for failed builds, this may be the right choice. On the other hand, if you have a fast deployment strategy, such as "every commit goes to prod" and don't mind versions being created for failed builds, this may be the right choice.
```yaml
- uses: paulhatch/semantic-version@latest
with:
bump_each_commit: true
bump_each_commit_patch_pattern: "(PATCH)"
```
### Tag Versioning ### Tag Versioning
This strategy is the most common and is the best option for many projects. It allows you to make the decision to release a version after the build has run, which is essentially the primary motivation and main purpose for this action. This strategy is the most common and is the best option for many projects. It allows you to make the decision to release a version after the build has run, which is essentially the primary motivation and main purpose for this action.
The only real limitation of this strategy is that it does not allow for multiple versions to receive ongoing updates, which may be necessary for certain types of projects which are distributed and receive ongoing maintenance of older versions. This is in contrast to projects that are developed only for a single deployment and are not distributed. The only real limitation of this strategy is that it does not allow for multiple versions to receive ongoing updates, which may be necessary for certain types of projects which are distributed and receive ongoing maintenance of older versions. This is in contrast to projects that are developed only for a single deployment and are not distributed.
Tags should generally not be created automatically as part of the build, which can cause strange behavior unless you've taken care to prevent race conditions. Creating tags automatically also largely negates the purpose of this strategy as only build automated test. Tags should generally not be created automatically as part of the build, which can cause strange behavior unless you've taken care to prevent race conditions. Creating tags automatically also largely negates the purpose of this strategy.
> Remaining strategies are still a work in progress. _This is the default behavior, so no special options are required._
## Branch Versioning ```yaml
- uses: paulhatch/semantic-version@latest
Moving past tag versioning is where things get a little more complicated, as there are many different ways to version branches. ```
### Version Branches with Tag Versioning
### Version from Branch Name (Non-Predictive)
### Version from Branch Name (Predictive)
## Branch Versioning: GitFlow
### Branch + Tag Versioning
So far all the options considered have assumed that a single, ever incrementing version is being released, and that once a new major or minor version is tagged no further updates are made for previous versions. This is appropriate for many projects such as web applications and most libraries, however if you need to support on-going update to multiple major or major+minor versions, using only the approaches above can lead to problems if you are merging updates into multiple branches, as any tags may be picked up and cause the version of an older branch to unexpectedly jump.
To accomplish this, we can enable the `version_from_branch`, which will cause the major and optionally the minor version to be taken from the current branch name rather than the tag, and to filter out tags that do not begin with the same version number(s). The `version_from_branch` input can be either a boolean or a regex string to be used to identify the version from the branch name. By default this will be `[0-9]+.[0-9]+$|[0-9]+$` e.g. match the final number or pair of numbers separated by a `.`. This default is probably appropriate for the majority of cases as it will match any prefix, for example branches named:
- `release/v1`
- `release/v1.2`
- `v1`
- `v1.2`
- `1`
- `1.2`
Note that when using this strategy you should always tag at the same time as the branch is created to ensure that the increment value is correct.
```yaml
- uses: paulhatch/semantic-version@latest
with:
version_from_branch: true
```
Alternately, you can override the branch pattern.
```yaml
- uses: paulhatch/semantic-version@latest
with:
version_from_branch: "/v([0-9]+.[0-9]+$|[0-9]+)$/"
```
## Namespace Services / "Monorepo" Support
If your project contains multiple services which you wish to version independently, you can use the `namespace` and `change_path` inputs to provide a version for a specific service which increments only when a file in the specified path is changed. (Or, if you are only build on push/pull requests you can just use the GitHub Action's [`paths`/`paths-ignore`](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onpushpull_requestpull_request_targetpathspaths-ignore) feature to block the trigger itself and run the workflow only when files in a specific path are changed. In contrast this method will also work on other triggers like `workflow_dispatch`.)
```yaml
- id: version
uses: paulhatch/semantic-version@latest
with:
change_path: "src/my-service"
namespace: my-service
- name: Cancel if Unchanged
if: ${{ ! fromJSON(steps.version.outputs.changed) }}
run: |
gh run cancel ${{ github.run_id }}
gh run watch ${{ github.run_id }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## Additional Configuration
| Value | Description |
| --- | --- |
| `tag_prefix` | The prefix to use for the tag. Defaults to `v`, generally you will use either `v` or an empty string. Note that the tag format is distinct from the version. Tags used for versioning must always follow the pattern `{tag_prefix}{major}.{minor}.{patch}` with and optional `-{namespace}` suffix. |
| `major_pattern` and `minor_pattern` | These strings are used to determine the type of version to create. If any commit message since matches the `major_pattern` the major version will be incremented, if it matches the `minor_pattern` the minor version will be incremented. If neither pattern matches, the patch version will be incremented. These can be specified either as strings or as regular expression by wrapping the expression in `/`. The defaults follow [Conventional Commits](https://www.conventionalcommits.org/): `/!:|BREAKING CHANGE:/` for major and `/feat:/` for minor. |
| `version_format` | A value such as `${major}.${minor}.${patch}-prerelease${increment}` that will be used to format the version value of the output, **formatting this value is the only effect of this input parameter!** It is not used for parsing or any other purpose. It is a convenient alternative to formatting the output in a subsequent step. |
| `user_format_type` | Indicates the format of the `authors` output. Can be `json` or `yaml`. |
| `enable_prerelease_mode` | If true, major changes to versions starting with 0 will result in a minor change, preventing ths initial version `1.0.0`` from being created automatically by someone checking in a commit with the major pattern. |

View file

@ -8,14 +8,16 @@ class ActionConfig {
this.branch = "HEAD"; this.branch = "HEAD";
/** The prefix to use to identify tags */ /** The prefix to use to identify tags */
this.tagPrefix = "v"; this.tagPrefix = "v";
/** Use branches instead of tags */ /** (Deprecated) Use branches instead of tags */
this.useBranches = false; this.useBranches = false;
/** If true, the branch will be used to select the maximum version. */
this.versionFromBranch = false;
/** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */
this.majorPattern = "(MAJOR)"; this.majorPattern = "/!:|BREAKING CHANGE:/";
/** A string which indicates the flags used by the `majorPattern` regular expression. */ /** A string which indicates the flags used by the `majorPattern` regular expression. */
this.majorFlags = ""; this.majorFlags = "";
/** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */
this.minorPattern = "(MINOR)"; this.minorPattern = "/feat:/";
/** A string which indicates the flags used by the `minorPattern` regular expression. */ /** A string which indicates the flags used by the `minorPattern` regular expression. */
this.minorFlags = ""; this.minorFlags = "";
/** Pattern to use when formatting output version */ /** Pattern to use when formatting output version */

View file

@ -36,8 +36,8 @@ exports.cmd = void 0;
// Using require instead of import to support integration testing // Using require instead of import to support integration testing
const exec = __importStar(require("@actions/exec")); const exec = __importStar(require("@actions/exec"));
const DebugManager_1 = require("./DebugManager"); const DebugManager_1 = require("./DebugManager");
const debugManager = DebugManager_1.DebugManager.getInstance();
const cmd = (command, ...args) => __awaiter(void 0, void 0, void 0, function* () { const cmd = (command, ...args) => __awaiter(void 0, void 0, void 0, function* () {
const debugManager = DebugManager_1.DebugManager.getInstance();
if (debugManager.isReplayMode()) { if (debugManager.isReplayMode()) {
return debugManager.replayCommand(command, args); return debugManager.replayCommand(command, args);
} }

View file

@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigurationProvider = void 0; exports.ConfigurationProvider = void 0;
const CsvUserFormatter_1 = require("./formatting/CsvUserFormatter"); const CsvUserFormatter_1 = require("./formatting/CsvUserFormatter");
const BranchVersioningTagFormatter_1 = require("./formatting/BranchVersioningTagFormatter");
const DefaultTagFormatter_1 = require("./formatting/DefaultTagFormatter"); const DefaultTagFormatter_1 = require("./formatting/DefaultTagFormatter");
const DefaultVersionFormatter_1 = require("./formatting/DefaultVersionFormatter"); const DefaultVersionFormatter_1 = require("./formatting/DefaultVersionFormatter");
const JsonUserFormatter_1 = require("./formatting/JsonUserFormatter"); const JsonUserFormatter_1 = require("./formatting/JsonUserFormatter");
@ -26,7 +27,12 @@ class ConfigurationProvider {
return new DefaultVersionClassifier_1.DefaultVersionClassifier(this.config); return new DefaultVersionClassifier_1.DefaultVersionClassifier(this.config);
} }
GetVersionFormatter() { return new DefaultVersionFormatter_1.DefaultVersionFormatter(this.config); } GetVersionFormatter() { return new DefaultVersionFormatter_1.DefaultVersionFormatter(this.config); }
GetTagFormatter() { return new DefaultTagFormatter_1.DefaultTagFormatter(this.config); } GetTagFormatter(branchName) {
if (this.config.versionFromBranch) {
return new BranchVersioningTagFormatter_1.BranchVersioningTagFormatter(this.config, branchName);
}
return new DefaultTagFormatter_1.DefaultTagFormatter(this.config);
}
GetUserFormatter() { GetUserFormatter() {
switch (this.config.userFormatType) { switch (this.config.userFormatType) {
case 'json': return new JsonUserFormatter_1.JsonUserFormatter(this.config); case 'json': return new JsonUserFormatter_1.JsonUserFormatter(this.config);

View file

@ -15,6 +15,10 @@ class DebugManager {
} }
return DebugManager.instance; return DebugManager.instance;
} }
/** Clears the singleton instance of the DebugManager (used for testing) */
static clearState() {
DebugManager.instance = new DebugManager();
}
/** Returns true if debug mode is enabled */ /** Returns true if debug mode is enabled */
isDebugEnabled() { isDebugEnabled() {
return this.debugEnabled; return this.debugEnabled;

View file

@ -22,12 +22,12 @@ function runAction(configurationProvider) {
const commitsProvider = configurationProvider.GetCommitsProvider(); const commitsProvider = configurationProvider.GetCommitsProvider();
const versionClassifier = configurationProvider.GetVersionClassifier(); const versionClassifier = configurationProvider.GetVersionClassifier();
const versionFormatter = configurationProvider.GetVersionFormatter(); const versionFormatter = configurationProvider.GetVersionFormatter();
const tagFormatter = configurationProvider.GetTagFormatter(); const tagFormatter = configurationProvider.GetTagFormatter(yield currentCommitResolver.ResolveBranchNameAsync());
const userFormatter = configurationProvider.GetUserFormatter(); const userFormatter = configurationProvider.GetUserFormatter();
const debugManager = DebugManager_1.DebugManager.getInstance(); const debugManager = DebugManager_1.DebugManager.getInstance();
if (yield currentCommitResolver.IsEmptyRepoAsync()) { if (yield currentCommitResolver.IsEmptyRepoAsync()) {
const versionInfo = new VersionInformation_1.VersionInformation(0, 0, 0, 0, VersionType_1.VersionType.None, [], false, false); const versionInfo = new VersionInformation_1.VersionInformation(0, 0, 0, 0, VersionType_1.VersionType.None, [], false, false);
return new VersionResult_1.VersionResult(versionInfo.major, versionInfo.minor, versionInfo.patch, versionInfo.increment, versionInfo.type, versionFormatter.Format(versionInfo), tagFormatter.Format(versionInfo), versionInfo.changed, versionInfo.isTagged, userFormatter.Format('author', []), '', '', '0.0.0', debugManager.getDebugOutput(true)); return new VersionResult_1.VersionResult(versionInfo.major, versionInfo.minor, versionInfo.patch, versionInfo.increment, versionInfo.type, versionFormatter.Format(versionInfo), tagFormatter.Format(versionInfo), versionInfo.changed, versionInfo.isTagged, userFormatter.Format('author', []), '', '', tagFormatter.Parse(tagFormatter.Format(versionInfo)).join('.'), debugManager.getDebugOutput(true));
} }
const currentCommit = yield currentCommitResolver.ResolveAsync(); const currentCommit = yield currentCommitResolver.ResolveAsync();
const lastRelease = yield lastReleaseResolver.ResolveAsync(currentCommit, tagFormatter); const lastRelease = yield lastReleaseResolver.ResolveAsync(currentCommit, tagFormatter);

View file

@ -0,0 +1,87 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BranchVersioningTagFormatter = void 0;
const DefaultTagFormatter_1 = require("./DefaultTagFormatter");
/** Default tag formatter which allows a prefix to be specified */
class BranchVersioningTagFormatter extends DefaultTagFormatter_1.DefaultTagFormatter {
getRegex(pattern) {
if (/^\/.+\/[i]*$/.test(pattern)) {
const regexEnd = pattern.lastIndexOf('/');
const parsedFlags = pattern.slice(pattern.lastIndexOf('/') + 1);
return new RegExp(pattern.slice(1, regexEnd), parsedFlags);
}
return new RegExp(pattern);
}
constructor(config, branchName) {
super(config);
const pattern = config.versionFromBranch === true ?
new RegExp("[0-9]+.[0-9]+$|[0-9]+$") :
this.getRegex(config.versionFromBranch);
const result = pattern.exec(branchName);
if (result === null) {
this.major = NaN;
this.onVersionBranch = false;
return;
}
let branchVersion;
switch (result === null || result === void 0 ? void 0 : result.length) {
case 1:
branchVersion = result[0];
break;
case 2:
branchVersion = result[1];
break;
default:
throw new Error(`Unable to parse version from branch named '${branchName}' using pattern '${pattern}'`);
}
this.onVersionBranch = true;
const versionValues = branchVersion.split('.');
if (versionValues.length > 2) {
throw new Error(`The version string '${branchVersion}' parsed from branch '${branchName}' is invalid. It must be in the format 'major.minor' or 'major'`);
}
this.major = parseInt(versionValues[0]);
if (isNaN(this.major)) {
throw new Error(`The major version '${versionValues[0]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
if (versionValues.length > 1) {
this.minor = parseInt(versionValues[1]);
if (isNaN(this.minor)) {
throw new Error(`The minor version '${versionValues[1]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
}
}
GetPattern() {
let pattern = super.GetPattern();
if (!this.onVersionBranch) {
return pattern;
}
if (this.minor === undefined) {
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.*[0-9].*[0-9]`);
}
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.${this.minor}.*[0-9]`);
}
IsValid(tag) {
if (!this.onVersionBranch) {
return super.IsValid(tag);
}
if (!super.IsValid(tag)) {
return false;
}
const parsed = super.Parse(tag);
if (parsed[0] !== this.major) {
return false;
}
if (this.minor !== undefined && parsed[1] !== this.minor) {
return false;
}
return true;
}
Parse(tag) {
if (!this.onVersionBranch) {
return super.Parse(tag);
}
const parsed = super.Parse(tag);
return [this.major, this.minor || parsed[1], parsed[2]];
}
}
exports.BranchVersioningTagFormatter = BranchVersioningTagFormatter;

View file

@ -22,6 +22,9 @@ class DefaultTagFormatter {
return `${this.tagPrefix}*[0-9].*[0-9].*[0-9]`; return `${this.tagPrefix}*[0-9].*[0-9].*[0-9]`;
} }
Parse(tag) { Parse(tag) {
if (tag === '') {
return [0, 0, 0];
}
let tagParts = tag let tagParts = tag
.replace(this.tagPrefix, '<--!PREFIX!-->') .replace(this.tagPrefix, '<--!PREFIX!-->')
.replace(this.namespace, '<--!NAMESPACE!-->') .replace(this.namespace, '<--!NAMESPACE!-->')

View file

@ -64,10 +64,29 @@ function setOutput(versionResult) {
} }
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
function toBool(value) {
if (!value || value.toLowerCase() === 'false') {
return false;
}
else if (value.toLowerCase() === 'true') {
return true;
}
return false;
}
function toStringOrBool(value) {
if (!value || value === 'false') {
return false;
}
if (value === 'true') {
return true;
}
return value;
}
const config = { const config = {
branch: core.getInput('branch'), branch: core.getInput('branch'),
tagPrefix: core.getInput('tag_prefix'), tagPrefix: core.getInput('tag_prefix'),
useBranches: core.getInput('use_branches') === 'true', useBranches: toBool(core.getInput('use_branches')),
versionFromBranch: toStringOrBool(core.getInput('version_from_branch')),
majorPattern: core.getInput('major_pattern'), majorPattern: core.getInput('major_pattern'),
minorPattern: core.getInput('minor_pattern'), minorPattern: core.getInput('minor_pattern'),
majorFlags: core.getInput('major_regexp_flags'), majorFlags: core.getInput('major_regexp_flags'),
@ -75,14 +94,17 @@ function run() {
versionFormat: core.getInput('version_format'), versionFormat: core.getInput('version_format'),
changePath: core.getInput('change_path'), changePath: core.getInput('change_path'),
namespace: core.getInput('namespace'), namespace: core.getInput('namespace'),
bumpEachCommit: core.getInput('bump_each_commit') === 'true', bumpEachCommit: toBool(core.getInput('bump_each_commit')),
searchCommitBody: core.getInput('search_commit_body') === 'true', searchCommitBody: toBool(core.getInput('search_commit_body')),
userFormatType: core.getInput('user_format_type'), userFormatType: core.getInput('user_format_type'),
enablePrereleaseMode: core.getInput('enable_prerelease_mode') === 'true', enablePrereleaseMode: toBool(core.getInput('enable_prerelease_mode')),
bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'), bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'),
debug: core.getInput('debug') === 'true', debug: toBool(core.getInput('debug')),
replay: '' replay: ''
}; };
if (config.useBranches) {
core.warning(`The 'use_branches' input option is deprecated, please see the documentation for more information on how to use branches`);
}
if (config.versionFormat === '' && core.getInput('format') !== '') { if (config.versionFormat === '' && core.getInput('format') !== '') {
core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`); core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`);
config.versionFormat = core.getInput('format'); config.versionFormat = core.getInput('format');

View file

@ -16,6 +16,7 @@ const VersionType_1 = require("./VersionType");
class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVersionClassifier { class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVersionClassifier {
constructor(config) { constructor(config) {
super(config); super(config);
this.enablePrereleaseMode = config.enablePrereleaseMode;
this.patchPattern = !config.bumpEachCommitPatchPattern ? this.patchPattern = !config.bumpEachCommitPatchPattern ?
_ => true : _ => true :
this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody); this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody);
@ -33,28 +34,54 @@ class BumpAlwaysVersionClassifier extends DefaultVersionClassifier_1.DefaultVers
} }
for (let commit of commitSet.commits.reverse()) { for (let commit of commitSet.commits.reverse()) {
if (this.majorPattern(commit)) { if (this.majorPattern(commit)) {
major += 1;
minor = 0;
patch = 0;
type = VersionType_1.VersionType.Major; type = VersionType_1.VersionType.Major;
increment = 0;
} }
else if (this.minorPattern(commit)) { else if (this.minorPattern(commit)) {
minor += 1;
patch = 0;
type = VersionType_1.VersionType.Minor; type = VersionType_1.VersionType.Minor;
increment = 0;
} }
else { else if (this.patchPattern(commit) ||
if (this.patchPattern(commit) ||
(major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) { (major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) {
patch += 1;
type = VersionType_1.VersionType.Patch; type = VersionType_1.VersionType.Patch;
increment = 0;
} }
else { else {
type = VersionType_1.VersionType.None; type = VersionType_1.VersionType.None;
}
if (this.enablePrereleaseMode && major === 0) {
switch (type) {
case VersionType_1.VersionType.Major:
case VersionType_1.VersionType.Minor:
minor += 1;
patch = 0;
increment = 0;
break;
case VersionType_1.VersionType.Patch:
patch += 1;
increment = 0;
break;
default:
increment++; increment++;
break;
}
}
else {
switch (type) {
case VersionType_1.VersionType.Major:
major += 1;
minor = 0;
patch = 0;
increment = 0;
break;
case VersionType_1.VersionType.Minor:
minor += 1;
patch = 0;
break;
case VersionType_1.VersionType.Patch:
patch += 1;
increment = 0;
break;
default:
increment++;
break;
} }
} }
} }

View file

@ -29,5 +29,11 @@ class DefaultCurrentCommitResolver {
return lastCommitAll === ''; return lastCommitAll === '';
}); });
} }
ResolveBranchNameAsync() {
return __awaiter(this, void 0, void 0, function* () {
const branchName = this.branch == 'HEAD' ? yield (0, CommandRunner_1.cmd)('git', 'rev-parse', '--abbrev-ref', 'HEAD') : this.branch;
return branchName.trim();
});
}
} }
exports.DefaultCurrentCommitResolver = DefaultCurrentCommitResolver; exports.DefaultCurrentCommitResolver = DefaultCurrentCommitResolver;

View file

@ -48,6 +48,7 @@ class DefaultLastReleaseResolver {
currentTag = tagFormatter.IsValid(currentTag) ? currentTag : ''; currentTag = tagFormatter.IsValid(currentTag) ? currentTag : '';
const isTagged = currentTag !== ''; const isTagged = currentTag !== '';
const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null]; const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null];
let tagsCount = 0;
let tag = ''; let tag = '';
try { try {
const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/'; const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/';
@ -55,16 +56,16 @@ class DefaultLastReleaseResolver {
// If we already have the current branch tagged, we are checking for the previous one // If we already have the current branch tagged, we are checking for the previous one
// so that we will have an accurate increment (assuming the new tag is the expected one) // so that we will have an accurate increment (assuming the new tag is the expected one)
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
tag = yield (0, CommandRunner_1.cmd)(command); const tags = (yield (0, CommandRunner_1.cmd)(command)).split('\n');
tag = tag tagsCount = tags.length;
.split('\n') tag = tags
.find(t => tagFormatter.IsValid(t) && t !== currentTag) || ''; .find(t => tagFormatter.IsValid(t) && t !== currentTag) || '';
} }
else { else {
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
let tags = yield (0, CommandRunner_1.cmd)(command); const tags = (yield (0, CommandRunner_1.cmd)(command)).split('\n');
tagsCount = tags.length;
tag = tags tag = tags
.split('\n')
.find(t => tagFormatter.IsValid(t)) || ''; .find(t => tagFormatter.IsValid(t)) || '';
} }
tag = tag.trim(); tag = tag.trim();
@ -77,10 +78,16 @@ class DefaultLastReleaseResolver {
// Since there is no remote, we assume that there are no other tags to pull. In // Since there is no remote, we assume that there are no other tags to pull. In
// practice this isn't likely to happen, but it keeps the test output from being // practice this isn't likely to happen, but it keeps the test output from being
// polluted with a bunch of warnings. // polluted with a bunch of warnings.
if (tagsCount > 0) {
core.warning(`None of the ${tagsCount} tags(s) found were valid version tags for the present configuration. If this is unexpected, check to ensure that the configuration is correct and matches the tag format you are using.`);
}
else {
core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.'); core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.');
} }
}
const [major, minor, patch] = tagFormatter.Parse('');
// no release tags yet, use the initial commit as the root // no release tags yet, use the initial commit as the root
return new ReleaseInformation_1.ReleaseInformation(0, 0, 0, '', currentMajor, currentMinor, currentPatch, isTagged); return new ReleaseInformation_1.ReleaseInformation(major, minor, patch, '', currentMajor, currentMinor, currentPatch, isTagged);
} }
// parse the version tag // parse the version tag
const [major, minor, patch] = tagFormatter.Parse(tag); const [major, minor, patch] = tagFormatter.Parse(tag);

View file

@ -96,8 +96,8 @@ class DefaultVersionClassifier {
// - commit 3 was tagged v2.0.0 - v2.0.0+0 // - commit 3 was tagged v2.0.0 - v2.0.0+0
// - commit 4 - v2.0.1+0 // - commit 4 - v2.0.1+0
const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch; const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch;
const currentIncremement = versionsMatch ? increment : 0; const currentIncrement = versionsMatch ? increment : 0;
return new VersionClassification_1.VersionClassification(VersionType_1.VersionType.None, currentIncremement, false, lastRelease.currentMajor, lastRelease.currentMinor, lastRelease.currentPatch); return new VersionClassification_1.VersionClassification(VersionType_1.VersionType.None, currentIncrement, false, lastRelease.currentMajor, lastRelease.currentMinor, lastRelease.currentPatch);
} }
return new VersionClassification_1.VersionClassification(type, increment, changed, major, minor, patch); return new VersionClassification_1.VersionClassification(type, increment, changed, major, minor, patch);
}); });

View file

@ -12,4 +12,4 @@ var VersionType;
VersionType["Patch"] = "Patch"; VersionType["Patch"] = "Patch";
/** Indicates no change--generally this means that the current commit is already tagged with a version */ /** Indicates no change--generally this means that the current commit is already tagged with a version */
VersionType["None"] = "None"; VersionType["None"] = "None";
})(VersionType = exports.VersionType || (exports.VersionType = {})); })(VersionType || (exports.VersionType = VersionType = {}));

3369
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@
"format-check": "prettier --check **/**.ts", "format-check": "prettier --check **/**.ts",
"lint": "eslint src/**/*.ts", "lint": "eslint src/**/*.ts",
"package": "ncc build --source-map --license licenses.txt", "package": "ncc build --source-map --license licenses.txt",
"test": "jest --config ./jest.config.js", "test": "jest --runInBand --config ./jest.config.js",
"all": "npm run build && npm run format && npm run lint && npm run package && npm test" "all": "npm run build && npm run format && npm run lint && npm run package && npm test"
}, },
"repository": { "repository": {
@ -28,20 +28,20 @@
}, },
"homepage": "https://github.com/paulhatch/semantic-version#readme", "homepage": "https://github.com/paulhatch/semantic-version#readme",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1" "@actions/exec": "^1.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^18.11.9", "@types/node": "^20.11.13",
"@typescript-eslint/parser": "^5.17.0", "@typescript-eslint/parser": "^6.20.0",
"@vercel/ncc": "^0.34.0", "@vercel/ncc": "^0.38.1",
"eslint": "^8.12.0", "eslint": "^8.56.0",
"eslint-plugin-github": "^4.3.6", "eslint-plugin-github": "^4.10.1",
"eslint-plugin-jest": "^27.1.3", "eslint-plugin-jest": "^27.6.3",
"jest": "^29.2.2", "jest": "^29.7.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"prettier": "^2.6.1", "prettier": "^3.2.4",
"ts-jest": "^29.0.3", "ts-jest": "^29.1.2",
"typescript": "^4.6.3" "typescript": "^5.3.3"
} }
} }

View file

@ -1,6 +1,6 @@
![Build](https://github.com/PaulHatch/semantic-version/workflows/Build/badge.svg) ![Build](https://github.com/PaulHatch/semantic-version/workflows/Build/badge.svg)
See [contributing.md](contributing.md) for information on how to get help or contribute to this project. See the [configuration guide](guide.md) for help getting started, selecting a versioning strategy and example configurations, or [contributing.md](contributing.md) for information on how to get help or contribute to this project.
# Git-Based Semantic Versioning # Git-Based Semantic Versioning
@ -13,8 +13,9 @@ automatically while publishing version that only increment by one value per
release. To accomplish this, the next version number is calculated along with release. To accomplish this, the next version number is calculated along with
a commit increment indicating the number of commits for this version. The a commit increment indicating the number of commits for this version. The
commit messages are inspected to determine the type of version change the next commit messages are inspected to determine the type of version change the next
version represents. Including the term `(MAJOR)` or `(MINOR)` in the commit version represents. By default, this action follows [Conventional Commits](https://www.conventionalcommits.org/)
message alters the type of change the next version will represent. patterns: commits with `feat:` trigger minor version bumps, and commits with a `!` suffix
(e.g., `feat!:`, `fix!:`) or containing `BREAKING CHANGE:` trigger major version bumps.
# Background # Background
@ -50,7 +51,8 @@ _Unless the current commit is already tagged, the version produced by this actio
## Major and Minor Versions ## Major and Minor Versions
The commit messages for the span of commits from the last tag are checked for the The commit messages for the span of commits from the last tag are checked for the
presence of the designated terms (`(MAJOR)` or `(MINOR)` by default), if a term presence of version bump patterns. By default, `feat:` triggers a minor version bump,
while `!:` (e.g., `feat!:`, `fix!:`) or `BREAKING CHANGE:` triggers a major version bump. If a pattern
is encountered that commit is treated as the start of a major or minor version is encountered that commit is treated as the start of a major or minor version
instead of the default patch level. As with normal commits the implied version instead of the default patch level. As with normal commits the implied version
will only increment by one value since the last tag regardless of how many major will only increment by one value since the last tag regardless of how many major
@ -73,17 +75,17 @@ it will be given the new version if the build were to be retriggered, for exampl
<!-- start usage --> <!-- start usage -->
```yaml ```yaml
- uses: paulhatch/semantic-version@v5.1.0 - uses: paulhatch/semantic-version@v5.4.0
with: with:
# The prefix to use to identify tags # The prefix to use to identify tags
tag_prefix: "v" tag_prefix: "v"
# A string which, if present in a git commit, indicates that a change represents a # A string which, if present in a git commit, indicates that a change represents a
# major (breaking) change, supports regular expressions wrapped with '/' # major (breaking) change, supports regular expressions wrapped with '/'
major_pattern: "(MAJOR)" major_pattern: "/!:|BREAKING CHANGE:/"
# A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs # A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs
major_regexp_flags: "" major_regexp_flags: ""
# Same as above except indicating a minor change, supports regular expressions wrapped with '/' # Same as above except indicating a minor change, supports regular expressions wrapped with '/'
minor_pattern: "(MINOR)" minor_pattern: "/feat:/"
# A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs # A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs
minor_regexp_flags: "" minor_regexp_flags: ""
# A string to determine the format of the version output # A string to determine the format of the version output
@ -104,6 +106,10 @@ it will be given the new version if the build were to be retriggered, for exampl
# Prevents pre-v1.0.0 version from automatically incrementing the major version. # Prevents pre-v1.0.0 version from automatically incrementing the major version.
# If enabled, when the major version is 0, major releases will be treated as minor and minor as patch. Note that the version_type output is unchanged. # If enabled, when the major version is 0, major releases will be treated as minor and minor as patch. Note that the version_type output is unchanged.
enable_prerelease_mode: true enable_prerelease_mode: true
# If enabled, diagnostic information will be added to the action output.
debug: false
# If true, the branch will be used to select the maximum version.
version_from_branch: false
``` ```
## Outputs ## Outputs
@ -119,6 +125,7 @@ it will be given the new version if the build were to be retriggered, for exampl
- *current_commit* is the current commit hash. - *current_commit* is the current commit hash.
- *previous_commit* is the previous commit hash. - *previous_commit* is the previous commit hash.
- *previous_version* is the previous version. - *previous_version* is the previous version.
- *debug_output* will show diagnostic information, if debug is enabled
There are two types of "version" string, one is the semantic version output that can be used to identify a build and can include prerelease data and metadata specific to the commit such as `v2.0.1-pre001+cf6e75` (you would produce this string yourself using the version information from this action plus whatever metadata you wanted to add), the other is the tag version string, which identifies a specific commit as being a specific version. There are two types of "version" string, one is the semantic version output that can be used to identify a build and can include prerelease data and metadata specific to the commit such as `v2.0.1-pre001+cf6e75` (you would produce this string yourself using the version information from this action plus whatever metadata you wanted to add), the other is the tag version string, which identifies a specific commit as being a specific version.
@ -151,12 +158,12 @@ like `v1.2.3+0-db` could be configured like this:
```yaml ```yaml
- name: Application Version - name: Application Version
id: version id: version
uses: paulhatch/semantic-version@v5.1.0 uses: paulhatch/semantic-version@v5.4.0
with: with:
change_path: "src/service" change_path: "src/service"
- name: Database Version - name: Database Version
id: db-version id: db-version
uses: paulhatch/semantic-version@v5.1.0 uses: paulhatch/semantic-version@v5.4.0
with: with:
major_pattern: "(MAJOR-DB)" major_pattern: "(MAJOR-DB)"
minor_pattern: "(MINOR-DB)" minor_pattern: "(MINOR-DB)"

View file

@ -4,14 +4,16 @@ export class ActionConfig {
public branch: string = "HEAD"; public branch: string = "HEAD";
/** The prefix to use to identify tags */ /** The prefix to use to identify tags */
public tagPrefix: string = "v"; public tagPrefix: string = "v";
/** Use branches instead of tags */ /** (Deprecated) Use branches instead of tags */
public useBranches: boolean = false; public useBranches: boolean = false;
/** If true, the branch will be used to select the maximum version. */
public versionFromBranch: string | boolean = false;
/** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */
public majorPattern: string = "(MAJOR)"; public majorPattern: string = "/!:|BREAKING CHANGE:/";
/** A string which indicates the flags used by the `majorPattern` regular expression. */ /** A string which indicates the flags used by the `majorPattern` regular expression. */
public majorFlags: string = ""; public majorFlags: string = "";
/** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */
public minorPattern: string = "(MINOR)"; public minorPattern: string = "/feat:/";
/** A string which indicates the flags used by the `minorPattern` regular expression. */ /** A string which indicates the flags used by the `minorPattern` regular expression. */
public minorFlags: string = ""; public minorFlags: string = "";
/** Pattern to use when formatting output version */ /** Pattern to use when formatting output version */

View file

@ -2,10 +2,10 @@
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import { DebugManager } from './DebugManager'; import { DebugManager } from './DebugManager';
const debugManager = DebugManager.getInstance();
export const cmd = async (command: string, ...args: any): Promise<string> => { export const cmd = async (command: string, ...args: any): Promise<string> => {
const debugManager = DebugManager.getInstance();
if (debugManager.isReplayMode()) { if (debugManager.isReplayMode()) {
return debugManager.replayCommand(command, args); return debugManager.replayCommand(command, args);
} }

View file

@ -1,4 +1,5 @@
import { CsvUserFormatter } from './formatting/CsvUserFormatter' import { CsvUserFormatter } from './formatting/CsvUserFormatter'
import { BranchVersioningTagFormatter } from './formatting/BranchVersioningTagFormatter'
import { DefaultTagFormatter } from './formatting/DefaultTagFormatter' import { DefaultTagFormatter } from './formatting/DefaultTagFormatter'
import { DefaultVersionFormatter } from './formatting/DefaultVersionFormatter' import { DefaultVersionFormatter } from './formatting/DefaultVersionFormatter'
import { JsonUserFormatter } from './formatting/JsonUserFormatter' import { JsonUserFormatter } from './formatting/JsonUserFormatter'
@ -41,7 +42,12 @@ export class ConfigurationProvider {
public GetVersionFormatter(): VersionFormatter { return new DefaultVersionFormatter(this.config); } public GetVersionFormatter(): VersionFormatter { return new DefaultVersionFormatter(this.config); }
public GetTagFormatter(): TagFormatter { return new DefaultTagFormatter(this.config); } public GetTagFormatter(branchName: string): TagFormatter {
if (this.config.versionFromBranch) {
return new BranchVersioningTagFormatter(this.config, branchName);
}
return new DefaultTagFormatter(this.config);
}
public GetUserFormatter(): UserFormatter { public GetUserFormatter(): UserFormatter {
switch (this.config.userFormatType) { switch (this.config.userFormatType) {

View file

@ -1,10 +1,8 @@
import exp from "constants";
import { ActionConfig } from "./ActionConfig"; import { ActionConfig } from "./ActionConfig";
/** Utility class for managing debug mode and diagnostic information */ /** Utility class for managing debug mode and diagnostic information */
export class DebugManager { export class DebugManager {
private constructor() { } private constructor() { }
private static instance: DebugManager; private static instance: DebugManager;
@ -16,6 +14,12 @@ export class DebugManager {
return DebugManager.instance; return DebugManager.instance;
} }
/** Clears the singleton instance of the DebugManager (used for testing) */
public static clearState() {
DebugManager.instance = new DebugManager();
}
private debugEnabled: boolean = false; private debugEnabled: boolean = false;
private replayMode: boolean = false; private replayMode: boolean = false;
private diagnosticInfo: DiagnosticInfo | null = null; private diagnosticInfo: DiagnosticInfo | null = null;

View file

@ -12,12 +12,13 @@ export async function runAction(configurationProvider: ConfigurationProvider): P
const commitsProvider = configurationProvider.GetCommitsProvider(); const commitsProvider = configurationProvider.GetCommitsProvider();
const versionClassifier = configurationProvider.GetVersionClassifier(); const versionClassifier = configurationProvider.GetVersionClassifier();
const versionFormatter = configurationProvider.GetVersionFormatter(); const versionFormatter = configurationProvider.GetVersionFormatter();
const tagFormatter = configurationProvider.GetTagFormatter(); const tagFormatter = configurationProvider.GetTagFormatter(await currentCommitResolver.ResolveBranchNameAsync());
const userFormatter = configurationProvider.GetUserFormatter(); const userFormatter = configurationProvider.GetUserFormatter();
const debugManager = DebugManager.getInstance(); const debugManager = DebugManager.getInstance();
if (await currentCommitResolver.IsEmptyRepoAsync()) { if (await currentCommitResolver.IsEmptyRepoAsync()) {
const versionInfo = new VersionInformation(0, 0, 0, 0, VersionType.None, [], false, false); const versionInfo = new VersionInformation(0, 0, 0, 0, VersionType.None, [], false, false);
return new VersionResult( return new VersionResult(
versionInfo.major, versionInfo.major,
@ -32,7 +33,7 @@ export async function runAction(configurationProvider: ConfigurationProvider): P
userFormatter.Format('author', []), userFormatter.Format('author', []),
'', '',
'', '',
'0.0.0', tagFormatter.Parse(tagFormatter.Format(versionInfo)).join('.'),
debugManager.getDebugOutput(true) debugManager.getDebugOutput(true)
); );
} }

View file

@ -0,0 +1,104 @@
import { ActionConfig } from '../ActionConfig';
import { DefaultTagFormatter } from './DefaultTagFormatter';
/** Default tag formatter which allows a prefix to be specified */
export class BranchVersioningTagFormatter extends DefaultTagFormatter {
private onVersionBranch: boolean;
private major: number;
private minor?: number;
private getRegex(pattern: string) {
if (/^\/.+\/[i]*$/.test(pattern)) {
const regexEnd = pattern.lastIndexOf('/');
const parsedFlags = pattern.slice(pattern.lastIndexOf('/') + 1);
return new RegExp(pattern.slice(1, regexEnd), parsedFlags);
}
return new RegExp(pattern);
}
constructor(config: ActionConfig, branchName: string) {
super(config);
const pattern = config.versionFromBranch === true ?
new RegExp("[0-9]+.[0-9]+$|[0-9]+$") :
this.getRegex(config.versionFromBranch as string);
const result = pattern.exec(branchName);
if (result === null) {
this.major = NaN;
this.onVersionBranch = false;
return;
}
let branchVersion: string;
switch (result?.length) {
case 1:
branchVersion = result[0];
break;
case 2:
branchVersion = result[1];
break;
default:
throw new Error(`Unable to parse version from branch named '${branchName}' using pattern '${pattern}'`);
}
this.onVersionBranch = true;
const versionValues = branchVersion.split('.');
if (versionValues.length > 2) {
throw new Error(`The version string '${branchVersion}' parsed from branch '${branchName}' is invalid. It must be in the format 'major.minor' or 'major'`);
}
this.major = parseInt(versionValues[0]);
if (isNaN(this.major)) {
throw new Error(`The major version '${versionValues[0]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
if (versionValues.length > 1) {
this.minor = parseInt(versionValues[1]);
if (isNaN(this.minor)) {
throw new Error(`The minor version '${versionValues[1]}' parsed from branch '${branchName}' is invalid. It must be a number.`);
}
}
}
public override GetPattern(): string {
let pattern = super.GetPattern();
if (!this.onVersionBranch) {
return pattern;
}
if(this.minor === undefined) {
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.*[0-9].*[0-9]`);
}
return pattern.replace('*[0-9].*[0-9].*[0-9]', `${this.major}.${this.minor}.*[0-9]`);
}
override IsValid(tag: string): boolean {
if (!this.onVersionBranch) {
return super.IsValid(tag);
}
if (!super.IsValid(tag)) {
return false;
}
const parsed = super.Parse(tag);
if (parsed[0] !== this.major) {
return false;
}
if (this.minor !== undefined && parsed[1] !== this.minor) {
return false;
}
return true;
}
override Parse(tag: string): [major: number, minor: number, patch: number] {
if (!this.onVersionBranch) {
return super.Parse(tag);
}
const parsed = super.Parse(tag);
return [this.major, this.minor || parsed[1], parsed[2]];
}
}

View file

@ -36,6 +36,10 @@ export class DefaultTagFormatter implements TagFormatter {
public Parse(tag: string): [major: number, minor: number, patch: number] { public Parse(tag: string): [major: number, minor: number, patch: number] {
if(tag === '') {
return [0, 0, 0];
}
let tagParts = tag let tagParts = tag
.replace(this.tagPrefix, '<--!PREFIX!-->') .replace(this.tagPrefix, '<--!PREFIX!-->')
.replace(this.namespace, '<--!NAMESPACE!-->') .replace(this.namespace, '<--!NAMESPACE!-->')

View file

@ -6,7 +6,7 @@ import { expect, test } from '@jest/globals'
import { runAction } from '../src/action'; import { runAction } from '../src/action';
import { ConfigurationProvider } from './ConfigurationProvider'; import { ConfigurationProvider } from './ConfigurationProvider';
import { ActionConfig } from './ActionConfig'; import { ActionConfig } from './ActionConfig';
import exp from 'constants'; import { DebugManager } from './DebugManager';
const windows = process.platform === "win32"; const windows = process.platform === "win32";
const timeout = 30000; const timeout = 30000;
@ -42,6 +42,7 @@ const createTestRepo = (repoDefaultConfig?: Partial<ActionConfig>) => {
run(`git merge ${branch}`); run(`git merge ${branch}`);
}, },
runAction: async (inputs?: Partial<ActionConfig>) => { runAction: async (inputs?: Partial<ActionConfig>) => {
DebugManager.clearState();
let config = new ActionConfig(); let config = new ActionConfig();
config = { ...config, ...{ versionFormat: "${major}.${minor}.${patch}+${increment}" }, ...repoDefaultConfig, ...inputs }; config = { ...config, ...{ versionFormat: "${major}.${minor}.${patch}+${increment}" }, ...repoDefaultConfig, ...inputs };
process.chdir(repoDirectory); process.chdir(repoDirectory);
@ -120,7 +121,7 @@ test('Minor update bumps minor version and resets increment', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MINOR)'); // 0.1.0+0 repo.makeCommit('feat: Second Commit'); // 0.1.0+0
const result = await repo.runAction(); const result = await repo.runAction();
expect(result.formattedVersion).toBe('0.1.0+0'); expect(result.formattedVersion).toBe('0.1.0+0');
@ -130,7 +131,7 @@ test('Major update bumps major version and resets increment', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
const result = await repo.runAction(); const result = await repo.runAction();
@ -141,8 +142,8 @@ test('Multiple major commits are idempotent', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
repo.makeCommit('Third Commit (MAJOR)'); // 1.0.0+1 repo.makeCommit('fix!: Third Commit'); // 1.0.0+1
const result = await repo.runAction(); const result = await repo.runAction();
@ -153,8 +154,8 @@ test('Minor commits after a major commit are ignored', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
repo.makeCommit('Third Commit (MINOR)'); // 1.0.0+1 repo.makeCommit('feat: Third Commit'); // 1.0.0+1
const result = await repo.runAction(); const result = await repo.runAction();
expect(result.formattedVersion).toBe('1.0.0+1'); expect(result.formattedVersion).toBe('1.0.0+1');
@ -187,32 +188,6 @@ test('Version pulled from last release branch', async () => {
expect(result.formattedVersion).toBe('5.6.8+0'); expect(result.formattedVersion).toBe('5.6.8+0');
}, timeout); }, timeout);
/* Removed for now
test('Tags on branches are used', async () => {
// This test checks that tags are counted correctly even if they are not on
// the main branch:
// master o--o--o--o <- expecting v0.0.2
// \
// release o--o <- taged v0.0.1
const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit'); // 0.0.1+1
repo.makeCommit('Third Commit'); // 0.1.1+2
repo.exec('git checkout -b release/0.0.1')
repo.makeCommit('Fourth Commit'); // 0.1.1+3
repo.exec('git tag v0.0.1');
repo.exec('git checkout master');
repo.makeCommit('Fifth Commit'); // 0.0.2.0
const result = await repo.runAction();
expect(result.formattedVersion).toBe('0.0.2+0');
});
*/
test('Merged tags do not affect version', async () => { test('Merged tags do not affect version', async () => {
// This test checks that merges don't override tags // This test checks that merges don't override tags
@ -373,6 +348,23 @@ test('Namespace is tracked separately', async () => {
expect(subprojectResult.formattedVersion).toBe('0.1.1+0'); expect(subprojectResult.formattedVersion).toBe('0.1.1+0');
}, timeout); }, timeout);
test('Version Namespace is tracked separately', async () => {
const repo = createTestRepo({ tagPrefix: '' }); // 0.0.0
repo.makeCommit('Initial Commit'); // 0.0.1
repo.exec('git tag 0.0.1');
repo.makeCommit('Second Commit'); // 0.0.2
repo.exec('git tag subproject0.1.0');
repo.makeCommit('Third Commit'); // 0.0.2 / 0.1.1
const result = await repo.runAction();
const subprojectResult = await repo.runAction({ tagPrefix: "subproject" });
expect(result.formattedVersion).toBe('0.0.2+1');
expect(subprojectResult.formattedVersion).toBe('0.1.1+0');
}, timeout);
test('Namespace allows dashes', async () => { test('Namespace allows dashes', async () => {
const repo = createTestRepo({ tagPrefix: '' }); // 0.0.0 const repo = createTestRepo({ tagPrefix: '' }); // 0.0.0
@ -441,11 +433,11 @@ test('Bump each commit works', async () => {
expect((await repo.runAction()).formattedVersion).toBe('0.0.2+0'); expect((await repo.runAction()).formattedVersion).toBe('0.0.2+0');
repo.makeCommit('Third Commit'); repo.makeCommit('Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.3+0'); expect((await repo.runAction()).formattedVersion).toBe('0.0.3+0');
repo.makeCommit('Fourth Commit (MINOR)'); repo.makeCommit('feat: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0+0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0+0');
repo.makeCommit('Fifth Commit'); repo.makeCommit('Fifth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.1+0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.1+0');
repo.makeCommit('Sixth Commit (MAJOR)'); repo.makeCommit('feat!: Sixth Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.0+0'); expect((await repo.runAction()).formattedVersion).toBe('1.0.0+0');
repo.makeCommit('Seventh Commit'); repo.makeCommit('Seventh Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.1+0'); expect((await repo.runAction()).formattedVersion).toBe('1.0.1+0');
@ -708,7 +700,7 @@ test('Correct previous version is returned when directly tagged with multiple pr
test('Prerelease suffixes are ignored', async () => { test('Prerelease suffixes are ignored', async () => {
const repo = createTestRepo(); const repo = createTestRepo();
repo.makeCommit('Initial Commit (MAJOR)'); repo.makeCommit('feat!: Initial Commit');
repo.makeCommit(`Second Commit`); repo.makeCommit(`Second Commit`);
repo.exec('git tag v1.0.0-alpha.1') repo.exec('git tag v1.0.0-alpha.1')
repo.makeCommit(`Third Commit`); repo.makeCommit(`Third Commit`);
@ -720,7 +712,7 @@ test('Prerelease suffixes are ignored', async () => {
test('Prerelease suffixes are ignored when namespaces are set', async () => { test('Prerelease suffixes are ignored when namespaces are set', async () => {
const repo = createTestRepo({ namespace: 'test' }); const repo = createTestRepo({ namespace: 'test' });
repo.makeCommit('Initial Commit (MAJOR)'); repo.makeCommit('feat!: Initial Commit');
repo.exec('git tag v1.0.0-test') repo.exec('git tag v1.0.0-test')
repo.makeCommit(`Second Commit`); repo.makeCommit(`Second Commit`);
repo.exec('git tag v1.0.1-test-alpha.1') repo.exec('git tag v1.0.1-test-alpha.1')
@ -869,23 +861,24 @@ test('Patch pattern increment is correct/matches non-bumped on empty repo', asyn
}, timeout); }, timeout);
test('Patch pattern applied when present', async () => { test('Patch pattern applied when present using tag as initial version', async () => {
const repo = createTestRepo({ tagPrefix: '', versionFormat: "${major}.${minor}.${patch}+${increment}", bumpEachCommit: true, bumpEachCommitPatchPattern: '(PATCH)' }); const repo = createTestRepo({ tagPrefix: '', versionFormat: "${major}.${minor}.${patch}+${increment}", bumpEachCommit: true, bumpEachCommitPatchPattern: '(PATCH)' });
repo.makeCommit('Initial Commit'); repo.makeCommit('Initial Commit');
const firstResult = await repo.runAction(); repo.exec('git tag 1.0.1');
const firstResult = await repo.runAction(); // 1.0.1+0
repo.makeCommit('Second Commit'); repo.makeCommit('Second Commit');
const secondResult = await repo.runAction(); const secondResult = await repo.runAction(); // 1.0.1+1
repo.makeCommit('Third Commit (PATCH)'); repo.makeCommit('Third Commit (PATCH)');
const thirdResult = await repo.runAction(); const thirdResult = await repo.runAction(); // 1.0.2+0
repo.makeCommit('fourth Commit'); repo.makeCommit('fourth Commit');
const fourthResult = await repo.runAction(); const fourthResult = await repo.runAction(); // 1.0.2+1
expect(firstResult.formattedVersion).toBe('0.0.1+0'); expect(firstResult.formattedVersion).toBe('1.0.1+0');
expect(secondResult.formattedVersion).toBe('0.0.1+1'); expect(secondResult.formattedVersion).toBe('1.0.1+1');
expect(thirdResult.formattedVersion).toBe('0.0.2+0'); expect(thirdResult.formattedVersion).toBe('1.0.2+0');
expect(fourthResult.formattedVersion).toBe('0.0.2+1'); expect(fourthResult.formattedVersion).toBe('1.0.2+1');
}, timeout); }, timeout);
@ -963,12 +956,12 @@ test('Pre-release mode does not update major version if major version is 0', asy
repo.makeCommit('Initial Commit'); repo.makeCommit('Initial Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('Second Commit (MINOR)'); repo.makeCommit('feat: Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('Third Commit (MAJOR)'); repo.makeCommit('feat!: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0');
repo.exec('git tag 0.1.0'); repo.exec('git tag 0.1.0');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0'); expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
}, timeout); }, timeout);
@ -979,12 +972,12 @@ test('Pre-release mode updates major version if major version is not 0', async (
repo.exec('git tag 1.0.0'); repo.exec('git tag 1.0.0');
repo.makeCommit('Second Commit'); repo.makeCommit('Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.1'); expect((await repo.runAction()).formattedVersion).toBe('1.0.1');
repo.makeCommit('Third Commit (MINOR)'); repo.makeCommit('feat: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.1.0'); expect((await repo.runAction()).formattedVersion).toBe('1.1.0');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('2.0.0'); expect((await repo.runAction()).formattedVersion).toBe('2.0.0');
repo.exec('git tag 2.0.0'); repo.exec('git tag 2.0.0');
repo.makeCommit('Fifth Commit (MAJOR)'); repo.makeCommit('feat!: Fifth Commit');
expect((await repo.runAction()).formattedVersion).toBe('3.0.0'); expect((await repo.runAction()).formattedVersion).toBe('3.0.0');
}, timeout); }, timeout);
@ -1002,12 +995,12 @@ test('Tagged commit is flagged as release', async () => {
expect(result.formattedVersion).toBe('1.0.1-prerelease.0') expect(result.formattedVersion).toBe('1.0.1-prerelease.0')
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Third Commit (MINOR)'); repo.makeCommit('feat: Third Commit');
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.0'); expect(result.formattedVersion).toBe('1.1.0-prerelease.0');
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Fourth Commit (MINOR)'); repo.makeCommit('feat: Fourth Commit');
repo.exec('git tag v1.1.0') repo.exec('git tag v1.1.0')
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.1'); expect(result.formattedVersion).toBe('1.1.0-prerelease.1');
@ -1015,6 +1008,40 @@ test('Tagged commit is flagged as release', async () => {
}, timeout); }, timeout);
test('Pre-release mode with bump each commit does not update major version if major version is 0', async () => {
const repo = createTestRepo({ tagPrefix: '', versionFormat: "${major}.${minor}.${patch}", enablePrereleaseMode: true, bumpEachCommit: true });
repo.makeCommit('Initial Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('feat: Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0');
repo.makeCommit('feat!: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
repo.exec('git tag 0.1.0');
repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
}, timeout);
test('Pre-release mode with bump each commit does not update major version if major version is 0, respecting patch pattern', async () => {
const repo = createTestRepo({
tagPrefix: '',
versionFormat: "${major}.${minor}.${patch}.${increment}",
enablePrereleaseMode: true,
bumpEachCommit: true,
bumpEachCommitPatchPattern: '(PATCH)',
});
repo.makeCommit('Initial Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1.0');
repo.makeCommit('Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1.1');
repo.makeCommit('Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1.2');
repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0.0');
}, timeout);
test('Highest tag is chosen when multiple tags are present', async () => { test('Highest tag is chosen when multiple tags are present', async () => {
const repo = createTestRepo(); const repo = createTestRepo();
@ -1057,4 +1084,63 @@ test('Debug records and replays expected data', async () => {
}, timeout); }, timeout);
test('Version branch using major version ignores other tags', async () => {
const repo = createTestRepo({ versionFromBranch: true });
repo.makeCommit('Initial Commit');
repo.makeCommit(`Second Commit`);
repo.exec("git checkout -b release/v3");
repo.exec('git tag v3.0.0');
repo.makeCommit(`Third Commit`);
repo.exec('git tag v4.0.0');
repo.makeCommit(`Fourth Commit`);
repo.makeCommit(`Fifth Commit`);
const result = await repo.runAction();
expect(result.formattedVersion).toBe('3.0.1+2');
}, timeout);
test('Versioning from branch always takes version from branch name even without tags', async () => {
const repo = createTestRepo({ versionFromBranch: true });
repo.makeCommit('Initial Commit');
repo.makeCommit(`Second Commit`);
repo.exec("git checkout -b release/v3.2");
repo.makeCommit(`Third Commit`);
repo.makeCommit(`Fourth Commit`);
repo.makeCommit(`Fifth Commit`);
const result = await repo.runAction();
expect(result.formattedVersion).toBe('3.2.1+4');
}, timeout);
test('Prerelease mode does not increment to 1.x.x', async () => {
const repo = createTestRepo({ tagPrefix: 'v', versionFormat: "${major}.${minor}.${patch}-prerelease.${increment}", enablePrereleaseMode: true });
repo.makeCommit('Initial Commit');
repo.exec('git tag v1.0.0');
var result = await repo.runAction();
expect(result.formattedVersion).toBe('1.0.0-prerelease.0');
expect(result.isTagged).toBe(true);
repo.makeCommit('Second Commit');
result = await repo.runAction();
expect(result.formattedVersion).toBe('1.0.1-prerelease.0')
expect(result.isTagged).toBe(false);
repo.makeCommit('feat: Third Commit');
result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.0');
expect(result.isTagged).toBe(false);
repo.makeCommit('feat: Fourth Commit');
repo.exec('git tag v1.1.0')
result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.1');
expect(result.isTagged).toBe(true);
}, timeout);

View file

@ -37,10 +37,30 @@ function setOutput(versionResult: VersionResult) {
export async function run() { export async function run() {
function toBool(value: string): boolean {
if (!value || value.toLowerCase() === 'false') {
return false;
} else if (value.toLowerCase() === 'true') {
return true;
}
return false;
}
function toStringOrBool(value: string): string | boolean {
if (!value || value === 'false') {
return false;
}
if (value === 'true') {
return true;
}
return value;
}
const config: ActionConfig = { const config: ActionConfig = {
branch: core.getInput('branch'), branch: core.getInput('branch'),
tagPrefix: core.getInput('tag_prefix'), tagPrefix: core.getInput('tag_prefix'),
useBranches: core.getInput('use_branches') === 'true', useBranches: toBool(core.getInput('use_branches')),
versionFromBranch: toStringOrBool(core.getInput('version_from_branch')),
majorPattern: core.getInput('major_pattern'), majorPattern: core.getInput('major_pattern'),
minorPattern: core.getInput('minor_pattern'), minorPattern: core.getInput('minor_pattern'),
majorFlags: core.getInput('major_regexp_flags'), majorFlags: core.getInput('major_regexp_flags'),
@ -48,15 +68,19 @@ export async function run() {
versionFormat: core.getInput('version_format'), versionFormat: core.getInput('version_format'),
changePath: core.getInput('change_path'), changePath: core.getInput('change_path'),
namespace: core.getInput('namespace'), namespace: core.getInput('namespace'),
bumpEachCommit: core.getInput('bump_each_commit') === 'true', bumpEachCommit: toBool(core.getInput('bump_each_commit')),
searchCommitBody: core.getInput('search_commit_body') === 'true', searchCommitBody: toBool(core.getInput('search_commit_body')),
userFormatType: core.getInput('user_format_type'), userFormatType: core.getInput('user_format_type'),
enablePrereleaseMode: core.getInput('enable_prerelease_mode') === 'true', enablePrereleaseMode: toBool(core.getInput('enable_prerelease_mode')),
bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'), bumpEachCommitPatchPattern: core.getInput('bump_each_commit_patch_pattern'),
debug: core.getInput('debug') === 'true', debug: toBool(core.getInput('debug')),
replay: '' replay: ''
}; };
if (config.useBranches) {
core.warning(`The 'use_branches' input option is deprecated, please see the documentation for more information on how to use branches`);
}
if (config.versionFormat === '' && core.getInput('format') !== '') { if (config.versionFormat === '' && core.getInput('format') !== '') {
core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`); core.warning(`The 'format' input is deprecated, use 'versionFormat' instead`);
config.versionFormat = core.getInput('format'); config.versionFormat = core.getInput('format');

View file

@ -9,10 +9,12 @@ import { VersionType } from "./VersionType";
export class BumpAlwaysVersionClassifier extends DefaultVersionClassifier { export class BumpAlwaysVersionClassifier extends DefaultVersionClassifier {
protected patchPattern: (commit: CommitInfo) => boolean; protected patchPattern: (commit: CommitInfo) => boolean;
protected enablePrereleaseMode: boolean;
constructor(config: ActionConfig) { constructor(config: ActionConfig) {
super(config); super(config);
this.enablePrereleaseMode = config.enablePrereleaseMode;
this.patchPattern = !config.bumpEachCommitPatchPattern ? this.patchPattern = !config.bumpEachCommitPatchPattern ?
_ => true : _ => true :
this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody); this.parsePattern(config.bumpEachCommitPatchPattern, "", config.searchCommitBody);
@ -33,28 +35,57 @@ export class BumpAlwaysVersionClassifier extends DefaultVersionClassifier {
} }
for (let commit of commitSet.commits.reverse()) { for (let commit of commitSet.commits.reverse()) {
if (this.majorPattern(commit)) { if (this.majorPattern(commit)) {
type = VersionType.Major;
} else if (this.minorPattern(commit)) {
type = VersionType.Minor;
} else if (this.patchPattern(commit) ||
(major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) {
type = VersionType.Patch;
} else {
type = VersionType.None;
}
if (this.enablePrereleaseMode && major === 0) {
switch (type) {
case VersionType.Major:
case VersionType.Minor:
minor += 1;
patch = 0;
increment = 0;
break;
case VersionType.Patch:
patch += 1;
increment = 0;
break;
default:
increment++;
break;
}
} else {
switch (type) {
case VersionType.Major:
major += 1; major += 1;
minor = 0; minor = 0;
patch = 0; patch = 0;
type = VersionType.Major;
increment = 0; increment = 0;
} else if (this.minorPattern(commit)) { break;
case VersionType.Minor:
minor += 1; minor += 1;
patch = 0; patch = 0;
type = VersionType.Minor; break;
increment = 0; case VersionType.Patch:
} else {
if (this.patchPattern(commit) ||
(major === 0 && minor === 0 && patch === 0 && commitSet.commits.length > 0)) {
patch += 1; patch += 1;
type = VersionType.Patch;
increment = 0; increment = 0;
} else { break;
type = VersionType.None; default:
increment++; increment++;
break;
} }
} }
} }
return new VersionClassification(type, increment, true, major, minor, patch); return new VersionClassification(type, increment, true, major, minor, patch);

View file

@ -10,4 +10,10 @@ export interface CurrentCommitResolver {
* @returns True if the repository is empty * @returns True if the repository is empty
*/ */
IsEmptyRepoAsync(): Promise<boolean>; IsEmptyRepoAsync(): Promise<boolean>;
/**
* Returns the current branch
* @returns The current branch
*/
ResolveBranchNameAsync(): Promise<string>;
} }

View file

@ -22,4 +22,12 @@ export class DefaultCurrentCommitResolver implements CurrentCommitResolver {
let lastCommitAll = (await cmd('git', 'rev-list', '-n1', '--all')).trim(); let lastCommitAll = (await cmd('git', 'rev-list', '-n1', '--all')).trim();
return lastCommitAll === ''; return lastCommitAll === '';
} }
public async ResolveBranchNameAsync(): Promise<string> {
const branchName =
this.branch == 'HEAD' ? await cmd('git', 'rev-parse', '--abbrev-ref', 'HEAD') : this.branch;
return branchName.trim();
}
} }

View file

@ -27,6 +27,8 @@ export class DefaultLastReleaseResolver implements LastReleaseResolver {
const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null]; const [currentMajor, currentMinor, currentPatch] = !!currentTag ? tagFormatter.Parse(currentTag) : [null, null, null];
let tagsCount = 0;
let tag = ''; let tag = '';
try { try {
const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/'; const refPrefixPattern = this.useBranches ? 'refs/heads/' : 'refs/tags/';
@ -34,16 +36,16 @@ export class DefaultLastReleaseResolver implements LastReleaseResolver {
// If we already have the current branch tagged, we are checking for the previous one // If we already have the current branch tagged, we are checking for the previous one
// so that we will have an accurate increment (assuming the new tag is the expected one) // so that we will have an accurate increment (assuming the new tag is the expected one)
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
tag = await cmd(command); const tags = (await cmd(command)).split('\n')
tag = tag tagsCount = tags.length;
.split('\n') tag = tags
.find(t => tagFormatter.IsValid(t) && t !== currentTag) || ''; .find(t => tagFormatter.IsValid(t) && t !== currentTag) || '';
} else { } else {
const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`; const command = `git for-each-ref --sort=-v:*refname --format=%(refname:short) --merged=${current} ${refPrefixPattern}${releasePattern}`;
let tags = await cmd(command); const tags = (await cmd(command)).split('\n')
tagsCount = tags.length;
tag = tags tag = tags
.split('\n')
.find(t => tagFormatter.IsValid(t)) || ''; .find(t => tagFormatter.IsValid(t)) || '';
} }
@ -60,10 +62,15 @@ export class DefaultLastReleaseResolver implements LastReleaseResolver {
// practice this isn't likely to happen, but it keeps the test output from being // practice this isn't likely to happen, but it keeps the test output from being
// polluted with a bunch of warnings. // polluted with a bunch of warnings.
if (tagsCount > 0) {
core.warning(`None of the ${tagsCount} tags(s) found were valid version tags for the present configuration. If this is unexpected, check to ensure that the configuration is correct and matches the tag format you are using.`);
} else {
core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.'); core.warning('No tags are present for this repository. If this is unexpected, check to ensure that tags have been pulled from the remote.');
} }
}
const [major, minor, patch] = tagFormatter.Parse('');
// no release tags yet, use the initial commit as the root // no release tags yet, use the initial commit as the root
return new ReleaseInformation(0, 0, 0, '', currentMajor, currentMinor, currentPatch, isTagged); return new ReleaseInformation(major, minor, patch, '', currentMajor, currentMinor, currentPatch, isTagged);
} }
// parse the version tag // parse the version tag

View file

@ -107,8 +107,8 @@ export class DefaultVersionClassifier implements VersionClassifier {
// - commit 4 - v2.0.1+0 // - commit 4 - v2.0.1+0
const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch; const versionsMatch = lastRelease.currentMajor === major && lastRelease.currentMinor === minor && lastRelease.currentPatch === patch;
const currentIncremement = versionsMatch ? increment : 0; const currentIncrement = versionsMatch ? increment : 0;
return new VersionClassification(VersionType.None, currentIncremement, false, <number>lastRelease.currentMajor, <number>lastRelease.currentMinor, <number>lastRelease.currentPatch); return new VersionClassification(VersionType.None, currentIncrement, false, <number>lastRelease.currentMajor, <number>lastRelease.currentMinor, <number>lastRelease.currentPatch);
} }