skuba 0.0.0-master-20231002013336 → 0.0.0-master-20240206001217

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 (221) hide show
  1. package/README.md +3 -3
  2. package/jest/transform.test.ts +3 -1
  3. package/lib/api/jest/index.d.ts +3 -3
  4. package/lib/api/jest/index.js +19 -1
  5. package/lib/api/jest/index.js.map +2 -2
  6. package/lib/api/net/compose.js +2 -1
  7. package/lib/api/net/compose.js.map +2 -2
  8. package/lib/cli/adapter/prettier.d.ts +1 -1
  9. package/lib/cli/adapter/prettier.js +11 -10
  10. package/lib/cli/adapter/prettier.js.map +2 -2
  11. package/lib/cli/build/index.js +0 -2
  12. package/lib/cli/build/index.js.map +2 -2
  13. package/lib/cli/buildPackage.js +0 -2
  14. package/lib/cli/buildPackage.js.map +2 -2
  15. package/lib/cli/configure/analyseConfiguration.d.ts +2 -0
  16. package/lib/cli/configure/analyseConfiguration.js.map +2 -2
  17. package/lib/cli/configure/getEntryPoint.js +1 -1
  18. package/lib/cli/configure/getEntryPoint.js.map +2 -2
  19. package/lib/cli/configure/getProjectType.d.ts +1 -1
  20. package/lib/cli/configure/getProjectType.js +6 -3
  21. package/lib/cli/configure/getProjectType.js.map +2 -2
  22. package/lib/cli/configure/index.js +11 -12
  23. package/lib/cli/configure/index.js.map +2 -2
  24. package/lib/cli/configure/modules/index.js +0 -2
  25. package/lib/cli/configure/modules/index.js.map +2 -2
  26. package/lib/cli/configure/modules/package.d.ts +1 -1
  27. package/lib/cli/configure/modules/package.js +2 -1
  28. package/lib/cli/configure/modules/package.js.map +2 -2
  29. package/lib/cli/configure/patchRenovateConfig.d.ts +2 -1
  30. package/lib/cli/configure/patchRenovateConfig.js +36 -21
  31. package/lib/cli/configure/patchRenovateConfig.js.map +2 -2
  32. package/lib/cli/configure/types.d.ts +2 -0
  33. package/lib/cli/configure/types.js.map +1 -1
  34. package/lib/cli/configure/upgrade/index.d.ts +15 -0
  35. package/lib/cli/configure/upgrade/index.js +130 -0
  36. package/lib/cli/configure/upgrade/index.js.map +7 -0
  37. package/lib/cli/configure/{addEmptyExports.d.ts → upgrade/patches/7.3.1/addEmptyExports.d.ts} +2 -2
  38. package/lib/cli/configure/{addEmptyExports.js → upgrade/patches/7.3.1/addEmptyExports.js} +15 -11
  39. package/lib/cli/configure/upgrade/patches/7.3.1/addEmptyExports.js.map +7 -0
  40. package/lib/cli/configure/upgrade/patches/7.3.1/index.d.ts +2 -0
  41. package/lib/cli/configure/upgrade/patches/7.3.1/index.js +55 -0
  42. package/lib/cli/configure/upgrade/patches/7.3.1/index.js.map +7 -0
  43. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.d.ts +2 -0
  44. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.js +94 -0
  45. package/lib/cli/configure/upgrade/patches/7.3.1/moveNpmrcOutOfGitignoreManagedSection.js.map +7 -0
  46. package/lib/cli/configure/upgrade/patches/7.3.1/patchDockerfile.d.ts +2 -0
  47. package/lib/cli/configure/{patchDockerfile.js → upgrade/patches/7.3.1/patchDockerfile.js} +18 -12
  48. package/lib/cli/configure/upgrade/patches/7.3.1/patchDockerfile.js.map +7 -0
  49. package/lib/cli/configure/upgrade/patches/7.3.1/patchServerListener.d.ts +2 -0
  50. package/lib/cli/configure/{patchServerListener.js → upgrade/patches/7.3.1/patchServerListener.js} +18 -14
  51. package/lib/cli/configure/upgrade/patches/7.3.1/patchServerListener.js.map +7 -0
  52. package/lib/cli/format.js +7 -14
  53. package/lib/cli/format.js.map +2 -2
  54. package/lib/cli/init/getConfig.d.ts +7 -5
  55. package/lib/cli/init/getConfig.js +61 -34
  56. package/lib/cli/init/getConfig.js.map +2 -2
  57. package/lib/cli/init/git.d.ts +2 -1
  58. package/lib/cli/init/git.js +2 -9
  59. package/lib/cli/init/git.js.map +2 -2
  60. package/lib/cli/init/index.d.ts +1 -1
  61. package/lib/cli/init/index.js +19 -10
  62. package/lib/cli/init/index.js.map +2 -2
  63. package/lib/cli/init/prompts.d.ts +26 -3
  64. package/lib/cli/init/prompts.js +10 -2
  65. package/lib/cli/init/prompts.js.map +2 -2
  66. package/lib/cli/init/types.d.ts +120 -27
  67. package/lib/cli/init/types.js +30 -35
  68. package/lib/cli/init/types.js.map +2 -2
  69. package/lib/cli/init/writePackageJson.d.ts +6 -0
  70. package/lib/cli/init/writePackageJson.js.map +2 -2
  71. package/lib/cli/lint/annotate/buildkite/index.d.ts +2 -1
  72. package/lib/cli/lint/annotate/buildkite/index.js +5 -3
  73. package/lib/cli/lint/annotate/buildkite/index.js.map +2 -2
  74. package/lib/cli/lint/annotate/buildkite/internal.d.ts +2 -0
  75. package/lib/cli/lint/annotate/buildkite/internal.js +45 -0
  76. package/lib/cli/lint/annotate/buildkite/internal.js.map +7 -0
  77. package/lib/cli/lint/annotate/github/index.d.ts +2 -1
  78. package/lib/cli/lint/annotate/github/index.js +4 -2
  79. package/lib/cli/lint/annotate/github/index.js.map +2 -2
  80. package/lib/cli/lint/annotate/github/internal.d.ts +3 -0
  81. package/lib/cli/lint/annotate/github/internal.js +36 -0
  82. package/lib/cli/lint/annotate/github/internal.js.map +7 -0
  83. package/lib/cli/lint/annotate/index.d.ts +4 -3
  84. package/lib/cli/lint/annotate/index.js +9 -3
  85. package/lib/cli/lint/annotate/index.js.map +2 -2
  86. package/lib/cli/lint/autofix.d.ts +3 -1
  87. package/lib/cli/lint/autofix.js +36 -59
  88. package/lib/cli/lint/autofix.js.map +3 -3
  89. package/lib/cli/lint/external.d.ts +6 -1
  90. package/lib/cli/lint/external.js +6 -29
  91. package/lib/cli/lint/external.js.map +2 -2
  92. package/lib/cli/lint/index.d.ts +2 -1
  93. package/lib/cli/lint/index.js +46 -14
  94. package/lib/cli/lint/index.js.map +2 -2
  95. package/lib/cli/lint/internal.d.ts +12 -1
  96. package/lib/cli/lint/internal.js +55 -19
  97. package/lib/cli/lint/internal.js.map +3 -3
  98. package/lib/cli/lint/internalLints/deleteFiles.d.ts +3 -0
  99. package/lib/cli/lint/internalLints/deleteFiles.js +102 -0
  100. package/lib/cli/lint/internalLints/deleteFiles.js.map +7 -0
  101. package/lib/cli/lint/internalLints/noSkubaTemplateJs.d.ts +3 -0
  102. package/lib/cli/lint/internalLints/noSkubaTemplateJs.js +75 -0
  103. package/lib/cli/lint/internalLints/noSkubaTemplateJs.js.map +7 -0
  104. package/lib/cli/lint/internalLints/refreshConfigFiles.d.ts +11 -0
  105. package/lib/cli/lint/internalLints/refreshConfigFiles.js +147 -0
  106. package/lib/cli/lint/internalLints/refreshConfigFiles.js.map +7 -0
  107. package/lib/cli/test/index.js +0 -2
  108. package/lib/cli/test/index.js.map +2 -2
  109. package/lib/skuba.d.ts +1 -1
  110. package/lib/skuba.js.map +1 -1
  111. package/lib/utils/error.d.ts +30 -10
  112. package/lib/utils/error.js +10 -20
  113. package/lib/utils/error.js.map +2 -2
  114. package/lib/utils/exec.d.ts +2 -1
  115. package/lib/utils/exec.js +3 -2
  116. package/lib/utils/exec.js.map +2 -2
  117. package/lib/utils/logging.d.ts +2 -0
  118. package/lib/utils/logging.js +1 -0
  119. package/lib/utils/logging.js.map +2 -2
  120. package/lib/utils/logo.js +6 -10
  121. package/lib/utils/logo.js.map +3 -3
  122. package/lib/utils/manifest.d.ts +4 -4
  123. package/lib/utils/manifest.js +10 -10
  124. package/lib/utils/manifest.js.map +2 -2
  125. package/lib/utils/npmrc.d.ts +1 -0
  126. package/lib/utils/npmrc.js +29 -0
  127. package/lib/utils/npmrc.js.map +7 -0
  128. package/lib/utils/packageManager.d.ts +24 -0
  129. package/lib/utils/packageManager.js +97 -0
  130. package/lib/utils/packageManager.js.map +7 -0
  131. package/lib/utils/template.d.ts +46 -13
  132. package/lib/utils/template.js +17 -15
  133. package/lib/utils/template.js.map +2 -2
  134. package/lib/utils/worker.d.ts +1 -0
  135. package/lib/wrapper/http.d.ts +1 -0
  136. package/package.json +50 -47
  137. package/template/base/_.dockerignore +0 -1
  138. package/template/base/_.eslintignore +1 -0
  139. package/template/base/_.gitignore +1 -1
  140. package/template/base/_.npmrc +8 -0
  141. package/template/express-rest-api/.buildkite/pipeline.yml +16 -12
  142. package/template/express-rest-api/.gantry/dev.yml +3 -0
  143. package/template/express-rest-api/.nvmrc +1 -1
  144. package/template/express-rest-api/Dockerfile +6 -12
  145. package/template/express-rest-api/Dockerfile.dev-deps +8 -7
  146. package/template/express-rest-api/README.md +12 -12
  147. package/template/express-rest-api/docker-compose.yml +0 -10
  148. package/template/express-rest-api/gantry.apply.yml +5 -0
  149. package/template/express-rest-api/gantry.build.yml +1 -2
  150. package/template/express-rest-api/package.json +4 -4
  151. package/template/express-rest-api/skuba.template.js +1 -0
  152. package/template/greeter/.buildkite/pipeline.yml +15 -11
  153. package/template/greeter/.nvmrc +1 -1
  154. package/template/greeter/Dockerfile +8 -7
  155. package/template/greeter/README.md +9 -9
  156. package/template/greeter/docker-compose.yml +0 -10
  157. package/template/greeter/package.json +3 -3
  158. package/template/greeter/skuba.template.js +1 -0
  159. package/template/koa-rest-api/.buildkite/pipeline.yml +16 -12
  160. package/template/koa-rest-api/.gantry/dev.yml +3 -0
  161. package/template/koa-rest-api/.nvmrc +1 -1
  162. package/template/koa-rest-api/Dockerfile +6 -12
  163. package/template/koa-rest-api/Dockerfile.dev-deps +8 -7
  164. package/template/koa-rest-api/README.md +12 -12
  165. package/template/koa-rest-api/docker-compose.yml +0 -10
  166. package/template/koa-rest-api/gantry.apply.yml +5 -0
  167. package/template/koa-rest-api/gantry.build.yml +1 -2
  168. package/template/koa-rest-api/package.json +10 -8
  169. package/template/koa-rest-api/skuba.template.js +1 -0
  170. package/template/koa-rest-api/src/app.test.ts +8 -4
  171. package/template/koa-rest-api/src/framework/validation.test.ts +48 -15
  172. package/template/koa-rest-api/src/framework/validation.ts +31 -8
  173. package/template/koa-rest-api/src/testing/types.ts +16 -4
  174. package/template/lambda-sqs-worker/.buildkite/pipeline.yml +25 -18
  175. package/template/lambda-sqs-worker/.nvmrc +1 -1
  176. package/template/lambda-sqs-worker/Dockerfile +8 -8
  177. package/template/lambda-sqs-worker/README.md +14 -14
  178. package/template/lambda-sqs-worker/_.npmrc +12 -0
  179. package/template/lambda-sqs-worker/docker-compose.yml +0 -15
  180. package/template/lambda-sqs-worker/package.json +6 -7
  181. package/template/lambda-sqs-worker/serverless.yml +5 -2
  182. package/template/lambda-sqs-worker/skuba.template.js +1 -0
  183. package/template/lambda-sqs-worker/src/framework/validation.test.ts +1 -1
  184. package/template/lambda-sqs-worker/src/hooks.ts +1 -2
  185. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +46 -21
  186. package/template/lambda-sqs-worker-cdk/.nvmrc +1 -1
  187. package/template/lambda-sqs-worker-cdk/Dockerfile +11 -9
  188. package/template/lambda-sqs-worker-cdk/cdk.json +12 -6
  189. package/template/lambda-sqs-worker-cdk/docker-compose.yml +0 -15
  190. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +1590 -228
  191. package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +23 -3
  192. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +128 -15
  193. package/template/lambda-sqs-worker-cdk/package.json +9 -7
  194. package/template/lambda-sqs-worker-cdk/shared/context-types.ts +1 -0
  195. package/template/lambda-sqs-worker-cdk/skuba.template.js +1 -0
  196. package/template/lambda-sqs-worker-cdk/src/app.ts +14 -1
  197. package/template/lambda-sqs-worker-cdk/src/postHook.ts +154 -0
  198. package/template/lambda-sqs-worker-cdk/src/preHook.ts +95 -0
  199. package/template/oss-npm-package/.github/workflows/release.yml +10 -7
  200. package/template/oss-npm-package/.github/workflows/validate.yml +10 -7
  201. package/template/oss-npm-package/.nvmrc +1 -1
  202. package/template/oss-npm-package/.releaserc +16 -0
  203. package/template/oss-npm-package/README.md +18 -18
  204. package/template/oss-npm-package/_package.json +3 -2
  205. package/template/oss-npm-package/skuba.template.js +1 -0
  206. package/template/private-npm-package/.nvmrc +1 -1
  207. package/template/private-npm-package/.releaserc +16 -0
  208. package/template/private-npm-package/README.md +18 -18
  209. package/template/private-npm-package/_package.json +3 -3
  210. package/template/private-npm-package/skuba.template.js +1 -0
  211. package/lib/cli/configure/addEmptyExports.js.map +0 -7
  212. package/lib/cli/configure/modules/tsconfig.d.ts +0 -2
  213. package/lib/cli/configure/modules/tsconfig.js +0 -87
  214. package/lib/cli/configure/modules/tsconfig.js.map +0 -7
  215. package/lib/cli/configure/patchDockerfile.d.ts +0 -1
  216. package/lib/cli/configure/patchDockerfile.js.map +0 -7
  217. package/lib/cli/configure/patchServerListener.d.ts +0 -3
  218. package/lib/cli/configure/patchServerListener.js.map +0 -7
  219. package/lib/cli/configure/refreshIgnoreFiles.d.ts +0 -3
  220. package/lib/cli/configure/refreshIgnoreFiles.js +0 -78
  221. package/lib/cli/configure/refreshIgnoreFiles.js.map +0 -7
@@ -43,13 +43,15 @@ describe('validate', () => {
43
43
  .expect(422)
44
44
  .expect(({ body }) =>
45
45
  expect(body).toMatchInlineSnapshot(`
46
- {
47
- "invalidFields": {
48
- "/id": "Expected string, received null",
49
- },
50
- "message": "Input validation failed",
51
- }
52
- `),
46
+ {
47
+ "invalidFields": {
48
+ "~union0/id": "Expected string, received null",
49
+ "~union1/id": "Expected number, received null",
50
+ "~union1/summary": "Required",
51
+ },
52
+ "message": "Input validation failed",
53
+ }
54
+ `),
53
55
  );
54
56
  });
55
57
 
@@ -60,13 +62,44 @@ describe('validate', () => {
60
62
  .expect(422)
61
63
  .expect(({ body }) =>
62
64
  expect(body).toMatchInlineSnapshot(`
63
- {
64
- "invalidFields": {
65
- "/description": "Required",
66
- "/id": "Required",
67
- },
68
- "message": "Input validation failed",
69
- }
70
- `),
65
+ {
66
+ "invalidFields": {
67
+ "~union0/description~union0": "Required",
68
+ "~union0/description~union1": "Required",
69
+ "~union0/id": "Required",
70
+ "~union1/id": "Required",
71
+ "~union1/summary": "Required",
72
+ },
73
+ "message": "Input validation failed",
74
+ }
75
+ `),
71
76
  ));
