@tahminator/pipeline 1.0.21 → 1.0.23

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.
@@ -7,7 +7,26 @@ export declare class GitHubClient {
7
7
  private readonly tagManager;
8
8
  private readonly outputManager;
9
9
  private readonly prManager;
10
- constructor(ghToken?: string);
10
+ private constructor();
11
+ /**
12
+ * @note `appId` can be `Client ID` or `App ID`. Hover over `appId` for more details.
13
+ */
14
+ static createWithGithubAppToken({ appId, privateKey, installationId, }: {
15
+ /**
16
+ * get it from https://github.com/settings/apps/<appName> -> `Client ID` or `App ID`
17
+ */
18
+ appId: string;
19
+ privateKey: string;
20
+ /**
21
+ * get it from github.com/settings/installations/<installationId>
22
+ */
23
+ installationId: string;
24
+ }): Promise<GitHubClient>;
25
+ static createWithDefaultCiToken(): Promise<GitHubClient>;
26
+ /**
27
+ * @deprecated use `createWithGithubAppToken`
28
+ */
29
+ static createWithPatCiToken(pat: string): Promise<GitHubClient>;
11
30
  createTag(...args: Parameters<GitHubTagManager["createTag"]>): Promise<void>;
12
31
  outputToGithubOutput(...args: Parameters<GitHubOutputManager["outputToGithubOutput"]>): Promise<void>;
13
32
  updateK8sTagWithPR(...args: Parameters<GitHubPRManager["updateK8sTagWithPR"]>): Promise<void>;
package/dist/gh/client.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createAppAuth } from "@octokit/auth-app";
1
2
  import { Octokit } from "@octokit/rest";
2
3
  import { GitHubOutputManager } from "./output";
3
4
  import { GitHubPRManager } from "./pr";
@@ -8,19 +9,43 @@ export class GitHubClient {
8
9
  tagManager;
9
10
  outputManager;
10
11
  prManager;
11
- constructor(ghToken) {
12
- this.isExplicitToken = !!ghToken;
13
- const token = ghToken ?? process.env.GH_TOKEN;
14
- if (!token) {
15
- throw new Error("No GitHub token has been provided & GH_TOKEN cannot be found in environment");
16
- }
17
- this.client = new Octokit({
18
- auth: token,
19
- });
12
+ constructor(client, isExplicitToken) {
13
+ this.client = client;
14
+ this.isExplicitToken = isExplicitToken;
20
15
  this.tagManager = new GitHubTagManager(this.client, this.isExplicitToken);
21
16
  this.outputManager = new GitHubOutputManager();
22
17
  this.prManager = new GitHubPRManager(this.client);
23
18
  }
19
+ /**
20
+ * @note `appId` can be `Client ID` or `App ID`. Hover over `appId` for more details.
21
+ */
22
+ static async createWithGithubAppToken({ appId, privateKey, installationId, }) {
23
+ return new this(new Octokit({
24
+ authStrategy: createAppAuth,
25
+ auth: {
26
+ appId,
27
+ privateKey,
28
+ installationId,
29
+ },
30
+ }), true);
31
+ }
32
+ static async createWithDefaultCiToken() {
33
+ const token = process.env.GH_TOKEN;
34
+ if (!token) {
35
+ throw new Error("GH_TOKEN cannot be found in environment");
36
+ }
37
+ return new this(new Octokit({
38
+ auth: token,
39
+ }), false);
40
+ }
41
+ /**
42
+ * @deprecated use `createWithGithubAppToken`
43
+ */
44
+ static async createWithPatCiToken(pat) {
45
+ return new this(new Octokit({
46
+ auth: pat,
47
+ }), true);
48
+ }
24
49
  createTag(...args) {
25
50
  return this.tagManager.createTag(...args);
26
51
  }
@@ -1,8 +1,12 @@
1
1
  import { GitHubClient } from "../../gh";
2
2
  import { Utils } from "../../utils";
3
3
  async function main() {
4
- const { githubPat } = parseCiEnv(await Utils.getEnvVariables(["ci"]));
5
- const ghClient = new GitHubClient(githubPat);
4
+ const { githubAppAppId, githubAppInstallationId, githubAppPrivateKeyB64 } = parseCiEnv(await Utils.getEnvVariables(["ci"]));
5
+ const ghClient = await GitHubClient.createWithGithubAppToken({
6
+ appId: githubAppAppId,
7
+ installationId: githubAppInstallationId,
8
+ privateKey: await Utils.decodeBase64EncodedString(githubAppPrivateKeyB64),
9
+ });
6
10
  await ghClient.createTag({
7
11
  onPreTagCreate: async (tag) => {
8
12
  const file = Bun.file("./package.json");
@@ -14,14 +18,28 @@ async function main() {
14
18
  });
15
19
  }
16
20
  function parseCiEnv(ciEnv) {
17
- const githubPat = (() => {
18
- const v = ciEnv["GITHUB_PAT"];
21
+ const githubAppAppId = (() => {
22
+ const v = ciEnv["GITHUB_APP_APP_ID"];
23
+ if (!v) {
24
+ throw new Error("Missing GITHUB_APP_APP_ID from .env.ci");
25
+ }
26
+ return v;
27
+ })();
28
+ const githubAppInstallationId = (() => {
29
+ const v = ciEnv["GITHUB_APP_INSTALLATION_ID"];
30
+ if (!v) {
31
+ throw new Error("Missing GITHUB_APP_INSTALLATION_ID from .env.ci");
32
+ }
33
+ return v;
34
+ })();
35
+ const githubAppPrivateKeyB64 = (() => {
36
+ const v = ciEnv["GITHUB_APP_PRIVATE_KEY_B64"];
19
37
  if (!v) {
20
- throw new Error("Missing GITHUB_PAT from .env.ci");
38
+ throw new Error("Missing GITHUB_APP_PRIVATE_KEY_B64 from .env.ci");
21
39
  }
22
40
  return v;
23
41
  })();
24
- return { githubPat };
42
+ return { githubAppAppId, githubAppInstallationId, githubAppPrivateKeyB64 };
25
43
  }
26
44
  main()
27
45
  .then(() => {
@@ -4,23 +4,53 @@ type SonarScannerOpts = {
4
4
  token: string;
5
5
  };
6
6
  run: {
7
+ /**
8
+ * Pass in a Bun command
9
+ *
10
+ * @example
11
+ * ```
12
+ * new SonarScannerClient({
13
+ * run: {
14
+ * runTestsCmd: $`./mvnw clean verify -Dspring.profiles.active=ci`
15
+ * }
16
+ * })
17
+ * ```
18
+ */
7
19
  runTestsCmd: $.ShellPromise;
8
20
  };
9
21
  scan: {
10
22
  hostUrl?: string;
23
+ /**
24
+ * All args will be formated into `-Dsonar.${key}=${value}`
25
+ */
11
26
  additionalArgs?: Record<string, string | number | boolean>;
12
27
  projectKey: string;
13
28
  organization: string;
29
+ /**
30
+ * Point this at where your source code files reside. e.g. `src/` or `src/java`
31
+ */
14
32
  sourceCodeDir: string;
15
33
  };
16
34
  };
17
35
  /**
18
- * @beta WIP
36
+ * Provides a unified way to run tests & upload test coverage to a SonarQube instance.
37
+ *
38
+ * This client can be used to wire up test coverage for any language & environment; essentially, if SonarQube
39
+ * supports it, this client can do it.
19
40
  */
20
41
  export declare class SonarScannerClient {
21
42
  private readonly opts;
43
+ /**
44
+ * Get `token`, `projectKey` & `organization` from https://sonarcloud.io/project/configuration/GitHubManual?id=<project_name>
45
+ */
22
46
  constructor(opts: SonarScannerOpts);
47
+ /**
48
+ * Runs `opts.run.runTestsCmd`
49
+ */
23
50
  runTests(): Promise<void>;
24
- uploadTests(): Promise<void>;
51
+ /**
52
+ * Upload test coverage to SonarQube.
53
+ */
54
+ uploadTestCoverage(): Promise<void>;
25
55
  }
26
56
  export {};
@@ -1,17 +1,29 @@
1
1
  import { $ } from "bun";
2
2
  import { isCmdAvailable } from "../utils/cmd";
3
3
  /**
4
- * @beta WIP
4
+ * Provides a unified way to run tests & upload test coverage to a SonarQube instance.
5
+ *
6
+ * This client can be used to wire up test coverage for any language & environment; essentially, if SonarQube
7
+ * supports it, this client can do it.
5
8
  */
6
9
  export class SonarScannerClient {
7
10
  opts;
11
+ /**
12
+ * Get `token`, `projectKey` & `organization` from https://sonarcloud.io/project/configuration/GitHubManual?id=<project_name>
13
+ */
8
14
  constructor(opts) {
9
15
  this.opts = opts;
10
16
  }
17
+ /**
18
+ * Runs `opts.run.runTestsCmd`
19
+ */
11
20
  async runTests() {
12
21
  await this.opts.run.runTestsCmd;
13
22
  }
14
- async uploadTests() {
23
+ /**
24
+ * Upload test coverage to SonarQube.
25
+ */
26
+ async uploadTestCoverage() {
15
27
  if (!(await isCmdAvailable("sonar"))) {
16
28
  console.log("Sonar is missing, installing globally via NPM...");
17
29
  await $ `npm i -g @sonar/scan`;
@@ -0,0 +1 @@
1
+ export declare function decodeBase64EncodedString(s: string): string;
@@ -0,0 +1,3 @@
1
+ export function decodeBase64EncodedString(s) {
2
+ return Buffer.from(s, "base64").toString("utf-8");
3
+ }
@@ -1,3 +1,4 @@
1
+ import { decodeBase64EncodedString } from "./b64";
1
2
  import { isCmdAvailable } from "./cmd";
2
3
  import { Colors } from "./colors";
3
4
  import { getEnvVariables } from "./env";
@@ -10,4 +11,5 @@ export declare class Utils {
10
11
  static generateShortId(...args: Parameters<typeof generateShortId>): string;
11
12
  static updateAllPackageJsonsWithVersion(version: string): Promise<void>;
12
13
  static isCmdAvailable(...args: Parameters<typeof isCmdAvailable>): Promise<boolean>;
14
+ static decodeBase64EncodedString(...args: Parameters<typeof decodeBase64EncodedString>): Promise<string>;
13
15
  }
@@ -1,4 +1,5 @@
1
1
  import { $ } from "bun";
2
+ import { decodeBase64EncodedString } from "./b64";
2
3
  import { isCmdAvailable } from "./cmd";
3
4
  import { Colors } from "./colors";
4
5
  import { getEnvVariables } from "./env";
@@ -29,4 +30,7 @@ export class Utils {
29
30
  static async isCmdAvailable(...args) {
30
31
  return isCmdAvailable(...args);
31
32
  }
33
+ static async decodeBase64EncodedString(...args) {
34
+ return decodeBase64EncodedString(...args);
35
+ }
32
36
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "author": "Tahmid Ahmed",
5
5
  "description": "A collection of Bun shell scripts that can be re-used in various CICD pipelines.",
6
- "version": "1.0.21",
6
+ "version": "1.0.23",
7
7
  "repository": {
8
8
  "url": "git+https://github.com/tahminator/pipeline.git"
9
9
  },
@@ -46,6 +46,7 @@
46
46
  "typescript": "^5"
47
47
  },
48
48
  "dependencies": {
49
+ "@octokit/auth-app": "^8.2.0",
49
50
  "@octokit/rest": "^22.0.1",
50
51
  "@types/semver": "^7.7.1",
51
52
  "@types/yargs": "^17.0.35",