keycloakify 4.7.6 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +45 -11
  3. package/bin/build-keycloak-theme/build-keycloak-theme.d.ts +1 -0
  4. package/bin/build-keycloak-theme/build-keycloak-theme.js +13 -8
  5. package/bin/build-keycloak-theme/build-keycloak-theme.js.map +1 -1
  6. package/bin/build-keycloak-theme/generateJavaStackFiles.d.ts +1 -0
  7. package/bin/build-keycloak-theme/generateJavaStackFiles.js +27 -2
  8. package/bin/build-keycloak-theme/generateJavaStackFiles.js.map +1 -1
  9. package/bin/build-keycloak-theme/generateKeycloakThemeResources.d.ts +4 -1
  10. package/bin/build-keycloak-theme/generateKeycloakThemeResources.js +18 -1
  11. package/bin/build-keycloak-theme/generateKeycloakThemeResources.js.map +1 -1
  12. package/bin/create-keycloak-theme-email-directory.d.ts +2 -0
  13. package/bin/create-keycloak-theme-email-directory.js +94 -0
  14. package/bin/create-keycloak-theme-email-directory.js.map +1 -0
  15. package/bin/download-builtin-keycloak-theme.js +54 -13
  16. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  17. package/bin/promptKeycloakVersion.d.ts +3 -0
  18. package/bin/promptKeycloakVersion.js +91 -0
  19. package/bin/promptKeycloakVersion.js.map +1 -0
  20. package/bin/tools/NpmModuleVersion.d.ts +22 -0
  21. package/bin/tools/NpmModuleVersion.js +103 -0
  22. package/bin/tools/NpmModuleVersion.js.map +1 -0
  23. package/bin/tools/createOctokit.d.ts +5 -0
  24. package/bin/tools/createOctokit.js +21 -0
  25. package/bin/tools/createOctokit.js.map +1 -0
  26. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.d.ts +15 -0
  27. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.js +112 -0
  28. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.js.map +1 -0
  29. package/bin/tools/octokit-addons/listTags.d.ts +13 -0
  30. package/bin/tools/octokit-addons/listTags.js +154 -0
  31. package/bin/tools/octokit-addons/listTags.js.map +1 -0
  32. package/lib/i18n/KcLanguageTag.d.ts +1 -1
  33. package/lib/i18n/useKcLanguageTag.d.ts +1 -1
  34. package/package.json +31 -4
  35. package/src/bin/build-keycloak-theme/build-keycloak-theme.ts +13 -6
  36. package/src/bin/build-keycloak-theme/generateJavaStackFiles.ts +9 -3
  37. package/src/bin/build-keycloak-theme/generateKeycloakThemeResources.ts +27 -1
  38. package/src/bin/create-keycloak-theme-email-directory.ts +36 -0
  39. package/src/bin/download-builtin-keycloak-theme.ts +10 -15
  40. package/src/bin/promptKeycloakVersion.ts +44 -0
  41. package/src/bin/tools/NpmModuleVersion.ts +73 -0
  42. package/src/bin/tools/createOctokit.ts +7 -0
  43. package/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +40 -0
  44. package/src/bin/tools/octokit-addons/listTags.ts +49 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloakify",
3
- "version": "4.7.6",
3
+ "version": "4.8.2",
4
4
  "description": "Keycloak theme generator for Reacts app",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,6 +10,7 @@
10
10
  "types": "lib/index.d.ts",
11
11
  "bin": {
12
12
  "build-keycloak-theme": "bin/build-keycloak-theme/index.js",
13
+ "create-keycloak-theme-email-directory": "bin/create-keycloak-theme-email-directory.js",
13
14
  "download-builtin-keycloak-theme": "bin/download-builtin-keycloak-theme.js"
14
15
  },
