From 2767ef86eebab0d3771bc4b83c787db6fed564f5 Mon Sep 17 00:00:00 2001 From: Peter Nigh Date: Tue, 28 Apr 2026 12:04:28 -0400 Subject: [PATCH 1/2] fix: Resolve multiple customer-blocking bugs (#126, #131, #132) Fix class-transformer version mismatch (0.3.1 -> 0.5.1) causing silent deserialization failures in generated projects. Remove @ts-ignore from Integer interface so consumers with skipLibCheck:false can compile. Fix timezone-dependent test failure in log-delivery tests. Bump lib version to 1.0.7. Closes #126, #132 --- package.json | 2 +- python/rpdk/typescript/templates/package.json | 2 +- src/interface.ts | 71 ++++++++++--------- tests/lib/log-delivery.test.ts | 8 +-- 4 files changed, 43 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index 4248584..bff0480 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@amazon-web-services-cloudformation/cloudformation-cli-typescript-lib", - "version": "1.0.6", + "version": "1.0.7", "description": "The CloudFormation Resource Provider Development Kit (RPDK) allows you to author your own resource providers that can be used by CloudFormation. This plugin library helps to provide runtime bindings for the execution of your providers by CloudFormation.", "private": false, "main": "dist/index.js", diff --git a/python/rpdk/typescript/templates/package.json b/python/rpdk/typescript/templates/package.json index f644acc..c760bdb 100644 --- a/python/rpdk/typescript/templates/package.json +++ b/python/rpdk/typescript/templates/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "{{lib_name}}": "{{lib_path}}", - "class-transformer": "0.3.1" + "class-transformer": "0.5.1" }, "devDependencies": { "@types/node": "^20.0.0", diff --git a/src/interface.ts b/src/interface.ts index d4ba07e..446ff8e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -66,9 +66,7 @@ export interface Callable, T> { (...args: R): T; } -// @ts-ignore -// eslint-disable-next-line -interface Integer extends BigInt { +interface Integer { /** * Defines the default JSON representation of * Integer (BigInt) to be a number. @@ -78,11 +76,12 @@ interface Integer extends BigInt { /** Returns the primitive value of the specified object. */ valueOf(): integer; + toString(radix?: number): string; + readonly [Symbol.toStringTag]: 'Integer'; } -// @ts-ignore -interface IntegerConstructor extends BigIntConstructor { +interface IntegerConstructor { (value?: bigint | integer | boolean | number | string): bigint; readonly prototype: Integer; /** @@ -96,36 +95,40 @@ interface IntegerConstructor extends BigIntConstructor { /** * Wrapper with additional JSON serialization for bigint type */ -// @ts-ignore -export const Integer: IntegerConstructor = new Proxy(BigInt, { - // @ts-ignore - apply( - target: IntegerConstructor, - _thisArg: unknown, - argArray?: unknown[] - ): integer { - target.prototype.toJSON = function (): number { - return Number(this.valueOf()); - }; - const isSafeInteger = (value: bigint): boolean => { - if ( - value && - (value < BigInt(Number.MIN_SAFE_INTEGER) || - value > BigInt(Number.MAX_SAFE_INTEGER)) - ) { - return false; +export const Integer: IntegerConstructor = new Proxy( + BigInt as unknown as IntegerConstructor, + { + apply( + target: IntegerConstructor, + _thisArg: unknown, + argArray: unknown[] + ): integer { + target.prototype.toJSON = function (): number { + return Number(this.valueOf()); + }; + const isSafeInteger = (value: bigint): boolean => { + if ( + value && + (value < BigInt(Number.MIN_SAFE_INTEGER) || + value > BigInt(Number.MAX_SAFE_INTEGER)) + ) { + return false; + } + return true; + }; + target.isSafeInteger = isSafeInteger; + const value = target( + ...(argArray as [bigint | integer | boolean | number | string]) + ); + if (value && !isSafeInteger(value)) { + throw new RangeError( + `Value is not a safe integer: ${value.toString()}` + ); } - return true; - }; - target.isSafeInteger = isSafeInteger; - // @ts-expect-error argArray is unknown - const value = target(...argArray); - if (value && !isSafeInteger(value)) { - throw new RangeError(`Value is not a safe integer: ${value.toString()}`); - } - return value; - }, -}) as IntegerConstructor; + return value; + }, + } +) as IntegerConstructor; export enum Action { Create = 'CREATE', diff --git a/tests/lib/log-delivery.test.ts b/tests/lib/log-delivery.test.ts index fd0a73b..1b32144 100644 --- a/tests/lib/log-delivery.test.ts +++ b/tests/lib/log-delivery.test.ts @@ -1271,11 +1271,11 @@ describe('when delivering logs', () => { loggerProxy.addLogPublisher(s3Logger); loggerProxy.log('count: [%d]', 5.12); - loggerProxy.log('timestamp: [%s]', new Date('2020-01-01')); + loggerProxy.log('timestamp: [%s]', new Date('2020-01-01').toISOString()); - loggerProxy.log('timestamp: [%s]', new Date('2020-01-02')); - loggerProxy.log('timestamp: [%s]', new Date('2020-01-03')); - loggerProxy.log('timestamp: [%s]', new Date('2020-01-04')); + loggerProxy.log('timestamp: [%s]', new Date('2020-01-02').toISOString()); + loggerProxy.log('timestamp: [%s]', new Date('2020-01-03').toISOString()); + loggerProxy.log('timestamp: [%s]', new Date('2020-01-04').toISOString()); expect(inspect.defaultOptions.depth).toBe(8); await loggerProxy.waitCompletion(); From 7e119db0022cac975a85838789ae636812aca878 Mon Sep 17 00:00:00 2001 From: Peter Nigh Date: Tue, 28 Apr 2026 12:04:50 -0400 Subject: [PATCH 2/2] ci: Modernize CI/CD workflows and tooling Replace macos-12 (removed by GitHub) with macos-13. Drop EOL Python 3.8/3.9, add 3.12. Bump python_requires from >=3.8 to >=3.10. Bump all GitHub Actions to v4. Fix upload-artifact unique name requirement. Fix pre-commit eslint hook: replace mirrors-eslint with local hook using project node_modules to prevent version drift. Bump flake8 5.0.4 -> 7.1.2 and bandit 1.7.1 -> 1.8.3 for Python 3.12 compat. Add PyPI release workflow for automated plugin publishing (requires PYPI_API_KEY_CLOUDFORMATION_CLI_TYPESCRIPT_PLUGIN secret). Add pyproject.toml for PEP 517 build system declaration. Install cloudformation-cli from GitHub master in CI to pick up pkg_resources fix not yet published to PyPI. Bump plugin version to 1.0.5. Closes #131 --- .github/workflows/cd.yml | 32 +++++++++----------- .github/workflows/ci.yml | 45 ++++++++++++++++------------- .github/workflows/pypi-release.yaml | 25 ++++++++++++++++ .gitignore | 2 ++ .pre-commit-config.yaml | 17 +++++------ pyproject.toml | 3 ++ python/rpdk/typescript/__init__.py | 2 +- setup.py | 5 ++-- 8 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/pypi-release.yaml create mode 100644 pyproject.toml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index e87853c..fd38e96 100755 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,4 +1,3 @@ ---- # Continuous Delivery (Release) name: cd @@ -12,8 +11,8 @@ jobs: name: Prepare for NPM runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 20 registry-url: https://registry.npmjs.org/ @@ -28,7 +27,7 @@ jobs: npm pack - name: Upload NPM Artifacts id: upload_npm - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: package-npm path: cfn-rpdk-${{ env.VERSION }}.tgz @@ -36,23 +35,20 @@ jobs: delivery-python: name: Prepare for PyPI runs-on: ubuntu-latest - strategy: - matrix: - python: [3.8] steps: - - uses: actions/checkout@v3 - - name: Setup Python ${{ matrix.python }} - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python }} + python-version: "3.12" - name: Install Dependencies and Package Project id: installing run: | python -m pip install --upgrade pip setuptools wheel python3 setup.py sdist bdist_wheel - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: dist-py${{ matrix.python }} + name: dist-python path: dist delivery-github: @@ -60,15 +56,15 @@ jobs: needs: [delivery-nodejs, delivery-python] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Download NPM Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: package-npm - - name: Download Python 3.8 Artifacts - uses: actions/download-artifact@v3 + - name: Download Python Artifacts + uses: actions/download-artifact@v4 with: - name: dist-py3.8 + name: dist-python path: dist/ - name: List Artifacts run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c36fd9..fab2b97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,3 @@ ---- # Continous Integration name: ci @@ -8,17 +7,29 @@ jobs: build: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: "3.12" + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - name: Install and Build + run: | + npm ci --include=optional + npm run build + - name: TypeScript Tests + run: | + npx jest --ci os_build: runs-on: ${{ matrix.os }} strategy: matrix: os: - ubuntu-latest - - macos-12 # Later versions of ARM-based macOS runners fail because the hypervisor framework required for Docker is not supported - python: [ "3.8", "3.9", "3.10", "3.11"] + - macos-13 + python: [ "3.10", "3.11", "3.12"] node: [ 20 ] env: SAM_CLI_TELEMETRY: "0" @@ -30,14 +41,14 @@ jobs: PIP_LOG_FILE: /tmp/pip.log HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Update Homebrew and save docker version if: runner.os == 'macOS' run: | brew tap homebrew/core cat "$(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/d/docker.rb" > .github/brew-formulae - name: Configure Homebrew docker cache files - uses: actions/cache@v3 + uses: actions/cache@v4 if: runner.os == 'macOS' with: path: | @@ -51,18 +62,12 @@ jobs: run: | brew install docker --cask brew install colima - # Docker engine is no longer available because of licensing - # Alternative Colima is part of the github macOS runner - # SAM v1.47.0+ needed for colima support, unable to use Python 3.6 colima start - # Ensure colima is configured for later user echo "DOCKER_HOST=unix://$HOME/.colima/default/docker.sock" >> $GITHUB_ENV - # Verify Docker docker ps docker --version - # Verify colima colima status - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} cache: 'pip' @@ -72,19 +77,19 @@ jobs: mkdir "$LOG_PATH" pip install --upgrade pip pip install --upgrade setuptools wheel aws-sam-cli -r https://raw.githubusercontent.com/aws-cloudformation/cloudformation-cli/master/requirements.txt + pip install git+https://github.com/aws-cloudformation/cloudformation-cli.git@master pip install . - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} cache: 'npm' - name: Install Dependencies Node.js id: install_nodejs - # Touch needed because of https://github.com/aws/aws-cli/issues/2639 run: | npm ci --include=optional find ./node_modules/* -mtime +10950 -exec touch {} \; npm run build - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.cache/pre-commit/ key: ${{ matrix.os }}-${{ env.pythonLocation }}${{ hashFiles('.pre-commit-config.yaml') }} @@ -100,9 +105,9 @@ jobs: bash codecov.sh -f coverage/ts/coverage-final.json -F unittests -n codecov-typescript - name: Upload Coverage Artifacts id: upload_coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: coverage + name: coverage-${{ matrix.os }}-py${{ matrix.python }} path: coverage/ - name: Run Integration Tests id: integration_testing @@ -140,7 +145,7 @@ jobs: - name: Upload Debug Artifacts id: upload_logs if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: debug-logs + name: debug-logs-${{ matrix.os }}-py${{ matrix.python }} path: ${{ env.LOG_PATH }} diff --git a/.github/workflows/pypi-release.yaml b/.github/workflows/pypi-release.yaml new file mode 100644 index 0000000..912695d --- /dev/null +++ b/.github/workflows/pypi-release.yaml @@ -0,0 +1,25 @@ +# This workflow will release project to PyPI +name: CloudFormation CLI TypeScript Plugin Release +on: + release: + types: [published] +jobs: + build: + if: endsWith(github.ref, '-plugin') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install dependencies + run: | + pip install --upgrade wheel twine + - name: Package project + run: | + python setup.py sdist bdist_wheel + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_KEY_CLOUDFORMATION_CLI_TYPESCRIPT_PLUGIN }} diff --git a/.gitignore b/.gitignore index 227448a..61e4be8 100644 --- a/.gitignore +++ b/.gitignore @@ -141,3 +141,5 @@ node_modules/ coverage/ *.iml +# Kiro IDE +.kiro/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 713a733..4287217 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: - id: check-merge-conflict # - id: check-yaml # have jinja yml templates so skipping this - repo: https://github.com/pycqa/flake8 - rev: "5.0.4" + rev: "7.1.2" hooks: - id: flake8 additional_dependencies: @@ -45,19 +45,18 @@ repos: - id: python-check-mock-methods - id: python-no-log-warn - repo: https://github.com/PyCQA/bandit - rev: 1.7.1 + rev: 1.8.3 hooks: - id: bandit files: "^python/" - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.26.0 + - repo: local hooks: - id: eslint - args: [--fix] - types: [] - files: (.*.js$|.*.ts$) - additional_dependencies: - - eslint@8.21.0 + name: eslint + description: Run eslint from local node_modules + entry: npx eslint --fix + language: system + files: \.(js|ts)$ - repo: local hooks: - id: pylint-local diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4e24dc1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=68.0", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/python/rpdk/typescript/__init__.py b/python/rpdk/typescript/__init__.py index affdd60..e54d992 100644 --- a/python/rpdk/typescript/__init__.py +++ b/python/rpdk/typescript/__init__.py @@ -1,5 +1,5 @@ import logging -__version__ = "1.0.4" +__version__ = "1.0.5" logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/setup.py b/setup.py index a26d836..2e5acb1 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ def find_version(*file_paths): # package_data -> use MANIFEST.in instead include_package_data=True, zip_safe=True, - python_requires=">=3.8", + python_requires=">=3.10", install_requires=[ "cloudformation-cli>=0.1.14", "zipfile38>=0.0.3,<0.2", @@ -60,10 +60,9 @@ def find_version(*file_paths): "Topic :: Software Development :: Code Generators", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], keywords="Amazon Web Services AWS CloudFormation", )