skuba 12.1.0-main-20250810101347 → 12.1.0-main-20250812041011
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.
- package/lib/cli/build/assets.js +1 -1
- package/lib/cli/build/assets.js.map +2 -2
- package/lib/cli/init/getConfig.js +1 -1
- package/lib/cli/init/getConfig.js.map +2 -2
- package/lib/cli/lint/internal.js +1 -1
- package/lib/cli/lint/internal.js.map +2 -2
- package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js +1 -1
- package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js.map +2 -2
- package/package.json +4 -4
- package/template/base/jest.setup.ts +1 -1
- package/template/express-rest-api/.buildkite/pipeline.yml +6 -0
- package/template/express-rest-api/.env +1 -1
- package/template/express-rest-api/.gantry/dev.yml +5 -1
- package/template/express-rest-api/.gantry/prod.yml +5 -1
- package/template/express-rest-api/Dockerfile +1 -1
- package/template/express-rest-api/README.md +5 -5
- package/template/express-rest-api/gantry.apply.yml +17 -1
- package/template/express-rest-api/package.json +9 -3
- package/template/express-rest-api/src/api/healthCheck.ts +2 -2
- package/template/express-rest-api/src/config.ts +7 -7
- package/template/express-rest-api/src/framework/logging.ts +11 -7
- package/template/express-rest-api/src/framework/metrics.ts +1 -1
- package/template/express-rest-api/src/tracing.ts +56 -0
- package/template/greeter/README.md +2 -2
- package/template/greeter/package.json +1 -1
- package/template/koa-rest-api/.buildkite/pipeline.yml +6 -0
- package/template/koa-rest-api/.env +1 -1
- package/template/koa-rest-api/.gantry/dev.yml +3 -3
- package/template/koa-rest-api/.gantry/prod.yml +3 -3
- package/template/koa-rest-api/README.md +6 -6
- package/template/koa-rest-api/gantry.apply.yml +15 -3
- package/template/koa-rest-api/package.json +2 -3
- package/template/koa-rest-api/src/api/healthCheck.ts +2 -2
- package/template/koa-rest-api/src/config.ts +7 -7
- package/template/koa-rest-api/src/framework/logging.ts +12 -8
- package/template/koa-rest-api/src/framework/metrics.ts +1 -1
- package/template/koa-rest-api/src/framework/server.test.ts +7 -7
- package/template/koa-rest-api/src/framework/server.ts +1 -4
- package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +6 -2
- package/template/lambda-sqs-worker-cdk/.env +1 -1
- package/template/lambda-sqs-worker-cdk/README.md +8 -8
- package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +34 -8
- package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +5 -8
- package/template/lambda-sqs-worker-cdk/infra/appStack.ts +11 -5
- package/template/lambda-sqs-worker-cdk/infra/config.ts +26 -17
- package/template/lambda-sqs-worker-cdk/infra/index.ts +1 -1
- package/template/lambda-sqs-worker-cdk/package.json +5 -5
- package/template/lambda-sqs-worker-cdk/src/app.test.ts +4 -4
- package/template/lambda-sqs-worker-cdk/src/config.ts +11 -16
- package/template/lambda-sqs-worker-cdk/src/framework/handler.test.ts +2 -2
- package/template/lambda-sqs-worker-cdk/src/framework/handler.ts +8 -21
- package/template/lambda-sqs-worker-cdk/src/framework/logging.ts +12 -8
- package/template/lambda-sqs-worker-cdk/src/framework/metrics.ts +1 -4
- package/template/oss-npm-package/.github/workflows/release.yml +1 -1
- package/template/oss-npm-package/.github/workflows/validate.yml +1 -1
package/lib/cli/build/assets.js
CHANGED
|
@@ -89,7 +89,7 @@ const copyAssetsConcurrently = async (configs) => {
|
|
|
89
89
|
);
|
|
90
90
|
await Promise.all(
|
|
91
91
|
configs.map(
|
|
92
|
-
({ outDir, name, prefixColor }) => copyAssets(
|
|
92
|
+
async ({ outDir, name, prefixColor }) => copyAssets(
|
|
93
93
|
outDir,
|
|
94
94
|
(0, import_logging.createLogger)({
|
|
95
95
|
debug: false,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cli/build/assets.ts"],
|
|
4
|
-
"sourcesContent": ["import path from 'path';\n\nimport chalk, { type Color } from 'chalk';\nimport fs from 'fs-extra';\n\nimport { copyFile } from '../../utils/copy.js';\nimport { buildPatternToFilepathMap, crawlDirectory } from '../../utils/dir.js';\nimport { type Logger, createLogger, log } from '../../utils/logging.js';\nimport {\n getConsumerManifest,\n getEntryPointFromManifest,\n getPropFromConsumerManifest,\n} from '../../utils/manifest.js';\n\nexport const copyAssets = async (\n destinationDir: string,\n logger: Logger = log,\n) => {\n const manifest = await getConsumerManifest();\n if (!manifest) {\n return;\n }\n\n const assets = await getPropFromConsumerManifest<string, string[]>('assets');\n if (!assets) {\n return;\n }\n\n const entryPoint = await getEntryPointFromManifest();\n if (!entryPoint) {\n return;\n }\n\n const pathSegments = entryPoint.split(path.sep);\n const srcDir = (pathSegments.length > 1 && pathSegments[0]) || '';\n const resolvedSrcDir = path.resolve(path.dirname(manifest.path), srcDir);\n const resolvedDestinationDir = path.resolve(\n path.dirname(manifest.path),\n destinationDir,\n );\n\n const allFiles = await crawlDirectory(resolvedSrcDir);\n const filesByPattern = buildPatternToFilepathMap(assets, allFiles, {\n cwd: resolvedSrcDir,\n dot: true,\n });\n const matchedFiles = Array.from(\n new Set(Object.values(filesByPattern).flat()),\n );\n\n await Promise.all(\n matchedFiles.map(async (filename) => {\n logger.subtle(`Copying ${filename}`);\n\n await fs.promises.mkdir(\n path.dirname(path.join(resolvedDestinationDir, filename)),\n { recursive: true },\n );\n await copyFile(\n path.join(resolvedSrcDir, filename),\n path.join(resolvedDestinationDir, filename),\n { processors: [] },\n );\n }),\n );\n};\n\ninterface CopyAssetsConfig {\n outDir: string;\n name: string;\n prefixColor: typeof Color;\n}\n\nexport const copyAssetsConcurrently = async (configs: CopyAssetsConfig[]) => {\n const maxNameLength = configs.reduce(\n (length, command) => Math.max(length, command.name.length),\n 0,\n );\n\n await Promise.all(\n configs.map(({ outDir, name, prefixColor }) =>\n copyAssets(\n outDir,\n createLogger({\n debug: false,\n prefixes: [chalk[prefixColor](`${name.padEnd(maxNameLength)} \u2502`)],\n }),\n ),\n ),\n );\n};\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,mBAAkC;AAClC,sBAAe;AAEf,kBAAyB;AACzB,iBAA0D;AAC1D,qBAA+C;AAC/C,sBAIO;AAEA,MAAM,aAAa,OACxB,gBACA,SAAiB,uBACd;AACH,QAAM,WAAW,UAAM,qCAAoB;AAC3C,MAAI,CAAC,UAAU;AACb;AAAA,EACF;AAEA,QAAM,SAAS,UAAM,6CAA8C,QAAQ;AAC3E,MAAI,CAAC,QAAQ;AACX;AAAA,EACF;AAEA,QAAM,aAAa,UAAM,2CAA0B;AACnD,MAAI,CAAC,YAAY;AACf;AAAA,EACF;AAEA,QAAM,eAAe,WAAW,MAAM,YAAAA,QAAK,GAAG;AAC9C,QAAM,SAAU,aAAa,SAAS,KAAK,aAAa,CAAC,KAAM;AAC/D,QAAM,iBAAiB,YAAAA,QAAK,QAAQ,YAAAA,QAAK,QAAQ,SAAS,IAAI,GAAG,MAAM;AACvE,QAAM,yBAAyB,YAAAA,QAAK;AAAA,IAClC,YAAAA,QAAK,QAAQ,SAAS,IAAI;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,WAAW,UAAM,2BAAe,cAAc;AACpD,QAAM,qBAAiB,sCAA0B,QAAQ,UAAU;AAAA,IACjE,KAAK;AAAA,IACL,KAAK;AAAA,EACP,CAAC;AACD,QAAM,eAAe,MAAM;AAAA,IACzB,IAAI,IAAI,OAAO,OAAO,cAAc,EAAE,KAAK,CAAC;AAAA,EAC9C;AAEA,QAAM,QAAQ;AAAA,IACZ,aAAa,IAAI,OAAO,aAAa;AACnC,aAAO,OAAO,WAAW,QAAQ,EAAE;AAEnC,YAAM,gBAAAC,QAAG,SAAS;AAAA,QAChB,YAAAD,QAAK,QAAQ,YAAAA,QAAK,KAAK,wBAAwB,QAAQ,CAAC;AAAA,QACxD,EAAE,WAAW,KAAK;AAAA,MACpB;AACA,gBAAM;AAAA,QACJ,YAAAA,QAAK,KAAK,gBAAgB,QAAQ;AAAA,QAClC,YAAAA,QAAK,KAAK,wBAAwB,QAAQ;AAAA,QAC1C,EAAE,YAAY,CAAC,EAAE;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAQO,MAAM,yBAAyB,OAAO,YAAgC;AAC3E,QAAM,gBAAgB,QAAQ;AAAA,IAC5B,CAAC,QAAQ,YAAY,KAAK,IAAI,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACzD;AAAA,EACF;AAEA,QAAM,QAAQ;AAAA,IACZ,QAAQ;AAAA,MAAI,
|
|
4
|
+
"sourcesContent": ["import path from 'path';\n\nimport chalk, { type Color } from 'chalk';\nimport fs from 'fs-extra';\n\nimport { copyFile } from '../../utils/copy.js';\nimport { buildPatternToFilepathMap, crawlDirectory } from '../../utils/dir.js';\nimport { type Logger, createLogger, log } from '../../utils/logging.js';\nimport {\n getConsumerManifest,\n getEntryPointFromManifest,\n getPropFromConsumerManifest,\n} from '../../utils/manifest.js';\n\nexport const copyAssets = async (\n destinationDir: string,\n logger: Logger = log,\n) => {\n const manifest = await getConsumerManifest();\n if (!manifest) {\n return;\n }\n\n const assets = await getPropFromConsumerManifest<string, string[]>('assets');\n if (!assets) {\n return;\n }\n\n const entryPoint = await getEntryPointFromManifest();\n if (!entryPoint) {\n return;\n }\n\n const pathSegments = entryPoint.split(path.sep);\n const srcDir = (pathSegments.length > 1 && pathSegments[0]) || '';\n const resolvedSrcDir = path.resolve(path.dirname(manifest.path), srcDir);\n const resolvedDestinationDir = path.resolve(\n path.dirname(manifest.path),\n destinationDir,\n );\n\n const allFiles = await crawlDirectory(resolvedSrcDir);\n const filesByPattern = buildPatternToFilepathMap(assets, allFiles, {\n cwd: resolvedSrcDir,\n dot: true,\n });\n const matchedFiles = Array.from(\n new Set(Object.values(filesByPattern).flat()),\n );\n\n await Promise.all(\n matchedFiles.map(async (filename) => {\n logger.subtle(`Copying ${filename}`);\n\n await fs.promises.mkdir(\n path.dirname(path.join(resolvedDestinationDir, filename)),\n { recursive: true },\n );\n await copyFile(\n path.join(resolvedSrcDir, filename),\n path.join(resolvedDestinationDir, filename),\n { processors: [] },\n );\n }),\n );\n};\n\ninterface CopyAssetsConfig {\n outDir: string;\n name: string;\n prefixColor: typeof Color;\n}\n\nexport const copyAssetsConcurrently = async (configs: CopyAssetsConfig[]) => {\n const maxNameLength = configs.reduce(\n (length, command) => Math.max(length, command.name.length),\n 0,\n );\n\n await Promise.all(\n configs.map(async ({ outDir, name, prefixColor }) =>\n copyAssets(\n outDir,\n createLogger({\n debug: false,\n prefixes: [chalk[prefixColor](`${name.padEnd(maxNameLength)} \u2502`)],\n }),\n ),\n ),\n );\n};\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,mBAAkC;AAClC,sBAAe;AAEf,kBAAyB;AACzB,iBAA0D;AAC1D,qBAA+C;AAC/C,sBAIO;AAEA,MAAM,aAAa,OACxB,gBACA,SAAiB,uBACd;AACH,QAAM,WAAW,UAAM,qCAAoB;AAC3C,MAAI,CAAC,UAAU;AACb;AAAA,EACF;AAEA,QAAM,SAAS,UAAM,6CAA8C,QAAQ;AAC3E,MAAI,CAAC,QAAQ;AACX;AAAA,EACF;AAEA,QAAM,aAAa,UAAM,2CAA0B;AACnD,MAAI,CAAC,YAAY;AACf;AAAA,EACF;AAEA,QAAM,eAAe,WAAW,MAAM,YAAAA,QAAK,GAAG;AAC9C,QAAM,SAAU,aAAa,SAAS,KAAK,aAAa,CAAC,KAAM;AAC/D,QAAM,iBAAiB,YAAAA,QAAK,QAAQ,YAAAA,QAAK,QAAQ,SAAS,IAAI,GAAG,MAAM;AACvE,QAAM,yBAAyB,YAAAA,QAAK;AAAA,IAClC,YAAAA,QAAK,QAAQ,SAAS,IAAI;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,WAAW,UAAM,2BAAe,cAAc;AACpD,QAAM,qBAAiB,sCAA0B,QAAQ,UAAU;AAAA,IACjE,KAAK;AAAA,IACL,KAAK;AAAA,EACP,CAAC;AACD,QAAM,eAAe,MAAM;AAAA,IACzB,IAAI,IAAI,OAAO,OAAO,cAAc,EAAE,KAAK,CAAC;AAAA,EAC9C;AAEA,QAAM,QAAQ;AAAA,IACZ,aAAa,IAAI,OAAO,aAAa;AACnC,aAAO,OAAO,WAAW,QAAQ,EAAE;AAEnC,YAAM,gBAAAC,QAAG,SAAS;AAAA,QAChB,YAAAD,QAAK,QAAQ,YAAAA,QAAK,KAAK,wBAAwB,QAAQ,CAAC;AAAA,QACxD,EAAE,WAAW,KAAK;AAAA,MACpB;AACA,gBAAM;AAAA,QACJ,YAAAA,QAAK,KAAK,gBAAgB,QAAQ;AAAA,QAClC,YAAAA,QAAK,KAAK,wBAAwB,QAAQ;AAAA,QAC1C,EAAE,YAAY,CAAC,EAAE;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAQO,MAAM,yBAAyB,OAAO,YAAgC;AAC3E,QAAM,gBAAgB,QAAQ;AAAA,IAC5B,CAAC,QAAQ,YAAY,KAAK,IAAI,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACzD;AAAA,EACF;AAEA,QAAM,QAAQ;AAAA,IACZ,QAAQ;AAAA,MAAI,OAAO,EAAE,QAAQ,MAAM,YAAY,MAC7C;AAAA,QACE;AAAA,YACA,6BAAa;AAAA,UACX,OAAO;AAAA,UACP,UAAU,CAAC,aAAAE,QAAM,WAAW,EAAE,GAAG,KAAK,OAAO,aAAa,CAAC,SAAI,CAAC;AAAA,QAClE,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["path", "fs", "chalk"]
|
|
7
7
|
}
|
|
@@ -65,7 +65,7 @@ const runForm = (props) => {
|
|
|
65
65
|
name,
|
|
66
66
|
validate: async (values) => {
|
|
67
67
|
const results = await Promise.all(
|
|
68
|
-
choices.map((choice) => choice.validate(values[choice.name]))
|
|
68
|
+
choices.map(async (choice) => choice.validate(values[choice.name]))
|
|
69
69
|
);
|
|
70
70
|
return results.find((result) => typeof result === "string") ?? results.every((result) => result === true);
|
|
71
71
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cli/init/getConfig.ts"],
|
|
4
|
-
"sourcesContent": ["import path from 'path';\n\nimport chalk from 'chalk';\nimport { Form, type FormChoice } from 'enquirer';\nimport fs from 'fs-extra';\n\nimport { copyFiles } from '../../utils/copy.js';\nimport { isErrorWithCode } from '../../utils/error.js';\nimport { log } from '../../utils/logging.js';\nimport {\n DEFAULT_PACKAGE_MANAGER,\n configForPackageManager,\n} from '../../utils/packageManager.js';\nimport { getRandomPort } from '../../utils/port.js';\nimport {\n TEMPLATE_CONFIG_FILENAME,\n TEMPLATE_DIR,\n type TemplateConfig,\n templateConfigSchema,\n} from '../../utils/template.js';\n\nimport { downloadGitHubTemplate } from './git.js';\nimport {\n BASE_PROMPT_PROPS,\n type BaseFields,\n type Choice,\n GIT_PATH_PROMPT,\n SHOULD_CONTINUE_PROMPT,\n TEMPLATE_PROMPT,\n} from './prompts.js';\nimport { type InitConfig, initConfigInputSchema } from './types.js';\n\nexport const runForm = <T = Record<string, string>>(props: {\n choices: readonly Choice[];\n message: string;\n name: string;\n}) => {\n const { message, name } = props;\n\n const choices = props.choices.map((choice) => ({\n ...choice,\n validate: (value: string | undefined) => {\n if (\n !value ||\n value === '' ||\n (value === choice.initial && !choice.allowInitial)\n ) {\n return 'Form is not complete';\n }\n\n return choice.validate?.(value) ?? true;\n },\n }));\n\n const form = new Form<T>({\n choices,\n message,\n name,\n validate: async (values) => {\n const results = await Promise.all(\n choices.map((choice) => choice.validate(values[choice.name])),\n );\n\n return (\n results.find((result) => typeof result === 'string') ??\n results.every((result) => result === true)\n );\n },\n });\n\n return form.run();\n};\n\nconst confirmShouldContinue = async (choices: readonly FormChoice[]) => {\n const fieldsList = choices.map((choice) => choice.message);\n\n log.newline();\n log.plain('This template uses the following information:');\n log.newline();\n fieldsList.forEach((message) => log.subtle(`- ${message}`));\n\n log.newline();\n const result = await SHOULD_CONTINUE_PROMPT.run();\n\n return result === 'yes';\n};\n\nconst createDirectory = async (dir: string) => {\n try {\n await fs.promises.mkdir(dir);\n } catch (err) {\n if (isErrorWithCode(err, 'EEXIST')) {\n log.err(`The directory '${dir}' already exists.`);\n process.exit(1);\n }\n\n throw err;\n }\n};\n\nconst cloneTemplate = async (\n templateName: string,\n destinationDir: string,\n): Promise<TemplateConfig> => {\n const isCustomTemplate = templateName.startsWith('github:');\n\n if (isCustomTemplate) {\n const gitHubPath = templateName.slice('github:'.length);\n\n await downloadGitHubTemplate(gitHubPath, destinationDir);\n } else {\n const templateDir = path.join(TEMPLATE_DIR, templateName);\n\n await copyFiles({\n // assume built-in templates have no extraneous files\n include: () => true,\n sourceRoot: templateDir,\n destinationRoot: destinationDir,\n processors: [],\n // built-in templates have files like _package.json\n stripUnderscorePrefix: true,\n });\n }\n\n const templateConfig = getTemplateConfig(\n path.join(process.cwd(), destinationDir),\n );\n\n if (isCustomTemplate) {\n log.newline();\n log.warn(\n 'You may need to run',\n log.bold(\n configForPackageManager(templateConfig.packageManager).print.exec,\n 'skuba',\n 'configure',\n ),\n 'once this is done.',\n );\n }\n\n return templateConfig;\n};\n\nconst getTemplateName = async () => {\n const templateSelection = await TEMPLATE_PROMPT.run();\n\n if (templateSelection === 'github \u2192') {\n const gitHubPath = await GIT_PATH_PROMPT.run();\n return `github:${gitHubPath}`;\n }\n\n return templateSelection;\n};\n\nconst generatePlaceholders = (choices: FormChoice[]) =>\n Object.fromEntries(\n choices.map(({ name }) => [name, `<%- ${name} %>`] as const),\n );\n\nexport const getTemplateConfig = (dir: string): TemplateConfig => {\n const templateConfigPath = path.join(dir, TEMPLATE_CONFIG_FILENAME);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const templateConfig = require(templateConfigPath) as unknown;\n\n return templateConfigSchema.parse(templateConfig);\n } catch (err) {\n if (isErrorWithCode(err, 'MODULE_NOT_FOUND')) {\n return {\n entryPoint: undefined,\n fields: [],\n packageManager: DEFAULT_PACKAGE_MANAGER,\n type: undefined,\n };\n }\n\n throw err;\n }\n};\n\nconst baseToTemplateData = async ({\n ownerName,\n platformName,\n repoName,\n defaultBranch,\n}: BaseFields) => {\n const [orgName, teamName] = ownerName.split('/');\n\n const port = String(await getRandomPort());\n\n if (!orgName) {\n throw new Error(`Invalid format for owner name: ${ownerName}`);\n }\n\n return {\n orgName,\n ownerName,\n repoName,\n defaultBranch,\n // Use standalone username in `teamName` contexts\n teamName: teamName ?? orgName,\n\n port,\n\n platformName,\n lambdaCdkArchitecture: platformName === 'amd64' ? 'X86_64' : 'ARM_64',\n lambdaServerlessArchitecture:\n platformName === 'amd64' ? 'x86_64' : platformName,\n };\n};\n\nexport const configureFromPrompt = async (): Promise<InitConfig> => {\n const { ownerName, platformName, repoName, defaultBranch } =\n await runForm<BaseFields>(BASE_PROMPT_PROPS);\n log.plain(chalk.cyan(repoName), 'by', chalk.cyan(ownerName));\n\n const templateData = await baseToTemplateData({\n ownerName,\n platformName,\n repoName,\n defaultBranch,\n });\n\n const destinationDir = repoName;\n\n await createDirectory(destinationDir);\n\n log.newline();\n const templateName = await getTemplateName();\n\n const { entryPoint, fields, noSkip, packageManager, type } =\n await cloneTemplate(templateName, destinationDir);\n\n if (fields.length === 0) {\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: true,\n templateData,\n templateName,\n type,\n };\n }\n\n const shouldContinue = noSkip ? true : await confirmShouldContinue(fields);\n\n if (shouldContinue) {\n log.newline();\n const customAnswers = await runForm({\n choices: fields,\n message: chalk.bold(`Complete ${chalk.cyan(templateName)}:`),\n name: 'customAnswers',\n });\n\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: true,\n templateData: { ...templateData, ...customAnswers },\n templateName,\n type,\n };\n }\n\n log.newline();\n log.warn(\n `Resume this later with ${chalk.bold(\n configForPackageManager(packageManager).print.exec,\n 'skuba configure',\n )}.`,\n );\n\n const customAnswers = generatePlaceholders(fields);\n\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: false,\n templateData: { ...templateData, ...customAnswers },\n templateName,\n type,\n };\n};\n\nexport const readJSONFromStdIn = async () => {\n let text = '';\n\n await new Promise((resolve) =>\n process.stdin\n .on('data', (chunk) => (text += chunk.toString()))\n .once('end', resolve),\n );\n\n text = text.trim();\n\n if (text === '') {\n log.err('No data from stdin.');\n process.exit(1);\n }\n\n let value: unknown;\n\n try {\n value = JSON.parse(text) as unknown;\n } catch {\n log.err('Invalid JSON from stdin.');\n process.exit(1);\n }\n\n return value;\n};\n\nconst configureFromPipe = async (): Promise<InitConfig> => {\n const value = await readJSONFromStdIn();\n\n const result = initConfigInputSchema.safeParse(value);\n\n if (!result.success) {\n log.err('Invalid data from stdin:');\n log.err(result.error);\n process.exit(1);\n }\n\n const { destinationDir, templateComplete, templateName } = result.data;\n\n const templateData = {\n ...(await baseToTemplateData(result.data.templateData)),\n ...result.data.templateData,\n };\n\n await createDirectory(destinationDir);\n\n const { entryPoint, fields, noSkip, packageManager, type } =\n await cloneTemplate(templateName, destinationDir);\n\n if (!templateComplete) {\n if (noSkip) {\n log.err('Templating for', log.bold(templateName), 'cannot be skipped.');\n process.exit(1);\n }\n\n return {\n ...result.data,\n entryPoint,\n packageManager,\n templateData: {\n ...templateData,\n ...generatePlaceholders(fields),\n },\n type,\n };\n }\n\n const required = fields.map(({ name }) => name);\n\n const provided = new Set(Object.keys(templateData));\n\n const missing = required.filter((name) => !provided.has(name));\n\n if (missing.length > 0) {\n log.err('This template uses the following information:');\n log.newline();\n missing.forEach((name) => log.err(`- ${name}`));\n process.exit(1);\n }\n\n return {\n ...result.data,\n entryPoint,\n packageManager,\n templateData,\n type,\n };\n};\n\nexport const getConfig = () =>\n process.stdin.isTTY ? configureFromPrompt() : configureFromPipe();\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiB;AAEjB,mBAAkB;AAClB,sBAAsC;AACtC,sBAAe;AAEf,kBAA0B;AAC1B,mBAAgC;AAChC,qBAAoB;AACpB,4BAGO;AACP,kBAA8B;AAC9B,sBAKO;AAEP,iBAAuC;AACvC,qBAOO;AACP,mBAAuD;AAEhD,MAAM,UAAU,CAA6B,UAI9C;AACJ,QAAM,EAAE,SAAS,KAAK,IAAI;AAE1B,QAAM,UAAU,MAAM,QAAQ,IAAI,CAAC,YAAY;AAAA,IAC7C,GAAG;AAAA,IACH,UAAU,CAAC,UAA8B;AACvC,UACE,CAAC,SACD,UAAU,MACT,UAAU,OAAO,WAAW,CAAC,OAAO,cACrC;AACA,eAAO;AAAA,MACT;AAEA,aAAO,OAAO,WAAW,KAAK,KAAK;AAAA,IACrC;AAAA,EACF,EAAE;AAEF,QAAM,OAAO,IAAI,qBAAQ;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,OAAO,WAAW;AAC1B,YAAM,UAAU,MAAM,QAAQ;AAAA,QAC5B,QAAQ,IAAI,
|
|
4
|
+
"sourcesContent": ["import path from 'path';\n\nimport chalk from 'chalk';\nimport { Form, type FormChoice } from 'enquirer';\nimport fs from 'fs-extra';\n\nimport { copyFiles } from '../../utils/copy.js';\nimport { isErrorWithCode } from '../../utils/error.js';\nimport { log } from '../../utils/logging.js';\nimport {\n DEFAULT_PACKAGE_MANAGER,\n configForPackageManager,\n} from '../../utils/packageManager.js';\nimport { getRandomPort } from '../../utils/port.js';\nimport {\n TEMPLATE_CONFIG_FILENAME,\n TEMPLATE_DIR,\n type TemplateConfig,\n templateConfigSchema,\n} from '../../utils/template.js';\n\nimport { downloadGitHubTemplate } from './git.js';\nimport {\n BASE_PROMPT_PROPS,\n type BaseFields,\n type Choice,\n GIT_PATH_PROMPT,\n SHOULD_CONTINUE_PROMPT,\n TEMPLATE_PROMPT,\n} from './prompts.js';\nimport { type InitConfig, initConfigInputSchema } from './types.js';\n\nexport const runForm = <T = Record<string, string>>(props: {\n choices: readonly Choice[];\n message: string;\n name: string;\n}) => {\n const { message, name } = props;\n\n const choices = props.choices.map((choice) => ({\n ...choice,\n validate: (value: string | undefined) => {\n if (\n !value ||\n value === '' ||\n (value === choice.initial && !choice.allowInitial)\n ) {\n return 'Form is not complete';\n }\n\n return choice.validate?.(value) ?? true;\n },\n }));\n\n const form = new Form<T>({\n choices,\n message,\n name,\n validate: async (values) => {\n const results = await Promise.all(\n choices.map(async (choice) => choice.validate(values[choice.name])),\n );\n\n return (\n results.find((result) => typeof result === 'string') ??\n results.every((result) => result === true)\n );\n },\n });\n\n return form.run();\n};\n\nconst confirmShouldContinue = async (choices: readonly FormChoice[]) => {\n const fieldsList = choices.map((choice) => choice.message);\n\n log.newline();\n log.plain('This template uses the following information:');\n log.newline();\n fieldsList.forEach((message) => log.subtle(`- ${message}`));\n\n log.newline();\n const result = await SHOULD_CONTINUE_PROMPT.run();\n\n return result === 'yes';\n};\n\nconst createDirectory = async (dir: string) => {\n try {\n await fs.promises.mkdir(dir);\n } catch (err) {\n if (isErrorWithCode(err, 'EEXIST')) {\n log.err(`The directory '${dir}' already exists.`);\n process.exit(1);\n }\n\n throw err;\n }\n};\n\nconst cloneTemplate = async (\n templateName: string,\n destinationDir: string,\n): Promise<TemplateConfig> => {\n const isCustomTemplate = templateName.startsWith('github:');\n\n if (isCustomTemplate) {\n const gitHubPath = templateName.slice('github:'.length);\n\n await downloadGitHubTemplate(gitHubPath, destinationDir);\n } else {\n const templateDir = path.join(TEMPLATE_DIR, templateName);\n\n await copyFiles({\n // assume built-in templates have no extraneous files\n include: () => true,\n sourceRoot: templateDir,\n destinationRoot: destinationDir,\n processors: [],\n // built-in templates have files like _package.json\n stripUnderscorePrefix: true,\n });\n }\n\n const templateConfig = getTemplateConfig(\n path.join(process.cwd(), destinationDir),\n );\n\n if (isCustomTemplate) {\n log.newline();\n log.warn(\n 'You may need to run',\n log.bold(\n configForPackageManager(templateConfig.packageManager).print.exec,\n 'skuba',\n 'configure',\n ),\n 'once this is done.',\n );\n }\n\n return templateConfig;\n};\n\nconst getTemplateName = async () => {\n const templateSelection = await TEMPLATE_PROMPT.run();\n\n if (templateSelection === 'github \u2192') {\n const gitHubPath = await GIT_PATH_PROMPT.run();\n return `github:${gitHubPath}`;\n }\n\n return templateSelection;\n};\n\nconst generatePlaceholders = (choices: FormChoice[]) =>\n Object.fromEntries(\n choices.map(({ name }) => [name, `<%- ${name} %>`] as const),\n );\n\nexport const getTemplateConfig = (dir: string): TemplateConfig => {\n const templateConfigPath = path.join(dir, TEMPLATE_CONFIG_FILENAME);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const templateConfig = require(templateConfigPath) as unknown;\n\n return templateConfigSchema.parse(templateConfig);\n } catch (err) {\n if (isErrorWithCode(err, 'MODULE_NOT_FOUND')) {\n return {\n entryPoint: undefined,\n fields: [],\n packageManager: DEFAULT_PACKAGE_MANAGER,\n type: undefined,\n };\n }\n\n throw err;\n }\n};\n\nconst baseToTemplateData = async ({\n ownerName,\n platformName,\n repoName,\n defaultBranch,\n}: BaseFields) => {\n const [orgName, teamName] = ownerName.split('/');\n\n const port = String(await getRandomPort());\n\n if (!orgName) {\n throw new Error(`Invalid format for owner name: ${ownerName}`);\n }\n\n return {\n orgName,\n ownerName,\n repoName,\n defaultBranch,\n // Use standalone username in `teamName` contexts\n teamName: teamName ?? orgName,\n\n port,\n\n platformName,\n lambdaCdkArchitecture: platformName === 'amd64' ? 'X86_64' : 'ARM_64',\n lambdaServerlessArchitecture:\n platformName === 'amd64' ? 'x86_64' : platformName,\n };\n};\n\nexport const configureFromPrompt = async (): Promise<InitConfig> => {\n const { ownerName, platformName, repoName, defaultBranch } =\n await runForm<BaseFields>(BASE_PROMPT_PROPS);\n log.plain(chalk.cyan(repoName), 'by', chalk.cyan(ownerName));\n\n const templateData = await baseToTemplateData({\n ownerName,\n platformName,\n repoName,\n defaultBranch,\n });\n\n const destinationDir = repoName;\n\n await createDirectory(destinationDir);\n\n log.newline();\n const templateName = await getTemplateName();\n\n const { entryPoint, fields, noSkip, packageManager, type } =\n await cloneTemplate(templateName, destinationDir);\n\n if (fields.length === 0) {\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: true,\n templateData,\n templateName,\n type,\n };\n }\n\n const shouldContinue = noSkip ? true : await confirmShouldContinue(fields);\n\n if (shouldContinue) {\n log.newline();\n const customAnswers = await runForm({\n choices: fields,\n message: chalk.bold(`Complete ${chalk.cyan(templateName)}:`),\n name: 'customAnswers',\n });\n\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: true,\n templateData: { ...templateData, ...customAnswers },\n templateName,\n type,\n };\n }\n\n log.newline();\n log.warn(\n `Resume this later with ${chalk.bold(\n configForPackageManager(packageManager).print.exec,\n 'skuba configure',\n )}.`,\n );\n\n const customAnswers = generatePlaceholders(fields);\n\n return {\n destinationDir,\n entryPoint,\n packageManager,\n templateComplete: false,\n templateData: { ...templateData, ...customAnswers },\n templateName,\n type,\n };\n};\n\nexport const readJSONFromStdIn = async () => {\n let text = '';\n\n await new Promise((resolve) =>\n process.stdin\n .on('data', (chunk) => (text += chunk.toString()))\n .once('end', resolve),\n );\n\n text = text.trim();\n\n if (text === '') {\n log.err('No data from stdin.');\n process.exit(1);\n }\n\n let value: unknown;\n\n try {\n value = JSON.parse(text) as unknown;\n } catch {\n log.err('Invalid JSON from stdin.');\n process.exit(1);\n }\n\n return value;\n};\n\nconst configureFromPipe = async (): Promise<InitConfig> => {\n const value = await readJSONFromStdIn();\n\n const result = initConfigInputSchema.safeParse(value);\n\n if (!result.success) {\n log.err('Invalid data from stdin:');\n log.err(result.error);\n process.exit(1);\n }\n\n const { destinationDir, templateComplete, templateName } = result.data;\n\n const templateData = {\n ...(await baseToTemplateData(result.data.templateData)),\n ...result.data.templateData,\n };\n\n await createDirectory(destinationDir);\n\n const { entryPoint, fields, noSkip, packageManager, type } =\n await cloneTemplate(templateName, destinationDir);\n\n if (!templateComplete) {\n if (noSkip) {\n log.err('Templating for', log.bold(templateName), 'cannot be skipped.');\n process.exit(1);\n }\n\n return {\n ...result.data,\n entryPoint,\n packageManager,\n templateData: {\n ...templateData,\n ...generatePlaceholders(fields),\n },\n type,\n };\n }\n\n const required = fields.map(({ name }) => name);\n\n const provided = new Set(Object.keys(templateData));\n\n const missing = required.filter((name) => !provided.has(name));\n\n if (missing.length > 0) {\n log.err('This template uses the following information:');\n log.newline();\n missing.forEach((name) => log.err(`- ${name}`));\n process.exit(1);\n }\n\n return {\n ...result.data,\n entryPoint,\n packageManager,\n templateData,\n type,\n };\n};\n\nexport const getConfig = () =>\n process.stdin.isTTY ? configureFromPrompt() : configureFromPipe();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["fs", "path", "chalk", "customAnswers"]
|
|
7
7
|
}
|
package/lib/cli/lint/internal.js
CHANGED
|
@@ -68,7 +68,7 @@ const lintConcurrently = async (mode, logger, additionalFlags) => {
|
|
|
68
68
|
results.push(
|
|
69
69
|
...await Promise.all(
|
|
70
70
|
lintGroup.map(
|
|
71
|
-
({ name, lint }) => lint(
|
|
71
|
+
async ({ name, lint }) => lint(
|
|
72
72
|
mode,
|
|
73
73
|
(0, import_logging.childLogger)(logger, { suffixes: [import_chalk.default.dim(name)] }),
|
|
74
74
|
additionalFlags
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cli/lint/internal.ts"],
|
|
4
|
-
"sourcesContent": ["import { inspect } from 'util';\n\nimport chalk from 'chalk';\n\nimport { type Logger, childLogger, createLogger } from '../../utils/logging.js';\n\nimport { tryDetectBadCodeowners } from './internalLints/detectBadCodeowners.js';\nimport { noSkubaTemplateJs } from './internalLints/noSkubaTemplateJs.js';\nimport { tryRefreshConfigFiles } from './internalLints/refreshConfigFiles.js';\nimport { upgradeSkuba } from './internalLints/upgrade/index.js';\nimport type { Input } from './types.js';\n\nexport type InternalLintResult = {\n ok: boolean;\n fixable: boolean;\n annotations?: Array<{\n start_line?: number;\n end_line?: number;\n path: string;\n message: string;\n }>;\n};\n\nconst lints: Array<\n Array<{\n name: string;\n lint: (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n ) => Promise<InternalLintResult>;\n }>\n> = [\n // Run upgradeSkuba first, in particular before refreshConfigFiles, for npmrc handling\n [{ name: 'upgrade-skuba', lint: upgradeSkuba }],\n [\n { name: 'no-skuba-template-js', lint: noSkubaTemplateJs },\n { name: 'refresh-config-files', lint: tryRefreshConfigFiles },\n { name: 'detect-bad-codeowners', lint: tryDetectBadCodeowners },\n ],\n];\n\nconst lintSerially = async (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n) => {\n const results: InternalLintResult[] = [];\n for (const lintGroup of lints) {\n for (const { lint, name } of lintGroup) {\n results.push(\n await lint(\n mode,\n childLogger(logger, { suffixes: [chalk.dim(name)] }),\n additionalFlags,\n ),\n );\n }\n }\n return results;\n};\n\nconst lintConcurrently = async (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n) => {\n const results: InternalLintResult[] = [];\n\n for (const lintGroup of lints) {\n results.push(\n ...(await Promise.all(\n lintGroup.map(({ name, lint }) =>\n lint(\n mode,\n childLogger(logger, { suffixes: [chalk.dim(name)] }),\n additionalFlags,\n ),\n ),\n )),\n );\n }\n\n return results;\n};\n\nconst selectLintFunction = (input?: Input) => {\n const isSerial = input?.debug || input?.serial;\n return isSerial ? lintSerially : lintConcurrently;\n};\n\nexport const internalLint = async (\n mode: 'format' | 'lint',\n input?: Input,\n): Promise<InternalLintResult> => {\n const start = process.hrtime.bigint();\n const logger = createLogger({\n debug: input?.debug ?? false,\n prefixes: [...(mode === 'lint' ? [chalk.blueBright('skuba \u2502')] : [])],\n });\n\n try {\n const lint = selectLintFunction(input);\n const results = await lint(mode, logger, input?.additionalFlags ?? []);\n const result = combineResults(results);\n const end = process.hrtime.bigint();\n logger.plain(`Processed skuba lints in ${logger.timing(start, end)}.`);\n return result;\n } catch (err) {\n logger.err(logger.bold('Failed to run skuba lints.'));\n logger.subtle(inspect(err));\n\n process.exitCode = 1;\n\n return { ok: false, fixable: false, annotations: [] };\n }\n};\n\nconst combineResults = (results: InternalLintResult[]): InternalLintResult =>\n results.reduce(\n (cur, next) => ({\n ok: cur.ok && next.ok,\n fixable: cur.fixable || next.fixable,\n annotations: [...(cur.annotations ?? []), ...(next.annotations ?? [])],\n }),\n { ok: true, fixable: false },\n );\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAwB;AAExB,mBAAkB;AAElB,qBAAuD;AAEvD,iCAAuC;AACvC,+BAAkC;AAClC,gCAAsC;AACtC,qBAA6B;AAc7B,MAAM,QASF;AAAA;AAAA,EAEF,CAAC,EAAE,MAAM,iBAAiB,MAAM,4BAAa,CAAC;AAAA,EAC9C;AAAA,IACE,EAAE,MAAM,wBAAwB,MAAM,2CAAkB;AAAA,IACxD,EAAE,MAAM,wBAAwB,MAAM,gDAAsB;AAAA,IAC5D,EAAE,MAAM,yBAAyB,MAAM,kDAAuB;AAAA,EAChE;AACF;AAEA,MAAM,eAAe,OACnB,MACA,QACA,oBACG;AACH,QAAM,UAAgC,CAAC;AACvC,aAAW,aAAa,OAAO;AAC7B,eAAW,EAAE,MAAM,KAAK,KAAK,WAAW;AACtC,cAAQ;AAAA,QACN,MAAM;AAAA,UACJ;AAAA,cACA,4BAAY,QAAQ,EAAE,UAAU,CAAC,aAAAA,QAAM,IAAI,IAAI,CAAC,EAAE,CAAC;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,mBAAmB,OACvB,MACA,QACA,oBACG;AACH,QAAM,UAAgC,CAAC;AAEvC,aAAW,aAAa,OAAO;AAC7B,YAAQ;AAAA,MACN,GAAI,MAAM,QAAQ;AAAA,QAChB,UAAU;AAAA,UAAI,
|
|
4
|
+
"sourcesContent": ["import { inspect } from 'util';\n\nimport chalk from 'chalk';\n\nimport { type Logger, childLogger, createLogger } from '../../utils/logging.js';\n\nimport { tryDetectBadCodeowners } from './internalLints/detectBadCodeowners.js';\nimport { noSkubaTemplateJs } from './internalLints/noSkubaTemplateJs.js';\nimport { tryRefreshConfigFiles } from './internalLints/refreshConfigFiles.js';\nimport { upgradeSkuba } from './internalLints/upgrade/index.js';\nimport type { Input } from './types.js';\n\nexport type InternalLintResult = {\n ok: boolean;\n fixable: boolean;\n annotations?: Array<{\n start_line?: number;\n end_line?: number;\n path: string;\n message: string;\n }>;\n};\n\nconst lints: Array<\n Array<{\n name: string;\n lint: (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n ) => Promise<InternalLintResult>;\n }>\n> = [\n // Run upgradeSkuba first, in particular before refreshConfigFiles, for npmrc handling\n [{ name: 'upgrade-skuba', lint: upgradeSkuba }],\n [\n { name: 'no-skuba-template-js', lint: noSkubaTemplateJs },\n { name: 'refresh-config-files', lint: tryRefreshConfigFiles },\n { name: 'detect-bad-codeowners', lint: tryDetectBadCodeowners },\n ],\n];\n\nconst lintSerially = async (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n) => {\n const results: InternalLintResult[] = [];\n for (const lintGroup of lints) {\n for (const { lint, name } of lintGroup) {\n results.push(\n await lint(\n mode,\n childLogger(logger, { suffixes: [chalk.dim(name)] }),\n additionalFlags,\n ),\n );\n }\n }\n return results;\n};\n\nconst lintConcurrently = async (\n mode: 'format' | 'lint',\n logger: Logger,\n additionalFlags: string[],\n) => {\n const results: InternalLintResult[] = [];\n\n for (const lintGroup of lints) {\n results.push(\n ...(await Promise.all(\n lintGroup.map(async ({ name, lint }) =>\n lint(\n mode,\n childLogger(logger, { suffixes: [chalk.dim(name)] }),\n additionalFlags,\n ),\n ),\n )),\n );\n }\n\n return results;\n};\n\nconst selectLintFunction = (input?: Input) => {\n const isSerial = input?.debug || input?.serial;\n return isSerial ? lintSerially : lintConcurrently;\n};\n\nexport const internalLint = async (\n mode: 'format' | 'lint',\n input?: Input,\n): Promise<InternalLintResult> => {\n const start = process.hrtime.bigint();\n const logger = createLogger({\n debug: input?.debug ?? false,\n prefixes: [...(mode === 'lint' ? [chalk.blueBright('skuba \u2502')] : [])],\n });\n\n try {\n const lint = selectLintFunction(input);\n const results = await lint(mode, logger, input?.additionalFlags ?? []);\n const result = combineResults(results);\n const end = process.hrtime.bigint();\n logger.plain(`Processed skuba lints in ${logger.timing(start, end)}.`);\n return result;\n } catch (err) {\n logger.err(logger.bold('Failed to run skuba lints.'));\n logger.subtle(inspect(err));\n\n process.exitCode = 1;\n\n return { ok: false, fixable: false, annotations: [] };\n }\n};\n\nconst combineResults = (results: InternalLintResult[]): InternalLintResult =>\n results.reduce(\n (cur, next) => ({\n ok: cur.ok && next.ok,\n fixable: cur.fixable || next.fixable,\n annotations: [...(cur.annotations ?? []), ...(next.annotations ?? [])],\n }),\n { ok: true, fixable: false },\n );\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAwB;AAExB,mBAAkB;AAElB,qBAAuD;AAEvD,iCAAuC;AACvC,+BAAkC;AAClC,gCAAsC;AACtC,qBAA6B;AAc7B,MAAM,QASF;AAAA;AAAA,EAEF,CAAC,EAAE,MAAM,iBAAiB,MAAM,4BAAa,CAAC;AAAA,EAC9C;AAAA,IACE,EAAE,MAAM,wBAAwB,MAAM,2CAAkB;AAAA,IACxD,EAAE,MAAM,wBAAwB,MAAM,gDAAsB;AAAA,IAC5D,EAAE,MAAM,yBAAyB,MAAM,kDAAuB;AAAA,EAChE;AACF;AAEA,MAAM,eAAe,OACnB,MACA,QACA,oBACG;AACH,QAAM,UAAgC,CAAC;AACvC,aAAW,aAAa,OAAO;AAC7B,eAAW,EAAE,MAAM,KAAK,KAAK,WAAW;AACtC,cAAQ;AAAA,QACN,MAAM;AAAA,UACJ;AAAA,cACA,4BAAY,QAAQ,EAAE,UAAU,CAAC,aAAAA,QAAM,IAAI,IAAI,CAAC,EAAE,CAAC;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,mBAAmB,OACvB,MACA,QACA,oBACG;AACH,QAAM,UAAgC,CAAC;AAEvC,aAAW,aAAa,OAAO;AAC7B,YAAQ;AAAA,MACN,GAAI,MAAM,QAAQ;AAAA,QAChB,UAAU;AAAA,UAAI,OAAO,EAAE,MAAM,KAAK,MAChC;AAAA,YACE;AAAA,gBACA,4BAAY,QAAQ,EAAE,UAAU,CAAC,aAAAA,QAAM,IAAI,IAAI,CAAC,EAAE,CAAC;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,MAAM,qBAAqB,CAAC,UAAkB;AAC5C,QAAM,WAAW,OAAO,SAAS,OAAO;AACxC,SAAO,WAAW,eAAe;AACnC;AAEO,MAAM,eAAe,OAC1B,MACA,UACgC;AAChC,QAAM,QAAQ,QAAQ,OAAO,OAAO;AACpC,QAAM,aAAS,6BAAa;AAAA,IAC1B,OAAO,OAAO,SAAS;AAAA,IACvB,UAAU,CAAC,GAAI,SAAS,SAAS,CAAC,aAAAA,QAAM,WAAW,iBAAY,CAAC,IAAI,CAAC,CAAE;AAAA,EACzE,CAAC;AAED,MAAI;AACF,UAAM,OAAO,mBAAmB,KAAK;AACrC,UAAM,UAAU,MAAM,KAAK,MAAM,QAAQ,OAAO,mBAAmB,CAAC,CAAC;AACrE,UAAM,SAAS,eAAe,OAAO;AACrC,UAAM,MAAM,QAAQ,OAAO,OAAO;AAClC,WAAO,MAAM,4BAA4B,OAAO,OAAO,OAAO,GAAG,CAAC,GAAG;AACrE,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,WAAO,IAAI,OAAO,KAAK,4BAA4B,CAAC;AACpD,WAAO,WAAO,qBAAQ,GAAG,CAAC;AAE1B,YAAQ,WAAW;AAEnB,WAAO,EAAE,IAAI,OAAO,SAAS,OAAO,aAAa,CAAC,EAAE;AAAA,EACtD;AACF;AAEA,MAAM,iBAAiB,CAAC,YACtB,QAAQ;AAAA,EACN,CAAC,KAAK,UAAU;AAAA,IACd,IAAI,IAAI,MAAM,KAAK;AAAA,IACnB,SAAS,IAAI,WAAW,KAAK;AAAA,IAC7B,aAAa,CAAC,GAAI,IAAI,eAAe,CAAC,GAAI,GAAI,KAAK,eAAe,CAAC,CAAE;AAAA,EACvE;AAAA,EACA,EAAE,IAAI,MAAM,SAAS,MAAM;AAC7B;",
|
|
6
6
|
"names": ["chalk"]
|
|
7
7
|
}
|
|
@@ -100,7 +100,7 @@ const writeTemporaryFiles = async (contents) => {
|
|
|
100
100
|
const dir = await fsp.mkdtemp("eslint-migrate-config");
|
|
101
101
|
await Promise.all(
|
|
102
102
|
Object.entries(contents).map(
|
|
103
|
-
([file, content]) => fsp.writeFile(import_path.default.join(dir, file), content)
|
|
103
|
+
async ([file, content]) => fsp.writeFile(import_path.default.join(dir, file), content)
|
|
104
104
|
)
|
|
105
105
|
);
|
|
106
106
|
return dir;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.ts"],
|
|
4
|
-
"sourcesContent": ["// eslint-disable-next-line no-restricted-imports -- fs-extra is mocked\nimport * as fsp from 'fs/promises';\nimport path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\n\nimport { createExec } from '../../../../../../utils/exec.js';\nimport { log } from '../../../../../../utils/logging.js';\nimport { createDestinationFileReader } from '../../../../../configure/analysis/project.js';\nimport { mergeWithConfigFile } from '../../../../../configure/processing/configFile.js';\nimport { formatPrettier } from '../../../../../configure/processing/prettier.js';\nimport type { PatchFunction, PatchReturnType } from '../../index.js';\n\nconst IGNORE_FILE = '.eslintignore';\nconst OLD_CONFIG_FILE = '.eslintrc.js';\nconst NEW_CONFIG_FILE_CJS = 'eslint.config.cjs';\nconst NEW_CONFIG_FILE_JS = 'eslint.config.js';\n\nconst upgradeESLint: PatchFunction = async ({\n mode,\n dir: cwd = process.cwd(),\n}): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(cwd);\n const [ignoreFileContents, oldConfig] = await Promise.all([\n readFile(IGNORE_FILE),\n readFile(OLD_CONFIG_FILE),\n ]);\n\n if (oldConfig === undefined) {\n return {\n result: 'skip',\n reason: `no ${OLD_CONFIG_FILE} - have you already migrated?`,\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const ignoreContentsWithoutSkubaManaged = mergeWithConfigFile(\n '',\n 'ignore',\n )(ignoreFileContents);\n\n const exec = createExec({\n cwd: process.cwd(),\n stdio: 'ignore',\n });\n\n // eslint-migrate-config require()s the file, so for testability, put it in a temporary location\n const dir = await writeTemporaryFiles({\n [OLD_CONFIG_FILE]: oldConfig,\n ...(ignoreContentsWithoutSkubaManaged.trim().length > 0\n ? { [IGNORE_FILE]: ignoreContentsWithoutSkubaManaged }\n : {}),\n });\n try {\n await exec(\n 'eslint-migrate-config',\n path.join(dir, OLD_CONFIG_FILE),\n '--commonjs',\n );\n\n const output = fiddleWithOutput(\n await fsp.readFile(path.join(dir, NEW_CONFIG_FILE_CJS), 'utf-8'),\n );\n await fs.promises.writeFile(\n NEW_CONFIG_FILE_JS,\n await formatPrettier(output, { filepath: NEW_CONFIG_FILE_JS }),\n );\n\n await Promise.all([\n ignoreFileContents === undefined\n ? Promise.resolve()\n : fs.promises.rm(IGNORE_FILE),\n fs.promises.rm(OLD_CONFIG_FILE),\n ]);\n\n return { result: 'apply' };\n } finally {\n await fsp.rm(dir, { recursive: true });\n }\n};\n\nconst writeTemporaryFiles = async (contents: Record<string, string>) => {\n const dir = await fsp.mkdtemp('eslint-migrate-config');\n\n await Promise.all(\n Object.entries(contents).map(([file, content]) =>\n fsp.writeFile(path.join(dir, file), content),\n ),\n );\n\n return dir;\n};\n\nconst fiddleWithOutput = (input: string) => {\n let output = input.replace(/compat.extends\\([\"']skuba[\"']\\)/, 'skuba');\n\n if (!output.includes('eslint-config-skuba')) {\n output = `const skuba = require('eslint-config-skuba');\\n\\n${output}`;\n }\n\n if (!output.includes('compat.')) {\n output = output.replace(/const compat = new FlatCompat\\(\\{[^}]+\\}\\);/m, '');\n output = output.replace(\n /const \\{\\s*FlatCompat,?\\s*\\}\\s*=\\s*require\\([\"']@eslint\\/eslintrc[\"']\\);/m,\n '',\n );\n }\n\n if (!output.includes('js.')) {\n output = output.replace(/const js = require\\(['\"]@eslint\\/js['\"]\\);/, '');\n }\n\n output = output.replace(\n /^const skuba = require\\('eslint-config-skuba'\\);\\s*module.exports = \\[...skuba\\];$/m,\n \"module.exports = require('eslint-config-skuba');\",\n );\n\n return output;\n};\n\nexport const tryUpgradeESLint: PatchFunction = async (config) => {\n try {\n return await upgradeESLint(config);\n } catch (err) {\n log.warn('Failed to upgrade ESLint to flat config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n};\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,UAAqB;AACrB,kBAAiB;AACjB,kBAAwB;AAExB,sBAAe;AAEf,kBAA2B;AAC3B,qBAAoB;AACpB,qBAA4C;AAC5C,wBAAoC;AACpC,sBAA+B;AAG/B,MAAM,cAAc;AACpB,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAE3B,MAAM,gBAA+B,OAAO;AAAA,EAC1C;AAAA,EACA,KAAK,MAAM,QAAQ,IAAI;AACzB,MAAgC;AAC9B,QAAM,eAAW,4CAA4B,GAAG;AAChD,QAAM,CAAC,oBAAoB,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,IACxD,SAAS,WAAW;AAAA,IACpB,SAAS,eAAe;AAAA,EAC1B,CAAC;AAED,MAAI,cAAc,QAAW;AAC3B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ,MAAM,eAAe;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,SAAS,QAAQ;AACnB,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AAEA,QAAM,wCAAoC;AAAA,IACxC;AAAA,IACA;AAAA,EACF,EAAE,kBAAkB;AAEpB,QAAM,WAAO,wBAAW;AAAA,IACtB,KAAK,QAAQ,IAAI;AAAA,IACjB,OAAO;AAAA,EACT,CAAC;AAGD,QAAM,MAAM,MAAM,oBAAoB;AAAA,IACpC,CAAC,eAAe,GAAG;AAAA,IACnB,GAAI,kCAAkC,KAAK,EAAE,SAAS,IAClD,EAAE,CAAC,WAAW,GAAG,kCAAkC,IACnD,CAAC;AAAA,EACP,CAAC;AACD,MAAI;AACF,UAAM;AAAA,MACJ;AAAA,MACA,YAAAA,QAAK,KAAK,KAAK,eAAe;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb,MAAM,IAAI,SAAS,YAAAA,QAAK,KAAK,KAAK,mBAAmB,GAAG,OAAO;AAAA,IACjE;AACA,UAAM,gBAAAC,QAAG,SAAS;AAAA,MAChB;AAAA,MACA,UAAM,gCAAe,QAAQ,EAAE,UAAU,mBAAmB,CAAC;AAAA,IAC/D;AAEA,UAAM,QAAQ,IAAI;AAAA,MAChB,uBAAuB,SACnB,QAAQ,QAAQ,IAChB,gBAAAA,QAAG,SAAS,GAAG,WAAW;AAAA,MAC9B,gBAAAA,QAAG,SAAS,GAAG,eAAe;AAAA,IAChC,CAAC;AAED,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B,UAAE;AACA,UAAM,IAAI,GAAG,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACF;AAEA,MAAM,sBAAsB,OAAO,aAAqC;AACtE,QAAM,MAAM,MAAM,IAAI,QAAQ,uBAAuB;AAErD,QAAM,QAAQ;AAAA,IACZ,OAAO,QAAQ,QAAQ,EAAE;AAAA,MAAI,
|
|
4
|
+
"sourcesContent": ["// eslint-disable-next-line no-restricted-imports -- fs-extra is mocked\nimport * as fsp from 'fs/promises';\nimport path from 'path';\nimport { inspect } from 'util';\n\nimport fs from 'fs-extra';\n\nimport { createExec } from '../../../../../../utils/exec.js';\nimport { log } from '../../../../../../utils/logging.js';\nimport { createDestinationFileReader } from '../../../../../configure/analysis/project.js';\nimport { mergeWithConfigFile } from '../../../../../configure/processing/configFile.js';\nimport { formatPrettier } from '../../../../../configure/processing/prettier.js';\nimport type { PatchFunction, PatchReturnType } from '../../index.js';\n\nconst IGNORE_FILE = '.eslintignore';\nconst OLD_CONFIG_FILE = '.eslintrc.js';\nconst NEW_CONFIG_FILE_CJS = 'eslint.config.cjs';\nconst NEW_CONFIG_FILE_JS = 'eslint.config.js';\n\nconst upgradeESLint: PatchFunction = async ({\n mode,\n dir: cwd = process.cwd(),\n}): Promise<PatchReturnType> => {\n const readFile = createDestinationFileReader(cwd);\n const [ignoreFileContents, oldConfig] = await Promise.all([\n readFile(IGNORE_FILE),\n readFile(OLD_CONFIG_FILE),\n ]);\n\n if (oldConfig === undefined) {\n return {\n result: 'skip',\n reason: `no ${OLD_CONFIG_FILE} - have you already migrated?`,\n };\n }\n\n if (mode === 'lint') {\n return { result: 'apply' };\n }\n\n const ignoreContentsWithoutSkubaManaged = mergeWithConfigFile(\n '',\n 'ignore',\n )(ignoreFileContents);\n\n const exec = createExec({\n cwd: process.cwd(),\n stdio: 'ignore',\n });\n\n // eslint-migrate-config require()s the file, so for testability, put it in a temporary location\n const dir = await writeTemporaryFiles({\n [OLD_CONFIG_FILE]: oldConfig,\n ...(ignoreContentsWithoutSkubaManaged.trim().length > 0\n ? { [IGNORE_FILE]: ignoreContentsWithoutSkubaManaged }\n : {}),\n });\n try {\n await exec(\n 'eslint-migrate-config',\n path.join(dir, OLD_CONFIG_FILE),\n '--commonjs',\n );\n\n const output = fiddleWithOutput(\n await fsp.readFile(path.join(dir, NEW_CONFIG_FILE_CJS), 'utf-8'),\n );\n await fs.promises.writeFile(\n NEW_CONFIG_FILE_JS,\n await formatPrettier(output, { filepath: NEW_CONFIG_FILE_JS }),\n );\n\n await Promise.all([\n ignoreFileContents === undefined\n ? Promise.resolve()\n : fs.promises.rm(IGNORE_FILE),\n fs.promises.rm(OLD_CONFIG_FILE),\n ]);\n\n return { result: 'apply' };\n } finally {\n await fsp.rm(dir, { recursive: true });\n }\n};\n\nconst writeTemporaryFiles = async (contents: Record<string, string>) => {\n const dir = await fsp.mkdtemp('eslint-migrate-config');\n\n await Promise.all(\n Object.entries(contents).map(async ([file, content]) =>\n fsp.writeFile(path.join(dir, file), content),\n ),\n );\n\n return dir;\n};\n\nconst fiddleWithOutput = (input: string) => {\n let output = input.replace(/compat.extends\\([\"']skuba[\"']\\)/, 'skuba');\n\n if (!output.includes('eslint-config-skuba')) {\n output = `const skuba = require('eslint-config-skuba');\\n\\n${output}`;\n }\n\n if (!output.includes('compat.')) {\n output = output.replace(/const compat = new FlatCompat\\(\\{[^}]+\\}\\);/m, '');\n output = output.replace(\n /const \\{\\s*FlatCompat,?\\s*\\}\\s*=\\s*require\\([\"']@eslint\\/eslintrc[\"']\\);/m,\n '',\n );\n }\n\n if (!output.includes('js.')) {\n output = output.replace(/const js = require\\(['\"]@eslint\\/js['\"]\\);/, '');\n }\n\n output = output.replace(\n /^const skuba = require\\('eslint-config-skuba'\\);\\s*module.exports = \\[...skuba\\];$/m,\n \"module.exports = require('eslint-config-skuba');\",\n );\n\n return output;\n};\n\nexport const tryUpgradeESLint: PatchFunction = async (config) => {\n try {\n return await upgradeESLint(config);\n } catch (err) {\n log.warn('Failed to upgrade ESLint to flat config.');\n log.subtle(inspect(err));\n return { result: 'skip', reason: 'due to an error' };\n }\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["path", "fs"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skuba",
|
|
3
|
-
"version": "12.1.0-main-
|
|
3
|
+
"version": "12.1.0-main-20250812041011",
|
|
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,7 @@
|
|
|
97
97
|
"tsx": "^4.16.2",
|
|
98
98
|
"typescript": "~5.9.0",
|
|
99
99
|
"zod": "^4.0.0",
|
|
100
|
-
"eslint-config-skuba": "7.1.0-main-
|
|
100
|
+
"eslint-config-skuba": "7.1.0-main-20250812041011"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@changesets/cli": "2.29.5",
|
|
@@ -116,9 +116,9 @@
|
|
|
116
116
|
"@types/picomatch": "4.0.2",
|
|
117
117
|
"@types/semver": "7.7.0",
|
|
118
118
|
"@types/supertest": "6.0.3",
|
|
119
|
-
"enhanced-resolve": "5.18.
|
|
119
|
+
"enhanced-resolve": "5.18.3",
|
|
120
120
|
"express": "5.1.0",
|
|
121
|
-
"fastify": "5.
|
|
121
|
+
"fastify": "5.5.0",
|
|
122
122
|
"jest-diff": "30.0.5",
|
|
123
123
|
"jsonfile": "6.1.0",
|
|
124
124
|
"koa": "3.0.1",
|
|
@@ -77,6 +77,9 @@ steps:
|
|
|
77
77
|
queue: <%- devBuildkiteQueueName %>
|
|
78
78
|
label: 🤞 Deploy Dev
|
|
79
79
|
concurrency_group: <%- teamName %>/deploy/gantry/<%- devGantryEnvironmentName %>
|
|
80
|
+
env:
|
|
81
|
+
DD_DEPLOYMENT_ENVIRONMENT: development
|
|
82
|
+
DD_DEPLOYMENT_SERVICE: <%- serviceName %>
|
|
80
83
|
key: deploy-dev
|
|
81
84
|
plugins:
|
|
82
85
|
- seek-jobs/gantry#v4.0.0:
|
|
@@ -93,6 +96,9 @@ steps:
|
|
|
93
96
|
branches: ${BUILDKITE_PIPELINE_DEFAULT_BRANCH}
|
|
94
97
|
concurrency_group: <%- teamName %>/deploy/gantry/<%- prodGantryEnvironmentName %>
|
|
95
98
|
depends_on: deploy-dev
|
|
99
|
+
env:
|
|
100
|
+
DD_DEPLOYMENT_ENVIRONMENT: production
|
|
101
|
+
DD_DEPLOYMENT_SERVICE: <%- serviceName %>
|
|
96
102
|
plugins:
|
|
97
103
|
- seek-jobs/gantry#v4.0.0:
|
|
98
104
|
command: apply
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
DEPLOYMENT=local
|
|
@@ -70,19 +70,19 @@ pnpm start:debug
|
|
|
70
70
|
|
|
71
71
|
This project is deployed through a [Buildkite pipeline](.buildkite/pipeline.yml).
|
|
72
72
|
|
|
73
|
-
- Commits to a feature branch can be deployed to the
|
|
74
|
-
- Commits to the default branch are automatically deployed to the
|
|
73
|
+
- Commits to a feature branch can be deployed to the development environment by unblocking a step in the Buildkite UI
|
|
74
|
+
- Commits to the default branch are automatically deployed to the development and production environments in sequence
|
|
75
75
|
|
|
76
76
|
To rapidly roll back a change,
|
|
77
77
|
retry an individual deployment step from the previous build in Buildkite.
|
|
78
|
-
Note that this will introduce drift between the head of the default Git branch and the live
|
|
78
|
+
Note that this will introduce drift between the head of the default Git branch and the live deployments;
|
|
79
79
|
use with caution and always follow up with a proper revert or fix in Git history.
|
|
80
80
|
|
|
81
81
|
## Support
|
|
82
82
|
|
|
83
83
|
### Dev
|
|
84
84
|
|
|
85
|
-
TODO: add support links for the dev
|
|
85
|
+
TODO: add support links for the dev deployment.
|
|
86
86
|
|
|
87
87
|
<!--
|
|
88
88
|
- CloudWatch dashboard
|
|
@@ -92,7 +92,7 @@ TODO: add support links for the dev environment.
|
|
|
92
92
|
|
|
93
93
|
### Prod
|
|
94
94
|
|
|
95
|
-
TODO: add support links for the prod
|
|
95
|
+
TODO: add support links for the prod deployment.
|
|
96
96
|
|
|
97
97
|
<!--
|
|
98
98
|
- CloudWatch dashboard
|
|
@@ -9,9 +9,14 @@ owner: '{{values "owner"}}'
|
|
|
9
9
|
image: '{{values "image"}}'
|
|
10
10
|
|
|
11
11
|
env:
|
|
12
|
-
|
|
12
|
+
DEPLOYMENT: '{{values "deployment"}}'
|
|
13
13
|
SERVICE: '{{values "service"}}'
|
|
14
14
|
|
|
15
|
+
DD_ENV: '{{values "env"}}'
|
|
16
|
+
DD_SERVICE: '{{values "service"}}'
|
|
17
|
+
|
|
18
|
+
OPENTELEMETRY_ENABLED: '{{values "openTelemetry.enabled"}}'
|
|
19
|
+
|
|
15
20
|
{{if .Values.cloudwatchDashboardDisabled}}
|
|
16
21
|
cloudwatchDashboardDisabled: {{values "cloudwatchDashboardDisabled"}}
|
|
17
22
|
{{end}}
|
|
@@ -20,6 +25,17 @@ cloudwatchDashboardDisabled: {{values "cloudwatchDashboardDisabled"}}
|
|
|
20
25
|
datadogSecretId: '{{values "datadogSecretId"}}'
|
|
21
26
|
{{end}}
|
|
22
27
|
|
|
28
|
+
# Uncomment if the `tin` tier is acceptable for your SEEK Auth Sidecar logs
|
|
29
|
+
# The eeeoh log forwarder bypasses Amazon CloudWatch for cost savings
|
|
30
|
+
# logSink:
|
|
31
|
+
# forwarder: eeeoh
|
|
32
|
+
# splunkIndex: '{{values "logSink.splunkIndex"}}'
|
|
33
|
+
|
|
34
|
+
openTelemetry:
|
|
35
|
+
datadogEnvironmentName: '{{values "env"}}'
|
|
36
|
+
enabled: {{values "openTelemetry.enabled"}}
|
|
37
|
+
useGantryServiceName: true
|
|
38
|
+
|
|
23
39
|
{{if .Values.pagerDutyEndpoint}}
|
|
24
40
|
pagerDutyEndpoint: '{{values "pagerDutyEndpoint"}}'
|
|
25
41
|
{{end}}
|
|
@@ -13,17 +13,23 @@
|
|
|
13
13
|
"test:watch": "skuba test --watch"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@
|
|
16
|
+
"@opentelemetry/api": "^1.9.0",
|
|
17
|
+
"@opentelemetry/core": "^2.0.0",
|
|
18
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.203.0",
|
|
19
|
+
"@opentelemetry/instrumentation-aws-sdk": "^0.56.0",
|
|
20
|
+
"@opentelemetry/instrumentation-http": "^0.203.0",
|
|
21
|
+
"@opentelemetry/propagator-b3": "^2.0.0",
|
|
22
|
+
"@opentelemetry/sdk-node": "^0.203.0",
|
|
23
|
+
"@seek/logger": "11.0.0",
|
|
17
24
|
"express": "^5.0.0",
|
|
18
25
|
"hot-shots": "^11.0.0",
|
|
19
|
-
"seek-datadog-custom-metrics": "^
|
|
26
|
+
"seek-datadog-custom-metrics": "^6.0.0",
|
|
20
27
|
"skuba-dive": "^2.0.0"
|
|
21
28
|
},
|
|
22
29
|
"devDependencies": {
|
|
23
30
|
"@types/express": "^5.0.0",
|
|
24
31
|
"@types/node": "^22.13.10",
|
|
25
32
|
"@types/supertest": "^6.0.0",
|
|
26
|
-
"mime": "^4.0.1",
|
|
27
33
|
"pino-pretty": "^13.0.0",
|
|
28
34
|
"skuba": "*",
|
|
29
35
|
"supertest": "^7.0.0"
|
|
@@ -3,8 +3,8 @@ import type { Handler } from 'express';
|
|
|
3
3
|
/**
|
|
4
4
|
* Signifies that the API is available to serve requests.
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
* unhealthy and needs to be recycled.
|
|
6
|
+
* The workload hosting environment calls this endpoint to see if the container
|
|
7
|
+
* is unhealthy and needs to be recycled.
|
|
8
8
|
*/
|
|
9
9
|
export const healthCheckHandler: Handler = (_req, res) => {
|
|
10
10
|
res.send('');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Env } from 'skuba-dive';
|
|
2
2
|
|
|
3
3
|
interface Config {
|
|
4
|
-
|
|
4
|
+
deployment: Deployment;
|
|
5
5
|
|
|
6
6
|
logLevel: string;
|
|
7
7
|
name: string;
|
|
@@ -11,17 +11,17 @@ interface Config {
|
|
|
11
11
|
port: number | null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
type
|
|
14
|
+
type Deployment = (typeof deployments)[number];
|
|
15
15
|
|
|
16
16
|
const dev = '<%- devGantryEnvironmentName %>';
|
|
17
17
|
const prod = '<%- prodGantryEnvironmentName %>';
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const deployments = ['local', 'test', dev, prod] as const;
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const deployment = Env.oneOf(deployments)('DEPLOYMENT');
|
|
22
22
|
|
|
23
23
|
/* istanbul ignore next: config verification makes more sense in a smoke test */
|
|
24
|
-
const configs: Record<
|
|
24
|
+
const configs: Record<Deployment, () => Omit<Config, 'deployment'>> = {
|
|
25
25
|
local: () => ({
|
|
26
26
|
logLevel: 'debug',
|
|
27
27
|
name: '<%- serviceName %>',
|
|
@@ -60,6 +60,6 @@ const configs: Record<Environment, () => Omit<Config, 'environment'>> = {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
export const config: Config = {
|
|
63
|
-
...configs[
|
|
64
|
-
|
|
63
|
+
...configs[deployment](),
|
|
64
|
+
deployment,
|
|
65
65
|
};
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import createLogger from '@seek/logger';
|
|
1
|
+
import { createLogger } from '@seek/logger';
|
|
2
2
|
|
|
3
3
|
import { config } from 'src/config.js';
|
|
4
4
|
|
|
5
5
|
export const logger = createLogger({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
eeeoh: {
|
|
7
|
+
/**
|
|
8
|
+
* TODO: choose an appropriate Datadog log tier.
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/seek-oss/logger/blob/master/docs/eeeoh.md#datadog-log-tiers
|
|
11
|
+
*/
|
|
12
|
+
datadog: 'tin',
|
|
13
|
+
team: '<%- teamName %>',
|
|
14
|
+
use: 'environment',
|
|
9
15
|
},
|
|
10
16
|
|
|
11
17
|
level: config.logLevel,
|
|
12
18
|
|
|
13
|
-
name: config.name,
|
|
14
|
-
|
|
15
19
|
transport:
|
|
16
|
-
config.
|
|
20
|
+
config.deployment === 'local' ? { target: 'pino-pretty' } : undefined,
|
|
17
21
|
});
|
|
@@ -7,5 +7,5 @@ import { logger } from './logging.js';
|
|
|
7
7
|
|
|
8
8
|
/* istanbul ignore next: StatsD client is not our responsibility */
|
|
9
9
|
export const metricsClient = createStatsDClient(StatsD, config, (err) =>
|
|
10
|
-
logger.error(
|
|
10
|
+
logger.error(err, 'StatsD error'),
|
|
11
11
|
);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry tracing initialisation. This is a standalone TS/JS module that is not
|
|
3
|
+
* referenced by application source code directly. It is required at runtime using the
|
|
4
|
+
* node command's `--require` argument, see Dockerfile for details.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { propagation } from '@opentelemetry/api';
|
|
8
|
+
import { CompositePropagator } from '@opentelemetry/core';
|
|
9
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
|
|
10
|
+
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';
|
|
11
|
+
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
12
|
+
import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3';
|
|
13
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
14
|
+
|
|
15
|
+
const app = 'opentelemetry';
|
|
16
|
+
const log = (level: string, msg: string, extra = {}) => {
|
|
17
|
+
const toLog = { msg, level, app, time: new Date().toISOString(), ...extra };
|
|
18
|
+
console.log(JSON.stringify(toLog)); // eslint-disable-line no-console
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const main = () => {
|
|
22
|
+
// Use B3 propagation to ensure proper propagation between systems that use
|
|
23
|
+
// OpenTelemetry and native Datadog APM, such as Istio/Envoy.
|
|
24
|
+
propagation.setGlobalPropagator(
|
|
25
|
+
new CompositePropagator({
|
|
26
|
+
propagators: [
|
|
27
|
+
new B3Propagator(),
|
|
28
|
+
new B3Propagator({ injectEncoding: B3InjectEncoding.MULTI_HEADER }),
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const sdk = new NodeSDK({
|
|
34
|
+
traceExporter: new OTLPTraceExporter(),
|
|
35
|
+
autoDetectResources: false,
|
|
36
|
+
instrumentations: [new HttpInstrumentation(), new AwsInstrumentation()],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
sdk.start();
|
|
40
|
+
|
|
41
|
+
process.on('SIGTERM', () => {
|
|
42
|
+
sdk
|
|
43
|
+
.shutdown()
|
|
44
|
+
.then(() => log('info', 'OpenTelemetry successfully terminated'))
|
|
45
|
+
.catch((err: Error) =>
|
|
46
|
+
log('error', 'OpenTelemetry failed to terminate', { err }),
|
|
47
|
+
)
|
|
48
|
+
.finally(() => process.exit(0)); // eslint-disable-line no-process-exit
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (process.env.OPENTELEMETRY_ENABLED === 'true') {
|
|
53
|
+
main();
|
|
54
|
+
} else {
|
|
55
|
+
log('info', 'OpenTelemetry not enabled');
|
|
56
|
+
}
|
|
@@ -75,7 +75,7 @@ For inspiration in this space, check out:
|
|
|
75
75
|
|
|
76
76
|
### Dev
|
|
77
77
|
|
|
78
|
-
TODO: add support links for the dev
|
|
78
|
+
TODO: add support links for the dev deployment.
|
|
79
79
|
|
|
80
80
|
<!--
|
|
81
81
|
- CloudWatch dashboard
|
|
@@ -85,7 +85,7 @@ TODO: add support links for the dev environment.
|
|
|
85
85
|
|
|
86
86
|
### Prod
|
|
87
87
|
|
|
88
|
-
TODO: add support links for the prod
|
|
88
|
+
TODO: add support links for the prod deployment.
|
|
89
89
|
|
|
90
90
|
<!--
|
|
91
91
|
- CloudWatch dashboard
|
|
@@ -77,6 +77,9 @@ steps:
|
|
|
77
77
|
queue: <%- devBuildkiteQueueName %>
|
|
78
78
|
label: 🤞 Deploy Dev
|
|
79
79
|
concurrency_group: <%- teamName %>/deploy/gantry/<%- devGantryEnvironmentName %>
|
|
80
|
+
env:
|
|
81
|
+
DD_DEPLOYMENT_ENVIRONMENT: development
|
|
82
|
+
DD_DEPLOYMENT_SERVICE: <%- serviceName %>
|
|
80
83
|
key: deploy-dev
|
|
81
84
|
plugins:
|
|
82
85
|
- seek-jobs/gantry#v4.0.0:
|
|
@@ -93,6 +96,9 @@ steps:
|
|
|
93
96
|
branches: ${BUILDKITE_PIPELINE_DEFAULT_BRANCH}
|
|
94
97
|
concurrency_group: <%- teamName %>/deploy/gantry/<%- prodGantryEnvironmentName %>
|
|
95
98
|
depends_on: deploy-dev
|
|
99
|
+
env:
|
|
100
|
+
DD_DEPLOYMENT_ENVIRONMENT: production
|
|
101
|
+
DD_DEPLOYMENT_SERVICE: <%- serviceName %>
|
|
96
102
|
plugins:
|
|
97
103
|
- seek-jobs/gantry#v4.0.0:
|
|
98
104
|
command: apply
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
DEPLOYMENT=local
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
deployment: dev
|
|
2
|
+
env: development
|
|
2
3
|
|
|
3
4
|
maxInstanceCount: 1
|
|
4
5
|
minInstanceCount: 1
|
|
@@ -7,5 +8,4 @@ minInstanceCount: 1
|
|
|
7
8
|
cloudwatchDashboardDisabled: true
|
|
8
9
|
|
|
9
10
|
openTelemetry:
|
|
10
|
-
|
|
11
|
-
enabled: false
|
|
11
|
+
enabled: true
|