15
16
  "lint-staged": {
@@ -35,14 +36,20 @@
35
36
  "src/bin/build-keycloak-theme/generateStartKeycloakTestingContainer.ts",
36
37
  "src/bin/build-keycloak-theme/index.ts",
37
38
  "src/bin/build-keycloak-theme/replaceImportFromStatic.ts",
39
+ "src/bin/create-keycloak-theme-email-directory.ts",
38
40
  "src/bin/download-builtin-keycloak-theme.ts",
39
41
  "src/bin/generate-i18n-messages.ts",
40
42
  "src/bin/link_in_test_app.ts",
43
+ "src/bin/promptKeycloakVersion.ts",
44
+ "src/bin/tools/NpmModuleVersion.ts",
41
45
  "src/bin/tools/crawl.ts",
46
+ "src/bin/tools/createOctokit.ts",
42
47
  "src/bin/tools/downloadAndUnzip.ts",
43
48
  "src/bin/tools/getProjectRoot.ts",
44
49
  "src/bin/tools/grant-exec-perms.ts",
45
50
  "src/bin/tools/isInside.ts",
51
+ "src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts",
52
+ "src/bin/tools/octokit-addons/listTags.ts",
46
53
  "src/bin/tools/rm.ts",
47
54
  "src/bin/tools/transformCodebase.ts",
48
55
  "src/lib/components/Error.tsx",
@@ -124,6 +131,9 @@
124
131
  "bin/build-keycloak-theme/replaceImportFromStatic.d.ts",
125
132
  "bin/build-keycloak-theme/replaceImportFromStatic.js",
126
133
  "bin/build-keycloak-theme/replaceImportFromStatic.js.map",
134
+ "bin/create-keycloak-theme-email-directory.d.ts",
135
+ "bin/create-keycloak-theme-email-directory.js",
136
+ "bin/create-keycloak-theme-email-directory.js.map",
127
137
  "bin/download-builtin-keycloak-theme.d.ts",
128
138
  "bin/download-builtin-keycloak-theme.js",
129
139
  "bin/download-builtin-keycloak-theme.js.map",
@@ -133,9 +143,18 @@
133
143
  "bin/link_in_test_app.d.ts",
134
144
  "bin/link_in_test_app.js",
135
145
  "bin/link_in_test_app.js.map",
146
+ "bin/promptKeycloakVersion.d.ts",
147
+ "bin/promptKeycloakVersion.js",
148
+ "bin/promptKeycloakVersion.js.map",
149
+ "bin/tools/NpmModuleVersion.d.ts",
150
+ "bin/tools/NpmModuleVersion.js",
151
+ "bin/tools/NpmModuleVersion.js.map",
136
152
  "bin/tools/crawl.d.ts",
137
153
  "bin/tools/crawl.js",
138
154
  "bin/tools/crawl.js.map",
155
+ "bin/tools/createOctokit.d.ts",
156
+ "bin/tools/createOctokit.js",
157
+ "bin/tools/createOctokit.js.map",
139
158
  "bin/tools/downloadAndUnzip.d.ts",
140
159
  "bin/tools/downloadAndUnzip.js",
141
160
  "bin/tools/downloadAndUnzip.js.map",
@@ -148,6 +167,12 @@
148
167
  "bin/tools/isInside.d.ts",
149
168
  "bin/tools/isInside.js",
150
169
  "bin/tools/isInside.js.map",
170
+ "bin/tools/octokit-addons/getLatestsSemVersionedTag.d.ts",
171
+ "bin/tools/octokit-addons/getLatestsSemVersionedTag.js",
172
+ "bin/tools/octokit-addons/getLatestsSemVersionedTag.js.map",
173
+ "bin/tools/octokit-addons/listTags.d.ts",
174
+ "bin/tools/octokit-addons/listTags.js",
175
+ "bin/tools/octokit-addons/listTags.js.map",
151
176
  "bin/tools/rm.d.ts",
152
177
  "bin/tools/rm.js",
153
178
  "bin/tools/rm.js.map",
@@ -325,7 +350,7 @@
325
350
  },
326
351
  "devDependencies": {
327
352
  "@emotion/react": "^11.4.1",
328
- "@types/node": "^10.0.0",
353
+ "@types/node": "^17.0.25",
329
354
  "@types/react": "^17.0.0",
330
355
  "copyfiles": "^2.4.1",
331
356
  "husky": "^4.3.8",
@@ -337,14 +362,16 @@
337
362
  "typescript": "^4.2.3"
338
363
  },
339
364
  "dependencies": {
365
+ "@octokit/rest": "^18.12.0",
340
366
  "cheerio": "^1.0.0-rc.5",
367
+ "cli-select": "^1.1.2",
341
368
  "evt": "2.0.0-beta.39",
342
369
  "minimal-polyfills": "^2.2.1",
343
370
  "path-browserify": "^1.0.1",
371
+ "powerhooks": "^0.14.0",
344
372
  "react-markdown": "^5.0.3",
345
373
  "scripting-tools": "^0.19.13",
346
374
  "tsafe": "^0.9.0",
347
- "tss-react": "^3.5.2",
348
- "powerhooks": "^0.14.0"
375
+ "tss-react": "^3.5.2"
349
376
  }
