skuba 7.3.1 → 7.4.0-horrible-hacks-20240206024353

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 (207) hide show
  1. package/README.md +3 -3
  2. package/jest/transform.test.ts +3 -1
  3. package/lib/api/jest/index.d.ts +1 -1
  4. package/lib/api/jest/index.js.map +2 -2
  5. package/lib/cli/adapter/prettier.d.ts +1 -1
  6. package/lib/cli/adapter/prettier.js +11 -10
  7. package/lib/cli/adapter/prettier.js.map +2 -2
  8. package/lib/cli/build/index.js +0 -2
  9. package/lib/cli/build/index.js.map +2 -2
  10. package/lib/cli/buildPackage.js +0 -2
  11. package/lib/cli/buildPackage.js.map +2 -2
  12. package/lib/cli/configure/analyseConfiguration.d.ts +2 -0
  13. package/lib/cli/configure/analyseConfiguration.js.map +2 -2
  14. package/lib/cli/configure/getEntryPoint.js +1 -1
  15. package/lib/cli/configure/getEntryPoint.js.map +2 -2
  16. package/lib/cli/configure/getProjectType.js +1 -1
  17. package/lib/cli/configure/getProjectType.js.map +2 -2
  18. package/lib/cli/configure/index.js +11 -8
  19. package/lib/cli/configure/index.js.map +2 -2
  20. package/lib/cli/configure/modules/index.js +0 -2
  21. package/lib/cli/configure/modules/index.js.map +2 -2
  22. package/lib/cli/configure/modules/package.d.ts +1 -1
  23. package/lib/cli/configure/modules/package.js +2 -1
  24. package/lib/cli/configure/modules/package.js.map +2 -2
  25. package/lib/cli/configure/patchRenovateConfig.d.ts +2 -1
  26. package/lib/cli/configure/patchRenovateConfig.js +23 -10
  27. package/lib/cli/configure/patchRenovateConfig.js.map +2 -2
  28. package/lib/cli/configure/types.d.ts +2 -0
  29. package/lib/cli/configure/types.js.map +1 -1
  30. package/lib/cli/configure/upgrade/index.d.ts +15 -0
  31. package/lib/cli/configure/upgrade/index.js +130 -0
  32. package/lib/cli/configure/upgrade/index.js.map +7 -0
  33. package/lib/cli/configure/{addEmptyExports.d.ts → upgrade/patches/7.3.1/addEmptyExports.d.ts} +2 -2
  34. package/lib/cli/configure/{addEmptyExports.js → upgrade/patches/7.3.1/addEmptyExports.js} +15 -11
  35. package/lib/cli/configure/upgrade/patches/7.3.1/addEmptyExports.js.map +7 -0
  36. package/lib/cli/configure/upgrade/patches/7.3.1/index.d.ts +2 -0
  37. package/lib/cli/configure/upgrade/patches/7.3.1/index.js +55 -0
  38. package/lib/cli/configure/upgrade/patches/7.3.1/index.js.map +7 -0
  39. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.d.ts +2 -0
  40. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.js +94 -0
  41. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.js.map +7 -0
  42. package/lib/cli/configure/upgrade/patches/7.3.1/patchDockerfile.d.ts +2 -0
  43. package/lib/cli/configure/{patchDockerfile.js → upgrade/patches/7.3.1/patchDockerfile.js} +18 -12
  44. package/lib/cli/configure/upgrade/patches/7.3.1/patchDockerfile.js.map +7 -0
  45. package/lib/cli/configure/upgrade/patches/7.3.1/patchServerListener.d.ts +2 -0
  46. package/lib/cli/configure/{patchServerListener.js → upgrade/patches/7.3.1/patchServerListener.js} +18 -14
  47. package/lib/cli/configure/upgrade/patches/7.3.1/patchServerListener.js.map +7 -0
  48. package/lib/cli/format.js +7 -14
  49. package/lib/cli/format.js.map +2 -2
  50. package/lib/cli/init/getConfig.d.ts +4 -2
  51. package/lib/cli/init/getConfig.js +53 -26
  52. package/lib/cli/init/getConfig.js.map +2 -2
  53. package/lib/cli/init/git.d.ts +2 -1
  54. package/lib/cli/init/git.js +2 -9
  55. package/lib/cli/init/git.js.map +2 -2
  56. package/lib/cli/init/index.d.ts +1 -1
  57. package/lib/cli/init/index.js +19 -9
  58. package/lib/cli/init/index.js.map +2 -2
  59. package/lib/cli/init/prompts.d.ts +26 -3
  60. package/lib/cli/init/prompts.js +10 -2
  61. package/lib/cli/init/prompts.js.map +2 -2
  62. package/lib/cli/init/types.d.ts +21 -0
  63. package/lib/cli/init/types.js +5 -1
  64. package/lib/cli/init/types.js.map +2 -2
  65. package/lib/cli/init/writePackageJson.d.ts +6 -0
  66. package/lib/cli/init/writePackageJson.js.map +2 -2
  67. package/lib/cli/lint/annotate/buildkite/index.d.ts +2 -1
  68. package/lib/cli/lint/annotate/buildkite/index.js +5 -3
  69. package/lib/cli/lint/annotate/buildkite/index.js.map +2 -2
  70. package/lib/cli/lint/annotate/buildkite/internal.d.ts +2 -0
  71. package/lib/cli/lint/annotate/buildkite/internal.js +45 -0
  72. package/lib/cli/lint/annotate/buildkite/internal.js.map +7 -0
  73. package/lib/cli/lint/annotate/github/index.d.ts +2 -1
  74. package/lib/cli/lint/annotate/github/index.js +4 -2
  75. package/lib/cli/lint/annotate/github/index.js.map +2 -2
  76. package/lib/cli/lint/annotate/github/internal.d.ts +3 -0
  77. package/lib/cli/lint/annotate/github/internal.js +36 -0
  78. package/lib/cli/lint/annotate/github/internal.js.map +7 -0
  79. package/lib/cli/lint/annotate/index.d.ts +4 -3
  80. package/lib/cli/lint/annotate/index.js +9 -3
  81. package/lib/cli/lint/annotate/index.js.map +2 -2
  82. package/lib/cli/lint/autofix.d.ts +3 -1
  83. package/lib/cli/lint/autofix.js +36 -59
  84. package/lib/cli/lint/autofix.js.map +3 -3
  85. package/lib/cli/lint/external.d.ts +6 -1
  86. package/lib/cli/lint/external.js +6 -29
  87. package/lib/cli/lint/external.js.map +2 -2
  88. package/lib/cli/lint/index.d.ts +2 -1
  89. package/lib/cli/lint/index.js +46 -14
  90. package/lib/cli/lint/index.js.map +2 -2
  91. package/lib/cli/lint/internal.d.ts +12 -1
  92. package/lib/cli/lint/internal.js +55 -19
  93. package/lib/cli/lint/internal.js.map +3 -3
  94. package/lib/cli/lint/internalLints/deleteFiles.d.ts +3 -0
  95. package/lib/cli/lint/internalLints/deleteFiles.js +102 -0
  96. package/lib/cli/lint/internalLints/deleteFiles.js.map +7 -0
  97. package/lib/cli/lint/internalLints/noSkubaTemplateJs.d.ts +3 -0
  98. package/lib/cli/lint/internalLints/noSkubaTemplateJs.js +75 -0
  99. package/lib/cli/lint/internalLints/noSkubaTemplateJs.js.map +7 -0
  100. package/lib/cli/lint/internalLints/refreshConfigFiles.d.ts +11 -0
  101. package/lib/cli/lint/internalLints/refreshConfigFiles.js +147 -0
  102. package/lib/cli/lint/internalLints/refreshConfigFiles.js.map +7 -0
  103. package/lib/cli/test/index.js +0 -2
  104. package/lib/cli/test/index.js.map +2 -2
  105. package/lib/skuba.d.ts +1 -1
  106. package/lib/skuba.js.map +1 -1
  107. package/lib/utils/exec.d.ts +2 -1
  108. package/lib/utils/exec.js +1 -0
  109. package/lib/utils/exec.js.map +2 -2
  110. package/lib/utils/logging.d.ts +2 -0
  111. package/lib/utils/logging.js +1 -0
  112. package/lib/utils/logging.js.map +2 -2
  113. package/lib/utils/logo.js +6 -10
  114. package/lib/utils/logo.js.map +3 -3
  115. package/lib/utils/manifest.d.ts +1 -1
  116. package/lib/utils/manifest.js +1 -1
  117. package/lib/utils/manifest.js.map +2 -2
  118. package/lib/utils/npmrc.d.ts +1 -0
  119. package/lib/utils/npmrc.js +29 -0
  120. package/lib/utils/npmrc.js.map +7 -0
  121. package/lib/utils/packageManager.d.ts +24 -0
  122. package/lib/utils/packageManager.js +97 -0
  123. package/lib/utils/packageManager.js.map +7 -0
  124. package/lib/utils/template.d.ts +3 -0
  125. package/lib/utils/template.js +2 -0
  126. package/lib/utils/template.js.map +2 -2
  127. package/lib/utils/worker.d.ts +1 -0
  128. package/lib/wrapper/http.d.ts +1 -0
  129. package/package.json +39 -36
  130. package/template/base/_.dockerignore +0 -1
  131. package/template/base/_.eslintignore +1 -0
  132. package/template/base/_.gitignore +1 -1
  133. package/template/base/_.npmrc +8 -0
  134. package/template/express-rest-api/.buildkite/pipeline.yml +13 -10
  135. package/template/express-rest-api/.gantry/dev.yml +3 -0
  136. package/template/express-rest-api/Dockerfile +6 -12
  137. package/template/express-rest-api/Dockerfile.dev-deps +6 -5
  138. package/template/express-rest-api/README.md +6 -6
  139. package/template/express-rest-api/docker-compose.yml +0 -10
  140. package/template/express-rest-api/gantry.apply.yml +5 -0
  141. package/template/express-rest-api/gantry.build.yml +1 -2
  142. package/template/express-rest-api/package.json +2 -2
  143. package/template/express-rest-api/skuba.template.js +1 -0
  144. package/template/greeter/.buildkite/pipeline.yml +12 -9
  145. package/template/greeter/Dockerfile +6 -5
  146. package/template/greeter/README.md +6 -6
  147. package/template/greeter/docker-compose.yml +0 -10
  148. package/template/greeter/package.json +1 -1
  149. package/template/greeter/skuba.template.js +1 -0
  150. package/template/koa-rest-api/.buildkite/pipeline.yml +13 -10
  151. package/template/koa-rest-api/.gantry/dev.yml +3 -0
  152. package/template/koa-rest-api/.nvmrc +1 -1
  153. package/template/koa-rest-api/Dockerfile +6 -12
  154. package/template/koa-rest-api/Dockerfile.dev-deps +6 -5
  155. package/template/koa-rest-api/README.md +6 -6
  156. package/template/koa-rest-api/docker-compose.yml +0 -10
  157. package/template/koa-rest-api/gantry.apply.yml +5 -0
  158. package/template/koa-rest-api/gantry.build.yml +1 -2
  159. package/template/koa-rest-api/package.json +8 -6
  160. package/template/koa-rest-api/skuba.template.js +1 -0
  161. package/template/koa-rest-api/src/framework/validation.test.ts +48 -15
  162. package/template/koa-rest-api/src/framework/validation.ts +31 -8
  163. package/template/koa-rest-api/src/testing/types.ts +16 -4
  164. package/template/lambda-sqs-worker/.buildkite/pipeline.yml +21 -15
  165. package/template/lambda-sqs-worker/Dockerfile +6 -6
  166. package/template/lambda-sqs-worker/README.md +8 -8
  167. package/template/lambda-sqs-worker/_.npmrc +12 -0
  168. package/template/lambda-sqs-worker/docker-compose.yml +0 -15
  169. package/template/lambda-sqs-worker/package.json +3 -4
  170. package/template/lambda-sqs-worker/serverless.yml +4 -1
  171. package/template/lambda-sqs-worker/skuba.template.js +1 -0
  172. package/template/lambda-sqs-worker/src/hooks.ts +1 -2
  173. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +42 -18
  174. package/template/lambda-sqs-worker-cdk/.nvmrc +1 -1
  175. package/template/lambda-sqs-worker-cdk/Dockerfile +9 -7
  176. package/template/lambda-sqs-worker-cdk/cdk.json +12 -6
  177. package/template/lambda-sqs-worker-cdk/docker-compose.yml +0 -15
  178. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +1587 -225
  179. package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +23 -3
  180. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +127 -14
  181. package/template/lambda-sqs-worker-cdk/package.json +5 -3
  182. package/template/lambda-sqs-worker-cdk/shared/context-types.ts +1 -0
  183. package/template/lambda-sqs-worker-cdk/skuba.template.js +1 -0
  184. package/template/lambda-sqs-worker-cdk/src/app.ts +14 -1
  185. package/template/lambda-sqs-worker-cdk/src/postHook.ts +154 -0
  186. package/template/lambda-sqs-worker-cdk/src/preHook.ts +95 -0
  187. package/template/oss-npm-package/.github/workflows/release.yml +10 -7
  188. package/template/oss-npm-package/.github/workflows/validate.yml +10 -7
  189. package/template/oss-npm-package/.releaserc +16 -0
  190. package/template/oss-npm-package/README.md +17 -17
  191. package/template/oss-npm-package/_package.json +3 -2
  192. package/template/oss-npm-package/skuba.template.js +1 -0
  193. package/template/private-npm-package/.releaserc +16 -0
  194. package/template/private-npm-package/README.md +16 -16
  195. package/template/private-npm-package/_package.json +3 -3
  196. package/template/private-npm-package/skuba.template.js +1 -0
  197. package/lib/cli/configure/addEmptyExports.js.map +0 -7
  198. package/lib/cli/configure/modules/tsconfig.d.ts +0 -2
  199. package/lib/cli/configure/modules/tsconfig.js +0 -87
  200. package/lib/cli/configure/modules/tsconfig.js.map +0 -7
  201. package/lib/cli/configure/patchDockerfile.d.ts +0 -1
  202. package/lib/cli/configure/patchDockerfile.js.map +0 -7
  203. package/lib/cli/configure/patchServerListener.d.ts +0 -3
  204. package/lib/cli/configure/patchServerListener.js.map +0 -7
  205. package/lib/cli/configure/refreshIgnoreFiles.d.ts +0 -3
  206. package/lib/cli/configure/refreshIgnoreFiles.js +0 -78
  207. package/lib/cli/configure/refreshIgnoreFiles.js.map +0 -7
