Skip to content

chore(deps-dev): bump pnpm from 11.1.2 to 11.2.2 in /frontend #1640

chore(deps-dev): bump pnpm from 11.1.2 to 11.2.2 in /frontend

chore(deps-dev): bump pnpm from 11.1.2 to 11.2.2 in /frontend #1640

Workflow file for this run

name: CI and Auto Merge for imgcompress
on:
push:
branches:
- main
- next_rc
- feature/*
- bugfix/*
- enhancements/*
- release/*
- prepare-rc-*
- prepair-rc-*
pull_request:
workflow_dispatch:
inputs:
upload_e2e_artifacts:
description: "Upload E2E test results artifact?"
required: false
default: "false"
upload_feature_flags_artifacts:
description: "Upload feature-flags matrix screenshots / videos artifact? (default on)"
required: false
default: "true"
deploy_nightly:
description: "After E2E tests succeed, trigger the nightly deployment workflow"
type: boolean
required: false
default: false
permissions:
contents: read
# Cancel superseded runs on the same PR / branch so we don't waste minutes
# building stale commits and so auto-merge always acts on the latest CI.
concurrency:
group: ci-auto-merge-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
lint-python:
name: lint Python
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install Ruff
run: |
python -m pip install --upgrade pip
python -m pip install ruff==0.15.14
- name: Run Ruff
run: ruff check backend tests healthcheck.py update_dockerhub_description.py
scan-image:
name: scan local image
needs: lint-python
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Authenticate to dhi.io for DHI base images
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: docker/login-action@v4
with:
registry: dhi.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build local application image
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64
load: true
tags: karimz1/imgcompress:local-scan
cache-from: type=gha,scope=app-linux/amd64
cache-to: type=gha,mode=max,scope=app-linux/amd64
- name: Run Trivy image scan
continue-on-error: true
env:
IMAGE_REF: karimz1/imgcompress:local-scan
SCAN_OUTPUT: scan-result.log
run: ./scripts/runTrivyImageScan.sh
- name: Upload Trivy scan result
if: always()
uses: actions/upload-artifact@v7
with:
name: trivy-scan-result
path: scan-result.log
retention-days: 7
test-backend:
needs: lint-python
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
platform: [ "linux/amd64", "linux/arm64" ]
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Authenticate to dhi.io for DHI base images
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: docker/login-action@v4
with:
registry: dhi.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Dev Container for ${{ matrix.platform }}
uses: docker/build-push-action@v7
with:
context: .devcontainer/
platforms: ${{ matrix.platform }}
load: true
tags: devcontainer:local-test
cache-from: type=gha,scope=devcontainer-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=devcontainer-${{ matrix.platform }}
- name: Run Backend Unit Tests on ${{ matrix.platform }}
run: |
docker run --rm \
--platform=${{ matrix.platform }} \
--entrypoint /bin/sh \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME/.docker/config.json:/root/.docker/config.json:ro" \
-v "$(pwd):/app/" \
-e IS_RUNNING_IN_GITHUB_ACTIONS=$IS_RUNNING_IN_GITHUB_ACTIONS \
--name devcontainer \
devcontainer:local-test /app/scripts/runUnitTests.sh
env:
IS_RUNNING_IN_GITHUB_ACTIONS: true
- name: Run Backend Integration (Docker) Tests on ${{ matrix.platform }}
run: |
docker run --rm \
--platform=${{ matrix.platform }} \
--entrypoint /bin/sh \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME/.docker/config.json:/root/.docker/config.json:ro" \
-v "$(pwd):/app/" \
-e IS_RUNNING_IN_GITHUB_ACTIONS=$IS_RUNNING_IN_GITHUB_ACTIONS \
--name devcontainer \
devcontainer:local-test /app/scripts/runIntegrationTests.sh
env:
IS_RUNNING_IN_GITHUB_ACTIONS: true
test-e2e:
needs: lint-python
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
platform: [ "linux/amd64" ] # works only on amd64 for now; a fix for arm64 is in progress
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Authenticate to dhi.io for DHI base images
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: docker/login-action@v4
with:
registry: dhi.io
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Application Container for ${{ matrix.platform }}
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
load: true
tags: karimz1/imgcompress:local-test
cache-from: type=gha,scope=app-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=app-${{ matrix.platform }}
- name: Run Application Container (Host Networking) for ${{ matrix.platform }}
run: |
docker run --rm -d \
--platform ${{ matrix.platform }} \
--network host \
--name app \
karimz1/imgcompress:local-test web
- name: Wait for Application to be Ready (using localhost) for ${{ matrix.platform }}
run: |
BASE_URL="http://localhost:5000"
echo "Waiting for the application to be ready on ${BASE_URL}..."
max_attempts=120
attempt_num=1
until curl -s --fail "$BASE_URL" > /dev/null; do
if [ "$attempt_num" -eq "$max_attempts" ]; then
echo "Application failed to start after $max_attempts attempts."
exit 1
fi
echo "Waiting for app... attempt $attempt_num"
attempt_num=$((attempt_num+1))
sleep 1
done
echo "Application is up! Continuing..."
- name: Build Dev Container for ${{ matrix.platform }}
uses: docker/build-push-action@v7
with:
context: .devcontainer/
platforms: ${{ matrix.platform }}
load: true
tags: devcontainer:local-test
cache-from: type=gha,scope=devcontainer-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=devcontainer-${{ matrix.platform }}
- name: Make E2E script executable
run: chmod +x ./scripts/run-e2e.sh
- name: Run E2E Tests in Dev Container (Host Networking)
run: |
docker run --rm \
--platform ${{ matrix.platform }} \
--entrypoint /bin/sh \
--network host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME/.docker/config.json:/root/.docker/config.json:ro" \
-v "$(pwd):/app/" \
-e IS_RUNNING_IN_GITHUB_ACTIONS=true \
-e PLAYWRIGHT_BASE_URL=http://localhost:5000 \
--name devcontainer_e2e \
devcontainer:local-test -c "/app/scripts/run-e2e.sh"
- name: Get CPU Architecture
run: echo "ARCH=$(uname -m | sed 's/[^a-zA-Z0-9]//g')" >> $GITHUB_ENV
- name: Ensure E2E Test Results Directory Exists
if: github.event_name == 'workflow_dispatch' && github.event.inputs.upload_e2e_artifacts == 'true'
run: mkdir -p frontend/e2e-test-results
- name: Zip E2E Test Results for ${{ env.ARCH }}
if: github.event_name == 'workflow_dispatch' && github.event.inputs.upload_e2e_artifacts == 'true'
run: |
if [ -d "frontend/e2e-test-results" ] && [ "$(ls -A frontend/e2e-test-results)" ]; then
zip -r e2e-test-results-${{ env.ARCH }}.zip frontend/e2e-test-results
else
echo "No test results found, creating an empty zip."
touch e2e-test-results-${{ env.ARCH }}.zip
fi
- name: Upload E2E Test Results Artifact for ${{ env.ARCH }}
if: github.event_name == 'workflow_dispatch' && github.event.inputs.upload_e2e_artifacts == 'true'
uses: actions/upload-artifact@v7
with:
name: e2e-test-results-${{ env.ARCH }}
path: e2e-test-results-${{ env.ARCH }}.zip
retention-days: 3
test-feature-flags-matrix:
# Job display name reads as the actual user-facing UI state instead of
# a confusing tuple of `disable_* = true/false` (double negative).
name: feature-flags (${{ matrix.scenario }})
needs: lint-python
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
# logo hidden + storage hidden (DISABLE_LOGO=true, DISABLE_STORAGE_MANAGEMENT=true)
- disable_logo: "true"
disable_storage_management: "true"
scenario: "logo HIDDEN | storage HIDDEN"
label: "logo-hidden_storage-hidden"
# logo hidden + storage shown (DISABLE_LOGO=true, DISABLE_STORAGE_MANAGEMENT=false)
- disable_logo: "true"
disable_storage_management: "false"
scenario: "logo HIDDEN | storage SHOWN"
label: "logo-hidden_storage-shown"
# logo shown + storage hidden (DISABLE_LOGO=false, DISABLE_STORAGE_MANAGEMENT=true)
- disable_logo: "false"
disable_storage_management: "true"
scenario: "logo SHOWN | storage HIDDEN"
label: "logo-shown_storage-hidden"
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Application Container
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64
load: true
tags: karimz1/imgcompress:local-test
cache-from: type=gha,scope=app-linux/amd64
cache-to: type=gha,mode=max,scope=app-linux/amd64
- name: Start app — ${{ matrix.scenario }}
run: |
echo "::group::Feature flag configuration for this matrix entry"
echo "Scenario: ${{ matrix.scenario }}"
echo "DISABLE_LOGO: ${{ matrix.disable_logo }} -> Logo $([ '${{ matrix.disable_logo }}' = 'true' ] && echo 'HIDDEN' || echo 'SHOWN')"
echo "DISABLE_STORAGE_MANAGEMENT: ${{ matrix.disable_storage_management }} -> Storage management button $([ '${{ matrix.disable_storage_management }}' = 'true' ] && echo 'HIDDEN' || echo 'SHOWN')"
echo "::endgroup::"
docker run --rm -d \
--platform linux/amd64 \
--network host \
--name app \
-e DISABLE_LOGO=${{ matrix.disable_logo }} \
-e DISABLE_STORAGE_MANAGEMENT=${{ matrix.disable_storage_management }} \
karimz1/imgcompress:local-test web
- name: Wait for Application to be Ready (using localhost)
run: |
BASE_URL="http://localhost:5000"
echo "Waiting for the application to be ready on ${BASE_URL}..."
max_attempts=120
attempt_num=1
until curl -s --fail "$BASE_URL" > /dev/null; do
if [ "$attempt_num" -eq "$max_attempts" ]; then
echo "Application failed to start after $max_attempts attempts."
docker logs --tail 200 app || true
exit 1
fi
echo "Waiting for app... attempt $attempt_num"
attempt_num=$((attempt_num+1))
sleep 1
done
echo "Application is up! Continuing..."
- name: Build Dev Container
uses: docker/build-push-action@v7
with:
context: .devcontainer/
platforms: linux/amd64
load: true
tags: devcontainer:local-test
cache-from: type=gha,scope=devcontainer-linux/amd64
cache-to: type=gha,mode=max,scope=devcontainer-linux/amd64
- name: Make E2E script executable
run: chmod +x ./scripts/run-e2e.sh
- name: Run feature-flags spec — ${{ matrix.scenario }}
run: |
docker run --rm \
--platform linux/amd64 \
--entrypoint /bin/sh \
--network host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$(pwd):/app/" \
-e IS_RUNNING_IN_GITHUB_ACTIONS=true \
-e PLAYWRIGHT_BASE_URL=http://localhost:5000 \
--name devcontainer_flags \
devcontainer:local-test -c "/app/scripts/run-e2e.sh tests/e2e/featureFlagsRuntime_Test.spec.ts"
- name: Stop Application Container
if: always()
run: |
docker stop app || true
docker rm app || true
- name: Ensure feature-flags results directory exists
if: always() && github.event.inputs.upload_feature_flags_artifacts != 'false'
run: mkdir -p frontend/e2e-test-results
- name: Zip feature-flags results — ${{ matrix.scenario }}
if: always() && github.event.inputs.upload_feature_flags_artifacts != 'false'
run: |
if [ -d "frontend/e2e-test-results" ] && [ "$(ls -A frontend/e2e-test-results)" ]; then
zip -r "feature-flags-${{ matrix.label }}.zip" frontend/e2e-test-results
else
echo "No feature-flags results found, creating an empty zip."
touch "feature-flags-${{ matrix.label }}.zip"
fi
- name: Upload feature-flags artifact — ${{ matrix.scenario }}
if: always() && github.event.inputs.upload_feature_flags_artifacts != 'false'
uses: actions/upload-artifact@v7
with:
name: feature-flags-${{ matrix.label }}
path: feature-flags-${{ matrix.label }}.zip
retention-days: 3
test-unverified-formats-api:
# Reader test for the long tail of "Other possible formats" advertised
# by the UI. Brings up the app container, then for each unverified
# extension generates an input file with Pillow, POSTs it to
# /api/compress, downloads the resulting PNG, and asserts it is real
# and non-blank. Blocking — if a format the UI claims to support stops
# working through the public HTTP API in the running image, deploys
# are gated. Read-only formats (no Pillow writer) are skipped with a
# documented reason; skips are not failures.
name: unverified-formats API reader
needs: lint-python
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build Application Container
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64
load: true
tags: karimz1/imgcompress:local-test
cache-from: type=gha,scope=app-linux/amd64
cache-to: type=gha,mode=max,scope=app-linux/amd64
- name: Run Application Container (Host Networking)
run: |
docker run --rm -d \
--platform linux/amd64 \
--network host \
--name app \
karimz1/imgcompress:local-test web
- name: Wait for Application to be Ready
run: |
BASE_URL="http://localhost:5000"
echo "Waiting for the application to be ready on ${BASE_URL}..."
max_attempts=120
attempt_num=1
until curl -s --fail "$BASE_URL/api/health/backend" > /dev/null; do
if [ "$attempt_num" -eq "$max_attempts" ]; then
echo "Application failed to start after $max_attempts attempts."
docker logs --tail 200 app || true
exit 1
fi
echo "Waiting for app... attempt $attempt_num"
attempt_num=$((attempt_num+1))
sleep 1
done
echo "Application is up! Continuing..."
- name: Build Dev Container
uses: docker/build-push-action@v7
with:
context: .devcontainer/
platforms: linux/amd64
load: true
tags: devcontainer:local-test
cache-from: type=gha,scope=devcontainer-linux/amd64
cache-to: type=gha,mode=max,scope=devcontainer-linux/amd64
- name: Run unverified-formats API reader test
run: |
docker run --rm \
--platform linux/amd64 \
--entrypoint /bin/sh \
--network host \
-v "$(pwd):/app/" \
-e IMGCOMPRESS_API_BASE=http://localhost:5000 \
-e IS_RUNNING_IN_GITHUB_ACTIONS=true \
--name devcontainer_unverified_api \
devcontainer:local-test \
-c ". /venv/bin/activate && pytest tests/integration/test_unverified_formats_api.py -s --tb=short -ra"
- name: Stop Application Container
if: always()
run: |
docker stop app || true
docker rm app || true
deploy-nightly:
needs:
- test-backend
- test-e2e
- test-feature-flags-matrix
- test-unverified-formats-api
if: >
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_dispatch' && inputs.deploy_nightly == true)
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Trigger Deployment Workflow (nightly)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPOSITORY: ${{ github.repository }}
DEPLOY_REF: ${{ github.head_ref || github.ref_name }}
run: |
gh api \
--method POST \
"repos/${REPOSITORY}/dispatches" \
-f event_type=deploy \
-f "client_payload[ref]=${DEPLOY_REF}"
auto-merge-dependabot:
needs:
- test-backend
- test-e2e
- test-feature-flags-matrix
- test-unverified-formats-api
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
# Same-branch sibling job: gates on the PR's author (always
# `dependabot[bot]` for a Dependabot PR), so it stays correct even when
# `imgcompress-chan[bot]` is the actor of the most recent push after
# `/chan-fix` has repaired the branch. Also restricted to same-repo PRs
# so fork PRs can't trigger an auto-merge with the chan App token.
if: >
github.event_name == 'pull_request' &&
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Mint imgcompress-chan token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.IMGCOMPRESS_CHAN_APP_ID }}
private-key: ${{ secrets.IMGCOMPRESS_CHAN_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- name: Squash-merge Dependabot PR
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: gh pr merge --squash --delete-branch "$PR_URL"
- name: Trigger Deployment Workflow
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REPOSITORY: ${{ github.repository }}
run: |
gh api \
--method POST \
"repos/${REPOSITORY}/dispatches" \
-f event_type=deploy \
-f "client_payload[ref]=main"