@skuba-lib/api 0.0.0 → 0.1.0-skuba-lib-api-20250925050503

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -0
  3. package/buildkite/package.json +5 -0
  4. package/git/package.json +5 -0
  5. package/github/package.json +5 -0
  6. package/lib/buildkite/index.d.mts +2 -0
  7. package/lib/buildkite/index.d.ts +2 -0
  8. package/lib/buildkite/index.js +6 -0
  9. package/lib/buildkite/index.mjs +5 -0
  10. package/lib/buildkite-BXHjSY0I.js +67 -0
  11. package/lib/buildkite-DSHpKA4z.mjs +50 -0
  12. package/lib/chunk-CZCtuq8p.mjs +37 -0
  13. package/lib/chunk-odGzh3W-.js +58 -0
  14. package/lib/exec-B2akdw0z.js +17597 -0
  15. package/lib/exec-p0gJ30UO.mjs +17580 -0
  16. package/lib/git/index.d.mts +2 -0
  17. package/lib/git/index.d.ts +2 -0
  18. package/lib/git/index.js +14 -0
  19. package/lib/git/index.mjs +3 -0
  20. package/lib/git-DDfcZdbm.mjs +379 -0
  21. package/lib/git-DVG_dHiI.js +474 -0
  22. package/lib/github/index.d.mts +3 -0
  23. package/lib/github/index.d.ts +3 -0
  24. package/lib/github/index.js +12 -0
  25. package/lib/github/index.mjs +5 -0
  26. package/lib/github-B4auwKt7.js +310 -0
  27. package/lib/github-vycKoVtK.mjs +269 -0
  28. package/lib/index-1eEu26nG.d.ts +255 -0
  29. package/lib/index-9i8gHTGu.d.mts +38 -0
  30. package/lib/index-B91wXiwr.d.ts +278 -0
  31. package/lib/index-CfnlMf_4.d.ts +39 -0
  32. package/lib/index-Cl--YMPq.d.mts +255 -0
  33. package/lib/index-DNXQKEza.d.mts +278 -0
  34. package/lib/index-DiqTDK1U.d.mts +39 -0
  35. package/lib/index-MmnRaakr.d.ts +38 -0
  36. package/lib/index.d.mts +5 -0
  37. package/lib/index.d.ts +5 -0
  38. package/lib/index.js +31 -0
  39. package/lib/index.mjs +8 -0
  40. package/lib/logging-6TTEX4U4.js +2217 -0
  41. package/lib/logging-Dr8kuQ_p.mjs +2194 -0
  42. package/lib/net/index.d.mts +2 -0
  43. package/lib/net/index.d.ts +2 -0
  44. package/lib/net/index.js +5 -0
  45. package/lib/net/index.mjs +5 -0
  46. package/lib/net-BteSPzmU.js +86 -0
  47. package/lib/net-ByUFe0qv.mjs +75 -0
  48. package/net/package.json +5 -0
  49. package/package.json +58 -8
