skuba 12.3.0-add-minimumReleaseAge-20250923031941 → 12.4.0-main-20250929003417

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 (144) hide show
  1. package/lib/cli/build/assets.js +3 -7
  2. package/lib/cli/build/assets.js.map +2 -2
  3. package/lib/cli/build/esbuild.d.ts +2 -1
  4. package/lib/cli/build/esbuild.js +4 -3
  5. package/lib/cli/build/esbuild.js.map +2 -2
  6. package/lib/cli/build/index.js +8 -4
  7. package/lib/cli/build/index.js.map +2 -2
  8. package/lib/cli/init/git.js +1 -1
  9. package/lib/cli/init/git.js.map +2 -2
  10. package/lib/cli/init/index.js +4 -4
  11. package/lib/cli/init/index.js.map +3 -3
  12. package/lib/cli/lint/annotate/buildkite/eslint.js +1 -1
  13. package/lib/cli/lint/annotate/buildkite/eslint.js.map +2 -2
  14. package/lib/cli/lint/annotate/buildkite/index.js +1 -1
  15. package/lib/cli/lint/annotate/buildkite/index.js.map +2 -2
  16. package/lib/cli/lint/annotate/buildkite/internal.js +1 -1
  17. package/lib/cli/lint/annotate/buildkite/internal.js.map +2 -2
  18. package/lib/cli/lint/annotate/buildkite/prettier.js +1 -1
  19. package/lib/cli/lint/annotate/buildkite/prettier.js.map +2 -2
  20. package/lib/cli/lint/annotate/buildkite/tsc.js +1 -1
  21. package/lib/cli/lint/annotate/buildkite/tsc.js.map +2 -2
  22. package/lib/cli/lint/annotate/github/eslint.d.ts +1 -1
  23. package/lib/cli/lint/annotate/github/eslint.js.map +2 -2
  24. package/lib/cli/lint/annotate/github/index.js +3 -4
  25. package/lib/cli/lint/annotate/github/index.js.map +2 -2
  26. package/lib/cli/lint/annotate/github/internal.d.ts +1 -1
  27. package/lib/cli/lint/annotate/github/internal.js.map +2 -2
  28. package/lib/cli/lint/annotate/github/prettier.d.ts +1 -1
  29. package/lib/cli/lint/annotate/github/prettier.js.map +2 -2
  30. package/lib/cli/lint/annotate/github/tsc.d.ts +1 -1
  31. package/lib/cli/lint/annotate/github/tsc.js.map +2 -2
  32. package/lib/cli/lint/autofix.d.ts +1 -1
  33. package/lib/cli/lint/autofix.js +3 -3
  34. package/lib/cli/lint/autofix.js.map +2 -2
  35. package/lib/cli/lint/internalLints/patchRenovateConfig.js +1 -1
  36. package/lib/cli/lint/internalLints/patchRenovateConfig.js.map +2 -2
  37. package/lib/cli/lint/internalLints/upgrade/patches/12.3.0/index.d.ts +2 -0
  38. package/lib/{api/net → cli/lint/internalLints/upgrade/patches/12.3.0}/index.js +12 -6
  39. package/lib/cli/lint/internalLints/upgrade/patches/12.3.0/index.js.map +7 -0
  40. package/lib/cli/lint/internalLints/upgrade/patches/12.3.0/patchDockerfileSyntaxDirective.d.ts +3 -0
  41. package/lib/cli/lint/internalLints/upgrade/patches/12.3.0/patchDockerfileSyntaxDirective.js +99 -0
  42. package/lib/cli/lint/internalLints/upgrade/patches/12.3.0/patchDockerfileSyntaxDirective.js.map +7 -0
  43. package/lib/cli/test/reporters/github/annotations.d.ts +1 -1
  44. package/lib/cli/test/reporters/github/annotations.js.map +1 -1
  45. package/lib/cli/test/reporters/github/index.js +3 -4
  46. package/lib/cli/test/reporters/github/index.js.map +2 -2
  47. package/lib/index.d.ts +4 -4
  48. package/lib/index.js +4 -4
  49. package/lib/index.js.map +2 -2
  50. package/lib/utils/dir.js +2 -2
  51. package/lib/utils/dir.js.map +3 -3
  52. package/lib/utils/manifest.d.ts +5 -1
  53. package/lib/utils/manifest.js +16 -7
  54. package/lib/utils/manifest.js.map +2 -2
  55. package/package.json +3 -2
  56. package/template/base/_pnpm-workspace.yaml +1 -0
  57. package/template/express-rest-api/Dockerfile.dev-deps +0 -2
  58. package/template/express-rest-api/package.json +1 -1
  59. package/template/greeter/Dockerfile +0 -2
  60. package/template/greeter/package.json +2 -2
  61. package/template/koa-rest-api/Dockerfile.dev-deps +0 -2
  62. package/template/koa-rest-api/package.json +1 -1
  63. package/template/lambda-sqs-worker-cdk/Dockerfile +0 -2
  64. package/template/lambda-sqs-worker-cdk/package.json +2 -2
  65. package/lib/api/buildkite/annotate.d.ts +0 -28
  66. package/lib/api/buildkite/annotate.js +0 -62
  67. package/lib/api/buildkite/annotate.js.map +0 -7
  68. package/lib/api/buildkite/index.d.ts +0 -3
  69. package/lib/api/buildkite/index.js +0 -32
  70. package/lib/api/buildkite/index.js.map +0 -7
  71. package/lib/api/buildkite/md.d.ts +0 -6
  72. package/lib/api/buildkite/md.js +0 -33
  73. package/lib/api/buildkite/md.js.map +0 -7
  74. package/lib/api/git/commit.d.ts +0 -15
  75. package/lib/api/git/commit.js +0 -52
  76. package/lib/api/git/commit.js.map +0 -7
  77. package/lib/api/git/commitAllChanges.d.ts +0 -19
  78. package/lib/api/git/commitAllChanges.js +0 -83
  79. package/lib/api/git/commitAllChanges.js.map +0 -7
  80. package/lib/api/git/currentBranch.d.ts +0 -10
  81. package/lib/api/git/currentBranch.js +0 -59
  82. package/lib/api/git/currentBranch.js.map +0 -7
  83. package/lib/api/git/findRoot.d.ts +0 -9
  84. package/lib/api/git/findRoot.js +0 -52
  85. package/lib/api/git/findRoot.js.map +0 -7
  86. package/lib/api/git/getChangedFiles.d.ts +0 -20
  87. package/lib/api/git/getChangedFiles.js +0 -81
  88. package/lib/api/git/getChangedFiles.js.map +0 -7
  89. package/lib/api/git/index.d.ts +0 -12
  90. package/lib/api/git/index.js +0 -61
  91. package/lib/api/git/index.js.map +0 -7
  92. package/lib/api/git/isFileGitIgnored.d.ts +0 -4
  93. package/lib/api/git/isFileGitIgnored.js +0 -49
  94. package/lib/api/git/isFileGitIgnored.js.map +0 -7
  95. package/lib/api/git/log.d.ts +0 -19
  96. package/lib/api/git/log.js +0 -71
  97. package/lib/api/git/log.js.map +0 -7
  98. package/lib/api/git/pull.d.ts +0 -35
  99. package/lib/api/git/pull.js +0 -69
  100. package/lib/api/git/pull.js.map +0 -7
  101. package/lib/api/git/push.d.ts +0 -52
  102. package/lib/api/git/push.js +0 -70
  103. package/lib/api/git/push.js.map +0 -7
  104. package/lib/api/git/remote.d.ts +0 -20
  105. package/lib/api/git/remote.js +0 -73
  106. package/lib/api/git/remote.js.map +0 -7
  107. package/lib/api/git/reset.d.ts +0 -12
  108. package/lib/api/git/reset.js +0 -62
  109. package/lib/api/git/reset.js.map +0 -7
  110. package/lib/api/git/statusMatrix.d.ts +0 -7
  111. package/lib/api/git/statusMatrix.js +0 -47
  112. package/lib/api/git/statusMatrix.js.map +0 -7
  113. package/lib/api/github/checkRun.d.ts +0 -44
  114. package/lib/api/github/checkRun.js +0 -81
  115. package/lib/api/github/checkRun.js.map +0 -7
  116. package/lib/api/github/environment.d.ts +0 -17
  117. package/lib/api/github/environment.js +0 -48
  118. package/lib/api/github/environment.js.map +0 -7
  119. package/lib/api/github/index.d.ts +0 -7
  120. package/lib/api/github/index.js +0 -48
  121. package/lib/api/github/index.js.map +0 -7
  122. package/lib/api/github/issueComment.d.ts +0 -61
  123. package/lib/api/github/issueComment.js +0 -99
  124. package/lib/api/github/issueComment.js.map +0 -7
  125. package/lib/api/github/octokit.d.ts +0 -6
  126. package/lib/api/github/octokit.js +0 -42
  127. package/lib/api/github/octokit.js.map +0 -7
  128. package/lib/api/github/pullRequest.d.ts +0 -21
  129. package/lib/api/github/pullRequest.js +0 -69
  130. package/lib/api/github/pullRequest.js.map +0 -7
  131. package/lib/api/github/push.d.ts +0 -85
  132. package/lib/api/github/push.js +0 -166
  133. package/lib/api/github/push.js.map +0 -7
  134. package/lib/api/net/compose.d.ts +0 -4
  135. package/lib/api/net/compose.js +0 -51
  136. package/lib/api/net/compose.js.map +0 -7
  137. package/lib/api/net/index.d.ts +0 -1
  138. package/lib/api/net/index.js.map +0 -7
  139. package/lib/api/net/socket.d.ts +0 -5
  140. package/lib/api/net/socket.js +0 -68
  141. package/lib/api/net/socket.js.map +0 -7
  142. package/lib/api/net/waitFor.d.ts +0 -22
  143. package/lib/api/net/waitFor.js +0 -40
  144. package/lib/api/net/waitFor.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/lint/autofix.ts"],