77
+
78
+ it('blocks invalid nested union prop', () => {
79
+ const idDescription = {
80
+ ...mockIdDescription(),
81
+ description: {
82
+ fontSize: chance.integer(),
83
+ },
84
+ };
85
+
86
+ return agent
87
+ .post('/')
88
+ .send({ ...idDescription, id: null })
89
+ .expect(422)
90
+ .expect(({ body }) =>
91
+ expect(body).toMatchInlineSnapshot(`
92
+ {
93
+ "invalidFields": {
94
+ "~union0/description~union0": "Expected string, received object",
95
+ "~union0/description~union1/content": "Required",
96
+ "~union0/id": "Expected string, received null",
97
+ "~union1/id": "Expected number, received null",
98
+ "~union1/summary": "Required",
99
+ },
100
+ "message": "Input validation failed",
101
+ }
102
+ `),
103
+ );
104
+ });
72
105
  });
@@ -1,8 +1,10 @@
1
1
  import { ErrorMiddleware } from 'seek-koala';
2
- import type { z } from 'zod';
2
+ import { ZodIssueCode, type z } from 'zod';
3
3
 
4
4
  import type { Context } from 'src/types/koa';
5
5
 
6
+ type InvalidFields = Record<string, string>;
7
+
6
8
  /**
7
9
  * Converts a `ZodError` into an `invalidFields` object
8
10
  *
@@ -28,13 +30,33 @@ import type { Context } from 'src/types/koa';
28
30
  * ```json
29
31
  * { "/advertiserId": "advertiserId is required in the URL" }
30
32
  * ```
33
+ *
34
+ * For union errors, the path will be appended with `~union${unionIdx}` to indicate which union type failed.
35
+ * @see [union error example](./validation.test.ts)
31
36
  */
32
- const parseInvalidFieldsFromError = ({
33
- errors,
34
- }: z.ZodError): Record<string, string> =>
35
- Object.fromEntries(
36
- errors.map((err) => [`/${err.path.join('/')}`, err.message]),
37
- );
37
+ const parseInvalidFieldsFromError = (err: z.ZodError): InvalidFields =>
38
+ Object.fromEntries(parseTuples(err, {}));
39
+
40
+ const parseTuples = (
41
+ { errors }: z.ZodError,
42
+ unions: Record<number, number[]>,
43
+ ): Array<readonly [string, string]> =>
44
+ errors.flatMap((issue) => {
45
+ if (issue.code === ZodIssueCode.invalid_union) {
46
+ return issue.unionErrors.flatMap((err, idx) =>
47
+ parseTuples(err, {
48
+ ...unions,
49
+ [issue.path.length]: [...(unions[issue.path.length] ?? []), idx],
50
+ }),
51
+ );
52
+ }
53
+
54
+ const path = ['', ...issue.path]
55
+ .map((prop, idx) => [prop, ...(unions[idx] ?? [])].join('~union'))
56
+ .join('/');
57
+
58
+ return [[path, issue.message]] as const;
59
+ });
38
60
 
39
61
  export const validate = <
40
62
  Output,