@@ -0,0 +1,2 @@
1
+ import { ChangedFile, commit$1 as commit, commitAllChanges$1 as commitAllChanges, currentBranch$1 as currentBranch, fastForwardBranch$1 as fastForwardBranch, findRoot$1 as findRoot, getChangedFiles$1 as getChangedFiles, getHeadCommitId$1 as getHeadCommitId, getHeadCommitMessage$1 as getHeadCommitMessage, getOwnerAndRepo$1 as getOwnerAndRepo, isFileGitIgnored$1 as isFileGitIgnored, push$1 as push, reset$1 as reset } from "../index-DNXQKEza.mjs";
2
+ export { ChangedFile, commit, commitAllChanges, currentBranch, fastForwardBranch, findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, isFileGitIgnored, push, reset };
@@ -0,0 +1,2 @@
1
+ import { ChangedFile, commit, commitAllChanges, currentBranch, fastForwardBranch, findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, isFileGitIgnored, push, reset } from "../index-B91wXiwr.js";
2
+ export { ChangedFile, commit, commitAllChanges, currentBranch, fastForwardBranch, findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, isFileGitIgnored, push, reset };
@@ -0,0 +1,14 @@
1
+ const require_git = require('../git-DVG_dHiI.js');
2
+
3
+ exports.commit = require_git.commit;
4
+ exports.commitAllChanges = require_git.commitAllChanges;
5
+ exports.currentBranch = require_git.currentBranch;
6
+ exports.fastForwardBranch = require_git.fastForwardBranch;
7
+ exports.findRoot = require_git.findRoot;
8
+ exports.getChangedFiles = require_git.getChangedFiles;
9
+ exports.getHeadCommitId = require_git.getHeadCommitId;
10
+ exports.getHeadCommitMessage = require_git.getHeadCommitMessage;
11
+ exports.getOwnerAndRepo = require_git.getOwnerAndRepo;
12
+ exports.isFileGitIgnored = require_git.isFileGitIgnored;
13
+ exports.push = require_git.push;
14
+ exports.reset = require_git.reset;
@@ -0,0 +1,3 @@
1
+ import { commit, commitAllChanges, currentBranch, fastForwardBranch, findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, isFileGitIgnored, push, reset } from "../git-DDfcZdbm.mjs";
2
+
3
+ export { commit, commitAllChanges, currentBranch, fastForwardBranch, findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, isFileGitIgnored, push, reset };
@@ -0,0 +1,379 @@
1
+ import { __export } from "./chunk-CZCtuq8p.mjs";
2
+ import path from "path";
3
+ import fs from "fs-extra";
4
+ import git, { findRoot } from "isomorphic-git";
5
+ import ignoreFilter from "ignore";
6
+ import http from "isomorphic-git/http/node";
7
+
8
+ //#region src/git/commit.ts
9
+ /**
10
+ * Writes a commit to the local Git repository.
11
+ */
12
+ const commit = async ({ author = { name: "skuba" }, committer = { name: "skuba" }, dir, message }) => git.commit({
13
+ author,
14
+ committer,
15
+ dir,
16
+ fs,
17
+ message
18
+ });
19
+
20
+ //#endregion
21
+ //#region src/git/findRoot.ts
22
+ /**
23
+ * Returns the first Git root directory encountered walking up from the provided
24
+ * `dir`.
25
+ */
26
+ const findRoot$1 = async ({ dir }) => {
27
+ try {
28
+ return await git.findRoot({
29
+ filepath: dir,
30
+ fs
31
+ });
32
+ } catch (err) {
33
+ if (err instanceof git.Errors.NotFoundError) return null;
34
+ throw err;
35
+ }
36
+ };
37
+
38
+ //#endregion
39
+ //#region src/git/statusMatrix.ts
40
+ const FILEPATH = 0;
41
+ const HEAD = 1;
42
+ const WORKDIR = 2;
43
+ const STAGE = 3;
44
+ const ABSENT = 0;
45
+ const UNMODIFIED = 1;
46
+ const MODIFIED = 2;
47
+
48
+ //#endregion
49
+ //#region src/git/getChangedFiles.ts
50
+ const mapState = (row) => {
51
+ if (row[HEAD] === ABSENT) return "added";
52
+ if (row[WORKDIR] === MODIFIED) return "modified";
53
+ return "deleted";
54
+ };
55
+ /**
56
+ * Returns all the files which have been added, modified or deleted in the
57
+ * working directory of the local Git repository since the last commit.
58
+ */
59
+ const getChangedFiles = async ({ dir, ignore = [] }) => {
60
+ const gitRoot = await findRoot({
61
+ fs,
62
+ filepath: dir
63
+ });
64
+ const [allFiles, isLfs] = await Promise.all([git.statusMatrix({
65
+ fs,
66
+ dir: gitRoot ?? dir
67
+ }), createIsLfsFilter(gitRoot)]);
68
+ return allFiles.filter((row) => row[HEAD] !== UNMODIFIED || row[WORKDIR] !== UNMODIFIED || row[STAGE] !== UNMODIFIED).map((row) => ({
69
+ path: row[FILEPATH],
70
+ state: mapState(row)
71
+ })).filter((changedFile) => !ignore.some((i) => i.path === changedFile.path && i.state === changedFile.state) && !isLfs(changedFile.path));
72
+ };
73
+ const createIsLfsFilter = async (gitRoot) => {
74
+ if (!gitRoot) return () => false;
75
+ const lfsFile = `${gitRoot}/.gitattributes`;
76
+ if (!await fs.pathExists(lfsFile)) return () => false;
77
+ const filter = ignoreFilter().add((await fs.readFile(lfsFile, "utf8")).split("\n").map((l) => l.trim()).filter((l) => !l.startsWith("#") && l.includes("filter=lfs")).map((l) => l.split(/\s+/)[0]).flatMap((l) => l ? [l] : []));
78
+ return (pathname) => filter.ignores(pathname);
79
+ };
80
+
81
+ //#endregion
82
+ //#region src/git/commitAllChanges.ts
83
+ /**
84
+ * Stages all changes and writes a commit to the local Git repository.
85
+ */
86
+ const commitAllChanges = async ({ dir, message, author, committer, ignore }) => {
87
+ const changedFiles = await getChangedFiles({
88
+ dir,
89
+ ignore
90
+ });
91
+ if (!changedFiles.length) return;
92
+ const gitRoot = await findRoot$1({ dir });
93
+ if (!gitRoot) throw new Error(`Could not find Git root from directory: ${dir}`);
94
+ await Promise.all(changedFiles.map(async (file) => {
95
+ const relativePath = path.relative(dir, file.path);
96
+ if (relativePath.startsWith("..")) return;
97
+ return file.state === "deleted" ? git.remove({
98
+ fs,
99
+ dir: gitRoot,
100
+ filepath: file.path
101
+ }) : git.add({
102
+ fs,
103
+ dir: gitRoot,
104
+ filepath: file.path
105
+ });
106
+ }));
107
+ return commit({
108
+ dir: gitRoot,
109
+ message,
110
+ author,
111
+ committer
112
+ });
113
+ };
114
+
115
+ //#endregion
116
+ //#region src/git/currentBranch.ts
117
+ /**
118
+ * Tries to return a Git branch name from CI environment variables.
119
+ */
120
+ const currentBranchFromEnvironment = (env = process.env) => env.BUILDKITE_BRANCH ?? env.GITHUB_HEAD_REF ?? env.GITHUB_REF_NAME;
121
+ /**
122
+ * Tries to return a Git branch name from CI environment variables, falling back
123
+ * to the local Git repository when the current working `dir` is supplied.
124
+ */
125
+ const currentBranch = async ({ dir, env = process.env } = {}) => {
126
+ const fromEnv = currentBranchFromEnvironment(env);
127
+ if (fromEnv) return fromEnv;
128
+ if (!dir) return;
129
+ const gitRoot = await git.findRoot({
130
+ filepath: dir,
131
+ fs
132
+ });
133
+ const fromRepo = await git.currentBranch({
134
+ dir: gitRoot,
135
+ fs
136
+ });
137
+ return fromRepo ?? void 0;
138
+ };
139
+
140
+ //#endregion
141
+ //#region src/git/log.ts
142
+ const EMPTY_GIT_LOG_ERROR = new Error("Git log does not contain any commits");
143
+ /**
144
+ * Gets the object ID of the head commit.
145
+ *
146
+ * This tries to extract the commit ID from common CI environment variables,
147
+ * and falls back to the local Git repository log.
148
+ */
149
+ const getHeadCommitId = async ({ dir, env = process.env }) => {
150
+ const oidFromEnv = env.BUILDKITE_COMMIT ?? env.GITHUB_SHA;
151
+ if (oidFromEnv) return oidFromEnv;
152
+ const [headResult] = await git.log({
153
+ depth: 1,
154
+ dir,
155
+ fs
156
+ });
157
+ if (!headResult) throw EMPTY_GIT_LOG_ERROR;
158
+ return headResult.oid;
159
+ };
160
+ /**
161
+ * Gets the message of the head commit.
162
+ *
163
+ * This tries to extract the message from common CI environment variables,
164
+ * and falls back to the local Git repository log.
165
+ */
166
+ const getHeadCommitMessage = async ({ dir, env = process.env }) => {
167
+ const messageFromEnv = env.BUILDKITE_MESSAGE;
168
+ if (messageFromEnv) return messageFromEnv;
169
+ const [headResult] = await git.log({
170
+ depth: 1,
171
+ dir,
172
+ fs
173
+ });
174
+ if (!headResult) throw EMPTY_GIT_LOG_ERROR;
175
+ return headResult.commit.message;
176
+ };
177
+
178
+ //#endregion
179
+ //#region src/git/remote.ts
180
+ /**
181
+ * Matches the owner and repository names in a GitHub repository URL.
182
+ *
183
+ * For example, given the following input strings:
184
+ *
185
+ * ```console
186
+ * git@github.com:seek-oss/skuba.git
187
+ * https://github.com/seek-oss/skuba.git
188
+ * ```
189
+ *
190
+ * This pattern will produce the following matches:
191
+ *
192
+ * 1. seek-oss
193
+ * 2. skuba
194
+ */
195
+ const ownerRepoRegex = /github.com(?::|\/)(.+)\/(.+).git$/;
196
+ const ownerAndRepoFromUrl = (url) => {
197
+ const match = ownerRepoRegex.exec(url);
198
+ const owner = match?.[1];
199
+ const repo = match?.[2];
200
+ return {
201
+ owner,
202
+ repo
203
+ };
204
+ };
205
+ /**
206
+ * Extracts the owner and repository names from CI environment variables,
207
+ * falling back to local Git remotes.
208
+ *
209
+ * Currently, only GitHub repository URLs are supported:
210
+ *
211
+ * ```console
212
+ * git@github.com:seek-oss/skuba.git
213
+ * https://github.com/seek-oss/skuba.git
214
+ * ```
215
+ */
216
+ const getOwnerAndRepo = async ({ dir, env = process.env }) => {
217
+ if (env.GITHUB_REPOSITORY) {
218
+ const [owner, repo] = env.GITHUB_REPOSITORY.split("/");
219
+ if (owner && repo) return {
220
+ owner,
221
+ repo
222
+ };
223
+ }
224
+ if (env.BUILDKITE_REPO) {
225
+ const { owner, repo } = ownerAndRepoFromUrl(env.BUILDKITE_REPO);
226
+ if (owner && repo) return {
227
+ owner,
228
+ repo
229
+ };
230
+ }
231
+ const gitRoot = await git.findRoot({
232
+ filepath: dir,
233
+ fs
234
+ });
235
+ const remotes = await git.listRemotes({
236
+ dir: gitRoot,
237
+ fs
238
+ });
239
+ for (const { url } of remotes) {
240
+ const { owner, repo } = ownerAndRepoFromUrl(url);
241
+ if (owner && repo) return {
242
+ owner,
243
+ repo
244
+ };
245
+ }
246
+ throw new Error("Could not find a GitHub remote");
247
+ };
248
+
249
+ //#endregion
250
+ //#region ../../src/utils/env.ts
251
+ /**
252
+ * Whether the code is executing in a CI environment.
253
+ */
254
+ const isCiEnv = (env = process.env) => Boolean(env.BUILDKITE || env.CI || env.GITHUB_ACTIONS);
255
+
256
+ //#endregion
257
+ //#region src/github/environment.ts
258
+ /**
259
+ * Returns the name of the build as seen in GitHub status checks.
260
+ *
261
+ * This is driven off of environment variables and falls back to `Build`.
262
+ */
263
+ const buildNameFromEnvironment = (env = process.env) => {
264
+ if (env.BUILDKITE_BUILD_NUMBER) return `Build #${env.BUILDKITE_BUILD_NUMBER}`;
265
+ if (env.GITHUB_RUN_NUMBER) return `${env.GITHUB_WORKFLOW ?? "Build"} #${env.GITHUB_RUN_NUMBER}`;
266
+ return "Build";
267
+ };
268
+ /**
269
+ * Whether GitHub API interactions should be enabled.
270
+ *
271
+ * This checks environment variables to see if the code is executing in a CI
272
+ * environment and has access to a GitHub API token.
273
+ */
274
+ const enabledFromEnvironment = (env = process.env) => isCiEnv(env) && Boolean(apiTokenFromEnvironment(env));
275
+ /**
276
+ * Tries to return a GitHub API token from the environment.
277
+ */
278
+ const apiTokenFromEnvironment = (env = process.env) => env.GITHUB_API_TOKEN ?? env.GITHUB_TOKEN;
279
+
280
+ //#endregion
281
+ //#region src/git/push.ts
282
+ /**
283
+ * Pushes the specified `ref` from the local Git repository to a remote.
284
+ */
285
+ const push = async ({ auth, dir, ref, remote, remoteRef, force }) => {
286
+ const { owner, repo } = await getOwnerAndRepo({ dir });
287
+ const url = `https://github.com/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
288
+ return git.push({
289
+ onAuth: () => ({
290
+ username: "x-access-token",
291
+ password: auth.token ?? apiTokenFromEnvironment()
292
+ }),
293
+ dir,
294
+ fs,
295
+ http,
296
+ ref,
297
+ remote,
298
+ remoteRef,
299
+ url,
300
+ force
301
+ });
302
+ };
303
+
304
+ //#endregion
305
+ //#region src/git/pull.ts
306
+ /**
307
+ * Fast forwards the specified `ref` on the local Git repository to match the remote branch.
308
+ */
309
+ const fastForwardBranch = async ({ auth, dir, ref, remote, remoteRef }) => {
310
+ const { owner, repo } = await getOwnerAndRepo({ dir });
311
+ const url = `https://github.com/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
312
+ return git.fastForward({
313
+ onAuth: () => ({
314
+ username: "x-access-token",
315
+ password: auth.token ?? apiTokenFromEnvironment()
316
+ }),
317
+ dir,
318
+ fs,
319
+ http,
320
+ ref,
321
+ remote,
322
+ remoteRef,
323
+ url,
324
+ singleBranch: true
325
+ });
326
+ };
327
+
328
+ //#endregion
329
+ //#region src/git/reset.ts
330
+ /**
331
+ * Resets the specified branch in the local Git repository to a particular
332
+ * commit.
333
+ */
334
+ const reset = async ({ dir, branch, commitId, hard }) => {
335
+ await fs.promises.writeFile(path.join(dir, ".git/refs/heads", branch), `${commitId}\n`);
336
+ if (hard) {
337
+ const allFiles = await git.statusMatrix({
338
+ dir,
339
+ fs
340
+ });
341
+ const modifiedFiles = allFiles.filter((row) => row[WORKDIR] > UNMODIFIED && row[STAGE] > UNMODIFIED).map((row) => row[FILEPATH]);
342
+ await Promise.all(modifiedFiles.map((filePath) => fs.promises.rm(filePath)));
343
+ await git.checkout({
344
+ dir,
345
+ fs,
346
+ ref: branch,
347
+ force: true
348
+ });
349
+ }
350
+ };
351
+
352
+ //#endregion
353
+ //#region src/git/isFileGitIgnored.ts
354
+ const isFileGitIgnored = ({ absolutePath, gitRoot }) => git.isIgnored({
355
+ dir: gitRoot,
356
+ filepath: path.relative(gitRoot, absolutePath),
357
+ fs
358
+ });
359
+
360
+ //#endregion
361
+ //#region src/git/index.ts
362
+ var git_exports = {};
363
+ __export(git_exports, {
364
+ commit: () => commit,
365
+ commitAllChanges: () => commitAllChanges,
366
+ currentBranch: () => currentBranch,
367
+ fastForwardBranch: () => fastForwardBranch,
368
+ findRoot: () => findRoot$1,
369
+ getChangedFiles: () => getChangedFiles,
370
+ getHeadCommitId: () => getHeadCommitId,
371
+ getHeadCommitMessage: () => getHeadCommitMessage,
372
+ getOwnerAndRepo: () => getOwnerAndRepo,
373
+ isFileGitIgnored: () => isFileGitIgnored,
374
+ push: () => push,
375
+ reset: () => reset
376
+ });
377
+
378
+ //#endregion
379
+ export { apiTokenFromEnvironment, buildNameFromEnvironment, commit, commitAllChanges, currentBranch, enabledFromEnvironment, fastForwardBranch, findRoot$1 as findRoot, getChangedFiles, getHeadCommitId, getHeadCommitMessage, getOwnerAndRepo, git_exports, isFileGitIgnored, push, reset };