Releases: seek-oss/skuba
v7.4.0
This version of skuba should not require significant upgrade effort for most projects, but it does contain some notable changes:
-
Internal linting and patching have been overhauled to streamline code generation on version upgrades.
To make upgrades easy now and going forward, we recommend setting up GitHub autofixes.
-
New projects will now be initialised with pnpm, along with improved pnpm support.
A future release of skuba may transition existing projects to pnpm. If you'd like to migrate before then, check out the pnpm deep dive.
Continue reading for more details on these changes and other improvements in this release.
Minor Changes
-
lint: Overhaul internal linting system (#1370)
Previously, internal lint rules would not fail a
skuba lint
check but would silently make changes to your working tree. These changes may have never been committed and may have caused subsequent noise when runningskuba format
orskuba lint
.Now, internal linting is now promoted to a top-level tool alongside ESLint, Prettier, and tsc. Rules will report whether changes need to be made, and changes will only be applied in
format
or autofix modes (in CI). As a consequence,skuba lint
may fail upon upgrading to this version if your project has internal lint violations that have been left unaddressed up to this point.You can configure
skuba lint
to automatically push autofixes; this eases adoption of linting rule changes and automatically resolves issues arising from a forgottenskuba format
. You'll need to configure your CI environment to support this feature. See our GitHub autofixes documentation to learn more. -
format: Switch Distroless image from
nodejs-debian11
tonodejs-debian12
(#1381) -
deps: Prettier 3.2 (#1384)
See the release notes for more information.
-
init: Initialise new projects with pnpm (#1289)
New projects based on built-in templates will now use pnpm as their package manager as per updated organisational guidance.
Custom templates will continue to default to Yarn 1.x until a future major version, though you can opt in to pnpm via
skuba.template.js
:module.exports = { + packageManager: 'pnpm', };
-
lint: Manage
.npmrc
for pnpm projects (#1413)skuba now manages a section of
.npmrc
when a project usespnpm
to enable dependency hoisting. It will continue to avoid committing autofixes to the file if it contains auth secrets. -
deps: TypeScript 5.3 (#1324)
This major release includes breaking changes. See the TypeScript 5.3 announcement for more information.
-
lint: Manage
.dockerignore
(#1433)skuba now manages a section of
.dockerignore
for you, ensuring that the file is up to date with the latest enhancements in skuba. -
init: Default to
arm64
platform andmain
branch (#1343) -
init: Run Prettier after templating (#1337)
-
init: Support
main
default branch (#1335) -
lint: Introduce skuba patches (#1274)
This feature adds patches which are run only once on the
lint
orformat
commands following a skuba update. If your build pipeline is utilising autofixes, these changes will be pushed up automatically.
Patch Changes
-
lint: Disable
Promise<void>
return checks in tests (#1366)This works around an existing incompatibility between Koa and the built-in
http.RequestListener
type:const app = new Koa(); const agent = supertest.agent(app.callback()); // ~~~~~~~~~~~~~~ // Promise returned in function argument where a void return was expected. // @typescript-eslint/no-misused-promises
-
deps: picomatch ^3.0.0 (#1309)
-
Jest: Export
Config
type (#1360)This resolves a TypeScript error that could present itself when using
Jest.mergePreset
with thedeclaration
compiler option:TS4082: Default export of the module has or is using private name
ConfigGlobals
. -
template/lambda-sqs-worker: Remove
@aws-sdk/util-utf8-node
library (#1326) -
build, build-package, test: Remove empty export synthesis for Jest setup files (#1274)
isolatedModules
was enabled by default in v5.0.0. To ease this migration, the commands listed above were updated to dynamically synthesise an empty export forjest.setup.ts
andjest.setup.int.ts
files; this compatibility logic has now been removed.Up-to-date projects are unlikely to be affected, but you can easily add an empty export statement to placate the TypeScript compiler:
jest.setup.ts(1,1): error TS1208: 'jest.setup.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.
process.env.ENVIRONMENT = 'test'; + export {};
-
template/lambda-sqs-worker-cdk: Switch to
aws-cdk-lib/assertions
(#1372) -
template/*-rest-api: Set
readonlyRootFilesystem
as a security best practice (#1394) -
template: Use
propagate-environment
for Docker Compose Buildkite plugin (#1392)This simplifies the Docker Compose environment variable configuration required for Buildkite and GitHub integrations.
In your
docker-compose.yml
:services: app: - environment: - # Enable Buildkite + GitHub integrations. - - BUILDKITE - - BUILDKITE_AGENT_ACCESS_TOKEN - - BUILDKITE_BRANCH - - BUILDKITE_BUILD_NUMBER - - BUILDKITE_JOB_ID - - BUILDKITE_PIPELINE_DEFAULT_BRANCH - - BUILDKITE_STEP_ID - - GITHUB_API_TOKEN image: ${BUILDKITE_PLUGIN_DOCKER_IMAGE:-''} init: true volumes: - ./:/workdir # Mount agent for Buildkite annotations. - /usr/bin/buildkite-agent:/usr/bin/buildkite-agent # Mount cached dependencies. - /workdir/node_modules
In your
.buildkite/pipeline.yml
:steps: - commands: - pnpm lint - pnpm test env: # At SEEK, this instructs the build agent to populate the GITHUB_API_TOKEN environment variable for this step. GET_GITHUB_TOKEN: 'please' plugins: - *aws-sm - *private-npm - *docker-ecr-cache - docker-compose#v4.16.0: + environment: + - GITHUB_API_TOKEN + propagate-environment: true run: app
-
template/*-rest-api: Disable dev CloudWatch dashboards for cost savings (#1395)
-
template/lambda-sqs-worker-cdk: Add blue-green deployment, smoke test and version pruning functionality (#1327)
-
template/lambda-sqs-worker*: Set maximum concurrency (#1412)
This prevents messages from going directly to the DLQ when the function reaches its reserved concurrency limit.
-
template/koa-rest-api: Improve input validation error response for Zod unions (#1339)
-
template/lambda-sqs-worker-cdk: Introduce bundling with esbuild,
--hotswap
and--watch
(#1321)This template now uses the
aws_lambda_nodejs.NodejsFunction
construct which uses esbuild to bundle the Lambda function. This reduces cold start time and time to build on CI.The
--hotswap
and--watch
options allow you to rapidly deploy your code changes to AWS, enhancing the developer feedback loop. This change introducesdeploy:hotswap
anddeploy:watch
scripts to thepackage.json
manifest and aDeploy Dev (Hotswap)
step to the Buildkite pipeline. Read more about watch and ...
v7.3.1
Patch Changes
-
deps: Prettier 3.1 (#1314)
See the release notes for more information.
-
init: Fix
skuba.template.js
validation (#1325)This resolves an "Invalid function return type" error on
skuba init
. -
template: Update to Node 20 (#1317)
Consider upgrading the Node.js version for your project across:
.nvmrc
package.json#/engines/node
serverless.yml
@types/node
package version- CI/CD configuration (
.buildkite/pipeline.yml
,Dockerfile
, etc.)
If you are updating your AWS Lambda runtime to
nodejs20.x
, consider reading the release announcement as there are some breaking changes with this upgrade.
v7.3.0
Minor Changes
-
Jest.mergePreset: Propagate root-level configuration options to
projects
(#1294)Jest.mergePreset
now propagates themoduleNameMapper
andtransform
options from root-level configuration to theprojects
array.If you were referencing the base config in the
projects
array:const baseConfig = Jest.mergePreset({ // ... }); export default { ...baseConfig, projects: [ { ...baseConfig, displayName: 'unit', setupFiles: ['<rootDir>/jest.setup.ts'], testPathIgnorePatterns: ['\\.int\\.test\\.ts'], }, { ...baseConfig, displayName: 'integration', setupFiles: ['<rootDir>/jest.setup.ts'], testMatch: ['**/*.int.test.ts'], }, ], };
You can replace it with the following:
export default Jest.mergePreset({ // ... projects: [ { displayName: 'unit', setupFiles: ['<rootDir>/jest.setup.ts'], testPathIgnorePatterns: ['\\.int\\.test\\.ts'], }, { displayName: 'integration', setupFiles: ['<rootDir>/jest.setup.ts'], testMatch: ['**/*.int.test.ts'], }, ], });
The
projects
option allows you to reuse a single Jest config file for different test types. View the Jest documentation for more information. -
Net.waitFor: Use Docker Compose V2 (#1281)
This function now executes
docker compose
under the hood asdocker-compose
stopped receiving updates in July 2023. See the Docker manual for more information. -
lint: Add
prettier-plugin-packagejson
(#1276)This Prettier plugin sorts and formats your
package.json
file.
Patch Changes
-
Git: Handle non-root working directories in
commitAllChanges
(#1269) -
template/koa-rest-api: Fix
app.test.ts
assertions (#1282)Previously, custom
.expect((res) => {})
assertions were incorrectly defined to return false rather than throw an error. The template has been updated to avoid this syntax, but the most straightforward diff to demonstrate the fix is as follows:- await agent.get('/').expect(({ status }) => status !== 404); + await agent.get('/').expect(({ status }) => expect(status).not.toBe(404));
-
template: seek-oss/docker-ecr-cache 2.1 (#1266)
This update brings a new
skip-pull-from-cache
option which is useful onWarm
/Build Cache
steps.At SEEK, our build agents no longer persist their Docker build cache from previous steps. This option allows a preparatory step to proceed on a cache hit without pulling the image from ECR, which can save on average ~1 minute per build for a 2GB Docker image.
-
lint: Resolve infinite autofix loop (#1262)
-
GitHub: Add working directory parameter to
readFileChanges
(#1269)The input
ChangedFiles
need to be evaluated against a working directory. While this is technically a breaking change, we have not found any external usage of the function inSEEK-Jobs
.- GitHub.readFileChanges(changedFiles) + GitHub.readFileChanges(dir, changedFiles)
-
lint: Handle non-root working directories in autofix commits (#1269)
Previously,
skuba lint
could produce surprising autofix commits if it was invoked in a directory other than the Git root. Now, it correctly evaluates its working directory in relation to the Git root, and will only commit file changes within its working directory. -
cli: Migrate from Runtypes to Zod (#1288)
The skuba CLI now uses Zod internally. This should not result in noticeable differences for consumers.
-
template: Mount npm build secret to a separate directory (#1278)
Our templated Buildkite pipelines currently retrieve a temporary
.npmrc
. This file contains an npm read token that allows us to fetch private@seek
-scoped packages.New projects now write this file to
/tmp/
on the Buildkite agent and mount it as a secret to/root/
in Docker. This separation allows you to commit a non-sensitive.npmrc
to your GitHub repository while avoiding accidental exposure of the npm read token. This is especially important if you are migrating a project to pnpm, which houses some of its configuration options in.npmrc
.Existing projects are generally advised to wait until we've paved a cleaner migration path for pnpm.
v7.2.0
Minor Changes
-
deps: TypeScript 5.2 (#1247)
This major release includes breaking changes. See the TypeScript 5.2 announcement for more information.
Patch Changes
-
deps: libnpmsearch 7 (#1255)
-
deps: Prettier 3.0.3 (#1247)
See the release notes for more information.
-
deps: sort-package-json 2.5.1 (#1257)
This should resolve the following TypeScript compiler error:
node_modules/@types/glob/index.d.ts(29,42): error TS2694: Namespace '"node_modules/minimatch/dist/cjs/index"' has no exported member 'IOptions'.
v7.1.1
v7.1.0
Minor Changes
-
format, lint: Skip autofixing on Renovate branches when there is no open pull request (#1226)
This prevents an issue where a Renovate branch can get stuck in the
Edited/Blocked
state without a pull request being raised. -
deps: eslint-config-skuba 3 (#1234)
This major upgrade brings in new rules from typescript-eslint v6.
Diff patch from eslint-config-skuba 2 and eslint-config-skuba 3
{ + '@typescript-eslint/array-type': '...', + '@typescript-eslint/ban-tslint-comment': '...', + '@typescript-eslint/ban-ts-comment': '...', + '@typescript-eslint/class-literal-property-style': '...', + '@typescript-eslint/consistent-generic-constructors': '...', + '@typescript-eslint/consistent-indexed-object-style': '...', + '@typescript-eslint/consistent-type-assertions': '...', + 'dot-notation': '...', + '@typescript-eslint/dot-notation': '...', + '@typescript-eslint/no-base-to-string': '...', + '@typescript-eslint/no-confusing-non-null-assertion': '...', + '@typescript-eslint/no-duplicate-enum-values': '...', + '@typescript-eslint/no-duplicate-type-constituents': '...', + '@typescript-eslint/no-empty-function': '...', + '@typescript-eslint/no-empty-interface': '...', + '@typescript-eslint/no-explicit-any': '...', + '@typescript-eslint/no-non-null-assertion': '...', + '@typescript-eslint/no-redundant-type-constituents': '...', + '@typescript-eslint/no-unsafe-declaration-merging': '...', + '@typescript-eslint/no-unsafe-enum-comparison': '...', + '@typescript-eslint/prefer-for-of': '...', + '@typescript-eslint/prefer-function-type': '...', + '@typescript-eslint/prefer-nullish-coalescing': '...', + '@typescript-eslint/prefer-optional-chain': '...', + '@typescript-eslint/prefer-string-starts-ends-with': '...', - 'no-extra-semi': '...', - '@typescript-eslint/no-extra-semi': '...', }
-
format, lint: Add
pnpm-lock.yaml
to.prettierignore
(#1225) -
deps: esbuild 0.19 (#1236)
-
format, lint: Switch distroless image from
nodejs
tonodejs-debian11
(#1224)skuba format
andskuba lint
will now automatically switch yourgcr.io/distroless/nodejs:18
image togcr.io/distroless/nodejs18-debian11
. This is now the recommended base image for Node.js.
Patch Changes
- template/*-rest-api: Switch distroless image from
nodejs:18
tonodejs18-debian11
(#1224)
v7.0.1
Patch Changes
-
test: Fix Prettier snapshot formatting (#1220)
Jest is not yet compatible with Prettier 3, causing snapshot updates to fail with the following error:
TypeError: prettier.resolveConfig.sync is not a function at runPrettier (node_modules/jest-snapshot/build/InlineSnapshots.js:308:30)
Our Jest preset now implements custom formatting as a workaround until jestjs/jest#14305 is resolved.
If you do not use our preset, you can temporarily disable formatting in your
jest.config.ts
then manually runskuba format
after updating snapshots:export default { + prettierPath: null, }
v7.0.0
Major Changes
-
deps: tsconfig-seek 2 (#1175)
This change sets the
noUncheckedIndexedAccess
compiler option totrue
by default.This will flag possible issues with indexed access of arrays and records.
Before:
const a: string[] = []; const b = a[0]; // ^? const b: string
After:
const a: string[] = []; const b = a[0]; // ^? const b: string | undefined
Unfortunately, this change is a double edged sword as your previous code which may look like this may now be invalid.
if (list.length === 3) { const b = list[1]; // ^? const b: string | undefined }
To address this you will need to also explicitly check the index you are accessing.
if (list.length === 3 && list[1]) { const b = list[1]; // ^? const b: string }
This may seem like overkill, however, when you consider that Javascript will also allow this it may make sense
const a: string[] = []; a[1000] = 'foo'; console.log(a.length); // 1001
Similarly with accessing records:
const foo: Record<string, string> = {foo: 'bar'}; const func = (a: string) => { if (foo[a]) { const bar = foo[a] // ^? const bar: string | undefined } }
To address this you will need to pull
foo[a]
out into a variable as Typescript does not support type narrowing for indexed access one[k]
wherek
is not a literal.const foo: Record<string, string> = {foo: 'bar'}; const func = (a: string) => { const b = foo[a]; if (b) { const bar = b; // ^? const bar: string } }
You can override this setting in your project's
tsconfig.json
by setting it to false.{ "compilerOptions": { "noUncheckedIndexedAccess": false } }
-
deps: Require Node.js 18.12+ (#1206)
Node.js 16 will reach end of life by September 2023. We have aligned our version support with sku 12.
Consider upgrading the Node.js version for your project across:
.nvmrc
package.json#/engines/node
@types/node
package version- CI/CD configuration (
.buildkite/pipeline.yml
,Dockerfile
, etc.)
Minor Changes
-
deps: esbuild 0.18 (#1190)
skuba build
will continue to infertarget
fromtsconfig.json
at this time. See the esbuild release notes for other details. -
format, lint: Have Prettier respect
.gitignore
(#1217)This aligns with the behaviour of the Prettier 3.0 CLI.
-
deps: TypeScript 5.1 (#1183)
This major release includes breaking changes. See the TypeScript 5.1 announcement for more information.
-
deps: Prettier 3.0 (#1202)
See the release notes for more information.
Patch Changes
-
template: Require Node.js 18.12+ (#1206)
-
template/oss-npm-package: Set
publishConfig.provenance
totrue
(#1182)See https://github.blog/2023-04-19-introducing-npm-package-provenance/ for more information.
-
template/lambda-sqs-worker: Change some info logs to debug (#1178)
The "Function succeeded" log message was changed from
info
todebug
to reduce the amount of unnecessary logs in production. The message will still be logged in dev environments but at adebug
level. -
tsconfig: Turn off
noUnusedLocals
andnoUnusedParameters
(#1181)SEEK's ESLint config has a rule which works for both function and types. We do not need both tools to do the same thing and ESLint has better support for ignoring files if needed.
-
lint: Resolve Git root before attempting to autofix (#1215)
-
configure: Resolve Git root before attempting to patch Renovate config (#1215)
-
template/lambda-sqs-worker: Bump aws-sdk-client-mock to 3.0.0 (#1197)
AWS SDK v3.363.0 shipped with breaking type changes.
v6.2.0
Minor Changes
-
build, build-package: Add a skuba config key named
assets
to copy assets to the output directory. (#1163)In your
package.json
:{ "skuba": { + "assets": [ + "**/*.vocab/*translations.json" + ], "entryPoint": "src/index.ts", "type": "package", } }
This will instruct skuba to copy the files matching the list of globs to the output directory/ies, preserving the directory structure from the source:
- for
skuba build-package
it will copy them tolib-commonjs
andlib-es2015
- for
skuba build
it will copy them totsconfig.json#/compilerOptions.outDir
(lib
by default)
- for
Patch Changes
-
template: Include manifest files in CODEOWNERS (#1162)
Our templates previously excluded
package.json
andyarn.lock
from CODEOWNERS. This was intended to support advanced workflows such as auto-merging PRs and augmenting GitHub push notifications with custom tooling. However, we are reverting this configuration as it is more common for SEEKers to prefer a simpler CODEOWNERS-based workflow.This will not affect existing projects. If you create a new project and wish to restore the previous behaviour, you can manually extend
.github/CODEOWNERS
:* @<%- ownerName %> + # Configured by Renovate + package.json + yarn.lock
-
deps: Bump @octokit dependencies (#1174)
This should resolve the following compiler error:
error TS2339: Property 'annotations' does not exist on type '{}'.
-
deps: ts-jest ^29.1.0 (#1166)
This resolves the following
skuba test
warning:Version 5.0.2 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=4.3.0 <5.0.0-0). Please do not report issues in ts-jest if you are using unsupported versions.
-
template/*-rest-api: Remove Gantry
ignoreAlarms
override (#1160)This issue has been resolved in Gantry v2.2.0; see its release notes for more information.
deployment: - # SEEK-Jobs/gantry#488 - ignoreAlarms: true
v6.1.0
Minor Changes
-
deps: eslint-config-skuba 2 (#1155)
This major upgrade removes eslint-plugin-react due to configuration issues experienced on non-React projects.
Raise a GitHub issue or send us a Slack message if this negatively affects your project.
-
start: Add
http.Server
support (#1159)skuba start
can now be used to create a live-reloading server forhttp.Server
instances. See theskuba start
documentation for more information. -
deps: eslint-config-seek 11 (#1155)
This major upgrade enforces consistent type imports and exports.
- import { Context } from 'aws-lambda'; + import type { Context } from 'aws-lambda';
skuba format
will modify your imports and exports to be consistent with linting rules. These changes are automatically committed if you have GitHub autofixes enabled on your project.