4
- "sourcesContent": ["import { inspect } from 'util';\n\nimport simpleGit from 'simple-git';\n\nimport * as Buildkite from '../../api/buildkite/index.js';\nimport * as Git from '../../api/git/index.js';\nimport * as GitHub from '../../api/github/index.js';\nimport { isCiEnv } from '../../utils/env.js';\nimport { createLogger, log } from '../../utils/logging.js';\nimport { hasNpmrcSecret } from '../../utils/npmrc.js';\nimport { throwOnTimeout } from '../../utils/wait.js';\nimport { runESLint } from '../adapter/eslint.js';\nimport { runPrettier } from '../adapter/prettier.js';\nimport { createDestinationFileReader } from '../configure/analysis/project.js';\n\nimport { internalLint } from './internal.js';\nimport type { Input } from './types.js';\n\nconst RENOVATE_DEFAULT_PREFIX = 'renovate';\n\nconst AUTOFIX_COMMIT_MESSAGE = 'Run `skuba format`';\n\nexport const AUTOFIX_IGNORE_FILES_BASE: Git.ChangedFile[] = [\n {\n path: 'Dockerfile-incunabulum',\n state: 'added',\n },\n];\n\nexport const AUTOFIX_IGNORE_FILES_NPMRC: Git.ChangedFile[] = [\n {\n path: '.npmrc',\n state: 'added',\n },\n {\n path: '.npmrc',\n state: 'modified',\n },\n];\n\nconst shouldPush = async ({\n currentBranch,\n dir,\n}: {\n currentBranch?: string;\n dir: string;\n}) => {\n if (!isCiEnv()) {\n // We're not running in a CI environment so we don't need to push autofixes.\n // Ideally we'd drive this off of repository write permissions, but that is\n // non-trivial to infer without attempting an actual write.\n return false;\n }\n\n const isDefaultBuildkiteBranch =\n currentBranch &&\n [process.env.BUILDKITE_PIPELINE_DEFAULT_BRANCH, 'master', 'main'].includes(\n currentBranch,\n );\n\n const isProtectedGitHubBranch = process.env.GITHUB_REF_PROTECTED === 'true';\n\n if (isDefaultBuildkiteBranch || isProtectedGitHubBranch) {\n // The current branch is a protected branch.\n // We respect GitHub Flow; avoid pushing directly to the default branch.\n return false;\n }\n\n if (currentBranch?.startsWith(RENOVATE_DEFAULT_PREFIX)) {\n try {\n await GitHub.getPullRequestNumber();\n } catch {\n const warning =\n 'An autofix is available, but it was not pushed because an open pull request for this Renovate branch could not be found. If a pull request has since been created, retry the lint step to push the fix.';\n log.warn(warning);\n try {\n await Buildkite.annotate(Buildkite.md.terminal(warning));\n } catch {}\n\n return false;\n }\n }\n\n let headCommitMessage;\n try {\n headCommitMessage = await Git.getHeadCommitMessage({ dir });\n } catch {}\n\n if (headCommitMessage?.startsWith(AUTOFIX_COMMIT_MESSAGE)) {\n // Short circuit when the head commit appears to be one of our autofixes.\n // Repeating the same operation is unlikely to correct outstanding issues.\n return false;\n }\n\n // Allow the push attempt to go ahead if our guards have been cleared.\n return true;\n};\n\nconst getIgnores = async (dir: string): Promise<Git.ChangedFile[]> => {\n const contents = await createDestinationFileReader(dir)('.npmrc');\n\n // If an .npmrc has secrets, we need to ignore it\n if (hasNpmrcSecret(contents ?? '')) {\n return [...AUTOFIX_IGNORE_FILES_BASE, ...AUTOFIX_IGNORE_FILES_NPMRC];\n }\n\n return AUTOFIX_IGNORE_FILES_BASE;\n};\n\ninterface AutofixParameters {\n debug: Input['debug'];\n\n eslint: boolean;\n prettier: boolean;\n internal: boolean;\n\n eslintConfigFile?: string;\n}\n\nexport const autofix = async (params: AutofixParameters): Promise<void> => {\n const dir = process.cwd();\n\n if (!params.eslint && !params.prettier && !params.internal) {\n return;\n }\n\n let currentBranch;\n try {\n currentBranch = await Git.currentBranch({ dir });\n } catch {}\n\n if (!(await shouldPush({ currentBranch, dir }))) {\n return;\n }\n\n try {\n log.newline();\n\n log.warn(\n `Attempting to autofix issues (${[\n params.eslint ? 'ESLint' : undefined,\n params.internal ? 'skuba' : undefined,\n 'Prettier', // Prettier is always run\n ]\n .filter((s) => s !== undefined)\n .join(', ')})...`,\n );\n\n const logger = createLogger({ debug: params.debug });\n\n if (params.internal) {\n await internalLint('format');\n }\n\n if (params.eslint) {\n await runESLint('format', logger, params.eslintConfigFile);\n }\n\n // Unconditionally re-run Prettier; reaching here means we have pre-existing\n // format violations or may have created new ones through ESLint/internal fixes.\n await runPrettier('format', logger);\n\n if (process.env.GITHUB_ACTIONS) {\n // GitHub runners have Git installed locally\n const ref = await Git.commitAllChanges({\n dir,\n message: AUTOFIX_COMMIT_MESSAGE,\n\n ignore: await getIgnores(dir),\n });\n\n if (!ref) {\n return log.warn('No autofixes detected.');\n }\n\n await throwOnTimeout(simpleGit().push(), { s: 30 });\n log.warn(`Pushed fix commit ${ref}.`);\n return;\n }\n\n // Other CI Environments, use GitHub API\n if (!currentBranch) {\n log.warn('Could not determine the current branch.');\n log.warn(\n 'Please propagate BUILDKITE_BRANCH, GITHUB_HEAD_REF, GITHUB_REF_NAME, or the .git directory to your container.',\n );\n return;\n }\n\n const ref = await throwOnTimeout(\n GitHub.uploadAllFileChanges({\n branch: currentBranch,\n dir,\n messageHeadline: AUTOFIX_COMMIT_MESSAGE,\n\n ignore: await getIgnores(dir),\n }),\n { s: 30 },\n );\n\n if (!ref) {\n return log.warn('No autofixes detected.');\n }\n\n log.warn(`Pushed fix commit ${ref}.`);\n } catch (err) {\n log.warn(log.bold('Failed to push fix commit.'));\n log.warn(\n log.bold(\n 'Does your CI environment have write access to your Git repository?',\n ),\n );\n log.subtle(inspect(err));\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { inspect } from 'util';\n\nimport simpleGit from 'simple-git';\n\nimport { isCiEnv } from '../../utils/env.js';\nimport { createLogger, log } from '../../utils/logging.js';\nimport { hasNpmrcSecret } from '../../utils/npmrc.js';\nimport { throwOnTimeout } from '../../utils/wait.js';\nimport { runESLint } from '../adapter/eslint.js';\nimport { runPrettier } from '../adapter/prettier.js';\nimport { createDestinationFileReader } from '../configure/analysis/project.js';\n\nimport { internalLint } from './internal.js';\nimport type { Input } from './types.js';\n\nimport * as Buildkite from '@skuba-lib/api/buildkite';\nimport * as Git from '@skuba-lib/api/git';\nimport * as GitHub from '@skuba-lib/api/github';\n\nconst RENOVATE_DEFAULT_PREFIX = 'renovate';\n\nconst AUTOFIX_COMMIT_MESSAGE = 'Run `skuba format`';\n\nexport const AUTOFIX_IGNORE_FILES_BASE: Git.ChangedFile[] = [\n {\n path: 'Dockerfile-incunabulum',\n state: 'added',\n },\n];\n\nexport const AUTOFIX_IGNORE_FILES_NPMRC: Git.ChangedFile[] = [\n {\n path: '.npmrc',\n state: 'added',\n },\n {\n path: '.npmrc',\n state: 'modified',\n },\n];\n\nconst shouldPush = async ({\n currentBranch,\n dir,\n}: {\n currentBranch?: string;\n dir: string;\n}) => {\n if (!isCiEnv()) {\n // We're not running in a CI environment so we don't need to push autofixes.\n // Ideally we'd drive this off of repository write permissions, but that is\n // non-trivial to infer without attempting an actual write.\n return false;\n }\n\n const isDefaultBuildkiteBranch =\n currentBranch &&\n [process.env.BUILDKITE_PIPELINE_DEFAULT_BRANCH, 'master', 'main'].includes(\n currentBranch,\n );\n\n const isProtectedGitHubBranch = process.env.GITHUB_REF_PROTECTED === 'true';\n\n if (isDefaultBuildkiteBranch || isProtectedGitHubBranch) {\n // The current branch is a protected branch.\n // We respect GitHub Flow; avoid pushing directly to the default branch.\n return false;\n }\n\n if (currentBranch?.startsWith(RENOVATE_DEFAULT_PREFIX)) {\n try {\n await GitHub.getPullRequestNumber();\n } catch {\n const warning =\n 'An autofix is available, but it was not pushed because an open pull request for this Renovate branch could not be found. If a pull request has since been created, retry the lint step to push the fix.';\n log.warn(warning);\n try {\n await Buildkite.annotate(Buildkite.md.terminal(warning));\n } catch {}\n\n return false;\n }\n }\n\n let headCommitMessage;\n try {\n headCommitMessage = await Git.getHeadCommitMessage({ dir });\n } catch {}\n\n if (headCommitMessage?.startsWith(AUTOFIX_COMMIT_MESSAGE)) {\n // Short circuit when the head commit appears to be one of our autofixes.\n // Repeating the same operation is unlikely to correct outstanding issues.\n return false;\n }\n\n // Allow the push attempt to go ahead if our guards have been cleared.\n return true;\n};\n\nconst getIgnores = async (dir: string): Promise<Git.ChangedFile[]> => {\n const contents = await createDestinationFileReader(dir)('.npmrc');\n\n // If an .npmrc has secrets, we need to ignore it\n if (hasNpmrcSecret(contents ?? '')) {\n return [...AUTOFIX_IGNORE_FILES_BASE, ...AUTOFIX_IGNORE_FILES_NPMRC];\n }\n\n return AUTOFIX_IGNORE_FILES_BASE;\n};\n\ninterface AutofixParameters {\n debug: Input['debug'];\n\n eslint: boolean;\n prettier: boolean;\n internal: boolean;\n\n eslintConfigFile?: string;\n}\n\nexport const autofix = async (params: AutofixParameters): Promise<void> => {\n const dir = process.cwd();\n\n if (!params.eslint && !params.prettier && !params.internal) {\n return;\n }\n\n let currentBranch;\n try {\n currentBranch = await Git.currentBranch({ dir });\n } catch {}\n\n if (!(await shouldPush({ currentBranch, dir }))) {\n return;\n }\n\n try {\n log.newline();\n\n log.warn(\n `Attempting to autofix issues (${[\n params.eslint ? 'ESLint' : undefined,\n params.internal ? 'skuba' : undefined,\n 'Prettier', // Prettier is always run\n ]\n .filter((s) => s !== undefined)\n .join(', ')})...`,\n );\n\n const logger = createLogger({ debug: params.debug });\n\n if (params.internal) {\n await internalLint('format');\n }\n\n if (params.eslint) {\n await runESLint('format', logger, params.eslintConfigFile);\n }\n\n // Unconditionally re-run Prettier; reaching here means we have pre-existing\n // format violations or may have created new ones through ESLint/internal fixes.\n await runPrettier('format', logger);\n\n if (process.env.GITHUB_ACTIONS) {\n // GitHub runners have Git installed locally\n const ref = await Git.commitAllChanges({\n dir,\n message: AUTOFIX_COMMIT_MESSAGE,\n\n ignore: await getIgnores(dir),\n });\n\n if (!ref) {\n return log.warn('No autofixes detected.');\n }\n\n await throwOnTimeout(simpleGit().push(), { s: 30 });\n log.warn(`Pushed fix commit ${ref}.`);\n return;\n }\n\n // Other CI Environments, use GitHub API\n if (!currentBranch) {\n log.warn('Could not determine the current branch.');\n log.warn(\n 'Please propagate BUILDKITE_BRANCH, GITHUB_HEAD_REF, GITHUB_REF_NAME, or the .git directory to your container.',\n );\n return;\n }\n\n const ref = await throwOnTimeout(\n GitHub.uploadAllFileChanges({\n branch: currentBranch,\n dir,\n messageHeadline: AUTOFIX_COMMIT_MESSAGE,\n\n ignore: await getIgnores(dir),\n }),\n { s: 30 },\n );\n\n if (!ref) {\n return log.warn('No autofixes detected.');\n }\n\n log.warn(`Pushed fix commit ${ref}.`);\n } catch (err) {\n log.warn(log.bold('Failed to push fix commit.'));\n log.warn(\n log.bold(\n 'Does your CI environment have write access to your Git repository?',\n ),\n );\n log.subtle(inspect(err));\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["ref", "simpleGit"]
7
7
  }
@@ -36,11 +36,11 @@ var import_util = require("util");
36
36
  var import_fs_extra = __toESM(require("fs-extra"));
