diff --git a/.github/workflows/cleanup-pr-preview.yml b/.github/workflows/cleanup-pr-preview.yml new file mode 100644 index 000000000..eb31fbbb8 --- /dev/null +++ b/.github/workflows/cleanup-pr-preview.yml @@ -0,0 +1,35 @@ +name: Cleanup PR Preview + +on: + pull_request: + types: [closed] + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Setup kubectl + uses: azure/setup-kubectl@v2.0 + + - name: Set Kubernetes context + uses: Azure/k8s-set-context@v2 + with: + kubeconfig: ${{ secrets.KUBE_CONFIG }} + + - name: Delete preview resources + run: | + PR_NUMBER="${{ github.event.pull_request.number }}" + + echo "Cleaning up preview resources for PR #${PR_NUMBER}..." + + # Delete deployment, service, and ingress + kubectl delete deployment sparrow-web-pr-${PR_NUMBER} \ + --namespace=sparrow-preview --ignore-not-found=true + + kubectl delete service sparrow-web-pr-${PR_NUMBER} \ + --namespace=sparrow-preview --ignore-not-found=true + + kubectl delete ingress sparrow-web-pr-${PR_NUMBER} \ + --namespace=sparrow-preview --ignore-not-found=true + + echo "✅ Preview resources cleaned up for PR #${PR_NUMBER}" diff --git a/.github/workflows/pr-build-trigger.yml b/.github/workflows/pr-build-trigger.yml index 536ee2ceb..4582677c9 100644 --- a/.github/workflows/pr-build-trigger.yml +++ b/.github/workflows/pr-build-trigger.yml @@ -79,7 +79,7 @@ jobs: const branch = pr.data.head.ref; const sha = pr.data.head.sha; - const repo = pr.data.base.repo.full_name; + const repo = pr.data.head.repo.full_name; const pr_number = pr.data.number; console.log(`Branch : ${branch}`); @@ -176,14 +176,19 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: [ - "🚀 **Build triggered** for branch `${{ needs.validate.outputs.branch }}` from `${{ needs.validate.outputs.repo }}`.", + "🚀 **Builds triggered** for branch `${{ needs.validate.outputs.branch }}` from `${{ needs.validate.outputs.repo }}`.", "", - "⏳ Build is currently in progress. You will receive a status update here once it completes." + "| Build | Type |", + "|-------|------|", + "| Desktop App (Win/Mac) | Binary |", + "| Webapp Preview | Docker + K8s |", + "", + "⏳ Builds are currently in progress. You will receive status updates here once they complete." ].join("\n") }); # Step 3 — Dispatch the PR build workflow with the source branch and repository - - name: Trigger PR Build Workflow + - name: Trigger Desktop PR Build Workflow id: dispatch uses: benc-uk/workflow-dispatch@v1 with: @@ -192,6 +197,16 @@ jobs: inputs: '{"branch": "${{ needs.validate.outputs.branch }}", "repository": "${{ needs.validate.outputs.repo }}", "pr_number": "${{ needs.validate.outputs.pr_number }}"}' token: ${{ secrets.PAT_TOKEN }} + # Step 3b — Dispatch the Webapp Preview workflow + - name: Trigger Webapp Preview Workflow + id: dispatch_webapp + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: sparrow-webapp-pr-preview.yml + ref: main + inputs: '{"branch": "${{ needs.validate.outputs.branch }}", "repository": "${{ needs.validate.outputs.repo }}", "pr_number": "${{ needs.validate.outputs.pr_number }}"}' + token: ${{ secrets.PAT_TOKEN }} + # Step 4 — Set commit status to success after dispatch # (Scenario 4 — build feedback posted to PR) - name: Set commit status — success @@ -219,9 +234,14 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: [ - "✅ **Build dispatched successfully** for branch `${{ needs.validate.outputs.branch }}` from `${{ needs.validate.outputs.repo }}`.", + "✅ **Builds dispatched successfully** for branch `${{ needs.validate.outputs.branch }}` from `${{ needs.validate.outputs.repo }}`.", + "", + "| Build | Status |", + "|-------|--------|", + "| Desktop App | 🚀 Dispatched |", + "| Webapp Preview | 🚀 Dispatched |", "", - "You can monitor the build progress in the [Actions tab](https://github.com/${{ github.repository }}/actions)." + "You can monitor progress in the [Actions tab](https://github.com/${{ github.repository }}/actions)." ].join("\n") }); diff --git a/.github/workflows/sparrow-app-pr-build.yml b/.github/workflows/sparrow-app-pr-build.yml index 9b91baf2b..5ee5c663b 100644 --- a/.github/workflows/sparrow-app-pr-build.yml +++ b/.github/workflows/sparrow-app-pr-build.yml @@ -342,6 +342,7 @@ jobs: } $msiFileName = $msiFile.Name $msiUrl = "https://sparrow-release-assests-dev.s3.us-west-1.amazonaws.com/windows/$msiFileName" + $webappPreviewUrl = "https://pr-${{ inputs.pr_number }}.preview.sparrowapp.dev" $buildDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $body = @{ "type" = "message" @@ -359,7 +360,7 @@ jobs: } @{ "type" = "TextBlock" - "text" = "Repository: ${{ inputs.repository }}" + "text" = "Fork Repository: ${{ inputs.repository }}" "wrap" = $true } @{ @@ -369,7 +370,7 @@ jobs: } @{ "type" = "TextBlock" - "text" = "PR: [View Pull Request](https://github.com/${{ inputs.repository }}/pull/${{ inputs.pr_number }})" + "text" = "PR: [View Pull Request](https://github.com/sparrowapp-dev/sparrow-app/pull/${{ inputs.pr_number }})" "wrap" = $true } @{ @@ -384,6 +385,11 @@ jobs: "title" = "📥 Download Windows Installer (.msi)" "url" = $msiUrl } + @{ + "type" = "Action.OpenUrl" + "title" = "🌐 Open Webapp Preview" + "url" = $webappPreviewUrl + } ) "$schema" = "http://adaptivecards.io/schemas/adaptive-card.json" "version" = "1.2" @@ -497,6 +503,7 @@ jobs: ARM64_FILENAME="$(basename "${ARM64_DMG%.dmg}").dmg" ARM64_URL="https://sparrow-release-assests-dev.s3.us-west-1.amazonaws.com/macos/$ARM64_FILENAME" + WEBAPP_PREVIEW_URL="https://pr-${{ inputs.pr_number }}.preview.sparrowapp.dev" curl -H "Content-Type: application/json" -d "{ \"type\": \"message\", @@ -514,7 +521,7 @@ jobs: }, { \"type\": \"TextBlock\", - \"text\": \"Repository: ${{ inputs.repository }}\", + \"text\": \"Fork Repository: ${{ inputs.repository }}\", \"wrap\": true }, { @@ -524,7 +531,7 @@ jobs: }, { \"type\": \"TextBlock\", - \"text\": \"PR: [View Pull Request](https://github.com/${{ inputs.repository }}/pull/${{ inputs.pr_number }})\", + \"text\": \"PR: [View Pull Request](https://github.com/sparrowapp-dev/sparrow-app/pull/${{ inputs.pr_number }})\", \"wrap\": true }, { @@ -538,6 +545,11 @@ jobs: \"type\": \"Action.OpenUrl\", \"title\": \"📥 Download Apple Silicon (arm64)\", \"url\": \"$ARM64_URL\" + }, + { + \"type\": \"Action.OpenUrl\", + \"title\": \"🌐 Open Webapp Preview\", + \"url\": \"$WEBAPP_PREVIEW_URL\" } ], \"\$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\", diff --git a/.github/workflows/sparrow-webapp-pr-preview.yml b/.github/workflows/sparrow-webapp-pr-preview.yml new file mode 100644 index 000000000..3471ea7e6 --- /dev/null +++ b/.github/workflows/sparrow-webapp-pr-preview.yml @@ -0,0 +1,183 @@ +name: Webapp PR Preview + +on: + workflow_dispatch: + inputs: + branch: + description: 'Branch to build' + required: true + type: string + repository: + description: 'Repository to build from (e.g., owner/repo)' + required: true + type: string + default: 'sparrowapp-dev/sparrow-app' + pr_number: + description: 'Pull Request number' + required: true + type: string + +jobs: + build: + runs-on: ubuntu-latest + environment: sparrow_web_Dev + outputs: + preview_url: ${{ steps.deploy_info.outputs.preview_url }} + + steps: + - name: Checkout PR branch + uses: actions/checkout@master + with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.branch }} + + - name: Azure Container Registry Login + uses: Azure/docker-login@v1 + with: + login-server: sparrowprod.azurecr.io + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Build and Push Docker Image + run: | + docker build -f ./Sparrow-Web.Dockerfile \ + --build-arg PORT=${{ vars.PORT }} \ + --build-arg VITE_WEB_API_URL=${{ vars.VITE_WEB_API_URL }} \ + --build-arg VITE_WEB_API_TIMEOUT=${{ vars.VITE_WEB_API_TIMEOUT }} \ + --build-arg VITE_WEB_ENABLE_MIX_PANEL=${{ vars.VITE_WEB_ENABLE_MIX_PANEL }} \ + --build-arg VITE_WEB_MIX_PANEL_TOKEN=${{ vars.VITE_WEB_MIX_PANEL_TOKEN }} \ + --build-arg VITE_WEB_SPARROW_SUPPORT_EMAIL=${{ vars.VITE_WEB_SPARROW_SUPPORT_EMAIL }} \ + --build-arg VITE_WEB_AUTH_URL=${{ vars.VITE_WEB_AUTH_URL }} \ + --build-arg VITE_WEB_SPARROW_GITHUB=${{ vars.VITE_WEB_SPARROW_GITHUB }} \ + --build-arg VITE_WEB_SPARROW_DOWNLOAD_LINK=${{ vars.VITE_WEB_SPARROW_DOWNLOAD_LINK }} \ + --build-arg VITE_WEB_RELEASE_NOTES_API=${{ vars.VITE_WEB_RELEASE_NOTES_API }} \ + --build-arg VITE_WEB_AZURE_CDN_URL=${{ vars.VITE_WEB_AZURE_CDN_URL }} \ + --build-arg VITE_WEB_BASE_URL=${{ vars.VITE_WEB_BASE_URL }} \ + --build-arg VITE_WEB_SPARROW_LINKEDIN=${{ vars.VITE_WEB_SPARROW_LINKEDIN }} \ + --build-arg VITE_WEB_AZURE_INSIGHTS_CONNECTION_STRING=${{ vars.VITE_WEB_AZURE_INSIGHTS_CONNECTION_STRING }} \ + --build-arg VITE_WEB_MARKETING_URL=${{ vars.VITE_WEB_MARKETING_URL }} \ + --build-arg VITE_WEB_SPARROW_DOCS=${{ vars.VITE_WEB_SPARROW_DOCS }} \ + --build-arg VITE_WEB_PROXY_SERVICE=${{ vars.VITE_WEB_PROXY_SERVICE }} \ + --build-arg VITE_WEB_SOCKET_IO_API_URL=${{ vars.VITE_WEB_SOCKET_IO_API_URL }} \ + --build-arg VITE_WEB_SPARROW_AI_WEBSOCKET=${{ vars.VITE_WEB_SPARROW_AI_WEBSOCKET }} \ + --build-arg VITE_WEB_APP_ENVIRONMENT_PATH=${{ vars.VITE_WEB_APP_ENVIRONMENT_PATH }} \ + --build-arg VITE_WEB_OPENFEEDBACK_FEEDBACK_URL=${{ vars.VITE_WEB_OPENFEEDBACK_FEEDBACK_URL }} \ + --build-arg VITE_WEB_OPENFEEDBACK_BOARD_ID=${{ vars.VITE_WEB_OPENFEEDBACK_BOARD_ID }} \ + --build-arg VITE_WEB_SPARROW_WEB_APP_URL=${{ vars.VITE_WEB_SPARROW_WEB_APP_URL }} \ + --build-arg VITE_WEB_SENTRY_DSN=${{ vars.VITE_WEB_SENTRY_DSN }} \ + --build-arg VITE_WEB_APP_ENVIRONMENT=${{ vars.VITE_WEB_APP_ENVIRONMENT }} \ + --build-arg VITE_WEB_POSTHOG_CONNECTION_API_KEY=${{ vars.VITE_WEB_POSTHOG_CONNECTION_API_KEY }} \ + --build-arg VITE_WEB_POSTHOG_API_URL=${{ vars.VITE_WEB_POSTHOG_API_URL }} \ + --build-arg VITE_WEB_SPARROW_ADMIN_URL=${{ vars.VITE_WEB_SPARROW_ADMIN_URL }} \ + --build-arg VITE_WEB_APP_EDITION=${{ vars.VITE_WEB_APP_EDITION }} \ + -t sparrowprod.azurecr.io/sparrow-web-preview:pr-${{ inputs.pr_number }} . + + docker push sparrowprod.azurecr.io/sparrow-web-preview:pr-${{ inputs.pr_number }} + + - name: Set deploy info + id: deploy_info + run: | + echo "preview_url=https://pr-${{ inputs.pr_number }}.preview.sparrowapp.dev" >> $GITHUB_OUTPUT + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.branch }} + + - name: Create preview deployment manifest + run: | + cat > /tmp/preview-deployment.yml << 'EOF' + apiVersion: apps/v1 + kind: Deployment + metadata: + name: sparrow-web-pr-${{ inputs.pr_number }} + namespace: sparrow-preview + labels: + app: sparrow-web-preview + pr: "${{ inputs.pr_number }}" + spec: + replicas: 1 + selector: + matchLabels: + app: sparrow-web-pr-${{ inputs.pr_number }} + template: + metadata: + labels: + app: sparrow-web-pr-${{ inputs.pr_number }} + spec: + containers: + - name: sparrow-web + image: sparrowprod.azurecr.io/sparrow-web-preview:pr-${{ inputs.pr_number }} + imagePullPolicy: Always + ports: + - containerPort: 80 + resources: + requests: + cpu: 100m + memory: 300Mi + limits: + cpu: 250m + memory: 400Mi + --- + apiVersion: v1 + kind: Service + metadata: + name: sparrow-web-pr-${{ inputs.pr_number }} + namespace: sparrow-preview + spec: + selector: + app: sparrow-web-pr-${{ inputs.pr_number }} + ports: + - port: 80 + targetPort: 80 + --- + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: sparrow-web-pr-${{ inputs.pr_number }} + namespace: sparrow-preview + annotations: + kubernetes.io/ingress.class: nginx + cert-manager.io/cluster-issuer: letsencrypt-prod + spec: + tls: + - hosts: + - pr-${{ inputs.pr_number }}.preview.sparrowapp.dev + secretName: sparrow-web-pr-${{ inputs.pr_number }}-tls + rules: + - host: pr-${{ inputs.pr_number }}.preview.sparrowapp.dev + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: sparrow-web-pr-${{ inputs.pr_number }} + port: + number: 80 + EOF + + - name: Setup kubectl + uses: azure/setup-kubectl@v2.0 + + - name: Set Kubernetes context + uses: Azure/k8s-set-context@v2 + with: + kubeconfig: ${{ secrets.KUBE_CONFIG }} + + - name: Create preview namespace if not exists + run: | + kubectl create namespace sparrow-preview --dry-run=client -o yaml | kubectl apply -f - + + - name: Deploy preview + run: | + kubectl apply -f /tmp/preview-deployment.yml + + - name: Wait for deployment + run: | + kubectl rollout status deployment/sparrow-web-pr-${{ inputs.pr_number }} \ + --namespace=sparrow-preview --timeout=300s