From 34c649cbda08b144f50d3408f4b71e6ab04dce27 Mon Sep 17 00:00:00 2001 From: Mathias Beaulieu-Duncan Date: Mon, 2 Feb 2026 00:57:40 -0500 Subject: [PATCH] Add Android and Linux desktop SDK variants with matrix pipelines Adds Dockerfile.android (Flutter + Android SDK/JDK 17) and Dockerfile.linux (Flutter + clang/cmake/GTK3 for desktop builds). Publish and Scout pipelines now use matrix strategy to build all three variants in parallel. Registry secrets updated to REGISTRY_USERNAME/REGISTRY_PASSWORD. Update-check adds explicit stable channel filter. Co-Authored-By: Claude Opus 4.5 --- .gitea/workflows/publish.yaml | 33 +++++++++----- .gitea/workflows/scout.yaml | 57 ++++++++++++----------- .gitea/workflows/update-check.yaml | 4 +- Dockerfile.android | 72 ++++++++++++++++++++++++++++++ Dockerfile.linux | 55 +++++++++++++++++++++++ 5 files changed, 179 insertions(+), 42 deletions(-) create mode 100644 Dockerfile.android create mode 100644 Dockerfile.linux diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index 04f8e48..b33cdbf 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -7,12 +7,21 @@ on: permissions: contents: read -env: - IMAGE_NAME: gpb-flutter-sdk-web - jobs: build-and-push: runs-on: ubuntu-latest + strategy: + matrix: + include: + - dockerfile: Dockerfile + image_name: gpb-flutter-sdk-web + description: Minimal Flutter SDK for Web/WASM CI builds + - dockerfile: Dockerfile.android + image_name: gpb-flutter-sdk-android + description: Flutter SDK for Android CI builds + - dockerfile: Dockerfile.linux + image_name: gpb-flutter-sdk-linux + description: Flutter SDK for Linux desktop CI builds steps: - name: Checkout code uses: actions/checkout@v3 @@ -32,19 +41,20 @@ jobs: - name: Login to Docker Registry uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} - password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build image for Scout analysis uses: docker/build-push-action@v5 with: context: . + file: ${{ matrix.dockerfile }} platforms: linux/amd64 push: false load: true build-args: | FLUTTER_VERSION=${{ github.event.release.tag_name }} - tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} + tags: ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }} - name: Install Docker Scout run: | @@ -53,12 +63,13 @@ jobs: - name: Docker Scout CVE Scan run: | - docker scout cves ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} --only-severity critical,high + docker scout cves ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }} --only-severity critical,high - name: Build and push with attestations uses: docker/build-push-action@v5 with: context: . + file: ${{ matrix.dockerfile }} platforms: linux/amd64 push: true sbom: true @@ -66,10 +77,10 @@ jobs: build-args: | FLUTTER_VERSION=${{ github.event.release.tag_name }} tags: | - ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} - ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag_type.outputs.tag }} + ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }} + ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ steps.tag_type.outputs.tag }} labels: | - org.opencontainers.image.title=${{ env.IMAGE_NAME }} - org.opencontainers.image.description=Minimal Flutter SDK for Web/WASM CI builds + org.opencontainers.image.title=${{ matrix.image_name }} + org.opencontainers.image.description=${{ matrix.description }} org.opencontainers.image.version=${{ github.event.release.tag_name }} org.opencontainers.image.revision=${{ github.sha }} diff --git a/.gitea/workflows/scout.yaml b/.gitea/workflows/scout.yaml index eb54796..7a7c096 100644 --- a/.gitea/workflows/scout.yaml +++ b/.gitea/workflows/scout.yaml @@ -8,63 +8,62 @@ permissions: contents: read pull-requests: write -env: - IMAGE_NAME: gpb-flutter-sdk-web - jobs: - check-image: + scout: runs-on: ubuntu-latest - outputs: - image_exists: ${{ steps.check.outputs.exists }} + strategy: + matrix: + include: + - dockerfile: Dockerfile + image_name: gpb-flutter-sdk-web + - dockerfile: Dockerfile.android + image_name: gpb-flutter-sdk-android + - dockerfile: Dockerfile.linux + image_name: gpb-flutter-sdk-linux steps: - name: Log in to DockerHub uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} - password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} - name: Check if latest image exists - id: check + id: should_run run: | - if docker manifest inspect ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest > /dev/null 2>&1; then - echo "exists=true" >> $GITHUB_OUTPUT - echo "Latest image found, Scout compare will run" + if docker manifest inspect ${{ vars.REGISTRY }}/${{ matrix.image_name }}:latest > /dev/null 2>&1; then + echo "run=true" >> $GITHUB_OUTPUT + echo "Latest ${{ matrix.image_name }} found, Scout compare will run" else - echo "exists=false" >> $GITHUB_OUTPUT - echo "No latest image found, skipping Scout compare (nothing to compare against)" + echo "run=false" >> $GITHUB_OUTPUT + echo "No latest ${{ matrix.image_name }} found, skipping (nothing to compare against)" fi - scout-amd64: - runs-on: ubuntu-latest - needs: check-image - if: needs.check-image.outputs.image_exists == 'true' - steps: - name: Checkout code + if: steps.should_run.outputs.run == 'true' uses: actions/checkout@v3 - name: Set up Docker Buildx + if: steps.should_run.outputs.run == 'true' uses: docker/setup-buildx-action@v3 - - name: Log in to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} - password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} - - - name: Build amd64 image + - name: Build image + if: steps.should_run.outputs.run == 'true' uses: docker/build-push-action@v5 with: context: . + file: ${{ matrix.dockerfile }} platforms: linux/amd64 push: false load: true - tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 + tags: ${{ vars.REGISTRY }}/${{ matrix.image_name }}:pr-${{ github.event.pull_request.number }} - name: Install Docker Scout + if: steps.should_run.outputs.run == 'true' run: | curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh sh install-scout.sh - - name: Docker Scout Compare (amd64) + - name: Docker Scout Compare + if: steps.should_run.outputs.run == 'true' run: | - docker scout compare ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 --to ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest --ignore-unchanged --only-severity critical,high + docker scout compare ${{ vars.REGISTRY }}/${{ matrix.image_name }}:pr-${{ github.event.pull_request.number }} --to ${{ vars.REGISTRY }}/${{ matrix.image_name }}:latest --ignore-unchanged --only-severity critical,high diff --git a/.gitea/workflows/update-check.yaml b/.gitea/workflows/update-check.yaml index fadfd7e..f2b643b 100644 --- a/.gitea/workflows/update-check.yaml +++ b/.gitea/workflows/update-check.yaml @@ -12,8 +12,8 @@ jobs: - name: Get latest Flutter stable version id: flutter run: | - LATEST=$(curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json \ - | jq -r '.current_release.stable as $hash | .releases[] | select(.hash == $hash) | .version') + RESPONSE=$(curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json) + LATEST=$(echo "$RESPONSE" | jq -r '.current_release.stable as $hash | .releases[] | select(.hash == $hash and .channel == "stable") | .version') echo "version=${LATEST}" >> $GITHUB_OUTPUT echo "Latest Flutter stable: ${LATEST}" diff --git a/Dockerfile.android b/Dockerfile.android new file mode 100644 index 0000000..fa35e25 --- /dev/null +++ b/Dockerfile.android @@ -0,0 +1,72 @@ +FROM debian:bookworm-slim + +ARG FLUTTER_VERSION=3.38.9 +ARG ANDROID_SDK_TOOLS_VERSION=11076708 +ARG ANDROID_COMPILE_SDK=35 +ARG ANDROID_BUILD_TOOLS=35.0.1 + +LABEL org.opencontainers.image.title="gpb-flutter-sdk-android" +LABEL org.opencontainers.image.description="Flutter SDK for Android CI builds" +LABEL org.opencontainers.image.version="${FLUTTER_VERSION}" + +# Install dependencies for Flutter + Android SDK +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + git \ + unzip \ + xz-utils \ + ca-certificates \ + openjdk-17-jdk-headless \ + && rm -rf /var/lib/apt/lists/* + +# Android SDK +ENV ANDROID_HOME=/opt/android-sdk +ENV PATH="${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}" + +RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" && \ + curl -fsSL "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip" \ + -o /tmp/cmdline-tools.zip && \ + unzip -q /tmp/cmdline-tools.zip -d /tmp/cmdline-tools && \ + mv /tmp/cmdline-tools/cmdline-tools "${ANDROID_HOME}/cmdline-tools/latest" && \ + rm -rf /tmp/cmdline-tools.zip /tmp/cmdline-tools + +# Accept licenses and install SDK components +RUN yes | sdkmanager --licenses > /dev/null 2>&1 && \ + sdkmanager --install \ + "platform-tools" \ + "platforms;android-${ANDROID_COMPILE_SDK}" \ + "build-tools;${ANDROID_BUILD_TOOLS}" + +# Flutter SDK +ENV FLUTTER_HOME=/opt/flutter +ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}" + +RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \ + -o /tmp/flutter.tar.xz && \ + tar xf /tmp/flutter.tar.xz -C /opt && \ + rm /tmp/flutter.tar.xz + +RUN git config --global --add safe.directory "${FLUTTER_HOME}" + +# Configure for Android-only +RUN flutter config --enable-android \ + --no-enable-web \ + --no-enable-ios \ + --no-enable-linux-desktop \ + --no-enable-macos-desktop \ + --no-enable-windows-desktop \ + --android-sdk "${ANDROID_HOME}" + +# Precache only Android artifacts +RUN flutter precache --android \ + --no-web \ + --no-ios \ + --no-linux \ + --no-macos \ + --no-windows \ + --no-fuchsia \ + --no-universal + +RUN flutter doctor -v + +WORKDIR /app diff --git a/Dockerfile.linux b/Dockerfile.linux new file mode 100644 index 0000000..535a595 --- /dev/null +++ b/Dockerfile.linux @@ -0,0 +1,55 @@ +FROM debian:bookworm-slim + +ARG FLUTTER_VERSION=3.38.9 + +LABEL org.opencontainers.image.title="gpb-flutter-sdk-linux" +LABEL org.opencontainers.image.description="Flutter SDK for Linux desktop CI builds" +LABEL org.opencontainers.image.version="${FLUTTER_VERSION}" + +# Install dependencies for Flutter + Linux desktop builds +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + git \ + unzip \ + xz-utils \ + ca-certificates \ + clang \ + cmake \ + ninja-build \ + pkg-config \ + libgtk-3-dev \ + liblzma-dev \ + libstdc++-12-dev \ + && rm -rf /var/lib/apt/lists/* + +ENV FLUTTER_HOME=/opt/flutter +ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}" + +RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \ + -o /tmp/flutter.tar.xz && \ + tar xf /tmp/flutter.tar.xz -C /opt && \ + rm /tmp/flutter.tar.xz + +RUN git config --global --add safe.directory "${FLUTTER_HOME}" + +# Configure for Linux desktop only +RUN flutter config --enable-linux-desktop \ + --no-enable-web \ + --no-enable-android \ + --no-enable-ios \ + --no-enable-macos-desktop \ + --no-enable-windows-desktop + +# Precache only Linux artifacts +RUN flutter precache --linux \ + --no-web \ + --no-android \ + --no-ios \ + --no-macos \ + --no-windows \ + --no-fuchsia \ + --no-universal + +RUN flutter doctor -v + +WORKDIR /app