@@ -51,11 +73,12 @@ export const validate = <
51
73
  }): Output => {
52
74
  const parseResult = schema.safeParse(input);
53
75
  if (parseResult.success === false) {
76
+ const invalidFields = parseInvalidFieldsFromError(parseResult.error);
54
77
  return ctx.throw(
55
78
  422,
56
79
  new ErrorMiddleware.JsonResponse('Input validation failed', {
57
80
  message: 'Input validation failed',
58
- invalidFields: parseInvalidFieldsFromError(parseResult.error),
81
+ invalidFields,
59
82
  }),
60
83
  );
61
84
  }
@@ -5,10 +5,22 @@ import type { JobInput } from 'src/types/jobs';
5
5
 
6
6
  export type IdDescription = z.infer<typeof IdDescriptionSchema>;
7
7
 
8
- export const IdDescriptionSchema = z.object({
9
- id: z.string(),
10
- description: z.string(),
11
- });
8
+ export const IdDescriptionSchema = z.union([
9
+ z.object({
10
+ id: z.string(),
11
+ description: z.union([
12
+ z.string(),
13
+ z.object({
14
+ fontSize: z.number(),
15
+ content: z.string(),
16
+ }),
17
+ ]),
18
+ }),
19
+ z.object({
20
+ id: z.number(),
21
+ summary: z.string(),
22
+ }),
23
+ ]);
12
24
 
13
25
  export const chance = new Chance();
14
26
 
@@ -4,37 +4,39 @@ agents:
4
4
  configs:
5
5
  plugins:
6
6
  - &aws-sm
7
- seek-oss/aws-sm#v2.3.1:
7
+ seek-oss/aws-sm#v2.3.2:
8
8
  env:
9
9
  NPM_READ_TOKEN: arn:aws:secretsmanager:ap-southeast-2:987872074697:secret:npm/npm-read-token
10
10
 
11
11
  - &docker-ecr-cache
12
- seek-oss/docker-ecr-cache#v2.1.0: &docker-ecr-cache-defaults
13
- cache-on:
14
- - package.json
15
- - yarn.lock
16
- secrets: id=npm,src=.npmrc
12
+ seek-oss/docker-ecr-cache#v2.1.1: &docker-ecr-cache-defaults
13
+ cache-on: pnpm-lock.yaml
14
+ secrets: id=npm,src=tmp/.npmrc
17
15
 
18
16
  - &private-npm
19
17
  seek-oss/private-npm#v1.2.0:
20
18
  env: NPM_READ_TOKEN
19
+ output-path: tmp/
21
20
 
22
21
  base-steps:
23
22
  - &deploy
24
23
  commands:
25
- - echo '+++ yarn deploy'
26
- - yarn deploy
24
+ - echo '--- pnpm install --offline'
25
+ - pnpm install --offline
26
+ - echo '+++ pnpm run deploy'
27
+ - pnpm run deploy
27
28
  concurrency: 1
28
29
  plugins:
29
- - artifacts#v1.9.2:
30
+ - artifacts#v1.9.3:
30
31
  build: ${BUILDKITE_BUILD_ID}
31
32
  download: lib/*
32
33
  - *aws-sm
33
34
  - *private-npm
34
35
  - *docker-ecr-cache
35
- - docker-compose#v4.14.0:
36
+ - docker-compose#v4.16.0:
36
37
  dependencies: false
37
38
  run: app
39
+ propagate-environment: true
38
40
  retry:
39
41
  manual:
40
42
  # Only use this if you need to roll back a deployment ASAP.
@@ -48,20 +50,25 @@ steps:
48
50
  - label: 🧪 Test, Lint & Build
49
51
  artifact_paths: lib/**/*
50
52
  commands:
51
- - echo '+++ yarn test:ci'
52
- - yarn test:ci
53
- - echo '--- yarn lint'
54
- - yarn lint
55
- - echo '--- yarn build'
56
- - yarn build
53
+ - echo '--- pnpm install --offline'
54
+ - pnpm install --offline
55
+ - echo '+++ pnpm run test:ci'
56
+ - pnpm run test:ci
57
+ - echo '--- pnpm run lint'
58
+ - pnpm run lint
59
+ - echo '--- pnpm run build'
60
+ - pnpm run build
57
61
  env:
58
62
  GET_GITHUB_TOKEN: please
59
63
  plugins:
60
64
  - *aws-sm
61
65
  - *private-npm
62
66
  - *docker-ecr-cache
63
- - docker-compose#v4.14.0:
67
+ - docker-compose#v4.16.0:
64
68
  run: app
69
+ environment:
70
+ - GITHUB_API_TOKEN
71
+ propagate-environment: true
65
72
  timeout_in_minutes: 10
66
73
 
67
74
  - agents:
@@ -72,7 +79,7 @@ steps:
72
79
  plugins:
73
80
  - *aws-sm
74
81
  - *private-npm
75
- - seek-oss/docker-ecr-cache#v2.1.0:
82
+ - seek-oss/docker-ecr-cache#v2.1.1:
76
83
  <<: *docker-ecr-cache-defaults
77
84
  skip-pull-from-cache: true
78
85
 
@@ -1 +1 @@
1
- 18
1
+ 20
@@ -1,12 +1,12 @@
1
- # syntax=docker/dockerfile:1.2
1
+ # syntax=docker/dockerfile:1.6
2
2
 
3
- FROM --platform=${BUILDPLATFORM:-<%- platformName %>} node:18-alpine AS dev-deps
3
+ FROM --platform=${BUILDPLATFORM:-<%- platformName %>} node:20-alpine AS dev-deps
4
4
 
5
- WORKDIR /workdir
5
+ RUN corepack enable pnpm
6
+ RUN pnpm config set store-dir /root/.pnpm-store
6
7
 
7
- COPY package.json yarn.lock ./
8
+ WORKDIR /workdir
8
9
 
9
- RUN \
10
- --mount=type=secret,id=npm,dst=/workdir/.npmrc \
11
- yarn install --frozen-lockfile --ignore-optional --non-interactive && \
12
- yarn cache clean
10
+ RUN --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
11
+ --mount=type=secret,id=npm,dst=/root/.npmrc,required=true \
12
+ pnpm fetch
@@ -7,7 +7,7 @@ Next steps:
7
7
  1. [ ] Finish templating if this was skipped earlier:
8
8
 
9
9
  ```shell
10
- yarn skuba configure
10
+ pnpm exec skuba configure
11
11
  ```
12
12
 
13
13
  2. [ ] Create a new repository in the appropriate GitHub organisation.
@@ -18,12 +18,12 @@ Next steps:
18
18
  6. [ ] Configure [GitHub repository settings].
19
19
  7. [ ] Delete this checklist 😌.
20
20
 
21
- [builds at seek]: https://builds-at-seek.ssod.skinfra.xyz
21
+ [builds at seek]: https://backstage.myseek.xyz/docs/default/component/builds-cicd-seek/
22
22
  [github repository settings]: https://github.com/<%-orgName%>/<%-repoName%>/settings
23
23
 
24
24
  ## Design
25
25
 
26
- <%-repoName %> is a Node.js [Lambda] application built in line with our [technology strategy].
26
+ <%-repoName %> is a Node.js [Lambda] application built in line with our [Technical Guidelines].
27
27
  It is backed by a typical SQS message + dead letter queue configuration and uses common SEEK packages.
28
28
  Workers enable fault-tolerant asynchronous processing of events.
29
29
 
@@ -47,33 +47,33 @@ This defaults to an invocation with an empty object `{}`, per [src/hooks.ts](src
47
47
 
48
48
  ```shell
49
49
  # Run Jest tests locally
50
- yarn test
50
+ pnpm run test
51
51
 
52
52
  # Authenticate to dev account
53
53
  awsauth
54
54
 
55
55
  # Run smoke test against deployed application
56
- ENVIRONMENT=dev yarn smoke
56
+ ENVIRONMENT=dev pnpm run smoke
57
57
  ```
58
58
 
59
59
  ### Lint
60
60
 
61
61
  ```shell
62
62
  # Fix issues
63
- yarn format
63
+ pnpm run format
64
64
 
65
65
  # Check for issues
66
- yarn lint
66
+ pnpm run lint
67
67
  ```
68
68
 
69
69
  ### Start
70
70
 
71
71
  ```shell
72
72
  # Start a local HTTP server
73
- yarn start
73
+ pnpm run start
74
74
 
75
75
  # Start with Node.js Inspector enabled
76
- yarn start:debug
76
+ pnpm run start:debug
77
77
  ```
78
78
 
79
79
  This serves the Lambda application over HTTP.
@@ -96,7 +96,7 @@ To deploy locally:
96
96
  # Authenticate to dev account
97
97
  awsauth
98
98
 
99
- ENVIRONMENT=dev yarn deploy
99
+ ENVIRONMENT=dev pnpm run deploy
100
100
  ```
101
101
 
102
102
  To rapidly roll back a change,
@@ -126,7 +126,7 @@ TODO: add support links for the prod environment.
126
126
  - Splunk logs
127
127
  -->
128
128
 
129
- [codedeploy]: https://docs.aws.amazon.com/codedeploy
130
- [lambda]: https://docs.aws.amazon.com/lambda
131
- [serverless]: https://www.serverless.com/
132
- [technology strategy]: https://tech-strategy.ssod.skinfra.xyz
129
+ [CodeDeploy]: https://docs.aws.amazon.com/codedeploy
130
+ [Lambda]: https://docs.aws.amazon.com/lambda
131
+ [Serverless]: https://www.serverless.com/
132
+ [Technical Guidelines]: https://myseek.atlassian.net/wiki/spaces/AA/pages/2358346017/
@@ -0,0 +1,12 @@
1
+ # managed by skuba
2
+ public-hoist-pattern[]="@types*"
3
+ public-hoist-pattern[]="*eslint*"
4
+ public-hoist-pattern[]="*prettier*"
5
+ public-hoist-pattern[]="esbuild"
6
+ public-hoist-pattern[]="jest"
7
+ public-hoist-pattern[]="tsconfig-seek"
8
+ # end managed by skuba
9
+
10
+ # Required for Serverless packaging
11
+ node-linker=hoisted
12
+ shamefully-hoist=true
@@ -2,21 +2,6 @@ version: '3.7'
2
2
 
3
3
  services:
4
4
  app:
5
- environment:
6
- # Enable Buildkite + GitHub integrations.
7
- - BUILDKITE
8
- - BUILDKITE_AGENT_ACCESS_TOKEN
9
- - BUILDKITE_BRANCH
10
- - BUILDKITE_BUILD_NUMBER
11
- - BUILDKITE_JOB_ID
12
- - BUILDKITE_PIPELINE_DEFAULT_BRANCH
13
- - BUILDKITE_STEP_ID
14
- - GITHUB_API_TOKEN
15
- # Tag AWS resources with the commit hash.
16
- - BUILDKITE_COMMIT
17
- # Pass through application configuration.
18
- - ENVIRONMENT
19
- - VERSION
20
5
  image: ${BUILDKITE_PLUGIN_DOCKER_IMAGE:-''}
21
6
  init: true
22
7
  volumes:
@@ -8,7 +8,7 @@
8
8
  "lint": "skuba lint",
9
9
  "smoke": "serverless invoke --data '{}' --function Worker",
10
10
  "start": "skuba start --port <%- port %>",
11
- "start:debug": "yarn start --inspect-brk",
11
+ "start:debug": "pnpm run --silent start --inspect-brk",
12
12
  "test": "skuba test",
13
13
  "test:ci": "skuba test --coverage",
14
14
  "test:watch": "skuba test --watch"
@@ -17,28 +17,27 @@
17
17
  "@aws-sdk/client-codedeploy": "^3.363.0",
18
18
  "@aws-sdk/client-lambda": "^3.363.0",
19
19
  "@aws-sdk/client-sns": "^3.363.0",
20
- "@aws-sdk/util-utf8-node": "^3.259.0",
21
20
  "@seek/logger": "^6.0.0",
22
- "datadog-lambda-js": "^7.0.0",
23
- "dd-trace": "^4.0.0",
21
+ "datadog-lambda-js": "^7.102.0",
22
+ "dd-trace": "^5.0.0",
24
23
  "skuba-dive": "^2.0.0",
25
24
  "zod": "^3.19.1"
26
25
  },
27
26
  "devDependencies": {
28
27
  "@types/aws-lambda": "^8.10.84",
29
28
  "@types/chance": "^1.1.3",
30
- "@types/node": "^18.11.9",
29
+ "@types/node": "^20.9.0",
31
30
  "aws-sdk-client-mock": "^3.0.0",
32
31
  "aws-sdk-client-mock-jest": "^3.0.0",
33
32
  "chance": "^1.1.8",
34
33
  "pino-pretty": "^10.0.0",
35
- "serverless": "^3.25.0",
34
+ "serverless": "^3.37.0",
36
35
  "serverless-plugin-canary-deployments": "^0.8.0",
37
36
  "serverless-plugin-datadog": "^5.12.0",
38
37
  "serverless-prune-plugin": "^2.0.0",
39
38
  "skuba": "*"
40
39
  },
41
40
  "engines": {
42
- "node": ">=18.12"
41
+ "node": ">=20"
43
42
  }
44
43
  }
@@ -9,9 +9,11 @@ params:
9
9
  dev:
10
10
  deploymentBucket: 'TODO: deployment-bucket-name'
11
11
  isProduction: false
12
+ concurrency: 2
12
13
  prod:
13
14
  deploymentBucket: 'TODO: deployment-bucket-name'
14
15
  isProduction: true
16
+ concurrency: 20
15
17
 
16
18
  custom:
17
19
  datadog:
@@ -37,7 +39,7 @@ provider:
37
39
  logRetentionInDays: 30
38
40
  name: aws
39
41
  region: ap-southeast-2
40
- runtime: nodejs18.x
42
+ runtime: nodejs20.x
41
43
  architecture: <%- lambdaServerlessArchitecture %>
42
44
  deploymentMethod: direct
43
45
  stackName: ${self:service}
@@ -91,7 +93,7 @@ functions:
91
93
  handler: lib/app.handler
92
94
  description: ${param:description}
93
95
  memorySize: 128
94
- reservedConcurrency: 20
96
+ reservedConcurrency: ${param:concurrency}
95
97
  timeout: 30
96
98
  deploymentSettings:
97
99
  type: AllAtOnce
@@ -107,6 +109,7 @@ functions:
107
109
  - sqs:
108
110
  arn: !GetAtt MessageQueue.Arn
109
111
  batchSize: 1
112
+ maximumConcurrency: ${param:concurrency}
110
113
  WorkerPreHook:
111
114
  name: ${self:functions.Worker.name}-pre-hook
112
115
  handler: lib/hooks.pre
@@ -28,5 +28,6 @@ module.exports = {
28
28
  validate: (value) => /^.+:.+$/.test(value),
29
29
  },
30
30
  ],
31
+ packageManager: 'pnpm',
31
32
  type: 'application',
32
33
  };
@@ -78,7 +78,7 @@ describe('validateJson', () => {
78
78
  expect(() =>
79
79
  validateJson(input, IdDescriptionSchema),
80
80
  ).toThrowErrorMatchingInlineSnapshot(
81
- `"Unexpected token } in JSON at position 0"`,
81
+ `"Unexpected token '}', "}" is not valid JSON"`,
82
82
  );
83
83
  });
84
84
  });
@@ -7,7 +7,6 @@ import {
7
7
  PutLifecycleEventHookExecutionStatusCommand,
8
8
  } from '@aws-sdk/client-codedeploy';
9
9
  import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda';
10
- import { toUtf8 } from '@aws-sdk/util-utf8-node';
11
10
 
12
11
  const codeDeploy = new CodeDeployClient({
13
12
  apiVersion: '2014-10-06',
@@ -51,7 +50,7 @@ const smokeTestLambdaFunction = async (): Promise<Status> => {
51
50
  if (response.FunctionError) {
52
51
  console.error('Error:', response.FunctionError);
53
52
  if (response.Payload) {
54
- console.error(toUtf8(response.Payload));
53
+ console.error(response.Payload.transformToString());
55
54
  }
56
55
  return 'Failed';
57
56
  }
@@ -4,61 +4,67 @@ agents:
4
4
  configs:
5
5
  plugins:
6
6
  - &aws-sm
7
- seek-oss/aws-sm#v2.3.1:
7
+ seek-oss/aws-sm#v2.3.2:
8
8
  env:
9
9
  NPM_READ_TOKEN: arn:aws:secretsmanager:ap-southeast-2:987872074697:secret:npm/npm-read-token
10
10
 
11
11
  - &docker-ecr-cache
12
- seek-oss/docker-ecr-cache#v2.1.0: &docker-ecr-cache-defaults
13
- cache-on:
14
- - package.json
15
- - yarn.lock
16
- secrets: id=npm,src=.npmrc
12
+ seek-oss/docker-ecr-cache#v2.1.1: &docker-ecr-cache-defaults
13
+ cache-on: pnpm-lock.yaml
14
+ secrets: id=npm,src=tmp/.npmrc
17
15
 
18
16
  - &private-npm
19
17
  seek-oss/private-npm#v1.2.0:
20
18
  env: NPM_READ_TOKEN
19
+ output-path: tmp/
21
20
 
22
21
  base-steps:
23
22
  - &deploy
24
23
  commands:
25
- - echo '+++ yarn deploy'
26
- - yarn deploy
24
+ - echo '--- pnpm install --offline'
25
+ - pnpm install --offline
26
+ - echo '+++ pnpm run deploy'
27
+ - pnpm run deploy
27
28
  concurrency: 1
28
29
  plugins:
29
- - artifacts#v1.9.2:
30
- build: ${BUILDKITE_BUILD_ID}
31
- download: lib/*
32
30
  - *aws-sm
33
31
  - *private-npm
34
32
  - *docker-ecr-cache
35
- - docker-compose#v4.14.0:
33
+ - docker-compose#v4.16.0:
36
34
  dependencies: false
37
35
  run: app
36
+ environment:
37
+ - GITHUB_API_TOKEN
38
+ propagate-environment: true
38
39
  retry:
39
40
  manual:
40
41
  # Only use this if you need to roll back a deployment ASAP.
41
42
  # Always follow up with a proper revert or fix in Git history.
42
43
  permit_on_passed: true
43
44
 
45
+ env:
46
+ VERSION: ${BUILDKITE_COMMIT:0:7}.${BUILDKITE_BUILD_NUMBER}
47
+
44
48
  steps:
45
49
  - label: 🧪 Test, Lint & Build
46
- artifact_paths: lib/**/*
47
50
  commands:
48
- - echo '+++ yarn test:ci'
49
- - yarn test
50
- - echo '--- yarn lint'
51
- - yarn lint
52
- - echo '--- yarn build'
53
- - yarn build
51
+ - echo '--- pnpm install --offline'
52
+ - pnpm install --offline
53
+ - echo '+++ pnpm run test:ci'
54
+ - pnpm run test
55
+ - echo '--- pnpm run lint'
56
+ - pnpm run lint
54
57
  env:
55
58
  GET_GITHUB_TOKEN: please
56
59
  plugins:
57
60
  - *aws-sm
58
61
  - *private-npm
59
62
  - *docker-ecr-cache
60
- - docker-compose#v4.14.0:
63
+ - docker-compose#v4.16.0:
61
64
  run: app
65
+ environment:
66
+ - GITHUB_API_TOKEN
67
+ propagate-environment: true
62
68
  timeout_in_minutes: 10
63
69
 
64
70
  - agents:
@@ -69,7 +75,7 @@ steps:
69
75
  plugins:
70
76
  - *aws-sm
71
77
  - *private-npm
72
- - seek-oss/docker-ecr-cache#v2.1.0:
78
+ - seek-oss/docker-ecr-cache#v2.1.1:
73
79
  <<: *docker-ecr-cache-defaults
74
80
  skip-pull-from-cache: true
75
81
 
@@ -86,6 +92,25 @@ steps:
86
92
  concurrency_group: '<%- repoName %>/deploy/dev'
87
93
  key: deploy-dev
88
94
 
95
+ - block: 🙋🏻‍♀️ Deploy Dev (Hotswap)
96
+ key: deploy-dev-hotswap-block
97
+ branches: '!${BUILDKITE_PIPELINE_DEFAULT_BRANCH}'
98
+
99
+ - <<: *deploy
100
+ branches: '!${BUILDKITE_PIPELINE_DEFAULT_BRANCH}'
101
+ depends_on: deploy-dev-hotswap-block
102
+ agents:
103
+ queue: <%- devBuildkiteQueueName %>
104
+ env:
105
+ ENVIRONMENT: dev
106
+ commands:
107
+ - echo '--- pnpm install --offline'
108
+ - pnpm install --offline
109
+ - echo '+++ pnpm run deploy:hotswap'
110
+ - pnpm run deploy:hotswap
111
+ label: 🤞 Deploy Dev (Hotswap)
112
+ concurrency_group: '<%- repoName %>/deploy/dev'
113
+
89
114
  - <<: *deploy
90
115
  env:
91
116
  ENVIRONMENT: prod
@@ -1 +1 @@
1
- 18
1
+ 20
@@ -1,13 +1,15 @@
1
- # syntax=docker/dockerfile:1.2
1
+ # syntax=docker/dockerfile:1.6
2
2
 
3
- FROM --platform=${BUILDPLATFORM:-<%- platformName %>} node:18-alpine AS dev-deps
3
+ FROM --platform=${BUILDPLATFORM:-<%- platformName %>} node:20-alpine AS dev-deps
4
4
 
5
- WORKDIR /workdir
5
+ # Needed for cdk
6
+ RUN apk add --no-cache bash
7
+
8
+ RUN corepack enable pnpm
9
+ RUN pnpm config set store-dir /root/.pnpm-store
6
10
 
7
- COPY package.json yarn.lock ./
11
+ WORKDIR /workdir
8
12
 
9
- RUN \
10
- --mount=type=secret,id=npm,dst=/workdir/.npmrc \
11
- yarn install --frozen-lockfile --ignore-optional --non-interactive && \
12
- yarn package && \
13
- yarn cache clean
13
+ RUN --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
14
+ --mount=type=secret,id=npm,dst=/root/.npmrc,required=true \
15
+ pnpm fetch