37
37
  var fleece = __toESM(require("golden-fleece"));
38
38
  var z = __toESM(require("zod/v4"));
39
- var Git = __toESM(require("../../../api/git/index.js"));
40
39
  var import_logging = require("../../../utils/logging.js");
41
40
  var import_project = require("../../configure/analysis/project.js");
42
41
  var import_renovate = require("../../configure/modules/renovate.js");
43
42
  var import_prettier = require("../../configure/processing/prettier.js");
43
+ var Git = __toESM(require("@skuba-lib/api/git"));
44
44
  const EXISTING_REPO_PRESET_REGEX = /(github|local)>(seek-jobs|seekasia)\//;
45
45
  const renovateConfigSchema = z.object({
46
46
  extends: z.array(z.string())
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cli/lint/internalLints/patchRenovateConfig.ts"],
4
- "sourcesContent": ["import path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\nimport * as fleece from 'golden-fleece';\nimport * as z from 'zod/v4';\n\nimport * as Git from '../../../api/git/index.js';\nimport { log } from '../../../utils/logging.js';\nimport { createDestinationFileReader } from '../../configure/analysis/project.js';\nimport { RENOVATE_CONFIG_FILENAMES } from '../../configure/modules/renovate.js';\nimport { formatPrettier } from '../../configure/processing/prettier.js';\n\nimport type { PatchFunction, PatchReturnType } from './upgrade/index.js';\n\nconst EXISTING_REPO_PRESET_REGEX = /(github|local)>(seek-jobs|seekasia)\\//;\n\ntype RenovateFiletype = 'json' | 'json5';\n\ntype RenovatePreset =\n | 'local>seekasia/renovate-config'\n | 'local>seek-jobs/renovate-config';\n\nconst renovateConfigSchema = z.object({\n extends: z.array(z.string()),\n});\n\nconst ownerToRenovatePreset = (owner: string): RenovatePreset | undefined => {\n const lowercaseOwner = owner.toLowerCase();\n\n switch (lowercaseOwner) {\n case 'seekasia':\n return 'local>seekasia/renovate-config';\n\n case 'seek-jobs':\n return 'local>seek-jobs/renovate-config';\n\n default:\n return;\n }\n};\n\ntype PatchFile = (props: {\n filepath: string;\n input: string;\n presetToAdd: RenovatePreset;\n}) => Promise<void>;\n\nconst patchJson: PatchFile = async ({ filepath, input, presetToAdd }) => {\n const json: unknown = JSON.parse(input);\n\n const config = renovateConfigSchema.safeParse(json);\n\n if (!config.success) {\n return;\n }\n\n config.data.extends.unshift(presetToAdd);\n\n await fs.promises.writeFile(\n filepath,\n await formatPrettier(JSON.stringify(config.data), { parser: 'json' }),\n );\n\n return;\n};\n\nconst patchJson5: PatchFile = async ({ filepath, input, presetToAdd }) => {\n const json: unknown = fleece.evaluate(input);\n\n const config = renovateConfigSchema.safeParse(json);\n\n if (!config.success) {\n return;\n }\n\n config.data.extends.unshift(presetToAdd);\n\n await fs.promises.writeFile(\n filepath,\n await formatPrettier(fleece.patch(input, config.data), { parser: 'json5' }),\n );\n\n return;\n};\n\nconst patchByFiletype: Record<RenovateFiletype, PatchFile> = {\n json: patchJson,\n json5: patchJson5,\n};\n\nconst patchRenovateConfig = async (\n mode: 'format' | 'lint',\n dir: string,\n): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(dir);\n\n const { owner } = await Git.getOwnerAndRepo({ dir });\n\n const presetToAdd = ownerToRenovatePreset(owner);\n\n if (!presetToAdd) {\n return {\n result: 'skip',\n reason: 'owner does not map to a SEEK preset',\n };\n }\n\n const maybeConfigs = await Promise.all(\n RENOVATE_CONFIG_FILENAMES.map(async (filepath) => ({\n input: await readFile(filepath),\n filepath,\n })),\n );\n\n const config = maybeConfigs.find((maybeConfig) => Boolean(maybeConfig.input));\n if (!config?.input) {\n return { result: 'skip', reason: 'no config found' };\n }\n\n if (\n // The file appears to mention the baseline preset for the configured Git\n // owner. This is a naive check for simplicity.\n config.input.includes(presetToAdd) ||\n // Ignore any renovate configuration which already extends a SEEK-Jobs or seekasia config\n EXISTING_REPO_PRESET_REGEX.exec(config.input)\n ) {\n return {\n result: 'skip',\n reason: 'config already has a SEEK preset',\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const filetype: RenovateFiletype = config.filepath\n .toLowerCase()\n .endsWith('.json5')\n ? 'json5'\n : 'json';\n\n const patchFile = patchByFiletype[filetype];\n\n await patchFile({\n filepath: path.resolve(dir, config.filepath),\n input: config.input,\n presetToAdd,\n });\n\n return { result: 'apply' };\n};\n\nexport const tryPatchRenovateConfig = (async ({\n mode,\n dir = process.cwd(),\n}) => {\n try {\n // In a monorepo we may be invoked within a subdirectory, but we are working\n // with Renovate config that should be relative to the repository root.\n const gitRoot = await Git.findRoot({ dir });\n if (!gitRoot) {\n return { result: 'skip', reason: 'no Git root found' };\n }\n\n return await patchRenovateConfig(mode, gitRoot);\n } catch (err) {\n log.warn('Failed to patch Renovate config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n}) satisfies PatchFunction;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\nimport * as fleece from 'golden-fleece';\nimport * as z from 'zod/v4';\n\nimport { log } from '../../../utils/logging.js';\nimport { createDestinationFileReader } from '../../configure/analysis/project.js';\nimport { RENOVATE_CONFIG_FILENAMES } from '../../configure/modules/renovate.js';\nimport { formatPrettier } from '../../configure/processing/prettier.js';\n\nimport type { PatchFunction, PatchReturnType } from './upgrade/index.js';\n\nimport * as Git from '@skuba-lib/api/git';\n\nconst EXISTING_REPO_PRESET_REGEX = /(github|local)>(seek-jobs|seekasia)\\//;\n\ntype RenovateFiletype = 'json' | 'json5';\n\ntype RenovatePreset =\n | 'local>seekasia/renovate-config'\n | 'local>seek-jobs/renovate-config';\n\nconst renovateConfigSchema = z.object({\n extends: z.array(z.string()),\n});\n\nconst ownerToRenovatePreset = (owner: string): RenovatePreset | undefined => {\n const lowercaseOwner = owner.toLowerCase();\n\n switch (lowercaseOwner) {\n case 'seekasia':\n return 'local>seekasia/renovate-config';\n\n case 'seek-jobs':\n return 'local>seek-jobs/renovate-config';\n\n default:\n return;\n }\n};\n\ntype PatchFile = (props: {\n filepath: string;\n input: string;\n presetToAdd: RenovatePreset;\n}) => Promise<void>;\n\nconst patchJson: PatchFile = async ({ filepath, input, presetToAdd }) => {\n const json: unknown = JSON.parse(input);\n\n const config = renovateConfigSchema.safeParse(json);\n\n if (!config.success) {\n return;\n }\n\n config.data.extends.unshift(presetToAdd);\n\n await fs.promises.writeFile(\n filepath,\n await formatPrettier(JSON.stringify(config.data), { parser: 'json' }),\n );\n\n return;\n};\n\nconst patchJson5: PatchFile = async ({ filepath, input, presetToAdd }) => {\n const json: unknown = fleece.evaluate(input);\n\n const config = renovateConfigSchema.safeParse(json);\n\n if (!config.success) {\n return;\n }\n\n config.data.extends.unshift(presetToAdd);\n\n await fs.promises.writeFile(\n filepath,\n await formatPrettier(fleece.patch(input, config.data), { parser: 'json5' }),\n );\n\n return;\n};\n\nconst patchByFiletype: Record<RenovateFiletype, PatchFile> = {\n json: patchJson,\n json5: patchJson5,\n};\n\nconst patchRenovateConfig = async (\n mode: 'format' | 'lint',\n dir: string,\n): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(dir);\n\n const { owner } = await Git.getOwnerAndRepo({ dir });\n\n const presetToAdd = ownerToRenovatePreset(owner);\n\n if (!presetToAdd) {\n return {\n result: 'skip',\n reason: 'owner does not map to a SEEK preset',\n };\n }\n\n const maybeConfigs = await Promise.all(\n RENOVATE_CONFIG_FILENAMES.map(async (filepath) => ({\n input: await readFile(filepath),\n filepath,\n })),\n );\n\n const config = maybeConfigs.find((maybeConfig) => Boolean(maybeConfig.input));\n if (!config?.input) {\n return { result: 'skip', reason: 'no config found' };\n }\n\n if (\n // The file appears to mention the baseline preset for the configured Git\n // owner. This is a naive check for simplicity.\n config.input.includes(presetToAdd) ||\n // Ignore any renovate configuration which already extends a SEEK-Jobs or seekasia config\n EXISTING_REPO_PRESET_REGEX.exec(config.input)\n ) {\n return {\n result: 'skip',\n reason: 'config already has a SEEK preset',\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const filetype: RenovateFiletype = config.filepath\n .toLowerCase()\n .endsWith('.json5')\n ? 'json5'\n : 'json';\n\n const patchFile = patchByFiletype[filetype];\n\n await patchFile({\n filepath: path.resolve(dir, config.filepath),\n input: config.input,\n presetToAdd,\n });\n\n return { result: 'apply' };\n};\n\nexport const tryPatchRenovateConfig = (async ({\n mode,\n dir = process.cwd(),\n}) => {\n try {\n // In a monorepo we may be invoked within a subdirectory, but we are working\n // with Renovate config that should be relative to the repository root.\n const gitRoot = await Git.findRoot({ dir });\n if (!gitRoot) {\n return { result: 'skip', reason: 'no Git root found' };\n }\n\n return await patchRenovateConfig(mode, gitRoot);\n } catch (err) {\n log.warn('Failed to patch Renovate config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n}) satisfies PatchFunction;\n"],
5
+ "mappings": "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",
6
6
  "names": ["fs", "path"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ import type { Patches } from '../../index.js';
2
+ export declare const patches: Patches;
@@ -16,14 +16,20 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var net_exports = {};
20
- __export(net_exports, {
21
- waitFor: () => import_waitFor.waitFor
19
+ var __exports = {};
20
+ __export(__exports, {
21
+ patches: () => patches
22
22
  });
23
- module.exports = __toCommonJS(net_exports);
24
- var import_waitFor = require("./waitFor.js");
23
+ module.exports = __toCommonJS(__exports);
24
+ var import_patchDockerfileSyntaxDirective = require("./patchDockerfileSyntaxDirective.js");
25
+ const patches = [
26
+ {
27
+ apply: import_patchDockerfileSyntaxDirective.tryPatchDockerfileSyntaxDirective,
28
+ description: "Remove Dockerfile syntax directives"
29
+ }
30
+ ];
25
31
  // Annotate the CommonJS export names for ESM import in node:
26
32
  0 && (module.exports = {
27
- waitFor
33
+ patches
28
34
  });
29
35
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/cli/lint/internalLints/upgrade/patches/12.3.0/index.ts"],
4
+ "sourcesContent": ["import type { Patches } from '../../index.js';\n\nimport { tryPatchDockerfileSyntaxDirective } from './patchDockerfileSyntaxDirective.js';\n\nexport const patches: Patches = [\n {\n apply: tryPatchDockerfileSyntaxDirective,\n description: 'Remove Dockerfile syntax directives',\n },\n];\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,4CAAkD;AAE3C,MAAM,UAAmB;AAAA,EAC9B;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { PatchFunction, PatchReturnType } from '../../index.js';
2
+ export declare const patchDockerfileSyntaxDirective: (mode: "lint" | "format") => Promise<PatchReturnType>;
3
+ export declare const tryPatchDockerfileSyntaxDirective: PatchFunction;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var patchDockerfileSyntaxDirective_exports = {};
30
+ __export(patchDockerfileSyntaxDirective_exports, {
31
+ patchDockerfileSyntaxDirective: () => patchDockerfileSyntaxDirective,
32
+ tryPatchDockerfileSyntaxDirective: () => tryPatchDockerfileSyntaxDirective
33
+ });
34
+ module.exports = __toCommonJS(patchDockerfileSyntaxDirective_exports);
35
+ var import_util = require("util");
36
+ var import_fast_glob = __toESM(require("fast-glob"));
37
+ var import_fs_extra = __toESM(require("fs-extra"));
38
+ var import_logging = require("../../../../../../utils/logging.js");
39
+ const dockerSyntaxRegex = /^#\s*syntax=\s*docker\/dockerfile:\S+\n+/;
40
+ const patchDockerfileSyntaxDirective = async (mode) => {
41
+ const dockerfilePaths = await (0, import_fast_glob.default)(["**/Dockerfile*"], {
42
+ ignore: ["**/.git", "**/node_modules"]
43
+ });
44
+ if (dockerfilePaths.length === 0) {
45
+ return {
46
+ result: "skip",
47
+ reason: "no dockerfiles found"
48
+ };
49
+ }
50
+ const dockerfiles = await Promise.all(
51
+ dockerfilePaths.map(async (file) => {
52
+ const contents = await import_fs_extra.default.readFile(file, "utf8");
53
+ return {
54
+ file,
55
+ contents
56
+ };
57
+ })
58
+ );
59
+ const dockerfilesToPatch = dockerfiles.filter(
60
+ ({ contents }) => dockerSyntaxRegex.test(contents)
61
+ );
62
+ if (dockerfilesToPatch.length === 0) {
63
+ return {
64
+ result: "skip",
65
+ reason: "no dockerfiles to patch"
66
+ };
67
+ }
68
+ if (mode === "lint") {
69
+ return {
70
+ result: "apply"
71
+ };
72
+ }
73
+ await Promise.all(
74
+ dockerfilesToPatch.map(async ({ file, contents }) => {
75
+ const updatedContents = contents.replace(dockerSyntaxRegex, "");
76
+ await import_fs_extra.default.writeFile(file, updatedContents, "utf8");
77
+ })
78
+ );
79
+ return {
80
+ result: "apply"
81
+ };
82
+ };
83
+ const tryPatchDockerfileSyntaxDirective = async ({
84
+ mode
85
+ }) => {
86
+ try {
87
+ return await patchDockerfileSyntaxDirective(mode);
88
+ } catch (err) {
89
+ import_logging.log.warn("Failed to apply Dockerfile syntax directive patch.");
90
+ import_logging.log.subtle((0, import_util.inspect)(err));
91
+ return { result: "skip", reason: "due to an error" };
92
+ }
93
+ };
94
+ // Annotate the CommonJS export names for ESM import in node:
95
+ 0 && (module.exports = {
96
+ patchDockerfileSyntaxDirective,
97
+ tryPatchDockerfileSyntaxDirective
98
+ });
99
+ //# sourceMappingURL=patchDockerfileSyntaxDirective.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/cli/lint/internalLints/upgrade/patches/12.3.0/patchDockerfileSyntaxDirective.ts"],
4
+ "sourcesContent": ["import { inspect } from 'util';\n\nimport fg from 'fast-glob';\nimport fs from 'fs-extra';\n\nimport { log } from '../../../../../../utils/logging.js';\nimport type { PatchFunction, PatchReturnType } from '../../index.js';\n\nconst dockerSyntaxRegex = /^#\\s*syntax=\\s*docker\\/dockerfile:\\S+\\n+/;\n\nexport const patchDockerfileSyntaxDirective = async (\n mode: 'lint' | 'format',\n): Promise<PatchReturnType> => {\n const dockerfilePaths = await fg(['**/Dockerfile*'], {\n ignore: ['**/.git', '**/node_modules'],\n });\n\n if (dockerfilePaths.length === 0) {\n return {\n result: 'skip',\n reason: 'no dockerfiles found',\n };\n }\n\n const dockerfiles = await Promise.all(\n dockerfilePaths.map(async (file) => {\n const contents = await fs.readFile(file, 'utf8');\n\n return {\n file,\n contents,\n };\n }),\n );\n\n const dockerfilesToPatch = dockerfiles.filter(({ contents }) =>\n dockerSyntaxRegex.test(contents),\n );\n\n if (dockerfilesToPatch.length === 0) {\n return {\n result: 'skip',\n reason: 'no dockerfiles to patch',\n };\n }\n\n if (mode === 'lint') {\n return {\n result: 'apply',\n };\n }\n\n await Promise.all(\n dockerfilesToPatch.map(async ({ file, contents }) => {\n const updatedContents = contents.replace(dockerSyntaxRegex, '');\n await fs.writeFile(file, updatedContents, 'utf8');\n }),\n );\n\n return {\n result: 'apply',\n };\n};\n\nexport const tryPatchDockerfileSyntaxDirective: PatchFunction = async ({\n mode,\n}) => {\n try {\n return await patchDockerfileSyntaxDirective(mode);\n } catch (err) {\n log.warn('Failed to apply Dockerfile syntax directive patch.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAwB;AAExB,uBAAe;AACf,sBAAe;AAEf,qBAAoB;AAGpB,MAAM,oBAAoB;AAEnB,MAAM,iCAAiC,OAC5C,SAC6B;AAC7B,QAAM,kBAAkB,UAAM,iBAAAA,SAAG,CAAC,gBAAgB,GAAG;AAAA,IACnD,QAAQ,CAAC,WAAW,iBAAiB;AAAA,EACvC,CAAC;AAED,MAAI,gBAAgB,WAAW,GAAG;AAChC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,cAAc,MAAM,QAAQ;AAAA,IAChC,gBAAgB,IAAI,OAAO,SAAS;AAClC,YAAM,WAAW,MAAM,gBAAAC,QAAG,SAAS,MAAM,MAAM;AAE/C,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,qBAAqB,YAAY;AAAA,IAAO,CAAC,EAAE,SAAS,MACxD,kBAAkB,KAAK,QAAQ;AAAA,EACjC;AAEA,MAAI,mBAAmB,WAAW,GAAG;AACnC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,SAAS,QAAQ;AACnB,WAAO;AAAA,MACL,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,QAAQ;AAAA,IACZ,mBAAmB,IAAI,OAAO,EAAE,MAAM,SAAS,MAAM;AACnD,YAAM,kBAAkB,SAAS,QAAQ,mBAAmB,EAAE;AAC9D,YAAM,gBAAAA,QAAG,UAAU,MAAM,iBAAiB,MAAM;AAAA,IAClD,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,EACV;AACF;AAEO,MAAM,oCAAmD,OAAO;AAAA,EACrE;AACF,MAAM;AACJ,MAAI;AACF,WAAO,MAAM,+BAA+B,IAAI;AAAA,EAClD,SAAS,KAAK;AACZ,uBAAI,KAAK,oDAAoD;AAC7D,uBAAI,WAAO,qBAAQ,GAAG,CAAC;AACvB,WAAO,EAAE,QAAQ,QAAQ,QAAQ,kBAAkB;AAAA,EACrD;AACF;",
6
+ "names": ["fg", "fs"]
7
+ }
@@ -1,5 +1,5 @@
1
1
  import type { TestResult } from '@jest/test-result';
2
- import type * as GitHub from '../../../../api/github/index.js';
2
+ import type * as GitHub from '@skuba-lib/api/github';
3
3
  export declare const createAnnotations: (testResults: TestResult[]) => GitHub.Annotation[];
4
4
  interface AnnotationEntry {
5
5
  annotations: GitHub.Annotation[];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/test/reporters/github/annotations.ts"],
4
- "sourcesContent": ["import path from 'path';\nimport { stripVTControlCharacters as stripAnsi } from 'util';\n\nimport type { TestResult } from '@jest/test-result';\nimport dedent from 'ts-dedent';\n\nimport type * as GitHub from '../../../../api/github/index.js';\n\n/**\n * Matches the first stack trace location in a Jest failure message.\n *\n * For example, given the following input message:\n *\n * ```console\n * Error: expect(received).toBe(expected) // Object.is equality\n *\n * Expected: \"a\"\n * Received: \"b\"\n * at Object.<anonymous> (/workdir/skuba/src/test.test.ts:2:15)\n * at Promise.then.completed (/workdir/skuba/node_modules/jest-circus/build/utils.js:390:28)\n * ...\n * ```\n *\n * or:\n *\n * ```console\n * Error: expect(received).toBe(expected) // Object.is equality\n *\n * Expected: \"a\"\n * Received: \"b\"\n * at /workdir/skuba/src/test.test.ts:2:15\n * at Promise.then.completed (/workdir/skuba/node_modules/jest-circus/build/utils.js:390:28)\n * ...\n * ```\n *\n * This pattern will produce the following matches:\n *\n * 1. /workdir/skuba/src/test.test.ts\n * 2. 2\n * 2. 15\n */\nconst JEST_LOCATION_REGEX = /\\n +at (.+\\()?(.+?):(\\d+):(\\d+)/;\n\nexport const createAnnotations = (\n testResults: TestResult[],\n): GitHub.Annotation[] => {\n const cwd = process.cwd();\n\n return testResults.flatMap((testResult) => {\n if (testResult.testExecError) {\n return {\n annotation_level: 'failure',\n path: path.relative(cwd, testResult.testFilePath),\n start_line: 1,\n end_line: 1,\n message: stripAnsi(\n testResult.failureMessage\n ? dedent(testResult.failureMessage)\n : testResult.testExecError.message,\n ),\n title: 'Jest',\n };\n }\n\n if (testResult.numFailingTests > 0) {\n return testResult.testResults.flatMap((assertionResult) =>\n assertionResult.failureMessages.flatMap((failureMessage) => {\n const match = JEST_LOCATION_REGEX.exec(failureMessage);\n if (match?.length === 5 && match[2]) {\n return {\n annotation_level: 'failure',\n path: path.relative(cwd, match[2]),\n start_line: Number(match[3]),\n end_line: Number(match[3]),\n start_column: Number(match[4]),\n end_column: Number(match[4]),\n message: stripAnsi(failureMessage),\n title: 'Jest',\n };\n }\n\n return [];\n }),\n );\n }\n\n return [];\n });\n};\n\nconst DEFAULT_DISPLAY_NAME = Symbol('DEFAULT_DISPLAY_NAME');\n\ninterface AnnotationEntry {\n annotations: GitHub.Annotation[];\n displayName: string | undefined;\n}\n\nexport const generateAnnotationEntries = (\n testResults: TestResult[],\n): AnnotationEntry[] => {\n type ResultsByDisplayName = Record<string | symbol, TestResult[]>;\n\n // Group test results by display name.\n const resultsByDisplayName = testResults.reduce<ResultsByDisplayName>(\n (acc, result) => {\n const displayName = result.displayName?.name ?? DEFAULT_DISPLAY_NAME;\n\n (acc[displayName] ??= []).push(result);\n\n return acc;\n },\n {},\n );\n\n const defaultResults = resultsByDisplayName[DEFAULT_DISPLAY_NAME];\n\n const entries = [\n ...(defaultResults?.length ? ([[undefined, defaultResults]] as const) : []),\n ...Object.entries(resultsByDisplayName),\n ];\n\n // Create annotations for each display name.\n return entries.map<AnnotationEntry>(([displayName, results]) => ({\n annotations: createAnnotations(results),\n displayName,\n }));\n};\n"],
4
+ "sourcesContent": ["import path from 'path';\nimport { stripVTControlCharacters as stripAnsi } from 'util';\n\nimport type { TestResult } from '@jest/test-result';\nimport dedent from 'ts-dedent';\n\nimport type * as GitHub from '@skuba-lib/api/github';\n\n/**\n * Matches the first stack trace location in a Jest failure message.\n *\n * For example, given the following input message:\n *\n * ```console\n * Error: expect(received).toBe(expected) // Object.is equality\n *\n * Expected: \"a\"\n * Received: \"b\"\n * at Object.<anonymous> (/workdir/skuba/src/test.test.ts:2:15)\n * at Promise.then.completed (/workdir/skuba/node_modules/jest-circus/build/utils.js:390:28)\n * ...\n * ```\n *\n * or:\n *\n * ```console\n * Error: expect(received).toBe(expected) // Object.is equality\n *\n * Expected: \"a\"\n * Received: \"b\"\n * at /workdir/skuba/src/test.test.ts:2:15\n * at Promise.then.completed (/workdir/skuba/node_modules/jest-circus/build/utils.js:390:28)\n * ...\n * ```\n *\n * This pattern will produce the following matches:\n *\n * 1. /workdir/skuba/src/test.test.ts\n * 2. 2\n * 2. 15\n */\nconst JEST_LOCATION_REGEX = /\\n +at (.+\\()?(.+?):(\\d+):(\\d+)/;\n\nexport const createAnnotations = (\n testResults: TestResult[],\n): GitHub.Annotation[] => {\n const cwd = process.cwd();\n\n return testResults.flatMap((testResult) => {\n if (testResult.testExecError) {\n return {\n annotation_level: 'failure',\n path: path.relative(cwd, testResult.testFilePath),\n start_line: 1,\n end_line: 1,\n message: stripAnsi(\n testResult.failureMessage\n ? dedent(testResult.failureMessage)\n : testResult.testExecError.message,\n ),\n title: 'Jest',\n };\n }\n\n if (testResult.numFailingTests > 0) {\n return testResult.testResults.flatMap((assertionResult) =>\n assertionResult.failureMessages.flatMap((failureMessage) => {\n const match = JEST_LOCATION_REGEX.exec(failureMessage);\n if (match?.length === 5 && match[2]) {\n return {\n annotation_level: 'failure',\n path: path.relative(cwd, match[2]),\n start_line: Number(match[3]),\n end_line: Number(match[3]),\n start_column: Number(match[4]),\n end_column: Number(match[4]),\n message: stripAnsi(failureMessage),\n title: 'Jest',\n };\n }\n\n return [];\n }),\n );\n }\n\n return [];\n });\n};\n\nconst DEFAULT_DISPLAY_NAME = Symbol('DEFAULT_DISPLAY_NAME');\n\ninterface AnnotationEntry {\n annotations: GitHub.Annotation[];\n displayName: string | undefined;\n}\n\nexport const generateAnnotationEntries = (\n testResults: TestResult[],\n): AnnotationEntry[] => {\n type ResultsByDisplayName = Record<string | symbol, TestResult[]>;\n\n // Group test results by display name.\n const resultsByDisplayName = testResults.reduce<ResultsByDisplayName>(\n (acc, result) => {\n const displayName = result.displayName?.name ?? DEFAULT_DISPLAY_NAME;\n\n (acc[displayName] ??= []).push(result);\n\n return acc;\n },\n {},\n );\n\n const defaultResults = resultsByDisplayName[DEFAULT_DISPLAY_NAME];\n\n const entries = [\n ...(defaultResults?.length ? ([[undefined, defaultResults]] as const) : []),\n ...Object.entries(resultsByDisplayName),\n ];\n\n // Create annotations for each display name.\n return entries.map<AnnotationEntry>(([displayName, results]) => ({\n annotations: createAnnotations(results),\n displayName,\n }));\n};\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AACjB,kBAAsD;AAGtD,uBAAmB;AAqCnB,MAAM,sBAAsB;AAErB,MAAM,oBAAoB,CAC/B,gBACwB;AACxB,QAAM,MAAM,QAAQ,IAAI;AAExB,SAAO,YAAY,QAAQ,CAAC,eAAe;AACzC,QAAI,WAAW,eAAe;AAC5B,aAAO;AAAA,QACL,kBAAkB;AAAA,QAClB,MAAM,YAAAA,QAAK,SAAS,KAAK,WAAW,YAAY;AAAA,QAChD,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,aAAS,YAAAC;AAAA,UACP,WAAW,qBACP,iBAAAC,SAAO,WAAW,cAAc,IAChC,WAAW,cAAc;AAAA,QAC/B;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,WAAW,kBAAkB,GAAG;AAClC,aAAO,WAAW,YAAY;AAAA,QAAQ,CAAC,oBACrC,gBAAgB,gBAAgB,QAAQ,CAAC,mBAAmB;AAC1D,gBAAM,QAAQ,oBAAoB,KAAK,cAAc;AACrD,cAAI,OAAO,WAAW,KAAK,MAAM,CAAC,GAAG;AACnC,mBAAO;AAAA,cACL,kBAAkB;AAAA,cAClB,MAAM,YAAAF,QAAK,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,cACjC,YAAY,OAAO,MAAM,CAAC,CAAC;AAAA,cAC3B,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,cACzB,cAAc,OAAO,MAAM,CAAC,CAAC;AAAA,cAC7B,YAAY,OAAO,MAAM,CAAC,CAAC;AAAA,cAC3B,aAAS,YAAAC,0BAAU,cAAc;AAAA,cACjC,OAAO;AAAA,YACT;AAAA,UACF;AAEA,iBAAO,CAAC;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,CAAC;AAAA,EACV,CAAC;AACH;AAEA,MAAM,uBAAuB,OAAO,sBAAsB;AAOnD,MAAM,4BAA4B,CACvC,gBACsB;AAItB,QAAM,uBAAuB,YAAY;AAAA,IACvC,CAAC,KAAK,WAAW;AACf,YAAM,cAAc,OAAO,aAAa,QAAQ;AAEhD,OAAC,IAAI,WAAW,MAAM,CAAC,GAAG,KAAK,MAAM;AAErC,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,iBAAiB,qBAAqB,oBAAoB;AAEhE,QAAM,UAAU;AAAA,IACd,GAAI,gBAAgB,SAAU,CAAC,CAAC,QAAW,cAAc,CAAC,IAAc,CAAC;AAAA,IACzE,GAAG,OAAO,QAAQ,oBAAoB;AAAA,EACxC;AAGA,SAAO,QAAQ,IAAqB,CAAC,CAAC,aAAa,OAAO,OAAO;AAAA,IAC/D,aAAa,kBAAkB,OAAO;AAAA,IACtC;AAAA,EACF,EAAE;AACJ;",
6
6
  "names": ["path", "stripAnsi", "dedent"]
7
7
  }
@@ -32,20 +32,19 @@ __export(github_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(github_exports);
34
34
  var import_util = require("util");
35
- var import_environment = require("../../../../api/github/environment.js");
36
- var GitHub = __toESM(require("../../../../api/github/index.js"));
37
35
  var import_logging = require("../../../../utils/logging.js");
38
36
  var import_wait = require("../../../../utils/wait.js");
39
37
  var import_annotations = require("./annotations.js");
38
+ var GitHub = __toESM(require("@skuba-lib/api/github"));
40
39
  class GitHubReporter {
41
40
  async onRunComplete(_contexts, { testResults }) {
42
- if (!(0, import_environment.enabledFromEnvironment)()) {
41
+ if (!GitHub.enabledFromEnvironment()) {
43
42
  return;
44
43
  }
45
44
  let lastCheckRun;
46
45
  try {
47
46
  const entries = (0, import_annotations.generateAnnotationEntries)(testResults);
48
- const build = (0, import_environment.buildNameFromEnvironment)();
47
+ const build = GitHub.buildNameFromEnvironment();
49
48
  for (const { displayName, annotations } of entries) {
50
49
  const name = `skuba/test${displayName ? ` (${displayName})` : ""}`;
51
50
  const isOk = !annotations.length;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/test/reporters/github/index.ts"],
4
- "sourcesContent": ["import { inspect } from 'util';\n\nimport type { Reporter, TestContext } from '@jest/reporters';\nimport type { AggregatedResult } from '@jest/test-result';\n\nimport {\n buildNameFromEnvironment,\n enabledFromEnvironment,\n} from '../../../../api/github/environment.js';\nimport * as GitHub from '../../../../api/github/index.js';\nimport { log } from '../../../../utils/logging.js';\nimport { throwOnTimeout } from '../../../../utils/wait.js';\n\nimport { generateAnnotationEntries } from './annotations.js';\n\nexport default class GitHubReporter implements Pick<Reporter, 'onRunComplete'> {\n async onRunComplete(\n _contexts: Set<TestContext>,\n { testResults }: AggregatedResult,\n ): Promise<void> {\n if (!enabledFromEnvironment()) {\n return;\n }\n\n type CheckRun = Parameters<typeof GitHub.createCheckRun>[0];\n\n let lastCheckRun: CheckRun | undefined;\n\n try {\n const entries = generateAnnotationEntries(testResults);\n\n const build = buildNameFromEnvironment();\n\n // Create a check run per display name.\n // Run in series to reduce the likelihood of exceeding GitHub rate limits.\n for (const { displayName, annotations } of entries) {\n const name = `skuba/test${displayName ? ` (${displayName})` : ''}`;\n\n const isOk = !annotations.length;\n\n const summary = isOk\n ? '`skuba test` passed.'\n : '`skuba test` found issues that require triage.';\n\n const checkRun: CheckRun = {\n name,\n annotations,\n conclusion: isOk ? 'success' : 'failure',\n summary,\n title: `${build} ${isOk ? 'passed' : 'failed'}`,\n };\n\n lastCheckRun = checkRun;\n\n await throwOnTimeout(GitHub.createCheckRun(checkRun), {\n s: 30,\n });\n }\n } catch (err) {\n log.warn('Failed to report test results to GitHub.');\n log.subtle(inspect(err));\n\n if (lastCheckRun) {\n log.subtle('Last request:');\n log.subtle(JSON.stringify(lastCheckRun));\n }\n }\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAwB;AAKxB,yBAGO;AACP,aAAwB;AACxB,qBAAoB;AACpB,kBAA+B;AAE/B,yBAA0C;AAE1C,MAAO,eAAwE;AAAA,EAC7E,MAAM,cACJ,WACA,EAAE,YAAY,GACC;AACf,QAAI,KAAC,2CAAuB,GAAG;AAC7B;AAAA,IACF;AAIA,QAAI;AAEJ,QAAI;AACF,YAAM,cAAU,8CAA0B,WAAW;AAErD,YAAM,YAAQ,6CAAyB;AAIvC,iBAAW,EAAE,aAAa,YAAY,KAAK,SAAS;AAClD,cAAM,OAAO,aAAa,cAAc,KAAK,WAAW,MAAM,EAAE;AAEhE,cAAM,OAAO,CAAC,YAAY;AAE1B,cAAM,UAAU,OACZ,yBACA;AAEJ,cAAM,WAAqB;AAAA,UACzB;AAAA,UACA;AAAA,UACA,YAAY,OAAO,YAAY;AAAA,UAC/B;AAAA,UACA,OAAO,GAAG,KAAK,IAAI,OAAO,WAAW,QAAQ;AAAA,QAC/C;AAEA,uBAAe;AAEf,kBAAM,4BAAe,OAAO,eAAe,QAAQ,GAAG;AAAA,UACpD,GAAG;AAAA,QACL,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,yBAAI,KAAK,0CAA0C;AACnD,yBAAI,WAAO,qBAAQ,GAAG,CAAC;AAEvB,UAAI,cAAc;AAChB,2BAAI,OAAO,eAAe;AAC1B,2BAAI,OAAO,KAAK,UAAU,YAAY,CAAC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { inspect } from 'util';\n\nimport type { Reporter, TestContext } from '@jest/reporters';\nimport type { AggregatedResult } from '@jest/test-result';\n\nimport { log } from '../../../../utils/logging.js';\nimport { throwOnTimeout } from '../../../../utils/wait.js';\n\nimport { generateAnnotationEntries } from './annotations.js';\n\nimport * as GitHub from '@skuba-lib/api/github';\n\nexport default class GitHubReporter implements Pick<Reporter, 'onRunComplete'> {\n async onRunComplete(\n _contexts: Set<TestContext>,\n { testResults }: AggregatedResult,\n ): Promise<void> {\n if (!GitHub.enabledFromEnvironment()) {\n return;\n }\n\n type CheckRun = Parameters<typeof GitHub.createCheckRun>[0];\n\n let lastCheckRun: CheckRun | undefined;\n\n try {\n const entries = generateAnnotationEntries(testResults);\n\n const build = GitHub.buildNameFromEnvironment();\n\n // Create a check run per display name.\n // Run in series to reduce the likelihood of exceeding GitHub rate limits.\n for (const { displayName, annotations } of entries) {\n const name = `skuba/test${displayName ? ` (${displayName})` : ''}`;\n\n const isOk = !annotations.length;\n\n const summary = isOk\n ? '`skuba test` passed.'\n : '`skuba test` found issues that require triage.';\n\n const checkRun: CheckRun = {\n name,\n annotations,\n conclusion: isOk ? 'success' : 'failure',\n summary,\n title: `${build} ${isOk ? 'passed' : 'failed'}`,\n };\n\n lastCheckRun = checkRun;\n\n await throwOnTimeout(GitHub.createCheckRun(checkRun), {\n s: 30,\n });\n }\n } catch (err) {\n log.warn('Failed to report test results to GitHub.');\n log.subtle(inspect(err));\n\n if (lastCheckRun) {\n log.subtle('Last request:');\n log.subtle(JSON.stringify(lastCheckRun));\n }\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAwB;AAKxB,qBAAoB;AACpB,kBAA+B;AAE/B,yBAA0C;AAE1C,aAAwB;AAExB,MAAO,eAAwE;AAAA,EAC7E,MAAM,cACJ,WACA,EAAE,YAAY,GACC;AACf,QAAI,CAAC,OAAO,uBAAuB,GAAG;AACpC;AAAA,IACF;AAIA,QAAI;AAEJ,QAAI;AACF,YAAM,cAAU,8CAA0B,WAAW;AAErD,YAAM,QAAQ,OAAO,yBAAyB;AAI9C,iBAAW,EAAE,aAAa,YAAY,KAAK,SAAS;AAClD,cAAM,OAAO,aAAa,cAAc,KAAK,WAAW,MAAM,EAAE;AAEhE,cAAM,OAAO,CAAC,YAAY;AAE1B,cAAM,UAAU,OACZ,yBACA;AAEJ,cAAM,WAAqB;AAAA,UACzB;AAAA,UACA;AAAA,UACA,YAAY,OAAO,YAAY;AAAA,UAC/B;AAAA,UACA,OAAO,GAAG,KAAK,IAAI,OAAO,WAAW,QAAQ;AAAA,QAC/C;AAEA,uBAAe;AAEf,kBAAM,4BAAe,OAAO,eAAe,QAAQ,GAAG;AAAA,UACpD,GAAG;AAAA,QACL,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,yBAAI,KAAK,0CAA0C;AACnD,yBAAI,WAAO,qBAAQ,GAAG,CAAC;AAEvB,UAAI,cAAc;AAChB,2BAAI,OAAO,eAAe;AAC1B,2BAAI,OAAO,KAAK,UAAU,YAAY,CAAC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/lib/index.d.ts CHANGED
@@ -9,11 +9,11 @@
9
9
  * const { Net } = require('skuba');
10
10
  * ```
11
11
  */
12
- export * as Buildkite from './api/buildkite/index.js';
13
- export * as Git from './api/git/index.js';
14
- export * as GitHub from './api/github/index.js';
12
+ export * as Buildkite from '@skuba-lib/api/buildkite';
13
+ export * as Git from '@skuba-lib/api/git';
14
+ export * as GitHub from '@skuba-lib/api/github';
15
+ export * as Net from '@skuba-lib/api/net';
15
16
  export * as Jest from './api/jest/index.js';
16
- export * as Net from './api/net/index.js';
17
17
  declare global {
18
18
  namespace WebAssembly {
19
19
  interface Module {
package/lib/index.js CHANGED
@@ -35,11 +35,11 @@ __export(index_exports, {
35
35
  Net: () => Net
36
36
  });
37
37
  module.exports = __toCommonJS(index_exports);
38
- var Buildkite = __toESM(require("./api/buildkite/index.js"));
39
- var Git = __toESM(require("./api/git/index.js"));
40
- var GitHub = __toESM(require("./api/github/index.js"));
38
+ var Buildkite = __toESM(require("@skuba-lib/api/buildkite"));
39
+ var Git = __toESM(require("@skuba-lib/api/git"));
40
+ var GitHub = __toESM(require("@skuba-lib/api/github"));
41
+ var Net = __toESM(require("@skuba-lib/api/net"));
41
42
  var Jest = __toESM(require("./api/jest/index.js"));
42
- var Net = __toESM(require("./api/net/index.js"));
43
43
  // Annotate the CommonJS export names for ESM import in node:
44
44
  0 && (module.exports = {
45
45
  Buildkite,
package/lib/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * Entry point for the Node.js development API.\n *\n * This is where skuba imports point to:\n *\n * ```typescript\n * import { Net } from 'skuba';\n *\n * const { Net } = require('skuba');\n * ```\n */\n\nexport * as Buildkite from './api/buildkite/index.js';\nexport * as Git from './api/git/index.js';\nexport * as GitHub from './api/github/index.js';\nexport * as Jest from './api/jest/index.js';\nexport * as Net from './api/net/index.js';\n\n// evanw/esbuild#2388\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace WebAssembly {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n interface Module {}\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,gBAA2B;AAC3B,UAAqB;AACrB,aAAwB;AACxB,WAAsB;AACtB,UAAqB;",
4
+ "sourcesContent": ["/**\n * Entry point for the Node.js development API.\n *\n * This is where skuba imports point to:\n *\n * ```typescript\n * import { Net } from 'skuba';\n *\n * const { Net } = require('skuba');\n * ```\n */\n\nexport * as Buildkite from '@skuba-lib/api/buildkite';\nexport * as Git from '@skuba-lib/api/git';\nexport * as GitHub from '@skuba-lib/api/github';\nexport * as Net from '@skuba-lib/api/net';\nexport * as Jest from './api/jest/index.js';\n\n// evanw/esbuild#2388\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace WebAssembly {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n interface Module {}\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,gBAA2B;AAC3B,UAAqB;AACrB,aAAwB;AACxB,UAAqB;AACrB,WAAsB;",
6
6
  "names": []
7
7
  }
package/lib/utils/dir.js CHANGED
@@ -41,8 +41,8 @@ var import_path = __toESM(require("path"));
41
41
  var import_fs_extra = __toESM(require("fs-extra"));
42
42
  var import_ignore = __toESM(require("ignore"));
43
43
  var import_picomatch = __toESM(require("picomatch"));
44
- var import_findRoot = require("../api/git/findRoot.js");
45
44
  var import_error = require("./error.js");
45
+ var Git = __toESM(require("@skuba-lib/api/git"));
46
46
  const buildPatternToFilepathMap = (patterns, allFilepaths, options) => Object.fromEntries(
47
47
  patterns.map((pattern) => {
48
48
  const isMatch = (0, import_picomatch.default)(pattern, options);
@@ -135,7 +135,7 @@ const findWorkspaceRoot = async (cwd = process.cwd()) => {
135
135
  locateNearestFile({ cwd, filename: "pnpm-lock.yaml" }),
136
136
  locateNearestFile({ cwd, filename: "yarn.lock" }),
137
137
  locateFurthestFile({ cwd, filename: "package.json" }),
138
- (0, import_findRoot.findRoot)({ dir: cwd })
138
+ Git.findRoot({ dir: cwd })
139
139
  ]);
140
140
  const candidates = [
141
141
  pnpmLock ? import_path.default.dirname(pnpmLock) : null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/dir.ts"],
4
- "sourcesContent": ["import path from 'path';\n\nimport fs from 'fs-extra';\nimport ignore from 'ignore';\nimport picomatch from 'picomatch';\n\nimport { findRoot as findGitRoot } from '../api/git/findRoot.js';\n\nimport { isErrorWithCode } from './error.js';\n\n/**\n * Build a map that associates each glob pattern with its matching filepaths.\n */\nexport const buildPatternToFilepathMap = (\n patterns: string[],\n allFilepaths: string[],\n options?: picomatch.PicomatchOptions,\n) =>\n Object.fromEntries(\n patterns.map((pattern) => {\n const isMatch = picomatch(pattern, options);\n\n const filepaths = allFilepaths.filter((filepath) => isMatch(filepath));\n\n return [pattern, filepaths] as const;\n }),\n );\n\n/**\n * List relative filepaths contained within a directory root.\n *\n * This excludes:\n *\n * - Patterns in the ignore files specified in `ignoreFilenames`\n * - `.git` subdirectories\n * - `node_modules` subdirectories\n */\nexport const crawlDirectory = async (\n root: string,\n ignoreFilenames = ['.gitignore'],\n) => {\n const ignoreFileFilter = await createInclusionFilter(\n ignoreFilenames.map((ignoreFilename) => path.join(root, ignoreFilename)),\n );\n\n const absoluteFilenames = await crawl(root, {\n includeDirName: (dirname) => !['.git', 'node_modules'].includes(dirname),\n includeFilePath: (pathname) =>\n ignoreFileFilter(path.relative(root, pathname)),\n });\n\n const relativeFilepaths = absoluteFilenames.map((filepath) =>\n path.relative(root, filepath),\n );\n\n return relativeFilepaths;\n};\n\n/**\n * Create a filter function that excludes filepaths based on ignore files like\n * `.gitignore` and `.prettierignore`.\n */\nexport const createInclusionFilter = async (ignoreFilepaths: string[]) => {\n const ignoreFiles = await Promise.all(\n ignoreFilepaths.map(async (ignoreFilepath) => {\n try {\n return await fs.promises.readFile(ignoreFilepath, 'utf8');\n } catch (err) {\n if (isErrorWithCode(err, 'ENOENT')) {\n return;\n }\n\n throw err;\n }\n }),\n );\n\n const managers = ignoreFiles\n .filter((value): value is string => typeof value === 'string')\n .map((value) => ignore().add(value));\n\n return ignore().add('.git').add(managers).createFilter();\n};\n\n/**\n * Recursively crawl a directory and return all file paths that match the\n * filters. `paths` is mutated and returned.\n */\nasync function crawl(\n directoryPath: string,\n filters: {\n includeDirName: (dirName: string) => boolean;\n includeFilePath: (path: string) => boolean;\n },\n paths: string[] = [],\n) {\n try {\n const entries = await fs.promises.readdir(directoryPath, {\n withFileTypes: true,\n });\n\n await Promise.all(\n entries.map(async (entry) => {\n const fullPath = path.join(directoryPath, entry.name);\n\n if (\n (entry.isFile() || entry.isSymbolicLink()) &&\n filters.includeFilePath(fullPath)\n ) {\n paths.push(fullPath);\n }\n\n if (entry.isDirectory() && filters.includeDirName(entry.name)) {\n await crawl(fullPath, filters, paths);\n }\n }),\n );\n } catch {\n // Ignore errors, because of e.g. permission issues reading directories\n }\n\n return paths;\n}\n\nexport const locateNearestFile = async ({\n cwd,\n filename,\n}: {\n cwd: string;\n filename: string;\n}) => {\n let currentDir = cwd;\n while (currentDir !== path.dirname(currentDir)) {\n const filePath = path.join(currentDir, filename);\n if (await fs.pathExists(filePath)) {\n return filePath;\n }\n currentDir = path.dirname(currentDir);\n }\n\n return null;\n};\n\nexport const locateFurthestFile = async ({\n cwd,\n filename,\n}: {\n cwd: string;\n filename: string;\n}) => {\n let currentDir = cwd;\n let furthestFilePath: string | null = null;\n\n while (currentDir !== path.dirname(currentDir)) {\n const filePath = path.join(currentDir, filename);\n if (await fs.pathExists(filePath)) {\n furthestFilePath = filePath;\n }\n currentDir = path.dirname(currentDir);\n }\n\n return furthestFilePath;\n};\n\nconst workspaceRootCache: Record<string, string | null> = {};\n\nexport const findWorkspaceRoot = async (\n cwd = process.cwd(),\n): Promise<string | null> => {\n const find = async (): Promise<string | null> => {\n const [pnpmLock, yarnLock, packageJson, gitRoot] = await Promise.all([\n locateNearestFile({ cwd, filename: 'pnpm-lock.yaml' }),\n locateNearestFile({ cwd, filename: 'yarn.lock' }),\n locateFurthestFile({ cwd, filename: 'package.json' }),\n findGitRoot({ dir: cwd }),\n ]);\n\n const candidates = [\n pnpmLock ? path.dirname(pnpmLock) : null,\n yarnLock ? path.dirname(yarnLock) : null,\n packageJson ? path.dirname(packageJson) : null,\n gitRoot,\n ].filter((dir): dir is string => dir !== null);\n\n if (candidates[0]) {\n // Pick the longest path. This will be the most specific, which helps guard against someone\n // having an accidental lockfile in a parent directory by mistake.\n\n return candidates.reduce((longest, current) => {\n if (current.split(path.sep).length > longest.split(path.sep).length) {\n return current;\n }\n return longest;\n }, candidates[0]);\n }\n\n return null;\n };\n\n return (workspaceRootCache[cwd] ??= await find());\n};\n\nexport const findCurrentWorkspaceProjectRoot = async (\n cwd = process.cwd(),\n): Promise<string | null> => {\n const packageJson = await locateNearestFile({\n cwd,\n filename: 'package.json',\n });\n return packageJson ? path.dirname(packageJson) : null;\n};\n"],
5
- "mappings": "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",
6
- "names": ["picomatch", "path", "fs", "ignore", "findGitRoot"]
4
+ "sourcesContent": ["import path from 'path';\n\nimport fs from 'fs-extra';\nimport ignore from 'ignore';\nimport picomatch from 'picomatch';\n\nimport { isErrorWithCode } from './error.js';\n\nimport * as Git from '@skuba-lib/api/git';\n\n/**\n * Build a map that associates each glob pattern with its matching filepaths.\n */\nexport const buildPatternToFilepathMap = (\n patterns: string[],\n allFilepaths: string[],\n options?: picomatch.PicomatchOptions,\n) =>\n Object.fromEntries(\n patterns.map((pattern) => {\n const isMatch = picomatch(pattern, options);\n\n const filepaths = allFilepaths.filter((filepath) => isMatch(filepath));\n\n return [pattern, filepaths] as const;\n }),\n );\n\n/**\n * List relative filepaths contained within a directory root.\n *\n * This excludes:\n *\n * - Patterns in the ignore files specified in `ignoreFilenames`\n * - `.git` subdirectories\n * - `node_modules` subdirectories\n */\nexport const crawlDirectory = async (\n root: string,\n ignoreFilenames = ['.gitignore'],\n) => {\n const ignoreFileFilter = await createInclusionFilter(\n ignoreFilenames.map((ignoreFilename) => path.join(root, ignoreFilename)),\n );\n\n const absoluteFilenames = await crawl(root, {\n includeDirName: (dirname) => !['.git', 'node_modules'].includes(dirname),\n includeFilePath: (pathname) =>\n ignoreFileFilter(path.relative(root, pathname)),\n });\n\n const relativeFilepaths = absoluteFilenames.map((filepath) =>\n path.relative(root, filepath),\n );\n\n return relativeFilepaths;\n};\n\n/**\n * Create a filter function that excludes filepaths based on ignore files like\n * `.gitignore` and `.prettierignore`.\n */\nexport const createInclusionFilter = async (ignoreFilepaths: string[]) => {\n const ignoreFiles = await Promise.all(\n ignoreFilepaths.map(async (ignoreFilepath) => {\n try {\n return await fs.promises.readFile(ignoreFilepath, 'utf8');\n } catch (err) {\n if (isErrorWithCode(err, 'ENOENT')) {\n return;\n }\n\n throw err;\n }\n }),\n );\n\n const managers = ignoreFiles\n .filter((value): value is string => typeof value === 'string')\n .map((value) => ignore().add(value));\n\n return ignore().add('.git').add(managers).createFilter();\n};\n\n/**\n * Recursively crawl a directory and return all file paths that match the\n * filters. `paths` is mutated and returned.\n */\nasync function crawl(\n directoryPath: string,\n filters: {\n includeDirName: (dirName: string) => boolean;\n includeFilePath: (path: string) => boolean;\n },\n paths: string[] = [],\n) {\n try {\n const entries = await fs.promises.readdir(directoryPath, {\n withFileTypes: true,\n });\n\n await Promise.all(\n entries.map(async (entry) => {\n const fullPath = path.join(directoryPath, entry.name);\n\n if (\n (entry.isFile() || entry.isSymbolicLink()) &&\n filters.includeFilePath(fullPath)\n ) {\n paths.push(fullPath);\n }\n\n if (entry.isDirectory() && filters.includeDirName(entry.name)) {\n await crawl(fullPath, filters, paths);\n }\n }),\n );\n } catch {\n // Ignore errors, because of e.g. permission issues reading directories\n }\n\n return paths;\n}\n\nexport const locateNearestFile = async ({\n cwd,\n filename,\n}: {\n cwd: string;\n filename: string;\n}) => {\n let currentDir = cwd;\n while (currentDir !== path.dirname(currentDir)) {\n const filePath = path.join(currentDir, filename);\n if (await fs.pathExists(filePath)) {\n return filePath;\n }\n currentDir = path.dirname(currentDir);\n }\n\n return null;\n};\n\nexport const locateFurthestFile = async ({\n cwd,\n filename,\n}: {\n cwd: string;\n filename: string;\n}) => {\n let currentDir = cwd;\n let furthestFilePath: string | null = null;\n\n while (currentDir !== path.dirname(currentDir)) {\n const filePath = path.join(currentDir, filename);\n if (await fs.pathExists(filePath)) {\n furthestFilePath = filePath;\n }\n currentDir = path.dirname(currentDir);\n }\n\n return furthestFilePath;\n};\n\nconst workspaceRootCache: Record<string, string | null> = {};\n\nexport const findWorkspaceRoot = async (\n cwd = process.cwd(),\n): Promise<string | null> => {\n const find = async (): Promise<string | null> => {\n const [pnpmLock, yarnLock, packageJson, gitRoot] = await Promise.all([\n locateNearestFile({ cwd, filename: 'pnpm-lock.yaml' }),\n locateNearestFile({ cwd, filename: 'yarn.lock' }),\n locateFurthestFile({ cwd, filename: 'package.json' }),\n Git.findRoot({ dir: cwd }),\n ]);\n\n const candidates = [\n pnpmLock ? path.dirname(pnpmLock) : null,\n yarnLock ? path.dirname(yarnLock) : null,\n packageJson ? path.dirname(packageJson) : null,\n gitRoot,\n ].filter((dir): dir is string => dir !== null);\n\n if (candidates[0]) {\n // Pick the longest path. This will be the most specific, which helps guard against someone\n // having an accidental lockfile in a parent directory by mistake.\n\n return candidates.reduce((longest, current) => {\n if (current.split(path.sep).length > longest.split(path.sep).length) {\n return current;\n }\n return longest;\n }, candidates[0]);\n }\n\n return null;\n };\n\n return (workspaceRootCache[cwd] ??= await find());\n};\n\nexport const findCurrentWorkspaceProjectRoot = async (\n cwd = process.cwd(),\n): Promise<string | null> => {\n const packageJson = await locateNearestFile({\n cwd,\n filename: 'package.json',\n });\n return packageJson ? path.dirname(packageJson) : null;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["picomatch", "path", "fs", "ignore"]
7
7
  }
@@ -5,6 +5,10 @@ export declare const projectTypeSchema: z.ZodUnion<readonly [z.ZodLiteral<"appli
5
5
  export declare const PROJECT_TYPES: readonly ["application", "package"];
6
6
  export declare const getSkubaManifest: () => Promise<NormalizedPackageJson>;
7
7
  export declare const getConsumerManifest: (cwd?: string) => Promise<readPkgUp.ReadResult | undefined>;
8
- export declare const getPropFromConsumerManifest: <T extends string, V = unknown>(prop: T) => Promise<V | undefined>;
8
+ export declare const getManifestProperties: <T extends string, V = unknown>(prop: T) => Promise<{
9
+ value: V | undefined;
10
+ type: string | undefined;
11
+ path: string;
12
+ } | undefined>;
9
13
  export declare const getStringPropFromConsumerManifest: <T extends string>(prop: T) => Promise<string | undefined>;
10
14
  export declare const getEntryPointFromManifest: () => Promise<string>;
@@ -31,7 +31,7 @@ __export(manifest_exports, {
31
31
  PROJECT_TYPES: () => PROJECT_TYPES,
32
32
  getConsumerManifest: () => getConsumerManifest,
33
33
  getEntryPointFromManifest: () => getEntryPointFromManifest,
34
- getPropFromConsumerManifest: () => getPropFromConsumerManifest,
34
+ getManifestProperties: () => getManifestProperties,
35
35
  getSkubaManifest: () => getSkubaManifest,
36
36
  getStringPropFromConsumerManifest: () => getStringPropFromConsumerManifest,
37
37
  projectTypeSchema: () => projectTypeSchema
@@ -58,13 +58,22 @@ const getSkubaManifest = async () => {
58
58
  return skubaManifest = result.packageJson;
59
59
  };
60
60
  const getConsumerManifest = (cwd) => (0, import_read_pkg_up.default)({ cwd, normalize: false });
61
- const getPropFromConsumerManifest = async (prop) => {
62
- const result = await getConsumerManifest();
63
- return result !== void 0 && (0, import_validation.hasProp)(result.packageJson.skuba, prop) ? result.packageJson.skuba[prop] : void 0;
61
+ const getManifestProperties = async (prop) => {
62
+ const manifest = await getConsumerManifest();
63
+ if (!manifest) {
64
+ return void 0;
65
+ }
66
+ const value = (0, import_validation.hasProp)(manifest.packageJson.skuba, prop) ? manifest.packageJson.skuba[prop] : void 0;
67
+ const type = typeof manifest.packageJson.type === "string" ? manifest.packageJson.type : void 0;
68
+ return {
69
+ value,
70
+ type,
71
+ path: manifest.path
72
+ };
64
73
  };
65
74
  const getStringPropFromConsumerManifest = async (prop) => {
66
- const result = await getPropFromConsumerManifest(prop);
67
- return typeof result === "string" ? result : void 0;
75
+ const manifest = await getManifestProperties(prop);
76
+ return typeof manifest?.value === "string" ? manifest.value : void 0;
68
77
  };
69
78
  const getEntryPointFromManifest = async () => {
70
79
  const entryPoint = await getStringPropFromConsumerManifest("entryPoint");
@@ -75,7 +84,7 @@ const getEntryPointFromManifest = async () => {
75
84
  PROJECT_TYPES,
76
85
  getConsumerManifest,
77
86
  getEntryPointFromManifest,
78
- getPropFromConsumerManifest,
87
+ getManifestProperties,
79
88
  getSkubaManifest,
80
89
  getStringPropFromConsumerManifest,
81
90
  projectTypeSchema
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/manifest.ts"],
4
- "sourcesContent": ["import readPkgUp, { type NormalizedPackageJson } from 'read-pkg-up';\nimport * as z from 'zod/v4';\n\nimport { hasProp } from './validation.js';\n\nexport type ProjectType = z.infer<typeof projectTypeSchema>;\n\nexport const projectTypeSchema = z.union([\n z.literal('application'),\n z.literal('package'),\n]);\n\nexport const PROJECT_TYPES = ['application', 'package'] as const;\n\nconst DEFAULT_ENTRY_POINT = 'src/app.ts';\n\nlet skubaManifest: NormalizedPackageJson | undefined;\n\nexport const getSkubaManifest = async (): Promise<NormalizedPackageJson> => {\n if (skubaManifest !== undefined) {\n return skubaManifest;\n }\n\n const result = await readPkgUp({ cwd: __dirname });\n\n if (result === undefined) {\n throw Error('skuba could not find its own manifest');\n }\n\n return (skubaManifest = result.packageJson);\n};\n\nexport const getConsumerManifest = (cwd?: string) =>\n readPkgUp({ cwd, normalize: false });\n\nexport const getPropFromConsumerManifest = async <\n T extends string,\n V = unknown,\n>(\n prop: T,\n): Promise<V | undefined> => {\n const result = await getConsumerManifest();\n\n return result !== undefined && hasProp<T, V>(result.packageJson.skuba, prop)\n ? result.packageJson.skuba[prop]\n : undefined;\n};\n\nexport const getStringPropFromConsumerManifest = async <T extends string>(\n prop: T,\n): Promise<string | undefined> => {\n const result = await getPropFromConsumerManifest(prop);\n\n return typeof result === 'string' ? result : undefined;\n};\n\nexport const getEntryPointFromManifest = async (): Promise<string> => {\n const entryPoint = await getStringPropFromConsumerManifest('entryPoint');\n\n return entryPoint ?? DEFAULT_ENTRY_POINT;\n};\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAsD;AACtD,QAAmB;AAEnB,wBAAwB;AAIjB,MAAM,oBAAoB,EAAE,MAAM;AAAA,EACvC,EAAE,QAAQ,aAAa;AAAA,EACvB,EAAE,QAAQ,SAAS;AACrB,CAAC;AAEM,MAAM,gBAAgB,CAAC,eAAe,SAAS;AAEtD,MAAM,sBAAsB;AAE5B,IAAI;AAEG,MAAM,mBAAmB,YAA4C;AAC1E,MAAI,kBAAkB,QAAW;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAM,mBAAAA,SAAU,EAAE,KAAK,UAAU,CAAC;AAEjD,MAAI,WAAW,QAAW;AACxB,UAAM,MAAM,uCAAuC;AAAA,EACrD;AAEA,SAAQ,gBAAgB,OAAO;AACjC;AAEO,MAAM,sBAAsB,CAAC,YAClC,mBAAAA,SAAU,EAAE,KAAK,WAAW,MAAM,CAAC;AAE9B,MAAM,8BAA8B,OAIzC,SAC2B;AAC3B,QAAM,SAAS,MAAM,oBAAoB;AAEzC,SAAO,WAAW,cAAa,2BAAc,OAAO,YAAY,OAAO,IAAI,IACvE,OAAO,YAAY,MAAM,IAAI,IAC7B;AACN;AAEO,MAAM,oCAAoC,OAC/C,SACgC;AAChC,QAAM,SAAS,MAAM,4BAA4B,IAAI;AAErD,SAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAEO,MAAM,4BAA4B,YAA6B;AACpE,QAAM,aAAa,MAAM,kCAAkC,YAAY;AAEvE,SAAO,cAAc;AACvB;",
4
+ "sourcesContent": ["import readPkgUp, { type NormalizedPackageJson } from 'read-pkg-up';\nimport * as z from 'zod/v4';\n\nimport { hasProp } from './validation.js';\n\nexport type ProjectType = z.infer<typeof projectTypeSchema>;\n\nexport const projectTypeSchema = z.union([\n z.literal('application'),\n z.literal('package'),\n]);\n\nexport const PROJECT_TYPES = ['application', 'package'] as const;\n\nconst DEFAULT_ENTRY_POINT = 'src/app.ts';\n\nlet skubaManifest: NormalizedPackageJson | undefined;\n\nexport const getSkubaManifest = async (): Promise<NormalizedPackageJson> => {\n if (skubaManifest !== undefined) {\n return skubaManifest;\n }\n\n const result = await readPkgUp({ cwd: __dirname });\n\n if (result === undefined) {\n throw Error('skuba could not find its own manifest');\n }\n\n return (skubaManifest = result.packageJson);\n};\n\nexport const getConsumerManifest = (cwd?: string) =>\n readPkgUp({ cwd, normalize: false });\n\nexport const getManifestProperties = async <T extends string, V = unknown>(\n prop: T,\n): Promise<\n | {\n value: V | undefined;\n type: string | undefined;\n path: string;\n }\n | undefined\n> => {\n const manifest = await getConsumerManifest();\n\n if (!manifest) {\n return undefined;\n }\n\n const value = hasProp<T, V>(manifest.packageJson.skuba, prop)\n ? manifest.packageJson.skuba[prop]\n : undefined;\n\n const type =\n typeof manifest.packageJson.type === 'string'\n ? manifest.packageJson.type\n : undefined;\n\n return {\n value,\n type,\n path: manifest.path,\n };\n};\n\nexport const getStringPropFromConsumerManifest = async <T extends string>(\n prop: T,\n): Promise<string | undefined> => {\n const manifest = await getManifestProperties(prop);\n\n return typeof manifest?.value === 'string' ? manifest.value : undefined;\n};\n\nexport const getEntryPointFromManifest = async (): Promise<string> => {\n const entryPoint = await getStringPropFromConsumerManifest('entryPoint');\n\n return entryPoint ?? DEFAULT_ENTRY_POINT;\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAsD;AACtD,QAAmB;AAEnB,wBAAwB;AAIjB,MAAM,oBAAoB,EAAE,MAAM;AAAA,EACvC,EAAE,QAAQ,aAAa;AAAA,EACvB,EAAE,QAAQ,SAAS;AACrB,CAAC;AAEM,MAAM,gBAAgB,CAAC,eAAe,SAAS;AAEtD,MAAM,sBAAsB;AAE5B,IAAI;AAEG,MAAM,mBAAmB,YAA4C;AAC1E,MAAI,kBAAkB,QAAW;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAM,mBAAAA,SAAU,EAAE,KAAK,UAAU,CAAC;AAEjD,MAAI,WAAW,QAAW;AACxB,UAAM,MAAM,uCAAuC;AAAA,EACrD;AAEA,SAAQ,gBAAgB,OAAO;AACjC;AAEO,MAAM,sBAAsB,CAAC,YAClC,mBAAAA,SAAU,EAAE,KAAK,WAAW,MAAM,CAAC;AAE9B,MAAM,wBAAwB,OACnC,SAQG;AACH,QAAM,WAAW,MAAM,oBAAoB;AAE3C,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,YAAQ,2BAAc,SAAS,YAAY,OAAO,IAAI,IACxD,SAAS,YAAY,MAAM,IAAI,IAC/B;AAEJ,QAAM,OACJ,OAAO,SAAS,YAAY,SAAS,WACjC,SAAS,YAAY,OACrB;AAEN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,SAAS;AAAA,EACjB;AACF;AAEO,MAAM,oCAAoC,OAC/C,SACgC;AAChC,QAAM,WAAW,MAAM,sBAAsB,IAAI;AAEjD,SAAO,OAAO,UAAU,UAAU,WAAW,SAAS,QAAQ;AAChE;AAEO,MAAM,4BAA4B,YAA6B;AACpE,QAAM,aAAa,MAAM,kCAAkC,YAAY;AAEvE,SAAO,cAAc;AACvB;",
6
6
  "names": ["readPkgUp"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skuba",
3
- "version": "12.3.0-add-minimumReleaseAge-20250923031941",
3
+ "version": "12.4.0-main-20250929003417",
4
4
  "private": false,
5
5
  "description": "SEEK development toolkit for backend applications and packages",
6
6
  "homepage": "https://github.com/seek-oss/skuba#readme",
@@ -97,7 +97,8 @@
97
97
  "tsx": "^4.16.2",
98
98
  "typescript": "~5.9.0",
99
99
  "zod": "^4.0.0",
100
- "eslint-config-skuba": "7.1.2-add-minimumReleaseAge-20250923031941"
100
+ "@skuba-lib/api": "^1.0.0-main-20250929003417",
101
+ "eslint-config-skuba": "7.1.2"
101
102
  },
102
103
  "devDependencies": {
103
104
  "@changesets/cli": "2.29.7",
@@ -3,6 +3,7 @@ ignorePatchFailures: false
3
3
  minimumReleaseAge: 4320 # 3 days
4
4
  minimumReleaseAgeExclude:
5
5
  - '@seek/*'
6
+ - '@skuba-lib/*'
6
7
  - eslint-config-seek
7
8
  - eslint-config-skuba
8
9
  - eslint-plugin-skuba
@@ -1,5 +1,3 @@
1
- # syntax=docker/dockerfile:1.18
2
-
3
1
  FROM public.ecr.aws/docker/library/node:22-alpine AS dev-deps
4
2
 
5
3
  RUN --mount=type=bind,source=package.json,target=package.json \
@@ -34,7 +34,7 @@
34
34
  "skuba": "*",
35
35
  "supertest": "^7.0.0"
36
36
  },
37
- "packageManager": "pnpm@10.17.0",
37
+ "packageManager": "pnpm@10.17.1",
38
38
  "engines": {
39
39
  "node": ">=22"
40
40
  }