mirror of
https://github.com/PaulHatch/semantic-version.git
synced 2026-02-11 08:49:21 +00:00
Merge pull request #186 from PaulHatch/commit-patterns
This commit is contained in:
commit
9c93fcdb24
7 changed files with 173 additions and 3 deletions
|
|
@ -36,6 +36,10 @@ inputs:
|
|||
description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs"
|
||||
required: false
|
||||
default: ""
|
||||
ignore_commits_pattern:
|
||||
description: "A pattern to match commits that should be ignored when calculating the version. Commits matching this pattern will not trigger any version bump. Wrap with '/' to use a regular expression."
|
||||
required: false
|
||||
default: ""
|
||||
version_format:
|
||||
description: "Pattern to use when formatting output version"
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ export class ActionConfig {
|
|||
public enablePrereleaseMode: boolean = false;
|
||||
/** If bump_each_commit is also set to true, setting this value will cause the version to increment only if the pattern specified is matched. */
|
||||
public bumpEachCommitPatchPattern: string = "";
|
||||
/** A pattern to match commits that should be ignored when calculating the version. Commits matching this pattern will not trigger any version bump. Wrap with '/' to use a regular expression. */
|
||||
public ignoreCommitsPattern: string = "";
|
||||
/** If enabled, diagnostic information will be added to the action output. */
|
||||
public debug: boolean = false;
|
||||
/** Diagnostics to replay */
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ program
|
|||
"/feat:/",
|
||||
)
|
||||
.option("--minor-flags <flags>", "Flags for minor pattern regex", "")
|
||||
.option(
|
||||
"-i, --ignore-commits-pattern <pattern>",
|
||||
"Pattern to match commits that should be ignored when calculating version",
|
||||
"",
|
||||
)
|
||||
.option(
|
||||
"--version-format <format>",
|
||||
"Version format template",
|
||||
|
|
@ -81,6 +86,7 @@ program
|
|||
config.majorFlags = options.majorFlags || "";
|
||||
config.minorPattern = options.minorPattern;
|
||||
config.minorFlags = options.minorFlags || "";
|
||||
config.ignoreCommitsPattern = options.ignoreCommitsPattern || "";
|
||||
config.bumpEachCommit = options.bumpEachCommit;
|
||||
config.bumpEachCommitPatchPattern =
|
||||
options.bumpEachCommitPatchPattern || "";
|
||||
|
|
|
|||
135
src/main.test.ts
135
src/main.test.ts
|
|
@ -1431,5 +1431,140 @@ testInterfaces.forEach((testInterface) => {
|
|||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Empty major pattern disables major version bumps",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
majorPattern: "",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("fix!: breaking fix");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.0.1+0");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Empty major pattern still allows normal behavior to verify test",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("fix!: breaking fix");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("2.0.0+0");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Empty minor pattern disables minor version bumps",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
minorPattern: "",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("feat: Feature Commit");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.0.1+0");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Empty major and minor patterns result in only patch bumps",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
majorPattern: "",
|
||||
minorPattern: "",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("feat!: Breaking Change");
|
||||
repo.makeCommit("feat: New Feature");
|
||||
repo.makeCommit("Regular Commit");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.0.1+2");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Commits matching ignore pattern are excluded from version calculation",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
ignoreCommitsPattern: "/^chore:|^docs:|^style:/",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("chore: update dependencies");
|
||||
repo.makeCommit("docs: update readme");
|
||||
repo.makeCommit("style: fix formatting");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.0.0+0");
|
||||
expect(result.changed).toBe(false);
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Non-ignored commits still trigger version bumps",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
ignoreCommitsPattern: "/^chore:|^docs:/",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("chore: update dependencies");
|
||||
repo.makeCommit("fix: bug fix");
|
||||
repo.makeCommit("docs: update readme");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.0.1+0");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
|
||||
test(
|
||||
"Ignored commits do not affect major/minor detection",
|
||||
async () => {
|
||||
const repo = createTestRepo(testRunner, {
|
||||
tagPrefix: "",
|
||||
ignoreCommitsPattern: "/^chore:/",
|
||||
});
|
||||
|
||||
repo.makeCommit("Initial Commit");
|
||||
repo.exec("git tag 1.0.0");
|
||||
repo.makeCommit("chore: update dependencies");
|
||||
repo.makeCommit("feat: new feature");
|
||||
repo.makeCommit("chore: cleanup");
|
||||
const result = await repo.runAction();
|
||||
|
||||
expect(result.formattedVersion).toBe("1.1.0+0");
|
||||
},
|
||||
timeout,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ export async function run() {
|
|||
userFormatType: core.getInput("user_format_type"),
|
||||
enablePrereleaseMode: toBool(core.getInput("enable_prerelease_mode")),
|
||||
bumpEachCommitPatchPattern: core.getInput("bump_each_commit_patch_pattern"),
|
||||
ignoreCommitsPattern: core.getInput("ignore_commits_pattern"),
|
||||
debug: toBool(core.getInput("debug")),
|
||||
replay: "",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,15 +38,17 @@ export class BumpAlwaysVersionClassifier extends DefaultVersionClassifier {
|
|||
);
|
||||
}
|
||||
|
||||
const filteredCommitSet = this.filterIgnoredCommits(commitSet);
|
||||
|
||||
let { major, minor, patch } = lastRelease;
|
||||
let type = VersionType.None;
|
||||
let increment = 0;
|
||||
|
||||
if (commitSet.commits.length === 0) {
|
||||
if (filteredCommitSet.commits.length === 0) {
|
||||
return new VersionClassification(type, 0, false, major, minor, patch);
|
||||
}
|
||||
|
||||
for (let commit of commitSet.commits.reverse()) {
|
||||
for (let commit of filteredCommitSet.commits.reverse()) {
|
||||
if (this.majorPattern(commit)) {
|
||||
type = VersionType.Major;
|
||||
} else if (this.minorPattern(commit)) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { VersionType } from "./VersionType";
|
|||
export class DefaultVersionClassifier implements VersionClassifier {
|
||||
protected majorPattern: (commit: CommitInfo) => boolean;
|
||||
protected minorPattern: (commit: CommitInfo) => boolean;
|
||||
protected ignorePattern: ((commit: CommitInfo) => boolean) | null;
|
||||
protected enablePrereleaseMode: boolean;
|
||||
|
||||
constructor(config: ActionConfig) {
|
||||
|
|
@ -23,14 +24,31 @@ export class DefaultVersionClassifier implements VersionClassifier {
|
|||
config.minorFlags,
|
||||
searchBody,
|
||||
);
|
||||
this.ignorePattern = config.ignoreCommitsPattern
|
||||
? this.parsePattern(config.ignoreCommitsPattern, "", searchBody)
|
||||
: null;
|
||||
this.enablePrereleaseMode = config.enablePrereleaseMode;
|
||||
}
|
||||
|
||||
protected filterIgnoredCommits(commitSet: CommitInfoSet): CommitInfoSet {
|
||||
if (!this.ignorePattern) {
|
||||
return commitSet;
|
||||
}
|
||||
const filteredCommits = commitSet.commits.filter(
|
||||
(commit) => !this.ignorePattern!(commit),
|
||||
);
|
||||
const changed = filteredCommits.length > 0 ? commitSet.changed : false;
|
||||
return new CommitInfoSet(changed, filteredCommits);
|
||||
}
|
||||
|
||||
protected parsePattern(
|
||||
pattern: string,
|
||||
flags: string,
|
||||
searchBody: boolean,
|
||||
): (pattern: CommitInfo) => boolean {
|
||||
if (pattern === "") {
|
||||
return (_commit: CommitInfo) => false;
|
||||
}
|
||||
if (/^\/.+\/[i]*$/.test(pattern)) {
|
||||
const regexEnd = pattern.lastIndexOf("/");
|
||||
const parsedFlags = pattern.slice(pattern.lastIndexOf("/") + 1);
|
||||
|
|
@ -149,7 +167,9 @@ export class DefaultVersionClassifier implements VersionClassifier {
|
|||
lastRelease: ReleaseInformation,
|
||||
commitSet: CommitInfoSet,
|
||||
): Promise<VersionClassification> {
|
||||
const { type, increment, changed } = this.resolveCommitType(commitSet);
|
||||
const filteredCommitSet = this.filterIgnoredCommits(commitSet);
|
||||
const { type, increment, changed } =
|
||||
this.resolveCommitType(filteredCommitSet);
|
||||
|
||||
const { major, minor, patch } = this.getNextVersion(lastRelease, type);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue