diff --git a/.flake8 b/.flake8 deleted file mode 100644 index c321e71c..00000000 --- a/.flake8 +++ /dev/null @@ -1,5 +0,0 @@ -[flake8] -ignore = E203, E266, E501, W503 -max-line-length = 80 -max-complexity = 18 -select = B,C,E,F,W,T4,B9 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cf7f756..031ef170 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,41 +34,21 @@ jobs: - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: - node-version: 24 + node-version-file: ".node-version" + cache: "npm" - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 id: setup-python with: - python-version: "3.14" + python-version-file: ".python-version" - - name: python - setup dependency cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + - name: python - setup uv + uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 with: - key: venv-${{ runner.os }}-${{ steps.setup_python.outputs.python-version}}-${{ hashFiles('requirements.txt') }} - path: .venv + enable-cache: true - - name: python - install dependencies - run: | - python -m venv .venv - source .venv/bin/activate - python -m pip install -r requirements.txt - echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH - echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV - - - name: python - lint - run: make py-lint - - - name: python - test - run: make py-test - - - name: npm - install dependencies - run: npm ci - - - name: npm - lint - run: make npm-lint - - - name: npm - test - run: make npm-test + - name: build and verify + run: make ci - name: conditionally semantic release if: ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} diff --git a/.github/workflows/update-snapshots.yml b/.github/workflows/update-snapshots.yml index 30f9de67..a6df97a1 100644 --- a/.github/workflows/update-snapshots.yml +++ b/.github/workflows/update-snapshots.yml @@ -66,13 +66,10 @@ jobs: - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: - node-version: 24 + node-version-file: ".node-version" - - name: Install dependencies - run: npm ci - - - name: Update CDK and Jest snapshots - run: make snapshots + - name: Build and update snapshots + run: make build - name: Check for snapshot changes id: check_changes diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..9e2934aa --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.11.1 diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..24ee5b1b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 6fbb752c..00000000 --- a/.tool-versions +++ /dev/null @@ -1,2 +0,0 @@ -nodejs 24 -python 3.14.2 diff --git a/Makefile b/Makefile index fa509591..daa26818 100644 --- a/Makefile +++ b/Makefile @@ -1,78 +1,135 @@ -VENV = .venv/bin - .PHONY: all -all: install-deps build fmt lint test +all: build -.PHONY: install-deps -install-deps: - @echo "=== Running target: install-deps ===" - npm install --ignore-scripts - python3 -m venv .venv && \ - $(VENV)/pip install -r requirements.txt +########################### +# Composite targets +# ########################### .PHONY: build -build: - @echo "=== Running target: build ===" - npm run build # runs build through prepare-script +build: install lint-fix fmt npm-build snapshots + +.PHONY: ci +ci: install lint fmt-check npm-build test + +.PHONY: install +install: py-install npm-install + +.PHONY: lint +lint: py-lint-check npm-lint-check + +.PHONY: lint-fix +lint-fix: py-lint-fix npm-lint-fix + +.PHONY: fmt +fmt: py-fmt-fix npm-fmt-fix + +.PHONY: fmt-check +fmt-check: py-fmt-check npm-fmt-check .PHONY: test -test: npm-test py-test +test: py-test npm-test + +.PHONY: snapshots +snapshots: npm-test-update + +.PHONY: clean +clean: npm-clean py-clean + +.PHONY: clean-all +clean-all: npm-clean-all py-clean-all + + +########################### +# NPM targets +########################### +.PHONY: npm-install +npm-install: +ifeq ($(CI),true) + npm ci +else + npm install --ignore-scripts +endif + +.PHONY: npm-build +npm-build: + npm run build + +.PHONY: npm-fmt-fix +npm-fmt-fix: + npm run fmt + +.PHONY: npm-fmt-check +npm-fmt-check: + npm run fmt:check + +.PHONY: npm-upgrade-deps +npm-upgrade-deps: + npm run upgrade-dependencies +.PHONY: npm-biome-migrate +npm-biome-migrate: + npm run biome-migrate + +.PHONY: npm-test npm-test: - @echo "=== Running target: npm-test ===" npm run test -py-test: - @echo "=== Running target: py-test ===" - TARGET_BUCKET_URL=s3://dummy/web \ - EXPIRE_SECONDS=86400 \ - DEPLOY_LOG_BUCKET_URL=s3://dummy/deployments.log \ - $(VENV)/python -m unittest discover webapp_deploy +.PHONY: npm-test-update +npm-test-update: + npm run test:update -.PHONY: fmt -fmt: +.PHONY: npm-lint-check +npm-lint-check: + npm run lint + +.PHONY: npm-lint-fix +npm-lint-fix: npm run lint:fix - $(VENV)/black webapp_deploy -.PHONY: npm-fmt -npm-fmt: - @echo "=== Running target: npm-fmt ===" - npm run format +.PHONY: npm-clean +npm-clean: + rm -rf dist/ lib/ -.PHONY: py-fmt -py-fmt: - @echo "=== Running target: py-fmt ===" - $(VENV)/black webapp_deploy +.PHONY: npm-clean-all +npm-clean-all: npm-clean + rm -rf node_modules/ -.PHONY: lint -lint: npm-lint py-lint -.PHONY: npm-lint -npm-lint: - @echo "=== Running target: npm-lint ===" - npm run lint +########################### +## Python targets +########################### +.PHONY: py-install +py-install: + uv sync -.PHONY: py-lint -py-lint: - @echo "=== Running target: py-lint ===" - $(VENV)/flake8 --exclude .venv webapp_deploy - $(VENV)/black --check webapp_deploy +.PHONY: py-lint-check +py-lint-check: + uv run ruff check webapp_deploy -.PHONY: snapshots -snapshots: - @echo "=== Running target: snapshots ===" - npm test -- --updateSnapshot +.PHONY: py-lint-fix +py-lint-fix: + uv run ruff check --fix webapp_deploy -.PHONY: clean -clean: - rm -rf dist/ lib/ +.PHONY: py-fmt-fix +py-fmt-fix: + uv run ruff format webapp_deploy -.PHONY: upgrade-deps -upgrade-deps: - @echo "=== Running target: upgrade-deps ===" - npm run upgrade-dependencies +.PHONY: py-fmt-check +py-fmt-check: + uv run ruff format --check webapp_deploy -.PHONY: biome-migrate -biome-migrate: - @echo "=== Running target: biome-migrate ===" - npm run biome-migrate +.PHONY: py-test +py-test: + TARGET_BUCKET_URL=s3://dummy/web \ + EXPIRE_SECONDS=86400 \ + DEPLOY_LOG_BUCKET_URL=s3://dummy/deployments.log \ + uv run python -m unittest discover webapp_deploy + +.PHONY: py-clean +py-clean: + uv run ruff clean + uv clean + +.PHONY: py-clean-all +py-clean-all: py-clean + rm -rf venv diff --git a/README.md b/README.md index 8f9b95a5..de84567f 100644 --- a/README.md +++ b/README.md @@ -55,18 +55,16 @@ aws lambda invoke \ Testing locally: ```bash -python3 -m venv .venv -source .venv/bin/activate -pip install -r requirements.txt +$ uv sync # Adjust to your project. See config.py for full list. -export TARGET_BUCKET_URL=s3://my-website/web -export EXPIRE_SECONDS=86400 -export DEPLOY_LOG_BUCKET_URL=s3://my-website/deployments.log -export CF_DISTRIBUTION_ID=EKJ2IPY1KTEAR1 +$ export TARGET_BUCKET_URL=s3://my-website/web +$ export EXPIRE_SECONDS=86400 +$ export DEPLOY_LOG_BUCKET_URL=s3://my-website/deployments.log +$ export CF_DISTRIBUTION_ID=EKJ2IPY1KTEAR1 # Adjust artifact path. -python -m webapp_deploy.main s3://my-bucket/my-release.tgz +$ uv run python -m webapp_deploy.main s3://my-bucket/my-release.tgz ``` ## Notes diff --git a/build.sh b/build.sh index f8821637..227733eb 100755 --- a/build.sh +++ b/build.sh @@ -8,6 +8,3 @@ cp -r webapp_deploy dist/ if [ -e dist/webapp_deploy/__pycache__ ]; then rm -rf dist/webapp_deploy/__pycache__ fi - -# We currently do not install requirements.txt as the -# items are already present in lambda runtime. diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..6ebdbd45 --- /dev/null +++ b/mise.toml @@ -0,0 +1,5 @@ +[settings] +idiomatic_version_file_enable_tools = ["python", "node"] + +[tools] +uv = "0.9.16" diff --git a/package.json b/package.json index 43c1baa0..8c877cea 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,11 @@ "build": "./build.sh && tsc", "watch": "tsc -w", "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "test:update": "NODE_OPTIONS=--experimental-vm-modules jest --updateSnapshot", "lint": "biome check", "lint:fix": "biome check --fix", + "fmt": "biome format --write", + "fmt:check": "biome format", "prepare": "npm run build && husky", "semantic-release": "semantic-release", "upgrade-dependencies": "ncu --upgrade --install always --format group", diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..c92b855f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[project] +name = "webapp-deploy-lambda" +version = "0.1.0" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "boto3==1.42.3", +] + +[dependency-groups] +dev = [ + "ruff>=0.8.6", +] + +[tool.ruff] +target-version = "py313" + +[tool.ruff.lint] +select = ["B", "C", "E", "F", "W", "B9"] + diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 7b399a5a..00000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -black==25.12.0 -boto3==1.42.4 -flake8==7.3.0 diff --git a/src/__snapshots__/index.test.ts.snap b/src/__snapshots__/index.test.ts.snap index 094d7bbf..ef7a9a1f 100644 --- a/src/__snapshots__/index.test.ts.snap +++ b/src/__snapshots__/index.test.ts.snap @@ -190,7 +190,7 @@ exports[`WebappDeploy 1`] = ` "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-123456789123-eu-west-1", - "S3Key": "68ecf29b534dac690c16738cfdbd0d0dec4f8fa63cd109c3196666432a89ffd0.zip", + "S3Key": "9ca2182f361a76bbc9ba6674672007ccc230e8a993d5f2b115df519fbf27a2c6.zip", }, "Environment": { "Variables": { @@ -489,7 +489,7 @@ exports[`WebappDeploy with source 1`] = ` "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-123456789123-eu-west-1", - "S3Key": "68ecf29b534dac690c16738cfdbd0d0dec4f8fa63cd109c3196666432a89ffd0.zip", + "S3Key": "9ca2182f361a76bbc9ba6674672007ccc230e8a993d5f2b115df519fbf27a2c6.zip", }, "Environment": { "Variables": { diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..98b5c844 --- /dev/null +++ b/uv.lock @@ -0,0 +1,126 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "boto3" +version = "1.42.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4e/b1add2d248d7120ee59df1ca1781a0d5fabdb9e45a477ef50c7598908e80/boto3-1.42.3.tar.gz", hash = "sha256:f7fe002c39806d5efe9105f0d74e836f001230e9520b4502c752dd4951f60041", size = 112797, upload-time = "2025-12-04T18:14:50.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/ac/81fb1f37bef7f29f7d0d4b71eb64c6425917cb230da437b42a2a58335ddf/boto3-1.42.3-py3-none-any.whl", hash = "sha256:163df55a774402fa940e95a152c308a33fb0f49cbcb5ec1725936e48635512f7", size = 140619, upload-time = "2025-12-04T18:14:48.581Z" }, +] + +[[package]] +name = "botocore" +version = "1.42.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/46/5b40b1deb780869ca9f0c1de47062a78a0494b53d6f9d6bad10fc38eef9d/botocore-1.42.5.tar.gz", hash = "sha256:37bfc487f14286d9795920807fcb8318b940835b18fff6bec5253449f377136f", size = 14851117, upload-time = "2025-12-08T20:28:26.876Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/9a/da5e6cabf4da855d182fcdacf3573b69f30899e0e6c3e0d91ce6ad92ce74/botocore-1.42.5-py3-none-any.whl", hash = "sha256:6aa487f1876c881e2143f6a186b7d8faaf042fc05e0ba7421d821f145356a0c9", size = 14525346, upload-time = "2025-12-08T20:28:24.06Z" }, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "ruff" +version = "0.8.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/00/089db7890ea3be5709e3ece6e46408d6f1e876026ec3fd081ee585fef209/ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", size = 3473116, upload-time = "2025-01-04T12:23:00.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/28/aa07903694637c2fa394a9f4fe93cf861ad8b09f1282fa650ef07ff9fe97/ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", size = 10628735, upload-time = "2025-01-04T12:21:53.632Z" }, + { url = "https://files.pythonhosted.org/packages/2b/43/827bb1448f1fcb0fb42e9c6edf8fb067ca8244923bf0ddf12b7bf949065c/ruff-0.8.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", size = 10386758, upload-time = "2025-01-04T12:22:00.349Z" }, + { url = "https://files.pythonhosted.org/packages/df/93/fc852a81c3cd315b14676db3b8327d2bb2d7508649ad60bfdb966d60738d/ruff-0.8.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", size = 10007808, upload-time = "2025-01-04T12:22:04.413Z" }, + { url = "https://files.pythonhosted.org/packages/94/e9/e0ed4af1794335fb280c4fac180f2bf40f6a3b859cae93a5a3ada27325ae/ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", size = 10861031, upload-time = "2025-01-04T12:22:09.252Z" }, + { url = "https://files.pythonhosted.org/packages/82/68/da0db02f5ecb2ce912c2bef2aa9fcb8915c31e9bc363969cfaaddbc4c1c2/ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", size = 10388246, upload-time = "2025-01-04T12:22:12.63Z" }, + { url = "https://files.pythonhosted.org/packages/ac/1d/b85383db181639019b50eb277c2ee48f9f5168f4f7c287376f2b6e2a6dc2/ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", size = 11424693, upload-time = "2025-01-04T12:22:17.244Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b7/30bc78a37648d31bfc7ba7105b108cb9091cd925f249aa533038ebc5a96f/ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", size = 12141921, upload-time = "2025-01-04T12:22:20.456Z" }, + { url = "https://files.pythonhosted.org/packages/60/b3/ee0a14cf6a1fbd6965b601c88d5625d250b97caf0534181e151504498f86/ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", size = 11692419, upload-time = "2025-01-04T12:22:23.62Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d6/c597062b2931ba3e3861e80bd2b147ca12b3370afc3889af46f29209037f/ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", size = 12981648, upload-time = "2025-01-04T12:22:26.663Z" }, + { url = "https://files.pythonhosted.org/packages/68/84/21f578c2a4144917985f1f4011171aeff94ab18dfa5303ac632da2f9af36/ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", size = 11251801, upload-time = "2025-01-04T12:22:29.59Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/1ac02537c8edeb13e0955b5db86b5c050a1dcba54f6d49ab567decaa59c1/ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", size = 10849857, upload-time = "2025-01-04T12:22:33.536Z" }, + { url = "https://files.pythonhosted.org/packages/eb/00/020cb222252d833956cb3b07e0e40c9d4b984fbb2dc3923075c8f944497d/ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", size = 10470852, upload-time = "2025-01-04T12:22:36.374Z" }, + { url = "https://files.pythonhosted.org/packages/00/56/e6d6578202a0141cd52299fe5acb38b2d873565f4670c7a5373b637cf58d/ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", size = 10972997, upload-time = "2025-01-04T12:22:41.424Z" }, + { url = "https://files.pythonhosted.org/packages/be/31/dd0db1f4796bda30dea7592f106f3a67a8f00bcd3a50df889fbac58e2786/ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", size = 11317760, upload-time = "2025-01-04T12:22:44.541Z" }, + { url = "https://files.pythonhosted.org/packages/d4/70/cfcb693dc294e034c6fed837fa2ec98b27cc97a26db5d049345364f504bf/ruff-0.8.6-py3-none-win32.whl", hash = "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", size = 8799729, upload-time = "2025-01-04T12:22:49.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/22/ae6bcaa0edc83af42751bd193138bfb7598b2990939d3e40494d6c00698c/ruff-0.8.6-py3-none-win_amd64.whl", hash = "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905", size = 9673857, upload-time = "2025-01-04T12:22:53.052Z" }, + { url = "https://files.pythonhosted.org/packages/91/f8/3765e053acd07baa055c96b2065c7fab91f911b3c076dfea71006666f5b0/ruff-0.8.6-py3-none-win_arm64.whl", hash = "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", size = 9149556, upload-time = "2025-01-04T12:22:57.173Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/1d/0f3a93cca1ac5e8287842ed4eebbd0f7a991315089b1a0b01c7788aa7b63/urllib3-2.6.1.tar.gz", hash = "sha256:5379eb6e1aba4088bae84f8242960017ec8d8e3decf30480b3a1abdaa9671a3f", size = 432678, upload-time = "2025-12-08T15:25:26.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/56/190ceb8cb10511b730b564fb1e0293fa468363dbad26145c34928a60cb0c/urllib3-2.6.1-py3-none-any.whl", hash = "sha256:e67d06fe947c36a7ca39f4994b08d73922d40e6cca949907be05efa6fd75110b", size = 131138, upload-time = "2025-12-08T15:25:25.51Z" }, +] + +[[package]] +name = "webapp-deploy-lambda" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "boto3" }, +] + +[package.dev-dependencies] +dev = [ + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "boto3", specifier = "==1.42.3" }] + +[package.metadata.requires-dev] +dev = [{ name = "ruff", specifier = ">=0.8.6" }] diff --git a/webapp_deploy/main.py b/webapp_deploy/main.py index 7f714366..ad857b41 100644 --- a/webapp_deploy/main.py +++ b/webapp_deploy/main.py @@ -49,7 +49,7 @@ def check_items(items, expiry): files to be deleted. """ - deployments = list(set([i.time for i in items])) + deployments = list({i.time for i in items}) deployments_old = sorted([i for i in deployments if i < expiry]) if len(deployments_old) <= 1: @@ -57,21 +57,24 @@ def check_items(items, expiry): delete_older_than = deployments_old[-1] - keep_files = list(set([i.filename for i in items if i.time >= delete_older_than])) + keep_files = list({i.filename for i in items if i.time >= delete_older_than}) delete_files = list( - set( - [ - i.filename - for i in items - if i.time < delete_older_than and i.filename not in keep_files - ] - ) + { + i.filename + for i in items + if i.time < delete_older_than and i.filename not in keep_files + } ) return [i for i in items if i.time >= delete_older_than], delete_files +def batch_items(items, batch_size): + for i in range(0, len(items), batch_size): + yield items[i : i + batch_size] + + def cleanup_delete_files(s3_target, files): s3_target_bucket, s3_target_key = parse_s3_url(s3_target) @@ -81,9 +84,7 @@ def cleanup_delete_files(s3_target, files): objects.append({"Key": os.path.join(s3_target_key, filename)}) # S3 delete_objects can only delete 1000 objects at a time - batch_size = 1000 - for i in range(0, len(objects), batch_size): - batch = objects[i : i + batch_size] + for batch in batch_items(objects, 1000): result = s3_client.delete_objects( Bucket=s3_target_bucket, Delete={"Objects": batch} ) @@ -153,7 +154,7 @@ def handle_file(container_path, container_extract): def construct_all_files(temp_dir, s3_upload_key_base): all_files = [] - for root, dirs, files in os.walk(temp_dir): + for root, _dirs, files in os.walk(temp_dir): for filename in files: local_path = os.path.join(root, filename) relpath = os.path.relpath(local_path, temp_dir)