From a91cd8f86fdec6cf1ab662065a4fd8fe5598b13a Mon Sep 17 00:00:00 2001 From: dungphampt Date: Fri, 6 Feb 2026 23:11:17 +0700 Subject: [PATCH] sentry intergration & upload source map (#4311) --- .github/workflows/image-sentry.yaml | 129 ++++++++++++++++++++++++++++ .github/workflows/image.yaml | 2 - Dockerfile | 50 ++++++++--- pubspec.yaml | 2 +- 4 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/image-sentry.yaml diff --git a/.github/workflows/image-sentry.yaml b/.github/workflows/image-sentry.yaml new file mode 100644 index 000000000..5fa20eae7 --- /dev/null +++ b/.github/workflows/image-sentry.yaml @@ -0,0 +1,129 @@ +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + +name: Build Docker images with Sentry + +permissions: + contents: read + packages: write + id-token: write + +jobs: + build-release-image-with-sentry: + name: Build release image with Sentry + if: github.event_name == 'workflow_dispatch' || (github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v')) + runs-on: ubuntu-latest + environment: prod + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract app version from pubspec.yaml + id: app_version + run: | + VERSION=$(grep '^version:' pubspec.yaml | awk '{print $2}') + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ github.repository_owner }}/tmail-web + ghcr.io/${{ github.repository_owner }}/tmail-web + tags: | + type=ref,event=tag + type=raw,value=release + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push image (release) + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + platforms: linux/amd64,linux/arm64 + cache-from: | + type=gha + cache-to: | + type=gha + build-args: | + FLUTTER_VERSION=3.32.8 + SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG=${{ secrets.SENTRY_ORG }} + SENTRY_PROJECT=${{ secrets.SENTRY_PROJECT }} + SENTRY_URL=${{ secrets.SENTRY_URL }} + SENTRY_RELEASE=${{ steps.app_version.outputs.version }} + GITHUB_SHA=${{ github.sha }} + VCS_REF=${{ github.repository }}@${{ github.sha }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Extract sourcemaps from Docker image + if: always() + run: | + # Get the first image tag (for amd64 platform) + IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1) + + if [ -z "$IMAGE_TAG" ]; then + echo "No image tag found, skipping sourcemap extraction" + exit 0 + fi + + echo "Extracting sourcemaps from image: $IMAGE_TAG" + + # Create temporary container to extract files + CONTAINER_ID=$(docker create --platform linux/amd64 "$IMAGE_TAG" 2>/dev/null | head -n1) + + if [ -n "$CONTAINER_ID" ]; then + echo "Created container: $CONTAINER_ID" + + # Create directory for sourcemaps + mkdir -p sourcemaps + + # Copy all files from container + docker cp "$CONTAINER_ID:/usr/share/nginx/html/." sourcemaps/ 2>/dev/null || true + + # Remove container + docker rm "$CONTAINER_ID" 2>/dev/null || true + + # Filter only .map files and keep directory structure + find sourcemaps -type f ! -name "*.map" -delete 2>/dev/null || true + + echo "Sourcemaps extracted:" + find sourcemaps -name "*.map" | head -10 || echo "No .map files found" + MAP_COUNT=$(find sourcemaps -name "*.map" 2>/dev/null | wc -l) + echo "Total .map files: $MAP_COUNT" + else + echo "Warning: Could not create container from image" + fi + + - name: Upload sourcemaps as artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: sourcemaps-${{ steps.app_version.outputs.version }} + path: sourcemaps/**/*.map + retention-days: 30 + if-no-files-found: warn diff --git a/.github/workflows/image.yaml b/.github/workflows/image.yaml index 1909af458..376461dfb 100644 --- a/.github/workflows/image.yaml +++ b/.github/workflows/image.yaml @@ -2,8 +2,6 @@ on: push: branches: - "master" - tags: - - "v*.*.*" name: Build Docker images diff --git a/Dockerfile b/Dockerfile index 48e3548cd..f4be0e43a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,48 @@ ARG FLUTTER_VERSION=3.32.8 -# Stage 1 - Install dependencies and build the app -# This matches the flutter version on our CI/CD pipeline on Github + FROM --platform=amd64 ghcr.io/instrumentisto/flutter:${FLUTTER_VERSION} AS build-env -# Set directory to Copy App -WORKDIR /app +ARG SENTRY_AUTH_TOKEN +ARG SENTRY_ORG +ARG SENTRY_PROJECT +ARG SENTRY_URL +ARG SENTRY_RELEASE +ARG VCS_REF +ARG GITHUB_SHA +WORKDIR /app COPY . . -# Precompile tmail flutter -RUN ./scripts/prebuild.sh -# Build flutter for web -RUN flutter build web --release --source-maps +ENV GITHUB_SHA=$GITHUB_SHA \ + SENTRY_ORG=$SENTRY_ORG \ + SENTRY_PROJECT=$SENTRY_PROJECT \ + SENTRY_URL=$SENTRY_URL \ + SENTRY_RELEASE=$SENTRY_RELEASE + +RUN ./scripts/prebuild.sh && \ + flutter build web --release --source-maps --dart-define=SENTRY_RELEASE=$SENTRY_RELEASE && \ + if [ -n "$SENTRY_AUTH_TOKEN" ] && [ -n "$SENTRY_ORG" ] && [ -n "$SENTRY_PROJECT" ] && [ -n "$SENTRY_RELEASE" ]; then \ + echo "Sentry configuration detected, uploading sourcemaps..." && \ + curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=2.20.7 bash && \ + sentry-cli releases new "$SENTRY_RELEASE" && \ + sentry-cli sourcemaps upload build/web \ + --org "$SENTRY_ORG" \ + --project "$SENTRY_PROJECT" \ + --auth-token "$SENTRY_AUTH_TOKEN" \ + --release "$SENTRY_RELEASE" \ + --dist "$GITHUB_SHA" \ + --url-prefix "~/" \ + --validate \ + --wait && \ + sentry-cli releases finalize "$SENTRY_RELEASE" && \ + echo "Sentry sourcemaps uploaded successfully"; \ + else \ + echo "Sentry configuration not complete, skipping sourcemap upload"; \ + fi -# Stage 2 - Create the run-time image FROM nginx:alpine RUN apk add gzip COPY --from=build-env /app/server/nginx.conf /etc/nginx COPY --from=build-env /app/build/web /usr/share/nginx/html - -# Record the exposed port EXPOSE 80 - -# Before stating NGinx, re-zip all the content to ensure customizations are propagated -CMD gzip -k -r -f /usr/share/nginx/html/ && nginx -g 'daemon off;' +CMD gzip -k -r -f /usr/share/nginx/html/ && nginx -g 'daemon off;' \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 00844895f..a6e6a08a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -301,7 +301,7 @@ dev_dependencies: patrol_finders: 2.9.0 plugin_platform_interface: 2.1.8 - + dependency_overrides: firebase_core_platform_interface: 4.8.0