350
377
  }
@@ -19,6 +19,7 @@ const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-asset
19
19
  const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
20
20
 
21
21
  export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
22
+ export const keycloakThemeEmailDirPath = pathJoin(keycloakThemeBuildingDirPath, "..", "keycloak_theme_email");
22
23
 
23
24
  function sanitizeThemeName(name: string) {
24
25
  return name
@@ -34,8 +35,9 @@ export function main() {
34
35
  const extraThemeProperties: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraThemeProperties"] ?? [];
35
36
  const themeName = sanitizeThemeName(parsedPackageJson.name);
36
37
 
37
- generateKeycloakThemeResources({
38
+ const { doBundleEmailTemplate } = generateKeycloakThemeResources({
38
39
  keycloakThemeBuildingDirPath,
40
+ keycloakThemeEmailDirPath,
39
41
  "reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
40
42
  themeName,
41
43
  ...(() => {
@@ -78,21 +80,24 @@ export function main() {
78
80
  });
79
81
 
80
82
  const { jarFilePath } = generateJavaStackFiles({
81
- version: parsedPackageJson.version,
83
+ "version": parsedPackageJson.version,
82
84
  themeName,
83
- homepage: parsedPackageJson.homepage,
85
+ "homepage": parsedPackageJson.homepage,
84
86
  keycloakThemeBuildingDirPath,
87
+ doBundleEmailTemplate,
85
88
  });
86
89
 
87
90
  child_process.execSync("mvn package", {
88
91
  "cwd": keycloakThemeBuildingDirPath,
89
92
  });
90
93
 
94
+ //We want, however to test in a container running the latest Keycloak version
95
+ const containerKeycloakVersion = "18.0.0";
96
+
91
97
  generateStartKeycloakTestingContainer({
92
98
  keycloakThemeBuildingDirPath,
93
99
  themeName,
94
- //We want, however to test in a container running the latest Keycloak version
95
- "keycloakVersion": "17.0.1",
100
+ "keycloakVersion": containerKeycloakVersion,
96
101
  });
97
102
 
98
103
  console.log(
@@ -129,10 +134,12 @@ export function main() {
129
134
  " value: -Dkeycloak.profile=preview",
130
135
  "",
131
136
  "",
132
- "To test your theme locally, with hot reloading, you can spin up a Keycloak container image with the theme loaded by running:",
137
+ `To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
133
138
  "",
134
139
  `👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename))} 👈`,
135
140
  "",
141
+ "Test with different Keycloak versions by editing the .sh file. see available versions here: https://quay.io/repository/keycloak/keycloak?tab=tags",
142
+ "",
136
143
  "Once your container is up and running: ",
137
144
  "- Log into the admin console 👉 http://localhost:8080/admin username: admin, password: admin 👈",
138
145
  '- Create a realm named "myrealm"',
@@ -2,10 +2,16 @@ import * as url from "url";
2
2
  import * as fs from "fs";
3
3
  import { join as pathJoin, dirname as pathDirname } from "path";
4
4
 
5
- export function generateJavaStackFiles(params: { version: string; themeName: string; homepage?: string; keycloakThemeBuildingDirPath: string }): {
5
+ export function generateJavaStackFiles(params: {
6
+ version: string;
7
+ themeName: string;
8
+ homepage?: string;
9
+ keycloakThemeBuildingDirPath: string;
10
+ doBundleEmailTemplate: boolean;
11
+ }): {
6
12
  jarFilePath: string;
7
13
  } {
8
- const { themeName, version, homepage, keycloakThemeBuildingDirPath } = params;
14
+ const { themeName, version, homepage, keycloakThemeBuildingDirPath, doBundleEmailTemplate } = params;
9
15
 
10
16
  {
11
17
  const { pomFileCode } = (function generatePomFileCode(): {
@@ -63,7 +69,7 @@ export function generateJavaStackFiles(params: { version: string; themeName: str
63
69
  "themes": [
64
70
  {
65
71
  "name": themeName,
66
- "types": ["login"],
72
+ "types": ["login", ...(doBundleEmailTemplate ? ["email"] : [])],
67
73
  },
68
74
  ],
69
75
  },
@@ -12,17 +12,19 @@ export function generateKeycloakThemeResources(params: {
12
12
  themeName: string;
13
13
  reactAppBuildDirPath: string;
14
14
  keycloakThemeBuildingDirPath: string;
15
+ keycloakThemeEmailDirPath: string;
15
16
  urlPathname: string;
16
17
  //If urlOrigin is not undefined then it means --externals-assets
17
18
  urlOrigin: undefined | string;
18
19
  extraPagesId: string[];
19
20
  extraThemeProperties: string[];
20
21
  keycloakVersion: string;
21
- }) {
22
+ }): { doBundleEmailTemplate: boolean } {
22
23
  const {
23
24
  themeName,
24
25
  reactAppBuildDirPath,
25
26
  keycloakThemeBuildingDirPath,
27
+ keycloakThemeEmailDirPath,
26
28
  urlPathname,
27
29
  urlOrigin,
28
30
  extraPagesId,
@@ -79,6 +81,28 @@ export function generateKeycloakThemeResources(params: {
79
81
  },
80
82
  });
81
83
 
84
+ let doBundleEmailTemplate: boolean;
85
+
86
+ email: {
87
+ if (!fs.existsSync(keycloakThemeEmailDirPath)) {
88
+ console.log(
89
+ [
90
+ `Not bundling email template because ${pathBasename(keycloakThemeEmailDirPath)} does not exist`,
91
+ `To start customizing the email template, run: 👉 npx create-keycloak-theme-email-directory 👈`,
92
+ ].join("\n"),
93
+ );
94
+ doBundleEmailTemplate = false;
95
+ break email;
96
+ }
97
+
98
+ doBundleEmailTemplate = true;
99
+
100
+ transformCodebase({
101
+ "srcDirPath": keycloakThemeEmailDirPath,
102
+ "destDirPath": pathJoin(themeDirPath, "..", "email"),
103
+ });
104
+ }
105
+
82
106
  const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
83
107
  "cssGlobalsToDefine": allCssGlobalsToDefine,
84
108
  "indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
@@ -139,4 +163,6 @@ export function generateKeycloakThemeResources(params: {
139
163
  pathJoin(themeDirPath, "theme.properties"),
140
164
  Buffer.from("parent=keycloak".concat("\n\n", extraThemeProperties.join("\n\n")), "utf8"),
141
165
  );
166
+
167
+ return { doBundleEmailTemplate };
142
168
  }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme";
4
+ import { keycloakThemeEmailDirPath } from "./build-keycloak-theme";
5
+ import { join as pathJoin, basename as pathBasename } from "path";
6
+ import { transformCodebase } from "./tools/transformCodebase";
7
+ import { promptKeycloakVersion } from "./promptKeycloakVersion";
8
+ import * as fs from "fs";
9
+
10
+ if (require.main === module) {
11
+ (async () => {
12
+ if (fs.existsSync(keycloakThemeEmailDirPath)) {
13
+ console.log(`There is already a ./${pathBasename(keycloakThemeEmailDirPath)} directory in your project. Aborting.`);
14
+
15
+ process.exit(-1);
16
+ }
17
+
18
+ const { keycloakVersion } = await promptKeycloakVersion();
19
+
20
+ const builtinKeycloakThemeTmpDirPath = pathJoin(keycloakThemeEmailDirPath, "..", "tmp_xIdP3_builtin_keycloak_theme");
21
+
22
+ downloadBuiltinKeycloakTheme({
23
+ keycloakVersion,
24
+ "destDirPath": builtinKeycloakThemeTmpDirPath,
25
+ });
26
+
27
+ transformCodebase({
28
+ "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"),
29
+ "destDirPath": keycloakThemeEmailDirPath,
30
+ });
31
+
32
+ console.log(`./${pathBasename(keycloakThemeEmailDirPath)} ready to be customized`);
33
+
34
+ fs.rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true, "force": true });
35
+ })();
36
+ }
@@ -3,6 +3,7 @@
3
3
  import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme";
4
4
  import { join as pathJoin } from "path";
5
5
  import { downloadAndUnzip } from "./tools/downloadAndUnzip";
6
+ import { promptKeycloakVersion } from "./promptKeycloakVersion";
6
7
 
7
8
  export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; destDirPath: string }) {
8
9
  const { keycloakVersion, destDirPath } = params;
@@ -17,22 +18,16 @@ export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string;
17
18
  }
18
19
 
19
20
  if (require.main === module) {
20
- const keycloakVersion = (() => {
21
- const keycloakVersion = process.argv[2] as string | undefined;
21
+ (async () => {
22
+ const { keycloakVersion } = await promptKeycloakVersion();
22
23
 
23
- if (keycloakVersion === undefined) {
24
- return "11.0.3";
25
- }
24
+ const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
26
25
 
27
- return keycloakVersion;
28
- })();
29
-
30
- const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
31
-
32
- console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
26
+ console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
33
27
 
34
- downloadBuiltinKeycloakTheme({
35
- keycloakVersion,
36
- destDirPath,
37
- });
28
+ downloadBuiltinKeycloakTheme({
29
+ keycloakVersion,
30
+ destDirPath,
31
+ });
32
+ })();
38
33
  }
@@ -0,0 +1,44 @@
1
+ import { getLatestsSemVersionedTagFactory } from "./tools/octokit-addons/getLatestsSemVersionedTag";
2
+ import { Octokit } from "@octokit/rest";
3
+ import cliSelect from "cli-select";
4
+
5
+ export async function promptKeycloakVersion() {
6
+ const { getLatestsSemVersionedTag } = (() => {
7
+ const { octokit } = (() => {
8
+ const githubToken = process.env.GITHUB_TOKEN;
9
+
10
+ const octokit = new Octokit(githubToken === undefined ? undefined : { "auth": githubToken });
11
+
12
+ return { octokit };
13
+ })();
14
+
15
+ const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ octokit });
16
+
17
+ return { getLatestsSemVersionedTag };
18
+ })();
19
+
20
+ console.log("Initialize the directory with email template from which keycloak version?");
21
+
22
+ const tags = await getLatestsSemVersionedTag({
23
+ "count": 15,
24
+ "doIgnoreBeta": true,
25
+ "owner": "keycloak",
26
+ "repo": "keycloak",
27
+ }).then(arr => arr.map(({ tag }) => tag));
28
+
29
+ if (process.env["GITHUB_ACTIONS"] === "true") {
30
+ return { "keycloakVersion": tags[0] };
31
+ }
32
+
33
+ const { value: keycloakVersion } = await cliSelect<string>({
34
+ "values": tags,
35
+ }).catch(() => {
36
+ console.log("Aborting");
37
+
38
+ process.exit(-1);
39
+ });
40
+
41
+ console.log(keycloakVersion);
42
+
43
+ return { keycloakVersion };
44
+ }
@@ -0,0 +1,73 @@
1
+ export type NpmModuleVersion = {
2
+ major: number;
3
+ minor: number;
4
+ patch: number;
5
+ betaPreRelease?: number;
6
+ };
7
+
8
+ export namespace NpmModuleVersion {
9
+ export function parse(versionStr: string): NpmModuleVersion {
10
+ const match = versionStr.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-beta.([0-9]+))?/);
11
+
12
+ if (!match) {
13
+ throw new Error(`${versionStr} is not a valid NPM version`);
14
+ }
15
+
16
+ return {
17
+ "major": parseInt(match[1]),
18
+ "minor": parseInt(match[2]),
19
+ "patch": parseInt(match[3]),
20
+ ...(() => {
21
+ const str = match[4];
22
+ return str === undefined ? {} : { "betaPreRelease": parseInt(str) };
23
+ })(),
24
+ };
25
+ }
26
+
27
+ export function stringify(v: NpmModuleVersion) {
28
+ return `${v.major}.${v.minor}.${v.patch}${v.betaPreRelease === undefined ? "" : `-beta.${v.betaPreRelease}`}`;
29
+ }
30
+
31
+ /**
32
+ *
33
+ * v1 < v2 => -1
34
+ * v1 === v2 => 0
35
+ * v1 > v2 => 1
36
+ *
37
+ */
38
+ export function compare(v1: NpmModuleVersion, v2: NpmModuleVersion): -1 | 0 | 1 {
39
+ const sign = (diff: number): -1 | 0 | 1 => (diff === 0 ? 0 : diff < 0 ? -1 : 1);
40
+ const noUndefined = (n: number | undefined) => n ?? Infinity;
41
+
42
+ for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
43
+ if (noUndefined(v1[level]) !== noUndefined(v2[level])) {
44
+ return sign(noUndefined(v1[level]) - noUndefined(v2[level]));
45
+ }
46
+ }
47
+
48
+ return 0;
49
+ }
50
+
51
+ /*
52
+ console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0")) === -1 )
53
+ console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0-beta.4")) === -1 )
54
+ console.log(compare(parse("3.0.0-beta.3"), parse("4.0.0")) === -1 )
55
+ */
56
+
57
+ export function bumpType(params: { versionBehindStr: string; versionAheadStr: string }): "major" | "minor" | "patch" | "betaPreRelease" | "same" {
58
+ const versionAhead = parse(params.versionAheadStr);
59
+ const versionBehind = parse(params.versionBehindStr);
60
+
61
+ if (compare(versionBehind, versionAhead) === 1) {
62
+ throw new Error(`Version regression ${versionBehind} -> ${versionAhead}`);
63
+ }
64
+
65
+ for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
66
+ if (versionBehind[level] !== versionAhead[level]) {
67
+ return level;
68
+ }
69
+ }
70
+
71
+ return "same";
72
+ }
73
+ }
@@ -0,0 +1,7 @@
1
+ import { Octokit } from "@octokit/rest";
2
+
3
+ export function createOctokit(params: { github_token: string }) {
4
+ const { github_token } = params;
5
+
6
+ return new Octokit({ ...(github_token !== "" ? { "auth": github_token } : {}) });
7
+ }
@@ -0,0 +1,40 @@
1
+ import { listTagsFactory } from "./listTags";
2
+ import type { Octokit } from "@octokit/rest";
3
+ import { NpmModuleVersion } from "../NpmModuleVersion";
4
+
5
+ export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) {
6
+ const { octokit } = params;
7
+
8
+ async function getLatestsSemVersionedTag(params: { owner: string; repo: string; doIgnoreBeta: boolean; count: number }): Promise<
9
+ {
10
+ tag: string;
11
+ version: NpmModuleVersion;
12
+ }[]
13
+ > {
14
+ const { owner, repo, doIgnoreBeta, count } = params;
15
+
16
+ const semVersionedTags: { tag: string; version: NpmModuleVersion }[] = [];
17
+
18
+ const { listTags } = listTagsFactory({ octokit });
19
+
20
+ for await (const tag of listTags({ owner, repo })) {
21
+ let version: NpmModuleVersion;
22
+
23
+ try {
24
+ version = NpmModuleVersion.parse(tag.replace(/^[vV]?/, ""));
25
+ } catch {
26
+ continue;
27
+ }
28
+
29
+ if (doIgnoreBeta && version.betaPreRelease !== undefined) {
30
+ continue;
31
+ }
32
+
33
+ semVersionedTags.push({ tag, version });
34
+ }
35
+
36
+ return semVersionedTags.sort(({ version: vX }, { version: vY }) => NpmModuleVersion.compare(vY, vX)).slice(0, count);
37
+ }
38
+
39
+ return { getLatestsSemVersionedTag };
40
+ }
@@ -0,0 +1,49 @@
1
+ import type { Octokit } from "@octokit/rest";
2
+
3
+ const per_page = 99;
4
+
5
+ export function listTagsFactory(params: { octokit: Octokit }) {
6
+ const { octokit } = params;
7
+
8
+ const octokit_repo_listTags = async (params: { owner: string; repo: string; per_page: number; page: number }) => {
9
+ return octokit.repos.listTags(params);
10
+ };
11
+
12
+ async function* listTags(params: { owner: string; repo: string }): AsyncGenerator<string> {
13
+ const { owner, repo } = params;
14
+
15
+ let page = 1;
16
+
17
+ while (true) {
18
+ const resp = await octokit_repo_listTags({
19
+ owner,
20
+ repo,
21
+ per_page,
22
+ "page": page++,
23
+ });
24
+
25
+ for (const branch of resp.data.map(({ name }) => name)) {
26
+ yield branch;
27
+ }
28
+
29
+ if (resp.data.length < 99) {
30
+ break;
31
+ }
32
+ }
33
+ }
34
+
35
+ /** Returns the same "latest" tag as deno.land/x, not actually the latest though */
36
+ async function getLatestTag(params: { owner: string; repo: string }): Promise<string | undefined> {
37
+ const { owner, repo } = params;
38
+
39
+ const itRes = await listTags({ owner, repo }).next();
40
+
41
+ if (itRes.done) {
42
+ return undefined;
43
+ }
44
+
45
+ return itRes.value;
46
+ }
47
+
48
+ return { listTags, getLatestTag };
49
+ }