@@ -90,12 +90,15 @@ const patchByFiletype = {
90
90
  json: patchJson,
91
91
  json5: patchJson5
92
92
  };
93
- const patchRenovateConfig = async (dir) => {
93
+ const patchRenovateConfig = async (mode, dir) => {
94
94
  const readFile = (0, import_project.createDestinationFileReader)(dir);
95
95
  const { owner } = await Git.getOwnerAndRepo({ dir });
96
96
  const presetToAdd = ownerToRenovatePreset(owner);
97
97
  if (!presetToAdd) {
98
- return;
98
+ return {
99
+ result: "skip",
100
+ reason: "owner does not map to a SEEK preset"
101
+ };
99
102
  }
100
103
  const maybeConfigs = await Promise.all(
101
104
  import_renovate.RENOVATE_CONFIG_FILENAMES.map(async (filepath) => ({
@@ -104,15 +107,22 @@ const patchRenovateConfig = async (dir) => {
104
107
  }))
105
108
  );
106
109
  const config = maybeConfigs.find((maybeConfig) => Boolean(maybeConfig.input));
110
+ if (!config?.input) {
111
+ return { result: "skip", reason: "no config found" };
112
+ }
107
113
  if (
108
- // No file was found.
109
- !config?.input || // The file appears to mention the baseline preset for the configured Git
110
- // owner. This is a very naive check that we don't want to overcomplicate
111
- // because it is invoked before each skuba format and lint.
114
+ // The file appears to mention the baseline preset for the configured Git
115
+ // owner. This is a naive check for simplicity.
112
116
  config.input.includes(presetToAdd) || // Ignore any renovate configuration which already extends a SEEK-Jobs or seekasia config
113
117
  EXISTING_REPO_PRESET_REGEX.exec(config.input)
114
118
  ) {
115
- return;
119
+ return {
120
+ result: "skip",
121
+ reason: "config already has a SEEK preset"
122
+ };
123
+ }
124
+ if (mode === "lint") {
125
+ return { result: "apply" };
116
126
  }
117
127
  const filetype = config.filepath.toLowerCase().endsWith(".json5") ? "json5" : "json";
118
128
  const patchFile = patchByFiletype[filetype];
@@ -121,16 +131,19 @@ const patchRenovateConfig = async (dir) => {
121
131
  input: config.input,
122
132
  presetToAdd
123
133
  });
134
+ return { result: "apply" };
124
135
  };
125
- const tryPatchRenovateConfig = async (dir = process.cwd()) => {
136
+ const tryPatchRenovateConfig = async (mode, dir = process.cwd()) => {
126
137
  try {
127
138
  const gitRoot = await Git.findRoot({ dir });
128
- if (gitRoot) {
129
- await patchRenovateConfig(gitRoot);
139
+ if (!gitRoot) {
140
+ return { result: "skip", reason: "no Git root found" };
130
141
  }
142
+ return await patchRenovateConfig(mode, gitRoot);
131
143
  } catch (err) {
132
144
  import_logging.log.warn("Failed to patch Renovate config.");
133
145
  import_logging.log.subtle((0, import_util.inspect)(err));
146
+ return { result: "skip", reason: "due to an error" };
134
147
  }
135
148
  };
136
149
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/configure/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 { z } from 'zod';\n\nimport * as Git from '../../api/git';\nimport { log } from '../../utils/logging';\n\nimport { createDestinationFileReader } from './analysis/project';\nimport { RENOVATE_CONFIG_FILENAMES } from './modules/renovate';\nimport { formatPrettier } from './processing/prettier';\n\nconst RENOVATE_PRESETS = [\n 'local>seekasia/renovate-config',\n 'local>seek-jobs/renovate-config',\n] as const;\n\nconst EXISTING_REPO_PRESET_REGEX = /(github|local)>(seek-jobs|seekasia)\\//;\n\ntype RenovateFiletype = 'json' | 'json5';\n\ntype RenovatePreset = (typeof RENOVATE_PRESETS)[number];\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 (dir: string) => {\n const readFile = createDestinationFileReader(dir);\n\n const { owner } = await Git.getOwnerAndRepo({ dir });\n\n const presetToAdd = ownerToRenovatePreset(owner);\n\n if (!presetToAdd) {\n // No baseline preset needs to be added for the configured Git owner.\n return;\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\n if (\n // No file was found.\n !config?.input ||\n // The file appears to mention the baseline preset for the configured Git\n // owner. This is a very naive check that we don't want to overcomplicate\n // because it is invoked before each skuba format and lint.\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 }\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\nexport const tryPatchRenovateConfig = async (dir = process.cwd()) => {\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\n if (gitRoot) {\n await patchRenovateConfig(gitRoot);\n }\n } catch (err) {\n log.warn('Failed to patch Renovate config.');\n log.subtle(inspect(err));\n }\n};\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 { z } from 'zod';\n\nimport * as Git from '../../api/git';\nimport { log } from '../../utils/logging';\n\nimport { createDestinationFileReader } from './analysis/project';\nimport { RENOVATE_CONFIG_FILENAMES } from './modules/renovate';\nimport { formatPrettier } from './processing/prettier';\nimport type { PatchFunction, PatchReturnType } from './upgrade';\n\nconst RENOVATE_PRESETS = [\n 'local>seekasia/renovate-config',\n 'local>seek-jobs/renovate-config',\n] as const;\n\nconst EXISTING_REPO_PRESET_REGEX = /(github|local)>(seek-jobs|seekasia)\\//;\n\ntype RenovateFiletype = 'json' | 'json5';\n\ntype RenovatePreset = (typeof RENOVATE_PRESETS)[number];\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: 'format' | 'lint',\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
  }
@@ -1,5 +1,6 @@
1
1
  import type { PackageJson as TypeFestPackageJson } from 'type-fest';
2
2
  import type { ProjectType } from '../../utils/manifest';
3
+ import type { PackageManagerConfig } from '../../utils/packageManager';
3
4
  export type { TsConfigJson } from 'type-fest';
4
5
  export type PackageJson = TypeFestPackageJson & Record<string, unknown>;
5
6
  export interface DependencySet {
@@ -22,5 +23,6 @@ export interface Options {
22
23
  destinationRoot: string;
23
24
  entryPoint: string;
24
25
  firstRun: boolean;
26
+ packageManager: PackageManagerConfig;
25
27
  type: ProjectType;
26
28
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/configure/types.ts"],
4
- "sourcesContent": ["import type { PackageJson as TypeFestPackageJson } from 'type-fest';\n\nimport type { ProjectType } from '../../utils/manifest';\n\nexport type { TsConfigJson } from 'type-fest';\n\nexport type PackageJson = TypeFestPackageJson & Record<string, unknown>;\n\nexport interface DependencySet {\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n type: ProjectType;\n}\n\nexport type DependencyDiff = Record<\n string,\n { operation: string; version: string }\n>;\n\ntype FileProcessor = (\n file: string | undefined,\n files: Files,\n initialFiles: Readonly<Files>,\n) => Promise<string | undefined> | string | undefined;\n\nexport type FileDiff = Record<\n string,\n { data: string | undefined; operation: string }\n>;\n\nexport type Files = Record<string, string | undefined>;\n\nexport type Module = Record<string, FileProcessor>;\n\nexport interface Options {\n destinationRoot: string;\n entryPoint: string;\n firstRun: boolean;\n type: ProjectType;\n}\n"],
4
+ "sourcesContent": ["import type { PackageJson as TypeFestPackageJson } from 'type-fest';\n\nimport type { ProjectType } from '../../utils/manifest';\nimport type { PackageManagerConfig } from '../../utils/packageManager';\n\nexport type { TsConfigJson } from 'type-fest';\n\nexport type PackageJson = TypeFestPackageJson & Record<string, unknown>;\n\nexport interface DependencySet {\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n type: ProjectType;\n}\n\nexport type DependencyDiff = Record<\n string,\n { operation: string; version: string }\n>;\n\ntype FileProcessor = (\n file: string | undefined,\n files: Files,\n initialFiles: Readonly<Files>,\n) => Promise<string | undefined> | string | undefined;\n\nexport type FileDiff = Record<\n string,\n { data: string | undefined; operation: string }\n>;\n\nexport type Files = Record<string, string | undefined>;\n\nexport type Module = Record<string, FileProcessor>;\n\nexport interface Options {\n destinationRoot: string;\n entryPoint: string;\n firstRun: boolean;\n packageManager: PackageManagerConfig;\n type: ProjectType;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,15 @@
1
+ import type { Logger } from '../../../utils/logging';
2
+ import type { InternalLintResult } from '../../lint/internal';
3
+ export type Patches = Patch[];
4
+ export type Patch = {
5
+ apply: PatchFunction;
6
+ description: string;
7
+ };
8
+ export type PatchReturnType = {
9
+ result: 'apply';
10
+ } | {
11
+ result: 'skip';
12
+ reason?: string;
13
+ };
14
+ export type PatchFunction = (mode: 'format' | 'lint') => Promise<PatchReturnType>;
15
+ export declare const upgradeSkuba: (mode: 'lint' | 'format', logger: Logger) => Promise<InternalLintResult>;
@@ -0,0 +1,130 @@
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 upgrade_exports = {};
30
+ __export(upgrade_exports, {
31
+ upgradeSkuba: () => upgradeSkuba
32
+ });
33
+ module.exports = __toCommonJS(upgrade_exports);
34
+ var import_path = __toESM(require("path"));
35
+ var import_fs_extra = require("fs-extra");
36
+ var import_semver = require("semver");
37
+ var import_manifest = require("../../../utils/manifest");
38
+ var import_packageManager = require("../../../utils/packageManager");
39
+ var import_version = require("../../../utils/version");
40
+ var import_package = require("../processing/package");
41
+ const getPatches = async (manifestVersion) => {
42
+ const patches = await (0, import_fs_extra.readdir)(import_path.default.join(__dirname, "patches"));
43
+ const patchesForVersion = (0, import_semver.sort)(
44
+ patches.filter((filename) => (0, import_semver.gte)(filename, manifestVersion))
45
+ );
46
+ return (await Promise.all(patchesForVersion.map(resolvePatches))).flat();
47
+ };
48
+ const fileExtensions = ["js", "ts"];
49
+ const resolvePatches = async (version) => {
50
+ for (const extension of fileExtensions) {
51
+ try {
52
+ return (await import(`./patches/${version}/index.${extension}`)).patches;
53
+ } catch {
54
+ }
55
+ }
56
+ throw new Error(`Could not resolve patches for ${version}`);
57
+ };
58
+ const upgradeSkuba = async (mode, logger) => {
59
+ const [currentVersion, manifest] = await Promise.all([
60
+ (0, import_version.getSkubaVersion)(),
61
+ (0, import_manifest.getConsumerManifest)()
62
+ ]);
63
+ if (!manifest) {
64
+ throw new Error("Could not find a package json for this project");
65
+ }
66
+ manifest.packageJson.skuba ??= { version: "1.0.0" };
67
+ const manifestVersion = manifest.packageJson.skuba.version;
68
+ if ((0, import_semver.gte)(manifestVersion, currentVersion)) {
69
+ return { ok: true, fixable: false };
70
+ }
71
+ const patches = await getPatches(manifestVersion);
72
+ if (patches.length === 0) {
73
+ return { ok: true, fixable: false };
74
+ }
75
+ if (mode === "lint") {
76
+ const results = await Promise.all(
77
+ patches.map(async ({ apply }) => await apply(mode))
78
+ );
79
+ if (results.every(({ result }) => result === "skip")) {
80
+ return { ok: true, fixable: false };
81
+ }
82
+ const packageManager = await (0, import_packageManager.detectPackageManager)();
83
+ logger.warn(
84
+ `skuba has patches to apply. Run ${logger.bold(
85
+ packageManager.exec,
86
+ "skuba",
87
+ "format"
88
+ )} to run them. ${logger.dim("skuba-patches")}`
89
+ );
90
+ return {
91
+ ok: false,
92
+ fixable: true,
93
+ annotations: [
94
+ {
95
+ // package.json as likely skuba version has changed
96
+ // TODO: locate the "skuba": {} config in the package.json and annotate on the version property
97
+ path: manifest.path,
98
+ message: `skuba has patches to apply. Run ${packageManager.exec} skuba format to run them.`
99
+ }
100
+ ]
101
+ };
102
+ }
103
+ logger.plain("Updating skuba...");
104
+ for (const { apply, description } of patches) {
105
+ const result = await apply(mode);
106
+ logger.newline();
107
+ if (result.result === "skip") {
108
+ logger.plain(
109
+ `Patch skipped: ${description}${result.reason ? ` - ${result.reason}` : ""}`
110
+ );
111
+ } else {
112
+ logger.plain(`Patch applied: ${description}`);
113
+ }
114
+ }
115
+ manifest.packageJson.skuba.version = currentVersion;
116
+ const updatedPackageJson = await (0, import_package.formatPackage)(manifest.packageJson);
117
+ await (0, import_fs_extra.writeFile)(manifest.path, updatedPackageJson);
118
+ logger.newline();
119
+ logger.plain("skuba update complete.");
120
+ logger.newline();
121
+ return {
122
+ ok: true,
123
+ fixable: false
124
+ };
125
+ };
126
+ // Annotate the CommonJS export names for ESM import in node:
127
+ 0 && (module.exports = {
128
+ upgradeSkuba
129
+ });
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/cli/configure/upgrade/index.ts"],
4
+ "sourcesContent": ["import path from 'path';\n\nimport { readdir, writeFile } from 'fs-extra';\nimport { gte, sort } from 'semver';\n\nimport type { Logger } from '../../../utils/logging';\nimport { getConsumerManifest } from '../../../utils/manifest';\nimport { detectPackageManager } from '../../../utils/packageManager';\nimport { getSkubaVersion } from '../../../utils/version';\nimport type { SkubaPackageJson } from '../../init/writePackageJson';\nimport type { InternalLintResult } from '../../lint/internal';\nimport { formatPackage } from '../processing/package';\n\nexport type Patches = Patch[];\nexport type Patch = {\n apply: PatchFunction;\n description: string;\n};\nexport type PatchReturnType =\n | { result: 'apply' }\n | { result: 'skip'; reason?: string };\nexport type PatchFunction = (\n mode: 'format' | 'lint',\n) => Promise<PatchReturnType>;\n\nconst getPatches = async (manifestVersion: string): Promise<Patches> => {\n const patches = await readdir(path.join(__dirname, 'patches'));\n\n // The patches are sorted by the version they were added from.\n // Only return patches that are newer or equal to the current version.\n const patchesForVersion = sort(\n patches.filter((filename) => gte(filename, manifestVersion)),\n );\n\n return (await Promise.all(patchesForVersion.map(resolvePatches))).flat();\n};\n\nconst fileExtensions = ['js', 'ts'];\n\n// Hack to allow our Jest environment/transform to resolve the patches\n// In normal scenarios this will resolve immediately after the .js import\nconst resolvePatches = async (version: string): Promise<Patches> => {\n for (const extension of fileExtensions) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n return (await import(`./patches/${version}/index.${extension}`)).patches;\n } catch {\n // Ignore\n }\n }\n throw new Error(`Could not resolve patches for ${version}`);\n};\n\nexport const upgradeSkuba = async (\n mode: 'lint' | 'format',\n logger: Logger,\n): Promise<InternalLintResult> => {\n const [currentVersion, manifest] = await Promise.all([\n getSkubaVersion(),\n getConsumerManifest(),\n ]);\n\n if (!manifest) {\n throw new Error('Could not find a package json for this project');\n }\n\n manifest.packageJson.skuba ??= { version: '1.0.0' };\n\n const manifestVersion = (manifest.packageJson.skuba as SkubaPackageJson)\n .version;\n\n // We are up to date, skip patches\n if (gte(manifestVersion, currentVersion)) {\n return { ok: true, fixable: false };\n }\n\n const patches = await getPatches(manifestVersion);\n // No patches to apply even if version out of date. Early exit to avoid unnecessary commits.\n if (patches.length === 0) {\n return { ok: true, fixable: false };\n }\n\n if (mode === 'lint') {\n const results = await Promise.all(\n patches.map(async ({ apply }) => await apply(mode)),\n );\n\n // No patches are applicable. Early exit to avoid unnecessary commits.\n if (results.every(({ result }) => result === 'skip')) {\n return { ok: true, fixable: false };\n }\n\n const packageManager = await detectPackageManager();\n\n logger.warn(\n `skuba has patches to apply. Run ${logger.bold(\n packageManager.exec,\n 'skuba',\n 'format',\n )} to run them. ${logger.dim('skuba-patches')}`,\n );\n\n return {\n ok: false,\n fixable: true,\n annotations: [\n {\n // package.json as likely skuba version has changed\n // TODO: locate the \"skuba\": {} config in the package.json and annotate on the version property\n path: manifest.path,\n message: `skuba has patches to apply. Run ${packageManager.exec} skuba format to run them.`,\n },\n ],\n };\n }\n\n logger.plain('Updating skuba...');\n\n // Run these in series in case a subsequent patch relies on a previous patch\n for (const { apply, description } of patches) {\n const result = await apply(mode);\n logger.newline();\n if (result.result === 'skip') {\n logger.plain(\n `Patch skipped: ${description}${\n result.reason ? ` - ${result.reason}` : ''\n }`,\n );\n } else {\n logger.plain(`Patch applied: ${description}`);\n }\n }\n\n (manifest.packageJson.skuba as SkubaPackageJson).version = currentVersion;\n\n const updatedPackageJson = await formatPackage(manifest.packageJson);\n\n await writeFile(manifest.path, updatedPackageJson);\n logger.newline();\n logger.plain('skuba update complete.');\n logger.newline();\n\n return {\n ok: true,\n fixable: false,\n };\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,sBAAmC;AACnC,oBAA0B;AAG1B,sBAAoC;AACpC,4BAAqC;AACrC,qBAAgC;AAGhC,qBAA8B;AAc9B,MAAM,aAAa,OAAO,oBAA8C;AACtE,QAAM,UAAU,UAAM,yBAAQ,YAAAA,QAAK,KAAK,WAAW,SAAS,CAAC;AAI7D,QAAM,wBAAoB;AAAA,IACxB,QAAQ,OAAO,CAAC,iBAAa,mBAAI,UAAU,eAAe,CAAC;AAAA,EAC7D;AAEA,UAAQ,MAAM,QAAQ,IAAI,kBAAkB,IAAI,cAAc,CAAC,GAAG,KAAK;AACzE;AAEA,MAAM,iBAAiB,CAAC,MAAM,IAAI;AAIlC,MAAM,iBAAiB,OAAO,YAAsC;AAClE,aAAW,aAAa,gBAAgB;AACtC,QAAI;AAEF,cAAQ,MAAM,OAAO,aAAa,OAAO,UAAU,SAAS,KAAK;AAAA,IACnE,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,IAAI,MAAM,iCAAiC,OAAO,EAAE;AAC5D;AAEO,MAAM,eAAe,OAC1B,MACA,WACgC;AAChC,QAAM,CAAC,gBAAgB,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,QACnD,gCAAgB;AAAA,QAChB,qCAAoB;AAAA,EACtB,CAAC;AAED,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,WAAS,YAAY,UAAU,EAAE,SAAS,QAAQ;AAElD,QAAM,kBAAmB,SAAS,YAAY,MAC3C;AAGH,UAAI,mBAAI,iBAAiB,cAAc,GAAG;AACxC,WAAO,EAAE,IAAI,MAAM,SAAS,MAAM;AAAA,EACpC;AAEA,QAAM,UAAU,MAAM,WAAW,eAAe;AAEhD,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,IAAI,MAAM,SAAS,MAAM;AAAA,EACpC;AAEA,MAAI,SAAS,QAAQ;AACnB,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,QAAQ,IAAI,OAAO,EAAE,MAAM,MAAM,MAAM,MAAM,IAAI,CAAC;AAAA,IACpD;AAGA,QAAI,QAAQ,MAAM,CAAC,EAAE,OAAO,MAAM,WAAW,MAAM,GAAG;AACpD,aAAO,EAAE,IAAI,MAAM,SAAS,MAAM;AAAA,IACpC;AAEA,UAAM,iBAAiB,UAAM,4CAAqB;AAElD,WAAO;AAAA,MACL,mCAAmC,OAAO;AAAA,QACxC,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MACF,CAAC,iBAAiB,OAAO,IAAI,eAAe,CAAC;AAAA,IAC/C;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,QACX;AAAA;AAAA;AAAA,UAGE,MAAM,SAAS;AAAA,UACf,SAAS,mCAAmC,eAAe,IAAI;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,mBAAmB;AAGhC,aAAW,EAAE,OAAO,YAAY,KAAK,SAAS;AAC5C,UAAM,SAAS,MAAM,MAAM,IAAI;AAC/B,WAAO,QAAQ;AACf,QAAI,OAAO,WAAW,QAAQ;AAC5B,aAAO;AAAA,QACL,kBAAkB,WAAW,GAC3B,OAAO,SAAS,MAAM,OAAO,MAAM,KAAK,EAC1C;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,MAAM,kBAAkB,WAAW,EAAE;AAAA,IAC9C;AAAA,EACF;AAEA,EAAC,SAAS,YAAY,MAA2B,UAAU;AAE3D,QAAM,qBAAqB,UAAM,8BAAc,SAAS,WAAW;AAEnE,YAAM,2BAAU,SAAS,MAAM,kBAAkB;AACjD,SAAO,QAAQ;AACf,SAAO,MAAM,wBAAwB;AACrC,SAAO,QAAQ;AAEf,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS;AAAA,EACX;AACF;",
6
+ "names": ["path"]
7
+ }
@@ -1,6 +1,6 @@
1
- export declare const JEST_SETUP_FILES: string[];
1
+ import type { PatchFunction } from '../..';
2
2
  /**
3
3
  * Tries to add an empty `export {}` statement to the bottom of Jest setup files
4
4
  * for compliance with TypeScript isolated modules.
5
5
  */
6
- export declare const tryAddEmptyExports: () => Promise<void>;
6
+ export declare const tryAddEmptyExports: PatchFunction;
@@ -28,19 +28,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var addEmptyExports_exports = {};
30
30
  __export(addEmptyExports_exports, {
31
- JEST_SETUP_FILES: () => JEST_SETUP_FILES,
32
31
  tryAddEmptyExports: () => tryAddEmptyExports
33
32
  });
34
33
  module.exports = __toCommonJS(addEmptyExports_exports);
35
34
  var import_path = __toESM(require("path"));
36
35
  var import_util = require("util");
37
36
  var import_fs_extra = __toESM(require("fs-extra"));
38
- var import_logging = require("../../utils/logging");
39
- var import_package = require("./analysis/package");
40
- var import_project = require("./analysis/project");
41
- var import_prettier = require("./processing/prettier");
37
+ var import_logging = require("../../../../../utils/logging");
38
+ var import_package = require("../../../analysis/package");
39
+ var import_project = require("../../../analysis/project");
40
+ var import_prettier = require("../../../processing/prettier");
42
41
  const JEST_SETUP_FILES = ["jest.setup.ts", "jest.setup.int.ts"];
43
- const addEmptyExports = async () => {
42
+ const addEmptyExports = async (mode) => {
44
43
  const manifest = await (0, import_package.getDestinationManifest)();
45
44
  const destinationRoot = import_path.default.dirname(manifest.path);
46
45
  const readDestinationFile = (0, import_project.createDestinationFileReader)(destinationRoot);
@@ -50,27 +49,32 @@ const addEmptyExports = async () => {
50
49
  // with isolated modules. This is a very naive check that we don't want to
51
50
  // overcomplicate because it is invoked before many skuba commands.
52
51
  inputFile.includes("import ") || inputFile.includes("export ")) {
53
- return;
52
+ return "skip";
53
+ }
54
+ if (mode === "lint") {
55
+ return "apply";
54
56
  }
55
57
  const data = await (0, import_prettier.formatPrettier)([inputFile, "export {}"].join("\n\n"), {
56
58
  parser: "typescript"
57
59
  });
58
60
  const filepath = import_path.default.join(destinationRoot, filename);
59
61
  await import_fs_extra.default.promises.writeFile(filepath, data);
62
+ return "apply";
60
63
  };
61
- await Promise.all(JEST_SETUP_FILES.map(addEmptyExport));
64
+ const results = await Promise.all(JEST_SETUP_FILES.map(addEmptyExport));
65
+ return results.every((result) => result === "skip") ? "skip" : "apply";
62
66
  };
63
- const tryAddEmptyExports = async () => {
67
+ const tryAddEmptyExports = async (mode) => {
64
68
  try {
65
- await addEmptyExports();
69
+ return { result: await addEmptyExports(mode) };
66
70
  } catch (err) {
67
71
  import_logging.log.warn("Failed to convert Jest setup files to isolated modules.");
68
72
  import_logging.log.subtle((0, import_util.inspect)(err));
73
+ return { result: "skip", reason: "due to an error" };
69
74
  }
70
75
  };
71
76
  // Annotate the CommonJS export names for ESM import in node:
72
77
  0 && (module.exports = {
73
- JEST_SETUP_FILES,
74
78
  tryAddEmptyExports
75
79
  });
76
80
  //# sourceMappingURL=addEmptyExports.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/cli/configure/upgrade/patches/7.3.1/addEmptyExports.ts"],
4
+ "sourcesContent": ["import path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\n\nimport type { PatchFunction } from '../..';\nimport { log } from '../../../../../utils/logging';\nimport { getDestinationManifest } from '../../../analysis/package';\nimport { createDestinationFileReader } from '../../../analysis/project';\nimport { formatPrettier } from '../../../processing/prettier';\n\nconst JEST_SETUP_FILES = ['jest.setup.ts', 'jest.setup.int.ts'];\n\nconst addEmptyExports = async (mode: 'format' | 'lint') => {\n const manifest = await getDestinationManifest();\n\n const destinationRoot = path.dirname(manifest.path);\n\n const readDestinationFile = createDestinationFileReader(destinationRoot);\n\n const addEmptyExport = async (filename: string) => {\n const inputFile = await readDestinationFile(filename);\n\n if (\n !inputFile ||\n // The file appears to have an import or export so it should be compatible\n // with isolated modules. This is a very naive check that we don't want to\n // overcomplicate because it is invoked before many skuba commands.\n inputFile.includes('import ') ||\n inputFile.includes('export ')\n ) {\n return 'skip';\n }\n\n if (mode === 'lint') {\n return 'apply';\n }\n\n const data = await formatPrettier([inputFile, 'export {}'].join('\\n\\n'), {\n parser: 'typescript',\n });\n\n const filepath = path.join(destinationRoot, filename);\n\n await fs.promises.writeFile(filepath, data);\n\n return 'apply';\n };\n\n const results = await Promise.all(JEST_SETUP_FILES.map(addEmptyExport));\n return results.every((result) => result === 'skip') ? 'skip' : 'apply';\n};\n\n/**\n * Tries to add an empty `export {}` statement to the bottom of Jest setup files\n * for compliance with TypeScript isolated modules.\n */\nexport const tryAddEmptyExports: PatchFunction = async (\n mode: 'format' | 'lint',\n) => {\n try {\n return { result: await addEmptyExports(mode) };\n } catch (err) {\n log.warn('Failed to convert Jest setup files to isolated modules.');\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,kBAAiB;AACjB,kBAAwB;AAExB,sBAAe;AAGf,qBAAoB;AACpB,qBAAuC;AACvC,qBAA4C;AAC5C,sBAA+B;AAE/B,MAAM,mBAAmB,CAAC,iBAAiB,mBAAmB;AAE9D,MAAM,kBAAkB,OAAO,SAA4B;AACzD,QAAM,WAAW,UAAM,uCAAuB;AAE9C,QAAM,kBAAkB,YAAAA,QAAK,QAAQ,SAAS,IAAI;AAElD,QAAM,0BAAsB,4CAA4B,eAAe;AAEvE,QAAM,iBAAiB,OAAO,aAAqB;AACjD,UAAM,YAAY,MAAM,oBAAoB,QAAQ;AAEpD,QACE,CAAC;AAAA;AAAA;AAAA,IAID,UAAU,SAAS,SAAS,KAC5B,UAAU,SAAS,SAAS,GAC5B;AACA,aAAO;AAAA,IACT;AAEA,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,UAAM,gCAAe,CAAC,WAAW,WAAW,EAAE,KAAK,MAAM,GAAG;AAAA,MACvE,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,WAAW,YAAAA,QAAK,KAAK,iBAAiB,QAAQ;AAEpD,UAAM,gBAAAC,QAAG,SAAS,UAAU,UAAU,IAAI;AAE1C,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,QAAQ,IAAI,iBAAiB,IAAI,cAAc,CAAC;AACtE,SAAO,QAAQ,MAAM,CAAC,WAAW,WAAW,MAAM,IAAI,SAAS;AACjE;AAMO,MAAM,qBAAoC,OAC/C,SACG;AACH,MAAI;AACF,WAAO,EAAE,QAAQ,MAAM,gBAAgB,IAAI,EAAE;AAAA,EAC/C,SAAS,KAAK;AACZ,uBAAI,KAAK,yDAAyD;AAClE,uBAAI,WAAO,qBAAQ,GAAG,CAAC;AACvB,WAAO,EAAE,QAAQ,QAAQ,QAAQ,kBAAkB;AAAA,EACrD;AACF;",
6
+ "names": ["path", "fs"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { Patches } from '../..';
2
+ export declare const patches: Patches;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __exports = {};
20
+ __export(__exports, {
21
+ patches: () => patches
22
+ });
23
+ module.exports = __toCommonJS(__exports);
24
+ var import_patchRenovateConfig = require("../../../patchRenovateConfig");
25
+ var import_addEmptyExports = require("./addEmptyExports");
26
+ var import_moveNpmrcOutOfGitignoreManagedSection = require("./moveNpmrcOutOfGitignoreManagedSection");
27
+ var import_patchDockerfile = require("./patchDockerfile");
28
+ var import_patchServerListener = require("./patchServerListener");
29
+ const patches = [
30
+ {
31
+ apply: import_addEmptyExports.tryAddEmptyExports,
32
+ description: "Add empty exports to Jest files for compliance with TypeScript isolated modules"
33
+ },
34
+ {
35
+ apply: import_patchRenovateConfig.tryPatchRenovateConfig,
36
+ description: "Update Renovate config to support private SEEK packages"
37
+ },
38
+ {
39
+ apply: import_patchDockerfile.tryPatchDockerfile,
40
+ description: "Upgrade Node.js Distroless Docker image to -debian12 variant"
41
+ },
42
+ {
43
+ apply: import_patchServerListener.tryPatchServerListener,
44
+ description: "Add keepAliveTimeout to server listener"
45
+ },
46
+ {
47
+ apply: import_moveNpmrcOutOfGitignoreManagedSection.tryMoveNpmrcOutOfGitignoreManagedSection,
48
+ description: "Move .npmrc out of the .gitignore managed section"
49
+ }
50
+ ];
51
+ // Annotate the CommonJS export names for ESM import in node:
52
+ 0 && (module.exports = {
53
+ patches
54
+ });
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/cli/configure/upgrade/patches/7.3.1/index.ts"],
4
+ "sourcesContent": ["import type { Patches } from '../..';\nimport { tryPatchRenovateConfig } from '../../../patchRenovateConfig';\n\nimport { tryAddEmptyExports } from './addEmptyExports';\nimport { tryMoveNpmrcOutOfGitignoreManagedSection } from './moveNpmrcOutOfGitignoreManagedSection';\nimport { tryPatchDockerfile } from './patchDockerfile';\nimport { tryPatchServerListener } from './patchServerListener';\n\nexport const patches: Patches = [\n {\n apply: tryAddEmptyExports,\n description:\n 'Add empty exports to Jest files for compliance with TypeScript isolated modules',\n },\n {\n apply: tryPatchRenovateConfig,\n description: 'Update Renovate config to support private SEEK packages',\n },\n {\n apply: tryPatchDockerfile,\n description: 'Upgrade Node.js Distroless Docker image to -debian12 variant',\n },\n {\n apply: tryPatchServerListener,\n description: 'Add keepAliveTimeout to server listener',\n },\n {\n apply: tryMoveNpmrcOutOfGitignoreManagedSection,\n description: 'Move .npmrc out of the .gitignore managed section',\n },\n];\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,iCAAuC;AAEvC,6BAAmC;AACnC,mDAAyD;AACzD,6BAAmC;AACnC,iCAAuC;AAEhC,MAAM,UAAmB;AAAA,EAC9B;AAAA,IACE,OAAO;AAAA,IACP,aACE;AAAA,EACJ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { PatchReturnType } from '../..';
2
+ export declare const tryMoveNpmrcOutOfGitignoreManagedSection: (mode: 'format' | 'lint', dir?: string) => Promise<PatchReturnType>;
@@ -0,0 +1,94 @@
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 moveNpmrcOutOfGitignoreManagedSection_exports = {};
30
+ __export(moveNpmrcOutOfGitignoreManagedSection_exports, {
31
+ tryMoveNpmrcOutOfGitignoreManagedSection: () => tryMoveNpmrcOutOfGitignoreManagedSection
32
+ });
33
+ module.exports = __toCommonJS(moveNpmrcOutOfGitignoreManagedSection_exports);
34
+ var import_path = __toESM(require("path"));
35
+ var import_util = require("util");
36
+ var import_fs_extra = __toESM(require("fs-extra"));
37
+ var import_logging = require("../../../../../utils/logging");
38
+ var import_project = require("../../../analysis/project");
39
+ const NPMRC_IGNORE_SECTION = `
40
+
41
+ # Ignore .npmrc. This is no longer managed by skuba as pnpm projects use a managed .npmrc.
42
+ # IMPORTANT: if migrating to pnpm, remove this line and add an .npmrc IN THE SAME COMMIT.
43
+ # You can use \`skuba format\` to generate the file or otherwise commit an empty file.
44
+ # Doing so will conflict with a local .npmrc and make it more difficult to unintentionally commit auth secrets.
45
+ .npmrc
46
+ `;
47
+ const moveNpmrcOutOfGitignoreManagedSection = async (mode, dir) => {
48
+ const readFile = (0, import_project.createDestinationFileReader)(dir);
49
+ const gitignore = await readFile(".gitignore");
50
+ if (!gitignore) {
51
+ return { result: "skip", reason: "no .gitignore file found" };
52
+ }
53
+ let isIgnored;
54
+ let currentlyInManagedSection = false;
55
+ for (const line of gitignore.split("\n")) {
56
+ if (line.trim() === "# managed by skuba") {
57
+ currentlyInManagedSection = true;
58
+ } else if (line.trim() === "# end managed by skuba") {
59
+ currentlyInManagedSection = false;
60
+ }
61
+ if (line.trim() === ".npmrc" || line.trim() === "/.npmrc") {
62
+ isIgnored = { inManaged: currentlyInManagedSection };
63
+ }
64
+ if (line.trim() === "!.npmrc" || line.trim() === "!/.npmrc") {
65
+ isIgnored = void 0;
66
+ }
67
+ }
68
+ if (isIgnored && !isIgnored.inManaged) {
69
+ return { result: "skip", reason: "already ignored in unmanaged section" };
70
+ }
71
+ if (!isIgnored) {
72
+ return { result: "skip", reason: "not ignored" };
73
+ }
74
+ if (mode === "lint") {
75
+ return { result: "apply" };
76
+ }
77
+ const newGitignore = gitignore.split("\n").filter((line) => line.trim().replace(/^[!/]+/g, "") !== ".npmrc").join("\n").trim() + NPMRC_IGNORE_SECTION;
78
+ await import_fs_extra.default.promises.writeFile(import_path.default.join(dir, ".gitignore"), newGitignore);
79
+ return { result: "apply" };
80
+ };
81
+ const tryMoveNpmrcOutOfGitignoreManagedSection = async (mode, dir = process.cwd()) => {
82
+ try {
83
+ return await moveNpmrcOutOfGitignoreManagedSection(mode, dir);
84
+ } catch (err) {
85
+ import_logging.log.warn("Failed to move .npmrc out of .gitignore managed section.");
86
+ import_logging.log.subtle((0, import_util.inspect)(err));
87
+ return { result: "skip", reason: "due to an error" };
88
+ }
89
+ };
90
+ // Annotate the CommonJS export names for ESM import in node:
91
+ 0 && (module.exports = {
92
+ tryMoveNpmrcOutOfGitignoreManagedSection
93
+ });
94
+ //# sourceMappingURL=moveNpmrcOutOfGitignoreManagedSection.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.ts"],
4
+ "sourcesContent": ["import path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\n\nimport type { PatchFunction, PatchReturnType } from '../..';\nimport { log } from '../../../../../utils/logging';\nimport { createDestinationFileReader } from '../../../analysis/project';\n\nconst NPMRC_IGNORE_SECTION = `\n\n# Ignore .npmrc. This is no longer managed by skuba as pnpm projects use a managed .npmrc.\n# IMPORTANT: if migrating to pnpm, remove this line and add an .npmrc IN THE SAME COMMIT.\n# You can use \\`skuba format\\` to generate the file or otherwise commit an empty file.\n# Doing so will conflict with a local .npmrc and make it more difficult to unintentionally commit auth secrets.\n.npmrc\n`;\n\nconst moveNpmrcOutOfGitignoreManagedSection = async (\n mode: 'format' | 'lint',\n dir: string,\n): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(dir);\n\n const gitignore = await readFile('.gitignore');\n\n if (!gitignore) {\n return { result: 'skip', reason: 'no .gitignore file found' };\n }\n\n let isIgnored: { inManaged: boolean } | undefined;\n let currentlyInManagedSection = false;\n\n for (const line of gitignore.split('\\n')) {\n if (line.trim() === '# managed by skuba') {\n currentlyInManagedSection = true;\n } else if (line.trim() === '# end managed by skuba') {\n currentlyInManagedSection = false;\n }\n\n if (line.trim() === '.npmrc' || line.trim() === '/.npmrc') {\n isIgnored = { inManaged: currentlyInManagedSection };\n }\n\n if (line.trim() === '!.npmrc' || line.trim() === '!/.npmrc') {\n isIgnored = undefined;\n }\n }\n\n if (isIgnored && !isIgnored.inManaged) {\n return { result: 'skip', reason: 'already ignored in unmanaged section' };\n }\n\n if (!isIgnored) {\n return { result: 'skip', reason: 'not ignored' };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const newGitignore =\n gitignore\n .split('\\n')\n .filter((line) => line.trim().replace(/^[!/]+/g, '') !== '.npmrc')\n .join('\\n')\n .trim() + NPMRC_IGNORE_SECTION;\n\n await fs.promises.writeFile(path.join(dir, '.gitignore'), newGitignore);\n\n return { result: 'apply' };\n};\n\nexport const tryMoveNpmrcOutOfGitignoreManagedSection = (async (\n mode: 'format' | 'lint',\n dir = process.cwd(),\n) => {\n try {\n return await moveNpmrcOutOfGitignoreManagedSection(mode, dir);\n } catch (err) {\n log.warn('Failed to move .npmrc out of .gitignore managed section.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n}) satisfies PatchFunction;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AACjB,kBAAwB;AAExB,sBAAe;AAGf,qBAAoB;AACpB,qBAA4C;AAE5C,MAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS7B,MAAM,wCAAwC,OAC5C,MACA,QAC6B;AAC7B,QAAM,eAAW,4CAA4B,GAAG;AAEhD,QAAM,YAAY,MAAM,SAAS,YAAY;AAE7C,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,QAAQ,QAAQ,QAAQ,2BAA2B;AAAA,EAC9D;AAEA,MAAI;AACJ,MAAI,4BAA4B;AAEhC,aAAW,QAAQ,UAAU,MAAM,IAAI,GAAG;AACxC,QAAI,KAAK,KAAK,MAAM,sBAAsB;AACxC,kCAA4B;AAAA,IAC9B,WAAW,KAAK,KAAK,MAAM,0BAA0B;AACnD,kCAA4B;AAAA,IAC9B;AAEA,QAAI,KAAK,KAAK,MAAM,YAAY,KAAK,KAAK,MAAM,WAAW;AACzD,kBAAY,EAAE,WAAW,0BAA0B;AAAA,IACrD;AAEA,QAAI,KAAK,KAAK,MAAM,aAAa,KAAK,KAAK,MAAM,YAAY;AAC3D,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,MAAI,aAAa,CAAC,UAAU,WAAW;AACrC,WAAO,EAAE,QAAQ,QAAQ,QAAQ,uCAAuC;AAAA,EAC1E;AAEA,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,QAAQ,QAAQ,QAAQ,cAAc;AAAA,EACjD;AAEA,MAAI,SAAS,QAAQ;AACnB,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AAEA,QAAM,eACJ,UACG,MAAM,IAAI,EACV,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,QAAQ,WAAW,EAAE,MAAM,QAAQ,EAChE,KAAK,IAAI,EACT,KAAK,IAAI;AAEd,QAAM,gBAAAA,QAAG,SAAS,UAAU,YAAAC,QAAK,KAAK,KAAK,YAAY,GAAG,YAAY;AAEtE,SAAO,EAAE,QAAQ,QAAQ;AAC3B;AAEO,MAAM,2CAA4C,OACvD,MACA,MAAM,QAAQ,IAAI,MACf;AACH,MAAI;AACF,WAAO,MAAM,sCAAsC,MAAM,GAAG;AAAA,EAC9D,SAAS,KAAK;AACZ,uBAAI,KAAK,0DAA0D;AACnE,uBAAI,WAAO,qBAAQ,GAAG,CAAC;AACvB,WAAO,EAAE,QAAQ,QAAQ,QAAQ,kBAAkB;AAAA,EACrD;AACF;",
6
+ "names": ["fs", "path"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { PatchFunction } from '../..';
2
+ export declare const tryPatchDockerfile: PatchFunction;
@@ -33,29 +33,35 @@ __export(patchDockerfile_exports, {
33
33
  module.exports = __toCommonJS(patchDockerfile_exports);
34
34
  var import_util = require("util");
35
35
  var import_fs_extra = __toESM(require("fs-extra"));
36
- var import_logging = require("../../utils/logging");
37
- var import_project = require("./analysis/project");
36
+ var import_logging = require("../../../../../utils/logging");
37
+ var import_project = require("../../../analysis/project");
38
38
  const DOCKERFILE_FILENAME = "Dockerfile";
39
- const VERSION_REGEX = /gcr.io\/distroless\/nodejs:(16|18|20)/g;
40
- const VERSION_DEBIAN_REPLACE = "gcr.io/distroless/nodejs$1-debian11";
41
- const patchDockerfile = async (dir) => {
39
+ const NON_DEBIAN_REGEX = /gcr.io\/distroless\/nodejs:(18|20)/g;
40
+ const DEBIAN_REGEX = /gcr.io\/distroless\/nodejs(18|20)-debian11/g;
41
+ const VERSION_DEBIAN_REPLACE = "gcr.io/distroless/nodejs$1-debian12";
42
+ const patchDockerfile = async (mode, dir) => {
42
43
  const readFile = (0, import_project.createDestinationFileReader)(dir);
43
44
  const maybeDockerfile = await readFile(DOCKERFILE_FILENAME);
44
45
  if (!maybeDockerfile) {
45
- return;
46
+ return { result: "skip", reason: "no Dockerfile found" };
47
+ }
48
+ const patched = maybeDockerfile.replaceAll(NON_DEBIAN_REGEX, VERSION_DEBIAN_REPLACE).replaceAll(DEBIAN_REGEX, VERSION_DEBIAN_REPLACE);
49
+ if (patched === maybeDockerfile) {
50
+ return { result: "skip" };
51
+ }
52
+ if (mode === "lint") {
53
+ return { result: "apply" };
46
54
  }
47
- const patched = maybeDockerfile.replaceAll(
48
- VERSION_REGEX,
49
- VERSION_DEBIAN_REPLACE
50
- );
51
55
  await import_fs_extra.default.promises.writeFile(DOCKERFILE_FILENAME, patched);
56
+ return { result: "apply" };
52
57
  };
53
- const tryPatchDockerfile = async (dir = process.cwd()) => {
58
+ const tryPatchDockerfile = async (mode, dir = process.cwd()) => {
54
59
  try {
55
- await patchDockerfile(dir);
60
+ return await patchDockerfile(mode, dir);
56
61
  } catch (err) {
57
62
  import_logging.log.warn("Failed to patch Dockerfile.");
58
63
  import_logging.log.subtle((0, import_util.inspect)(err));
64
+ return { result: "skip", reason: "due to an error" };
59
65
  }
60
66
  };
61
67
  // Annotate the CommonJS export names for ESM import in node: