From c87da436671d677d1fee276d0932ea7edd431f78 Mon Sep 17 00:00:00 2001 From: Momo Kornher Date: Wed, 8 Nov 2023 13:58:02 +0000 Subject: [PATCH 1/4] feat(jsii-reflect): TypeSystem can be locked to improve reflection performance (#4318) Memoizes additional calls that rely on the typesystem to retrieve type instances. These calls can (theoretically) change when the typesystem is changed. Therefore we cannot assume it's okay to always memoize the first call. To workaround this limitation, we introduce a new mechanism to manually `lock` the typesystem once all assemblies are loaded. We then can start memoizing the additional calls. For example in `awslint` this reduces the runtime against `aws-cdk-lib` by ~20s. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- packages/jsii-reflect/lib/_memoized.ts | 67 ++++++++++++----- packages/jsii-reflect/lib/class.ts | 14 +++- packages/jsii-reflect/lib/method.ts | 2 + packages/jsii-reflect/lib/type-system.ts | 19 +++++ packages/jsii-reflect/lib/type.ts | 2 +- packages/jsii-reflect/test/_memoized.test.ts | 79 ++++++++++++++++++++ 6 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 packages/jsii-reflect/test/_memoized.test.ts diff --git a/packages/jsii-reflect/lib/_memoized.ts b/packages/jsii-reflect/lib/_memoized.ts index 3cc46383ed..9bce919802 100644 --- a/packages/jsii-reflect/lib/_memoized.ts +++ b/packages/jsii-reflect/lib/_memoized.ts @@ -1,7 +1,30 @@ -/* eslint-disable @typescript-eslint/ban-types -- WeakMap demands T extends object */ +import { TypeSystem } from './type-system'; +/* eslint-disable @typescript-eslint/ban-types -- WeakMap demands T extends object */ const CACHE = new WeakMap>(); +function memoizedGet(original: () => any, propertyKey: string): () => any { + return function (this: object): unknown { + let cache = CACHE.get(this); + if (cache == null) { + cache = new Map(); + CACHE.set(this, cache); + } + if (cache.has(propertyKey)) { + const result = cache.get(propertyKey); + if (Array.isArray(result)) { + // Return a copy of arrays as a precaution + return Array.from(result); + } + return result; + } + const result = original.call(this); + // If the result is an array, memoize a copy for safety. + cache.set(propertyKey, Array.isArray(result) ? Array.from(result) : result); + return result; + }; +} + /** * Decorates property readers for readonly properties so that their results are * memoized in a `WeakMap`-based cache. Those properties will consequently be @@ -9,6 +32,10 @@ const CACHE = new WeakMap>(); * * This can only be applied to property accessors (`public get foo(): any`), and not to * property declarations (`public readonly foo: any`). + * + * This should not be applied to any computations relying on a typesystem. + * The typesystem can be changed and thus change the result of the call. + * Use `memoizedWhenLocked` instead. */ export function memoized( _prototype: unknown, @@ -23,23 +50,27 @@ export function memoized( } const original = descriptor.get; - descriptor.get = function memoizedGet(this: object): unknown { - let cache = CACHE.get(this); - if (cache == null) { - cache = new Map(); - CACHE.set(this, cache); - } - if (cache.has(propertyKey)) { - const result = cache.get(propertyKey); - if (Array.isArray(result)) { - // Return a copy of arrays as a precaution - return Array.from(result); - } - return result; + descriptor.get = memoizedGet(original, propertyKey); +} + +export function memoizedWhenLocked( + _prototype: T, + propertyKey: string, + descriptor: PropertyDescriptor, +): void { + if (!descriptor.get) { + throw new Error(`@memoized can only be applied to property getters!`); + } + if (descriptor.set) { + throw new Error(`@memoized can only be applied to readonly properties!`); + } + + const original = descriptor.get; + descriptor.get = function (this: T): unknown { + if (this.system.isLocked) { + return memoizedGet(original, propertyKey).call(this); } - const result = original.call(this); - // If the result is an array, memoize a copy for safety. - cache.set(propertyKey, Array.isArray(result) ? Array.from(result) : result); - return result; + + return original.call(this); }; } diff --git a/packages/jsii-reflect/lib/class.ts b/packages/jsii-reflect/lib/class.ts index 21a8d703d8..866ae8ab83 100644 --- a/packages/jsii-reflect/lib/class.ts +++ b/packages/jsii-reflect/lib/class.ts @@ -1,5 +1,6 @@ import * as jsii from '@jsii/spec'; +import { memoizedWhenLocked } from './_memoized'; import { Assembly } from './assembly'; import { Initializer } from './initializer'; import { InterfaceType } from './interface'; @@ -20,6 +21,7 @@ export class ClassType extends ReferenceType { /** * Base class (optional). */ + @memoizedWhenLocked public get base(): ClassType | undefined { if (!this.spec.base) { return undefined; @@ -60,12 +62,22 @@ export class ClassType extends ReferenceType { /** * Returns list of all base classes (first is the direct base and last is the top-most). + * + * @deprecated use ClassType.ancestors instead */ public getAncestors() { + return this.ancestors; + } + + /** + * Returns list of all base classes (first is the direct base and last is the top-most). + */ + @memoizedWhenLocked + public get ancestors() { const out = new Array(); if (this.base) { out.push(this.base); - out.push(...this.base.getAncestors()); + out.push(...this.base.ancestors); } return out; } diff --git a/packages/jsii-reflect/lib/method.ts b/packages/jsii-reflect/lib/method.ts index 88f326a0fc..78bfad12d8 100644 --- a/packages/jsii-reflect/lib/method.ts +++ b/packages/jsii-reflect/lib/method.ts @@ -1,5 +1,6 @@ import * as jsii from '@jsii/spec'; +import { memoizedWhenLocked } from './_memoized'; import { Assembly } from './assembly'; import { Callable } from './callable'; import { Documentable } from './docs'; @@ -42,6 +43,7 @@ export class Method return this.spec.name; } + @memoizedWhenLocked public get overrides(): Type | undefined { if (!this.spec.overrides) { return undefined; diff --git a/packages/jsii-reflect/lib/type-system.ts b/packages/jsii-reflect/lib/type-system.ts index 6855924fb6..965a9d301a 100644 --- a/packages/jsii-reflect/lib/type-system.ts +++ b/packages/jsii-reflect/lib/type-system.ts @@ -22,6 +22,11 @@ export class TypeSystem { private readonly _cachedClasses = new Map(); + private _locked = false; + public get isLocked(): boolean { + return this._locked; + } + /** * All assemblies in this type system. */ @@ -29,6 +34,16 @@ export class TypeSystem { return Array.from(this._assemblyLookup.values()); } + /** + * Locks the TypeSystem from further changes + * + * Call this once all assemblies have been loaded. + * This allows the reflection to optimize and cache certain expensive calls. + */ + public lock() { + this._locked = true; + } + /** * Load all JSII dependencies of the given NPM package directory. * @@ -164,6 +179,10 @@ export class TypeSystem { } public addAssembly(asm: Assembly, options: { isRoot?: boolean } = {}) { + if (this.isLocked) { + throw new Error('The typesystem has been locked from further changes'); + } + if (asm.system !== this) { throw new Error('Assembly has been created for different typesystem'); } diff --git a/packages/jsii-reflect/lib/type.ts b/packages/jsii-reflect/lib/type.ts index 80d0841e3d..a05722136f 100644 --- a/packages/jsii-reflect/lib/type.ts +++ b/packages/jsii-reflect/lib/type.ts @@ -124,7 +124,7 @@ export abstract class Type implements Documentable, SourceLocatable { return this.getInterfaces(true).some((iface) => iface === base); } if (this.isClassType() && base.isClassType()) { - return this.getAncestors().some((clazz) => clazz === base); + return this.ancestors.some((clazz) => clazz === base); } return false; } diff --git a/packages/jsii-reflect/test/_memoized.test.ts b/packages/jsii-reflect/test/_memoized.test.ts new file mode 100644 index 0000000000..2dc69cb9e3 --- /dev/null +++ b/packages/jsii-reflect/test/_memoized.test.ts @@ -0,0 +1,79 @@ +import { TypeSystem } from '../lib'; +import { memoized, memoizedWhenLocked } from '../lib/_memoized'; + +const accessorSpy = jest.fn(() => 'foobar'); + +class TestClass { + public constructor(public readonly system: TypeSystem) {} + + public get uncached(): string { + return accessorSpy(); + } + + @memoized + public get cached(): string { + return accessorSpy(); + } + + @memoizedWhenLocked + public get cachedWhenLocked(): string { + return accessorSpy(); + } +} + +// eslint-disable-next-line @typescript-eslint/no-empty-function +function noop(_val: unknown) {} + +describe('memoized', () => { + beforeEach(() => { + accessorSpy.mockClear(); + }); + const subject = new TestClass(new TypeSystem()); + + test('cached property is memoized', () => { + // Access the property twice + noop(subject.cached); + noop(subject.cached); + + expect(accessorSpy).toHaveBeenCalledTimes(1); + expect(subject.cached).toBe('foobar'); + }); + + test('uncached property is not memoized', () => { + // Access the property twice + noop(subject.uncached); + noop(subject.uncached); + + expect(accessorSpy).toHaveBeenCalledTimes(2); + expect(subject.uncached).toBe('foobar'); + }); +}); + +describe('memoizedWhenLocked', () => { + let subject: TestClass; + beforeEach(() => { + accessorSpy.mockClear(); + subject = new TestClass(new TypeSystem()); + }); + + test('property is memoized when the typesystem is locked', () => { + // Lock the typesystem to enable memoizing + subject.system.lock(); + + // Access the property twice + noop(subject.cachedWhenLocked); + noop(subject.cachedWhenLocked); + + expect(accessorSpy).toHaveBeenCalledTimes(1); + expect(subject.cachedWhenLocked).toBe('foobar'); + }); + + test('property is not memoized when the typesystem is not locked', () => { + // Access the property twice + noop(subject.cachedWhenLocked); + noop(subject.cachedWhenLocked); + + expect(accessorSpy).toHaveBeenCalledTimes(2); + expect(subject.cachedWhenLocked).toBe('foobar'); + }); +}); From f8c2e0c20ff6937c5dfb3a9ccab9c2f6262fea5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:36:37 +0000 Subject: [PATCH 2/4] chore(deps): Bump golang.org/x/tools from 0.14.0 to 0.15.0 in /packages/@jsii/go-runtime-test/project (#4320) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.14.0 to 0.15.0.
Release notes

Sourced from golang.org/x/tools's releases.

gopls/v0.14.1

This release contains just two changes:

  • A workaround for a regression affecting some users of GOPACKAGESDRIVER: golang/go#63751, for example those using gopls with an older version of Bazel. When the go/packages driver is missing compiler or architecture information, gopls now assumes a default value rather than failing to load package information.
  • A fix for a minor bug in the new "remove unused parameter" refactoring: golang/go#63755. Notably, this bug was discovered via an automated report from someone who had opted in to Go telemetry.
Commits
  • 729e159 go.mod: update golang.org/x dependencies
  • 38ed81a gopls/internal/regtest/marker: porting extract tests
  • bbf8380 gopls/internal/regtest/marker: use golden diffs for suggested fixes
  • 51df92b go/ssa: two minor cleanups
  • e7fb31a internal/cmd/deadcode: rename -format to -f
  • c538b4e internal/cmd/deadcode: add -whylive=function flag
  • b753e58 internal/lsp/helper: fix misspelled "Code generated" comment
  • 2638d66 internal/cmd/deadcode: omit package/func keywords in default output
  • 118c362 gopls/internal/lsp/source: fix signatureHelp with pointer receivers
  • 4124316 gopls/internal/lsp/cache: remove baseCtx from the View
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/tools&package-manager=go_modules&previous-version=0.14.0&new-version=0.15.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- packages/@jsii/go-runtime-test/project/go.mod | 6 +++--- packages/@jsii/go-runtime-test/project/go.sum | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/@jsii/go-runtime-test/project/go.mod b/packages/@jsii/go-runtime-test/project/go.mod index 2df4c28d4c..63f2d81cff 100644 --- a/packages/@jsii/go-runtime-test/project/go.mod +++ b/packages/@jsii/go-runtime-test/project/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/jsii/jsii-calc/go/scopejsiicalclib v0.0.0-devpreview github.com/stretchr/testify v1.8.4 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/tools v0.14.0 + golang.org/x/tools v0.15.0 ) require ( @@ -21,8 +21,8 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/yuin/goldmark v1.4.13 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sys v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/packages/@jsii/go-runtime-test/project/go.sum b/packages/@jsii/go-runtime-test/project/go.sum index f70e5dce91..51e269bb6a 100644 --- a/packages/@jsii/go-runtime-test/project/go.sum +++ b/packages/@jsii/go-runtime-test/project/go.sum @@ -28,12 +28,15 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -50,6 +53,8 @@ golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= @@ -64,6 +69,8 @@ golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 87847254c8a39f6e99383bfa3a375ae6c8d9a8a5 Mon Sep 17 00:00:00 2001 From: Momo Kornher Date: Mon, 13 Nov 2023 19:54:12 +0000 Subject: [PATCH 3/4] feat: make node 18 the default (#4325) Removes testing and superchain releases for EOL Node 16 Deprecation and EOL messages of node versions are automated, so no need to announce or wait. We are well past the promised 30 days support after Node 16 went EOL. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- .github/workflows/docker-images.yml | 6 +- .github/workflows/main.yml | 38 +++++------ packages/@jsii/check-node/src/constants.ts | 7 +- packages/@jsii/check-node/src/index.test.ts | 2 +- packages/@jsii/check-node/src/index.ts | 7 +- .../python-runtime/tests/test_invoke_bin.py | 6 +- superchain/Dockerfile | 4 +- superchain/README.md | 64 +++++++++---------- 8 files changed, 65 insertions(+), 69 deletions(-) diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index 0409219a56..b9daa0fc3b 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -22,8 +22,8 @@ jobs: fail-fast: false matrix: debian: - - 'buster' # 10 - node: ['16', '18', '20'] + - 'buster' # 10 + node: ['18', '20'] include: - debian: 'bullseye' # 11 node: '20' @@ -31,7 +31,7 @@ jobs: node: '20' env: # Node version whose images will be aliased without the -nodeXX segment - DEFAULT_NODE_MAJOR_VERSION: 16 + DEFAULT_NODE_MAJOR_VERSION: 18 steps: - name: Check out uses: actions/checkout@v4 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 884e769d3d..799e338529 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,11 +42,11 @@ jobs: with: distribution: 'zulu' java-version: '8' - - name: Set up Node 16 + - name: Set up Node 18 uses: actions/setup-node@v4 with: cache: yarn - node-version: '16' + node-version: '18' - name: Set up Python 3.7 uses: actions/setup-python@v4 with: @@ -125,11 +125,11 @@ jobs: with: distribution: 'zulu' java-version: '8' - - name: Set up Node 16 + - name: Set up Node 18 uses: actions/setup-node@v4 with: cache: yarn - node-version: '16' + node-version: '18' - name: Set up Python 3.7 uses: actions/setup-python@v4 with: @@ -195,10 +195,10 @@ jobs: dotnet: ['6.0.x'] go: ['1.18'] java: ['8'] - node: ['16'] # EOL 2023-09-11 + node: ['18'] # EOL 2025-04-30 os: [ubuntu-latest] python: ['3.7'] - # Add specific combinations to be tested against "node 14" (to restrict cardinality) + # Add specific combinations to be tested against (to restrict cardinality) include: # Test using Windows - title: 'Windows' @@ -206,7 +206,7 @@ jobs: dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' python: '3.7' # Test using macOS - title: 'macOS' @@ -214,16 +214,9 @@ jobs: dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' python: '3.7' # Test alternate Nodes - - title: 'Node 16' - java: '8' - dotnet: '6.0.x' - go: '1.18' - node: '16' # EOL 2023-09-11 - os: ubuntu-latest - python: '3.7' - title: 'Node 18' java: '8' dotnet: '6.0.x' @@ -243,7 +236,7 @@ jobs: java: '8' dotnet: '7.0.x' go: '1.18' - node: '16' + node: '18' os: ubuntu-latest python: '3.7' # Test alternate Gos @@ -251,7 +244,7 @@ jobs: java: '8' dotnet: '6.0.x' go: '1.19' - node: '16' + node: '18' os: ubuntu-latest python: '3.7' # Test alternate Javas @@ -259,7 +252,7 @@ jobs: java: '11' dotnet: '6.0.x' go: '1.18' - node: '16' + node: '18' os: ubuntu-latest python: '3.7' # Test alternate Pythons @@ -268,28 +261,28 @@ jobs: dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' os: ubuntu-latest - title: 'Python 3.9' python: '3.9' dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' os: ubuntu-latest - title: 'Python 3.10' python: '3.10' dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' os: ubuntu-latest - title: 'Python 3.11' python: '3.11' dotnet: '6.0.x' go: '1.18' java: '8' - node: '16' + node: '18' os: ubuntu-latest runs-on: ${{ matrix.os }} @@ -479,4 +472,3 @@ jobs: with: name: integtest_aws-cdk-lib path: ./node_modules/aws-cdk-lib/dist/ - diff --git a/packages/@jsii/check-node/src/constants.ts b/packages/@jsii/check-node/src/constants.ts index a267bc0b20..def0d5f8eb 100644 --- a/packages/@jsii/check-node/src/constants.ts +++ b/packages/@jsii/check-node/src/constants.ts @@ -35,9 +35,6 @@ export class NodeRelease { endOfLife: new Date('2022-04-30'), supportedRange: '^12.7.0', }), - new NodeRelease(19, { endOfLife: new Date('2023-06-01') }), - - // Currently active releases (as of last edit to this file...) new NodeRelease(16, { endOfLife: new Date('2023-09-11'), supportedRange: '^16.3.0', @@ -46,8 +43,12 @@ export class NodeRelease { endOfLife: new Date('2022-06-01'), supportedRange: '^17.3.0', }), + new NodeRelease(19, { endOfLife: new Date('2023-06-01') }), + + // Currently active releases (as of last edit to this file...) new NodeRelease(18, { endOfLife: new Date('2025-04-30') }), new NodeRelease(20, { endOfLife: new Date('2026-04-30') }), + new NodeRelease(21, { endOfLife: new Date('2024-06-01') }), // Future (planned releases) ]; diff --git a/packages/@jsii/check-node/src/index.test.ts b/packages/@jsii/check-node/src/index.test.ts index 47f5cb8973..b7b5126e19 100644 --- a/packages/@jsii/check-node/src/index.test.ts +++ b/packages/@jsii/check-node/src/index.test.ts @@ -11,7 +11,7 @@ test('tested node releases are correctly registered & supported', () => { // This test is there to ensure house-keeping happens when it should. If we are // testing a given node release, it must not have been EOL for over 60 days. -test(`tested node release (${process.version}) has not ben EOL for more than 60 days`, () => { +test(`tested node release (${process.version}) has not been EOL for more than 60 days`, () => { const { nodeRelease } = NodeRelease.forThisRuntime(); expect(nodeRelease?.endOfLifeDate?.getTime()).toBeGreaterThan( Date.now() - 60 * 86_400_000, diff --git a/packages/@jsii/check-node/src/index.ts b/packages/@jsii/check-node/src/index.ts index 4c9fdbb5f3..aacd28441d 100644 --- a/packages/@jsii/check-node/src/index.ts +++ b/packages/@jsii/check-node/src/index.ts @@ -22,12 +22,13 @@ export function checkNode(envPrefix = 'JSII'): void { if (nodeRelease?.endOfLife) { const silenceVariable = `${envPrefix}_SILENCE_WARNING_END_OF_LIFE_NODE_VERSION`; - const acknowledgeNodeEol = - 'Node14 is now end of life (EOL) as of April 30, 2023. Support of EOL runtimes are only guaranteed for 30 days after EOL. By silencing this warning you acknowledge that you are using an EOL version of Node and will upgrade to a supported version as soon as possible.'; + const silencedVersions = (process.env[silenceVariable] ?? '') + .split(',') + .map((v) => v.trim()); const qualifier = nodeRelease.endOfLifeDate ? ` on ${nodeRelease.endOfLifeDate.toISOString().slice(0, 10)}` : ''; - if (!(process.env[silenceVariable] === acknowledgeNodeEol)) + if (!silencedVersions.includes(nodeRelease.majorVersion.toString())) veryVisibleMessage( bgRed.white.bold, `Node ${nodeRelease.majorVersion} has reached end-of-life${qualifier} and is not supported.`, diff --git a/packages/@jsii/python-runtime/tests/test_invoke_bin.py b/packages/@jsii/python-runtime/tests/test_invoke_bin.py index 8ff6a94271..f4e91fbee5 100644 --- a/packages/@jsii/python-runtime/tests/test_invoke_bin.py +++ b/packages/@jsii/python-runtime/tests/test_invoke_bin.py @@ -23,8 +23,10 @@ def silence_node_deprecation_warnings(): for var in variables: environ[var] = "1" - nodeEolAcknowledgement = "Node14 is now end of life (EOL) as of April 30, 2023. Support of EOL runtimes are only guaranteed for 30 days after EOL. By silencing this warning you acknowledge that you are using an EOL version of Node and will upgrade to a supported version as soon as possible." - environ["JSII_SILENCE_WARNING_END_OF_LIFE_NODE_VERSION"] = nodeEolAcknowledgement + # silence this for the next decades + environ[ + "JSII_SILENCE_WARNING_END_OF_LIFE_NODE_VERSION" + ] = "14,16,18,20,22,24,26,28,30,32,34" # Execute the test yield diff --git a/superchain/Dockerfile b/superchain/Dockerfile index c157ccf7ab..a557605549 100644 --- a/superchain/Dockerfile +++ b/superchain/Dockerfile @@ -232,10 +232,10 @@ COPY superchain/m2-settings.xml /root/.m2/settings.xml # Install Go COPY --from=bindist /opt/golang/go ${GOROOT} -# Install Node 14+ (configurable with '--build-arg NODE_MAJOR_VERSION=xxx') and yarn +# Install Node (configurable with '--build-arg NODE_MAJOR_VERSION=xxx') and yarn # (Put this as late as possible in the Dockerfile so we get to reuse the layer cache # for most of the multiple builds). -ARG NODE_MAJOR_VERSION="16" +ARG NODE_MAJOR_VERSION="18" COPY superchain/gpg/nodesource.asc /tmp/nodesource.asc COPY superchain/gpg/yarn.asc /tmp/yarn.asc RUN apt-key add /tmp/nodesource.asc && rm /tmp/nodesource.asc \ diff --git a/superchain/README.md b/superchain/README.md index 5bd89c07c9..a50226a9e2 100644 --- a/superchain/README.md +++ b/superchain/README.md @@ -8,15 +8,15 @@ required in order to package [jsii] projects in all supported languages. ## Included Language SDKs -SDK | Version -----------------|------------------------------------------- -`OpenJDK 20` | Amazon Corretto `>= 20.0.0` -`.NET SDK` | `>= 6.0.14` -`mono` | `>= 6.8.0.105` -`Javascript` | see [NodeJS and NPM](#nodejs-and-npm) -`PowerShell` | `pwsh >= 7.1.3` -`Python 3` | `python3 >= 3.7.4` with `pip3 >= 20.0.2` -`Go` | `go >= 1.18` +| SDK | Version | +| ------------ | ---------------------------------------- | +| `OpenJDK 20` | Amazon Corretto `>= 20.0.0` | +| `.NET SDK` | `>= 6.0.14` | +| `mono` | `>= 6.8.0.105` | +| `Javascript` | see [NodeJS and NPM](#nodejs-and-npm) | +| `PowerShell` | `pwsh >= 7.1.3` | +| `Python 3` | `python3 >= 3.7.4` with `pip3 >= 20.0.2` | +| `Go` | `go >= 1.18` | ## Image tags @@ -31,9 +31,7 @@ public.ecr.aws/jsii/superchain:-(-node)(-nightly) - `` is the base image tag (e.g: `buster-slim`, `bullseye-slim`, `bookworm-slim`) - The only supported value is `buster-slim` - `` is the major version of node contained in the image - - `14` corresponds to node 14.x, this is the default - - `16` corresponds to node 16.x - - `18` corresponds to node 18.x + - `18` corresponds to node 18.x, this is the default - `20` corresponds to node 20.x - `-nightly` images are released from the `HEAD` of the [`aws/jsii`][jsii] repository and should typically not be used for production workloads @@ -42,12 +40,14 @@ The previous image tags have been discontinued: - `:latest` (users should migrate to `:1-buster-slim`) - `:nightly` (users should migrate to `:1-buster-slim-nightly`) -- `:node10` (users should migrate to `:1-buster-slim-node14`) -- `:node10-nightly` (users should migrate to `:1-buster-slim-node14-nightly`) -- `:node12` (users shoudl migrate to `:1-buster-slim-node14`) -- `:node12-nightly` (users shoudl migrate to `:1-buster-slim-node14-nightly`) -- `:node14` (users shoudl migrate to `:1-buster-slim-node14`) -- `:node14-nightly` (users shoudl migrate to `:1-buster-slim-node14-nightly`) +- `:node10` (users should migrate to `:1-buster-slim-node18`) +- `:node10-nightly` (users should migrate to `:1-buster-slim-node18-nightly`) +- `:node12` (users should migrate to `:1-buster-slim-node18`) +- `:node12-nightly` (users shoudl migrate to `:1-buster-slim-node18-nightly`) +- `:node14` (users should migrate to `:1-buster-slim-node18`) +- `:node14-nightly` (users shoudl migrate to `:1-buster-slim-node18-nightly`) +- `:node16` (users should migrate to `:1-buster-slim-node18`) +- `:node16-nightly` (users shoudl migrate to `:1-buster-slim-node18-nightly`) ## Building @@ -82,20 +82,20 @@ jsii$ docker build [...] --build-arg NODE_MAJOR_VERSION=16 ## Included Tools & Utilities -Tool / Utility | Version ----------------|-------------------------------------------- -`aws` | `>= 2.11.17` -`bundler` | `>= 1.17.3` and `>= 2.1.4` -`docker` | `>= 18.09.9-ce` -`git` | `>= 2.23.1` -`make` | `>= 3.82` -`maven` | `>= 3.6.3` -`openssl` | `>= 1.0.2k-fips` -`rsync` | `>= 3.1.2` -`yarn` | `>= 1.21.1` -`zip` & `unzip`| `>= 6.0-19` -`gh` | `>= 1.9.2` -`sam` | `>= 1.37.0` +| Tool / Utility | Version | +| --------------- | -------------------------- | +| `aws` | `>= 2.11.17` | +| `bundler` | `>= 1.17.3` and `>= 2.1.4` | +| `docker` | `>= 18.09.9-ce` | +| `git` | `>= 2.23.1` | +| `make` | `>= 3.82` | +| `maven` | `>= 3.6.3` | +| `openssl` | `>= 1.0.2k-fips` | +| `rsync` | `>= 3.1.2` | +| `yarn` | `>= 1.21.1` | +| `zip` & `unzip` | `>= 6.0-19` | +| `gh` | `>= 1.9.2` | +| `sam` | `>= 1.37.0` | ## License From a2ab31609d361ac5ceca6c928584ec59f2d705d3 Mon Sep 17 00:00:00 2001 From: Momo Kornher Date: Mon, 13 Nov 2023 23:43:23 +0000 Subject: [PATCH 4/4] fix(kernel): invokeBinScript fails when using symlinked cache (#4324) Invoking bin scripts from jsii packages would fail if the symlinked cache was enabled and the invoked script depended on an other package. The reason for this was that scripts were only invoked with `--preserve-symlinks`, however for "main scripts" (like standalone binaries), we also need to call `--preserve-symlinks-main` on the node process. Note this cannot be tested in the kernel package itself, as it's not possible to invoke the test process with the correct options. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- packages/@jsii/kernel/src/kernel.ts | 11 +++++++++-- packages/@jsii/kernel/src/tar-cache/index.ts | 2 +- packages/jsii-calc/bin/run.ts | 5 +++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/@jsii/kernel/src/kernel.ts b/packages/@jsii/kernel/src/kernel.ts index 7acf8a37c1..5b310ec9a5 100644 --- a/packages/@jsii/kernel/src/kernel.ts +++ b/packages/@jsii/kernel/src/kernel.ts @@ -1371,13 +1371,20 @@ export class Kernel { throw new JsiiFault(`Script with name ${req.script} was not defined.`); } + // Make sure the current NODE_OPTIONS are honored if we shell out to node + const nodeOptions = [...process.execArgv]; + + // When we are using the symlinked version of the cache, we need to preserve both symlink settings for binaries + if (nodeOptions.includes('--preserve-symlinks')) { + nodeOptions.push('--preserve-symlinks-main'); + } + return { command: path.join(packageDir, scriptPath), args: req.args ?? [], env: { ...process.env, - // Make sure the current NODE_OPTIONS are honored if we shell out to node - NODE_OPTIONS: process.execArgv.join(' '), + NODE_OPTIONS: nodeOptions.join(' '), // Make sure "this" node is ahead of $PATH just in case PATH: `${path.dirname(process.execPath)}:${process.env.PATH}`, }, diff --git a/packages/@jsii/kernel/src/tar-cache/index.ts b/packages/@jsii/kernel/src/tar-cache/index.ts index 1bc67cdfa9..7d7fbc0358 100644 --- a/packages/@jsii/kernel/src/tar-cache/index.ts +++ b/packages/@jsii/kernel/src/tar-cache/index.ts @@ -15,7 +15,7 @@ export interface ExtractResult { * When `'hit'`, the data was already present in cache and was returned from * cache. * - * When `'miss'`, the data was extracted into the caache and returned from + * When `'miss'`, the data was extracted into the cache and returned from * cache. * * When `undefined`, the cache is not enabled. diff --git a/packages/jsii-calc/bin/run.ts b/packages/jsii-calc/bin/run.ts index bfa844c8e6..647ffebc53 100755 --- a/packages/jsii-calc/bin/run.ts +++ b/packages/jsii-calc/bin/run.ts @@ -2,11 +2,16 @@ /* eslint-disable no-console */ +import * as calcLib from '@scope/jsii-calc-lib'; + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const runCommand = async () => { console.info('Hello World!'); + // Make sure this binary depends on an external package to test dependencies with invokeBinScript + new calcLib.Number(1); + const args = process.argv.slice(2); if (args.length > 0) { console.info(` arguments: ${args.join(', ')}`);