generated from hasundue/template-deno
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
111 lines (97 loc) · 2.85 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { intersect } from "https://deno.land/std@0.201.0/collections/intersect.ts";
import {
format,
gt,
increment,
parse,
SemVer,
} from "https://deno.land/std@0.201.0/semver/mod.ts";
import * as commit from "https://deno.land/x/commit@0.1.5/mod.ts";
import { Octokit } from "https://esm.sh/@octokit/core@5.0.0";
const octokit = new Octokit({ auth: Deno.env.get("GITHUB_TOKEN") });
type CommitTypes = {
major: string[];
minor: string[];
patch: string[];
};
type VersioningOptions = {
types: CommitTypes;
};
const defaultVersioningOptions: VersioningOptions = {
types: {
major: ["BREAKING"],
minor: ["feat"],
patch: ["fix"],
},
};
async function getLatestRelease(
owner: string,
repo: string,
) {
try {
const { data: release } = await octokit.request(
"GET /repos/{owner}/{repo}/releases/latest",
{ owner, repo },
);
return release;
} catch {
return null;
}
}
async function getCommits(
owner: string,
repo: string,
base?: string,
) {
if (base) {
const { data } = await octokit.request(
"GET /repos/{owner}/{repo}/compare/{base}...{head}",
{ owner, repo, base, head: "HEAD" },
);
return data.commits.map((entry) => entry.commit);
} else {
const { data } = await octokit.request(
"GET /repos/{owner}/{repo}/commits",
{ owner, repo },
);
return data.map((entry) => entry.commit);
}
}
export function bumpSemVer(
version: string | SemVer,
types: (commit.Field | undefined)[],
options: VersioningOptions = defaultVersioningOptions,
): SemVer {
const include = (triggers: string[]) => intersect(types, triggers).length;
const semver = parse(version);
if (semver.major === 0) {
// an unstable version, for which we do not bump the major version.
const triggers = [...options.types.major, ...options.types.minor];
if (include(triggers)) return increment(semver, "minor");
} else {
// a stable version.
if (include(options.types.major)) return increment(semver, "major");
if (include(options.types.minor)) return increment(semver, "minor");
}
if (include(options.types.patch)) return increment(semver, "patch");
return semver; // no version bump.
}
export async function getNewVersion(
owner: string,
repo: string,
options: VersioningOptions = defaultVersioningOptions,
): Promise<string | null> {
const release = await getLatestRelease(owner, repo);
const commits = await getCommits(owner, repo, release?.tag_name);
const semver = parse(release?.tag_name ?? "0.0.0");
if (!semver) {
throw new Error(
`The latest release tag ${
release!.tag_name
} does not follow the sementic versioning.`,
);
}
const types = commits.map((entry) => commit.parse(entry.message).type);
const newSemVer = bumpSemVer(semver, types, options)!;
return gt(newSemVer, semver) ? format(newSemVer) : null;
}