skuba 5.0.0 → 5.1.0

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 (79) hide show
  1. package/jest/transform.js +31 -9
  2. package/jest/transform.test.ts +11 -0
  3. package/lib/api/buildkite/annotate.d.ts +1 -1
  4. package/lib/api/git/getChangedFiles.d.ts +1 -1
  5. package/lib/api/github/checkRun.d.ts +2 -2
  6. package/lib/api/jest/index.d.ts +2 -2
  7. package/lib/cli/adapter/prettier.js +15 -1
  8. package/lib/cli/adapter/prettier.js.map +2 -2
  9. package/lib/cli/configure/processing/prettier.d.ts +1 -1
  10. package/lib/cli/configure/processing/typescript.d.ts +2 -2
  11. package/lib/cli/configure/types.d.ts +6 -6
  12. package/lib/cli/init/getConfig.js +18 -5
  13. package/lib/cli/init/getConfig.js.map +2 -2
  14. package/lib/cli/init/prompts.d.ts +14 -1
  15. package/lib/cli/init/prompts.js +7 -1
  16. package/lib/cli/init/prompts.js.map +2 -2
  17. package/lib/cli/init/types.d.ts +3 -2
  18. package/lib/cli/init/types.js +2 -1
  19. package/lib/cli/init/types.js.map +2 -2
  20. package/lib/cli/init/validation.d.ts +5 -0
  21. package/lib/cli/init/validation.js +10 -2
  22. package/lib/cli/init/validation.js.map +2 -2
  23. package/lib/skuba.js.map +1 -1
  24. package/lib/utils/command.d.ts +1 -1
  25. package/lib/utils/copy.d.ts +1 -1
  26. package/lib/utils/error.d.ts +1 -1
  27. package/lib/utils/exec.d.ts +2 -2
  28. package/lib/utils/logging.d.ts +1 -1
  29. package/lib/utils/manifest.d.ts +1 -1
  30. package/lib/utils/template.d.ts +2 -2
  31. package/lib/utils/version.d.ts +1 -1
  32. package/lib/utils/wait.d.ts +1 -1
  33. package/lib/wrapper/main.js.map +1 -1
  34. package/package.json +14 -14
  35. package/template/express-rest-api/.buildkite/pipeline.yml +1 -1
  36. package/template/express-rest-api/.gantry/common.yml +1 -1
  37. package/template/express-rest-api/.gantry/dev.yml +1 -0
  38. package/template/express-rest-api/.gantry/prod.yml +1 -0
  39. package/template/express-rest-api/Dockerfile +1 -1
  40. package/template/express-rest-api/Dockerfile.dev-deps +1 -1
  41. package/template/express-rest-api/README.md +7 -10
  42. package/template/express-rest-api/gantry.apply.yml +2 -2
  43. package/template/express-rest-api/gantry.build.yml +1 -1
  44. package/template/greeter/.buildkite/pipeline.yml +1 -1
  45. package/template/greeter/Dockerfile +1 -1
  46. package/template/greeter/README.md +6 -9
  47. package/template/koa-rest-api/.buildkite/pipeline.yml +1 -1
  48. package/template/koa-rest-api/.gantry/common.yml +1 -1
  49. package/template/koa-rest-api/.gantry/dev.yml +1 -0
  50. package/template/koa-rest-api/.gantry/prod.yml +1 -0
  51. package/template/koa-rest-api/Dockerfile +1 -1
  52. package/template/koa-rest-api/Dockerfile.dev-deps +1 -1
  53. package/template/koa-rest-api/README.md +7 -10
  54. package/template/koa-rest-api/gantry.apply.yml +2 -2
  55. package/template/koa-rest-api/gantry.build.yml +1 -1
  56. package/template/koa-rest-api/package.json +2 -2
  57. package/template/lambda-sqs-worker/.buildkite/pipeline.yml +4 -4
  58. package/template/lambda-sqs-worker/.nvmrc +1 -1
  59. package/template/lambda-sqs-worker/Dockerfile +1 -1
  60. package/template/lambda-sqs-worker/README.md +7 -10
  61. package/template/lambda-sqs-worker/package.json +10 -5
  62. package/template/lambda-sqs-worker/serverless.yml +2 -4
  63. package/template/lambda-sqs-worker/src/app.test.ts +5 -6
  64. package/template/lambda-sqs-worker/src/framework/handler.test.ts +2 -2
  65. package/template/lambda-sqs-worker/src/hooks.ts +22 -30
  66. package/template/lambda-sqs-worker/src/services/aws.ts +2 -2
  67. package/template/lambda-sqs-worker/src/services/pipelineEventSender.test.ts +9 -7
  68. package/template/lambda-sqs-worker/src/services/pipelineEventSender.ts +6 -4
  69. package/template/lambda-sqs-worker/src/testing/services.ts +11 -7
  70. package/template/lambda-sqs-worker/tsconfig.json +2 -2
  71. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +4 -4
  72. package/template/lambda-sqs-worker-cdk/.nvmrc +1 -1
  73. package/template/lambda-sqs-worker-cdk/Dockerfile +1 -1
  74. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +2 -4
  75. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +4 -4
  76. package/template/lambda-sqs-worker-cdk/package.json +4 -4
  77. package/template/lambda-sqs-worker-cdk/tsconfig.json +2 -2
  78. package/template/oss-npm-package/_package.json +1 -1
  79. package/template/private-npm-package/_package.json +1 -1
@@ -2,28 +2,21 @@
2
2
  /* istanbul ignore file */
3
3
 
4
4
  // Use minimal dependencies to reduce the chance of crashes on module load.
5
- import { CodeDeploy, Lambda } from 'aws-sdk';
5
+ import {
6
+ CodeDeployClient,
7
+ PutLifecycleEventHookExecutionStatusCommand,
8
+ } from '@aws-sdk/client-codedeploy';
9
+ import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda';
10
+ import { toUtf8 } from '@aws-sdk/util-utf8-node';
6
11
 
7
- /**
8
- * Common AWS options to avoid hanging the deployment on a transient error.
9
- *
10
- * AWS uses exponential backoff, so we wait for ~15 seconds total per request.
11
- */
12
- const awsRetryOptions = {
13
- maxRetries: 5,
14
- retryDelayOptions: {
15
- base: 500,
16
- },
17
- };
18
-
19
- const codeDeploy = new CodeDeploy({
20
- ...awsRetryOptions,
12
+ const codeDeploy = new CodeDeployClient({
21
13
  apiVersion: '2014-10-06',
14
+ maxAttempts: 5,
22
15
  });
23
16
 
24
- const lambda = new Lambda({
25
- ...awsRetryOptions,
17
+ const lambda = new LambdaClient({
26
18
  apiVersion: '2015-03-31',
19
+ maxAttempts: 5,
27
20
  });
28
21
 
29
22
  type Status = 'Succeeded' | 'Failed';
@@ -43,24 +36,23 @@ const smokeTestLambdaFunction = async (): Promise<Status> => {
43
36
 
44
37
  console.info('Function:', functionName);
45
38
 
46
- const response = await lambda
47
- .invoke({
39
+ const response = await lambda.send(
40
+ new InvokeCommand({
48
41
  FunctionName: functionName,
49
42
  InvocationType: 'RequestResponse',
50
43
  // Treat an empty object as our smoke test event.
51
- Payload: '{}',
52
- // An unqualified reference implicitly invokes $LATEST, which has been
53
- // updated to point to the new version when this pre hook runs.
54
- Qualifier: undefined,
55
- })
56
- .promise();
44
+ Payload: Buffer.from('{}'),
45
+ }),
46
+ );
57
47
 
58
48
  console.info('Version:', response.ExecutedVersion ?? '?');
59
49
  console.info('Status', response.StatusCode ?? '?');
60
50
 
61
51
  if (response.FunctionError) {
62
52
  console.error('Error:', response.FunctionError);
63
- console.error(response.Payload);
53
+ if (response.Payload) {
54
+ console.error(toUtf8(response.Payload));
55
+ }
64
56
  return 'Failed';
65
57
  }
66
58
 
@@ -94,11 +86,11 @@ export const pre = async (
94
86
  status = 'Failed';
95
87
  }
96
88
 
97
- await codeDeploy
98
- .putLifecycleEventHookExecutionStatus({
89
+ await codeDeploy.send(
90
+ new PutLifecycleEventHookExecutionStatusCommand({
99
91
  deploymentId: event.DeploymentId,
100
92
  lifecycleEventHookExecutionId: event.LifecycleEventHookExecutionId,
101
93
  status,
102
- })
103
- .promise();
94
+ }),
95
+ );
104
96
  };
@@ -1,5 +1,5 @@
1
- import { SNS } from 'aws-sdk';
1
+ import { SNSClient } from '@aws-sdk/client-sns';
2
2
 
3
- export const sns = new SNS({
3
+ export const sns = new SNSClient({
4
4
  apiVersion: '2010-03-31',
5
5
  });
@@ -1,33 +1,35 @@
1
+ import { PublishCommand } from '@aws-sdk/client-sns';
2
+
1
3
  import { sns } from 'src/testing/services';
2
4
  import { chance } from 'src/testing/types';
3
5
 
4
6
  import { sendPipelineEvent } from './pipelineEventSender';
5
7
 
6
8
  describe('sendPipelineEvent', () => {
7
- beforeAll(sns.spy);
8
-
9
- afterEach(sns.clear);
9
+ afterEach(() => {
10
+ jest.clearAllMocks();
11
+ });
10
12
 
11
13
  it('handles happy path', async () => {
12
14
  const messageId = chance.guid({ version: 4 });
13
15
 
14
- sns.publish.mockPromise(Promise.resolve({ MessageId: messageId }));
16
+ sns.publish.resolves({ MessageId: messageId });
15
17
 
16
18
  await expect(sendPipelineEvent({})).resolves.toBe(messageId);
17
19
 
18
- expect(sns.publish).toHaveBeenCalledTimes(1);
20
+ expect(sns.client).toReceiveCommandTimes(PublishCommand, 1);
19
21
  });
20
22
 
21
23
  it('bubbles up SNS error', () => {
22
24
  const err = Error(chance.sentence());
23
25
 
24
- sns.publish.mockPromise(Promise.reject(err));
26
+ sns.publish.rejects(err);
25
27
 
26
28
  return expect(sendPipelineEvent({})).rejects.toThrow(err);
27
29
  });
28
30
 
29
31
  it('throws on missing message ID', () => {
30
- sns.publish.mockPromise(Promise.resolve({}));
32
+ sns.publish.resolves({});
31
33
 
32
34
  return expect(
33
35
  sendPipelineEvent({}),
@@ -1,3 +1,5 @@
1
+ import { PublishCommand } from '@aws-sdk/client-sns';
2
+
1
3
  import { config } from 'src/config';
2
4
 
3
5
  import { sns } from './aws';
@@ -6,8 +8,8 @@ export const sendPipelineEvent = async (
6
8
  event: unknown,
7
9
  smokeTest: boolean = false,
8
10
  ): Promise<string> => {
9
- const snsResponse = await sns
10
- .publish({
11
+ const snsResponse = await sns.send(
12
+ new PublishCommand({
11
13
  Message: JSON.stringify(event),
12
14
  ...(smokeTest && {
13
15
  MessageAttributes: {
@@ -20,8 +22,8 @@ export const sendPipelineEvent = async (
20
22
  },
21
23
  }),
22
24
  TopicArn: config.destinationSnsTopicArn,
23
- })
24
- .promise();
25
+ }),
26
+ );
25
27
 
26
28
  if (snsResponse.MessageId === undefined) {
27
29
  throw Error('SNS did not return a message ID');
@@ -1,4 +1,9 @@
1
- import * as aws from 'src/services/aws';
1
+ import 'aws-sdk-client-mock-jest';
2
+
3
+ import { PublishCommand } from '@aws-sdk/client-sns';
4
+ import { mockClient } from 'aws-sdk-client-mock';
5
+
6
+ import { sns as snsClient } from 'src/services/aws';
2
7
  import * as jobScorer from 'src/services/jobScorer';
3
8
 
4
9
  export const scoringService = {
@@ -12,13 +17,12 @@ export const scoringService = {
12
17
  .mockImplementation(scoringService.request),
13
18
  };
14
19
 
20
+ const snsMock = mockClient(snsClient);
21
+
15
22
  export const sns = {
16
- publish: Object.assign(jest.fn(), {
17
- mockPromise: (promise: Promise<unknown>) =>
18
- sns.publish.mockReturnValue({ promise: () => promise } as any),
19
- }),
23
+ publish: snsMock.on(PublishCommand),
20
24
 
21
- clear: () => sns.publish.mockClear(),
25
+ clear: () => snsMock.resetHistory(),
22
26
 
23
- spy: () => jest.spyOn(aws.sns, 'publish').mockImplementation(sns.publish),
27
+ client: snsMock,
24
28
  };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "baseUrl": ".",
4
- "lib": ["ES2020"],
4
+ "lib": ["ES2022"],
5
5
  "outDir": "lib",
6
6
  "paths": {
7
7
  "src": ["src"]
8
8
  },
9
- "target": "ES2020"
9
+ "target": "ES2022"
10
10
  },
11
11
  "exclude": ["lib*/**/*"],
12
12
  "extends": "skuba/config/tsconfig.json"
@@ -26,13 +26,13 @@ configs:
26
26
  - yarn deploy
27
27
  concurrency: 1
28
28
  plugins:
29
- - artifacts#v1.7.0:
29
+ - artifacts#v1.8.0:
30
30
  build: ${BUILDKITE_BUILD_ID}
31
31
  download: lib/*
32
32
  - *aws-sm
33
33
  - *private-npm
34
34
  - *docker-ecr-cache
35
- - docker-compose#v4.5.0:
35
+ - docker-compose#v4.9.0:
36
36
  dependencies: false
37
37
  run: app
38
38
  retry:
@@ -57,13 +57,13 @@ steps:
57
57
  - *aws-sm
58
58
  - *private-npm
59
59
  - *docker-ecr-cache
60
- - docker-compose#v4.5.0:
60
+ - docker-compose#v4.9.0:
61
61
  run: app
62
62
  timeout_in_minutes: 10
63
63
 
64
64
  - agents:
65
65
  queue: <%- devBuildkiteQueueName %>
66
- branches: '!renovate--*'
66
+ branches: '!renovate-*'
67
67
  label: 🧖‍♀️ Warm Dev
68
68
  command: ':'
69
69
  plugins:
@@ -1 +1 @@
1
- 16
1
+ 18
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.2
2
2
 
3
- FROM --platform=${BUILDPLATFORM:-arm64} node:16-alpine AS dev-deps
3
+ FROM --platform=${BUILDPLATFORM:-<%- platformName %>} node:18-alpine AS dev-deps
4
4
 
5
5
  WORKDIR /workdir
6
6
 
@@ -157,7 +157,6 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
157
157
  },
158
158
  "Environment": {
159
159
  "Variables": {
160
- "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1",
161
160
  "NODE_ENV": "production",
162
161
  "NODE_OPTIONS": "--enable-source-maps",
163
162
  "SOMETHING": "dev",
@@ -177,7 +176,7 @@ exports[`returns expected CloudFormation stack for dev 1`] = `
177
176
  "Arn",
178
177
  ],
179
178
  },
180
- "Runtime": "nodejs16.x",
179
+ "Runtime": "nodejs18.x",
181
180
  },
182
181
  "Type": "AWS::Lambda::Function",
183
182
  },
@@ -519,7 +518,6 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
519
518
  },
520
519
  "Environment": {
521
520
  "Variables": {
522
- "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1",
523
521
  "NODE_ENV": "production",
524
522
  "NODE_OPTIONS": "--enable-source-maps",
525
523
  "SOMETHING": "prod",
@@ -539,7 +537,7 @@ exports[`returns expected CloudFormation stack for prod 1`] = `
539
537
  "Arn",
540
538
  ],
541
539
  },
542
- "Runtime": "nodejs16.x",
540
+ "Runtime": "nodejs18.x",
543
541
  },
544
542
  "Type": "AWS::Lambda::Function",
545
543
  },
@@ -50,16 +50,16 @@ export class AppStack extends Stack {
50
50
  encryptionMasterKey: kmsKey,
51
51
  });
52
52
 
53
+ const architecture = '<%- lambdaCdkArchitecture %>';
54
+
53
55
  const worker = new aws_lambda.Function(this, 'worker', {
54
- architecture: aws_lambda.Architecture.ARM_64,
56
+ architecture: aws_lambda.Architecture[architecture],
55
57
  code: new aws_lambda.AssetCode('./lib'),
56
- runtime: aws_lambda.Runtime.NODEJS_16_X,
58
+ runtime: aws_lambda.Runtime.NODEJS_18_X,
57
59
  handler: 'app.handler',
58
60
  functionName: '<%- serviceName %>',
59
61
  environmentEncryption: kmsKey,
60
62
  environment: {
61
- // https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-reusing-connections.html
62
- AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
63
63
  NODE_ENV: 'production',
64
64
  // https://nodejs.org/api/cli.html#cli_node_options_options
65
65
  NODE_OPTIONS: '--enable-source-maps',
@@ -18,13 +18,13 @@
18
18
  "devDependencies": {
19
19
  "@aws-cdk/assert": "^2.24.0",
20
20
  "@types/aws-lambda": "^8.10.82",
21
- "@types/node": "16.11.64",
22
- "aws-cdk": "^2.24.0",
23
- "aws-cdk-lib": "^2.24.0",
21
+ "@types/node": "^18.11.9",
22
+ "aws-cdk": "^2.51.1",
23
+ "aws-cdk-lib": "^2.51.1",
24
24
  "constructs": "^10.0.17",
25
25
  "skuba": "*"
26
26
  },
27
27
  "engines": {
28
- "node": ">=16"
28
+ "node": ">=18"
29
29
  }
30
30
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "baseUrl": ".",
4
- "lib": ["ES2020"],
4
+ "lib": ["ES2022"],
5
5
  "outDir": "lib",
6
6
  "paths": {
7
7
  "src": ["src"]
8
8
  },
9
- "target": "ES2020"
9
+ "target": "ES2022"
10
10
  },
11
11
  "exclude": ["lib*/**/*"],
12
12
  "extends": "skuba/config/tsconfig.json"
@@ -2,7 +2,7 @@
2
2
  "dependencies": {},
3
3
  "description": "<%- description %>",
4
4
  "devDependencies": {
5
- "@types/node": "16.11.64",
5
+ "@types/node": "^16.18.3",
6
6
  "commitizen": "^4.2.4",
7
7
  "skuba": "*"
8
8
  },
@@ -2,7 +2,7 @@
2
2
  "dependencies": {},
3
3
  "description": "<%- description %>",
4
4
  "devDependencies": {
5
- "@types/node": "16.11.64",
5
+ "@types/node": "^16.18.3",
6
6
  "commitizen": "^4.2.4",
7
7
  "skuba": "*"
8
8
  },