Pin dependency @radix-ui/react-switch to 1.2.6 (#25309) #1994
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI (Docker) | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| push: | |
| # Ref: GHA Filter pattern syntax: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#filter-pattern-cheat-sheet | |
| # Run on pushes to main, release branches, and previous/future major version branches | |
| branches: | |
| - main | |
| - 'v[0-9]+.*' # Matches any release branch, e.g. v6.0.3, v12.1.0 | |
| - '[0-9]+.x' # Matches any major version branch, e.g. 5.x, 23.x | |
| env: | |
| HEAD_COMMIT: ${{ github.sha }} | |
| CACHED_DEPENDENCY_PATHS: | | |
| ${{ github.workspace }}/node_modules | |
| ${{ github.workspace }}/apps/*/node_modules | |
| ${{ github.workspace }}/ghost/*/node_modules | |
| ${{ github.workspace }}/e2e/node_modules | |
| ~/.cache/ms-playwright/ | |
| NODE_VERSION: 22.13.1 | |
| jobs: | |
| setup: | |
| name: Setup | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| IS_DEVELOPMENT: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/5.x' || github.ref == 'refs/heads/6.x' }} | |
| permissions: | |
| pull-requests: read | |
| steps: | |
| - name: Checkout current commit | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.HEAD_COMMIT }} | |
| fetch-depth: 2 | |
| - name: Output GitHub context | |
| if: env.RUNNER_DEBUG == '1' | |
| run: | | |
| echo "GITHUB_EVENT_NAME: ${{ github.event_name }}" | |
| echo "GITHUB_CONTEXT: ${{ toJson(github.event) }}" | |
| - name: Get metadata (push) | |
| if: github.event_name == 'push' | |
| run: | | |
| NUMBER_OF_COMMITS=$(printf "%s\n" '${{ toJson(github.event.commits.*.id) }}' | jq length) | |
| echo "There are $NUMBER_OF_COMMITS commits in this push." | |
| echo "BASE_COMMIT=$(git rev-parse HEAD~$NUMBER_OF_COMMITS)" >> $GITHUB_ENV | |
| - name: Get metadata (pull_request) | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| BASE_COMMIT=$(curl --location --request GET 'https://api.github.com/repos/TryGhost/Ghost/pulls/${{ github.event.pull_request.number }}' --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' | jq -r .base.sha) | |
| echo "Setting BASE_COMMIT to $BASE_COMMIT" | |
| echo "BASE_COMMIT=$BASE_COMMIT" >> $GITHUB_ENV | |
| - name: Check user org membership | |
| id: check_user_org_membership | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| echo "Looking up: ${{ github.triggering_actor }}" | |
| ENCODED_USERNAME=$(printf '%s' '${{ github.triggering_actor }}' | jq -sRr @uri) | |
| LOOKUP_USER=$(curl --write-out "%{http_code}" --silent --output /dev/null --location "https://api.github.com/orgs/tryghost/members/$ENCODED_USERNAME" --header "Authorization: Bearer ${{ secrets.CANARY_DOCKER_BUILD }}") | |
| if [ "$LOOKUP_USER" == "204" ]; then | |
| echo "User is in the org" | |
| echo "is_member=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "User is not in the org" | |
| echo "is_member=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Compute lockfile hash | |
| run: echo "hash=lockfile-${{ hashFiles('yarn.lock') }}" >> "$GITHUB_ENV" | |
| - name: Compute dependency cache key | |
| run: echo "cachekey=dep-cache-${{ hashFiles('yarn.lock') }}-${{ env.HEAD_COMMIT }}" >> "$GITHUB_ENV" | |
| - name: Compute dependency cache restore key | |
| run: | | |
| EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) | |
| echo "DEPENDENCY_CACHE_RESTORE_KEYS<<$EOF" >> "$GITHUB_ENV" | |
| echo "dep-cache-${{ env.hash }}-${{ github.sha }}" >> "$GITHUB_ENV" | |
| echo "dep-cache-${{ env.hash }}" >> "$GITHUB_ENV" | |
| echo "dep-cache" >> "$GITHUB_ENV" | |
| echo "$EOF" >> "$GITHUB_ENV" | |
| - name: Check dependency cache | |
| uses: actions/cache@v4 | |
| id: cache_dependencies | |
| with: | |
| path: ${{ env.CACHED_DEPENDENCY_PATHS }} | |
| key: ${{ env.cachekey }} | |
| restore-keys: ${{ env.IS_DEVELOPMENT == 'false' && env.DEPENDENCY_CACHE_RESTORE_KEYS || 'dep-never-restore'}} | |
| - name: Set up Node | |
| uses: actions/setup-node@v4 | |
| env: | |
| FORCE_COLOR: 0 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install dependencies | |
| run: yarn install --prefer-offline --frozen-lockfile | |
| outputs: | |
| dependency_cache_key: ${{ env.cachekey }} | |
| node_version: ${{ env.NODE_VERSION }} | |
| build: | |
| name: Build & Push | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # We can't access secrets from forks, so we can't push to the registry | |
| # Instead, we upload the image as an artifact, and download it in downstream jobs | |
| - name: Determine build strategy | |
| id: strategy | |
| run: | | |
| IS_FORK_PR="false" | |
| if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then | |
| IS_FORK_PR="true" | |
| fi | |
| IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/ghost-development" | |
| if [ "$IS_FORK_PR" = "true" ]; then | |
| IMAGE_NAME="ghcr.io/${{ github.event.pull_request.head.repo.owner.login }}/ghost-development" | |
| fi | |
| CACHE_KEY=$(echo $IMAGE_NAME | tr '[:upper:]' '[:lower:]') | |
| echo "is-fork-pr=$IS_FORK_PR" >> $GITHUB_OUTPUT | |
| echo "should-push=$( [ "$IS_FORK_PR" = "false" ] && echo "true" || echo "false" )" >> $GITHUB_OUTPUT | |
| echo "should-load=$( [ "$IS_FORK_PR" = "true" ] && echo "true" || echo "false" )" >> $GITHUB_OUTPUT | |
| echo "image-name=$IMAGE_NAME" >> $GITHUB_OUTPUT | |
| echo "cache-key=$CACHE_KEY" >> $GITHUB_OUTPUT | |
| echo "Build Strategy: " | |
| echo " Is fork PR: $IS_FORK_PR" | |
| echo " Should push: $( [ "$IS_FORK_PR" = "false" ] && echo "true" || echo "false" )" | |
| echo " Should load: $( [ "$IS_FORK_PR" = "true" ] && echo "true" || echo "false" )" | |
| echo " Image name: $IMAGE_NAME" | |
| echo " Cache key: $CACHE_KEY" | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ${{ steps.strategy.outputs.image-name }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=sha | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| labels: | | |
| org.opencontainers.image.title=Ghost Development | |
| org.opencontainers.image.description=Ghost development build | |
| org.opencontainers.image.vendor=TryGhost | |
| maintainer=TryGhost | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v6 | |
| id: build | |
| with: | |
| context: . | |
| file: .docker/Dockerfile | |
| push: ${{ steps.strategy.outputs.should-push }} | |
| load: ${{ steps.strategy.outputs.should-load }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| # On PRs: use both main cache and PR-specific cache | |
| # On main: only use main cache | |
| cache-from: | | |
| type=registry,ref=${{ steps.strategy.outputs.cache-key }}:cache-main | |
| ${{ github.event_name == 'pull_request' && format('type=registry,ref={0}:cache-pr-{1}', steps.strategy.outputs.cache-key, github.event.pull_request.number) || '' }} | |
| # Only export cache if we can push (not on fork PRs) | |
| cache-to: ${{ steps.strategy.outputs.should-push == 'true' && format('type=registry,ref={0}:cache-{1},mode=max', steps.strategy.outputs.cache-key, github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'main') || '' }} | |
| - name: Save image as artifact (fork PR) | |
| if: steps.strategy.outputs.is-fork-pr == 'true' | |
| run: | | |
| # Get the first tag from the multi-line tags output | |
| IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1) | |
| echo "Saving image: $IMAGE_TAG" | |
| docker save "$IMAGE_TAG" | gzip > docker-image.tar.gz | |
| echo "Image saved as docker-image.tar.gz" | |
| ls -lh docker-image.tar.gz | |
| - name: Upload image artifact (fork PR) | |
| if: steps.strategy.outputs.is-fork-pr == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docker-image | |
| path: docker-image.tar.gz | |
| retention-days: 1 | |
| outputs: | |
| image-tags: ${{ steps.meta.outputs.tags }} | |
| image-digest: ${{ steps.build.outputs.digest }} | |
| is-fork: ${{ steps.strategy.outputs.is-fork-pr }} | |
| inspect_image: | |
| name: Inspect Docker Image | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| sparse-checkout: | | |
| .github/actions/load-docker-image | |
| - name: Load Docker Image | |
| id: load | |
| uses: ./.github/actions/load-docker-image | |
| with: | |
| is-fork: ${{ needs.build.outputs.is-fork }} | |
| image-tags: ${{ needs.build.outputs.image-tags }} | |
| - name: Inspect image size and layers | |
| shell: bash | |
| run: | | |
| IMAGE_TAG="${{ steps.load.outputs.image-tag }}" | |
| echo "Analyzing Docker image: $IMAGE_TAG" | |
| # Get the image size in bytes | |
| IMAGE_SIZE_BYTES=$(docker inspect "$IMAGE_TAG" --format='{{.Size}}') | |
| # Convert to human readable format | |
| IMAGE_SIZE_MB=$(( IMAGE_SIZE_BYTES / 1024 / 1024 )) | |
| IMAGE_SIZE_GB=$(echo "scale=2; $IMAGE_SIZE_BYTES / 1024 / 1024 / 1024" | bc) | |
| # Format size display based on magnitude | |
| if [ $IMAGE_SIZE_MB -ge 1024 ]; then | |
| IMAGE_SIZE_DISPLAY="${IMAGE_SIZE_GB} GB" | |
| else | |
| IMAGE_SIZE_DISPLAY="${IMAGE_SIZE_MB} MB" | |
| fi | |
| echo "Image size: ${IMAGE_SIZE_DISPLAY}" | |
| # Write to GitHub Step Summary | |
| { | |
| echo "# Docker Image Analysis" | |
| echo "" | |
| echo "**Image:** \`$IMAGE_TAG\`" | |
| echo "" | |
| echo "**Total Size:** ${IMAGE_SIZE_DISPLAY}" | |
| echo "" | |
| echo "## Image Layers" | |
| echo "" | |
| echo "| Size | Layer |" | |
| echo "|------|-------|" | |
| # Get all layers (including 0B ones) | |
| docker history "$IMAGE_TAG" --format "{{.Size}}@@@{{.CreatedBy}}" --no-trunc | \ | |
| while IFS='@@@' read -r size cmd; do | |
| # Clean up the command for display | |
| cmd_clean=$(echo "$cmd" | sed 's/^\/bin\/sh -c //' | sed 's/^#(nop) //' | sed 's/^@@//' | sed 's/|/\\|/g' | cut -c1-80) | |
| if [ ${#cmd} -gt 80 ]; then | |
| cmd_clean="${cmd_clean}..." | |
| fi | |
| echo "| $size | \`${cmd_clean}\` |" | |
| done | |
| } >> $GITHUB_STEP_SUMMARY | |
| test_e2e: | |
| name: E2E Tests (Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}) | |
| runs-on: ubuntu-latest | |
| needs: [build, setup] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shardIndex: [1, 2] | |
| shardTotal: [2] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| # TODO: Build tb-cli in a separate workflow and pull from GHCR instead of building here | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build Tinybird CLI Image | |
| uses: docker/build-push-action@v6 | |
| id: build | |
| with: | |
| context: . | |
| file: .docker/tb-cli/Dockerfile | |
| push: false | |
| load: true | |
| tags: ghost-tb-cli | |
| - name: Load Image | |
| uses: ./.github/actions/load-docker-image | |
| id: load | |
| with: | |
| is-fork: ${{ needs.build.outputs.is-fork }} | |
| image-tags: ${{ needs.build.outputs.image-tags }} | |
| - name: Setup Docker Registry Mirrors | |
| uses: ./.github/actions/setup-docker-registry-mirrors | |
| - name: Pull images | |
| env: | |
| GHOST_IMAGE_TAG: ${{ steps.load.outputs.image-tag }} | |
| run: docker compose -f e2e/compose.yml pull | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Restore caches | |
| uses: ./.github/actions/restore-cache | |
| env: | |
| DEPENDENCY_CACHE_KEY: ${{ needs.setup.outputs.dependency_cache_key }} | |
| - name: Setup Playwright | |
| uses: ./.github/actions/setup-playwright | |
| - name: Run e2e tests | |
| env: | |
| GHOST_IMAGE_TAG: ${{ steps.load.outputs.image-tag }} | |
| run: yarn test:e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} | |
| - name: Upload blob report to GitHub Actions Artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: blob-report-${{ matrix.shardIndex }} | |
| path: e2e/blob-report | |
| retention-days: 1 | |
| - name: Upload test results artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-${{ matrix.shardIndex }} | |
| path: e2e/test-results | |
| retention-days: 7 | |
| merge_reports: | |
| name: Merge Playwright Reports | |
| if: always() && needs.test_e2e.result == 'failure' | |
| needs: [test_e2e, setup] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Restore caches | |
| uses: ./.github/actions/restore-cache | |
| env: | |
| DEPENDENCY_CACHE_KEY: ${{ needs.setup.outputs.dependency_cache_key }} | |
| - name: Download blob reports from GitHub Actions Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: e2e/all-blob-reports | |
| pattern: blob-report-* | |
| merge-multiple: true | |
| - name: Download test results from GitHub Actions Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: e2e/all-test-results | |
| pattern: test-results-* | |
| merge-multiple: true | |
| - name: Merge into HTML Report | |
| run: npx playwright merge-reports --reporter html ./all-blob-reports | |
| working-directory: e2e | |
| - name: Upload HTML report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: e2e/playwright-report | |
| retention-days: 14 | |
| - name: Upload merged test results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: e2e/all-test-results | |
| retention-days: 7 | |
| - name: View Test Report command | |
| run: | | |
| echo -e "::notice::To view the Playwright report locally, run:\n\nREPORT_DIR=\$(mktemp -d) && gh run download ${{ github.run_id }} -n playwright-report -D \"\$REPORT_DIR\" && npx playwright show-report \"\$REPORT_DIR\"" | |
| - name: Comment on PR with test report command | |
| if: github.event_name == 'pull_request' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh pr comment ${{ github.event.pull_request.number }} --body "## E2E Tests Failed | |
| To view the Playwright test report locally, run: | |
| \`\`\`bash | |
| REPORT_DIR=\$(mktemp -d) && gh run download ${{ github.run_id }} -n playwright-report -D \"\$REPORT_DIR\" && npx playwright show-report \"\$REPORT_DIR\" | |
| \`\`\`" |