name: Build and Deploy API Server & Frontend on: push: branches: - main - develop pull_request: branches: - main env: ARTIFACT_DIR: /opt/api-artifacts GO_VERSION: '1.24' NODE_VERSION: '20' jobs: build-backend: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: false - name: Get commit info id: commit run: | echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_OUTPUT echo "date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT echo "github output is $GITHUB_OUTPUT" - name: Download dependencies working-directory: ./backend run: go mod download # takes too long, investigate why it takes so long # - name: Run tests # working-directory: ./backend # run: go test -v ./... - name: Build binary working-directory: ./backend run: | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ -ldflags="-s -w -X main.Version=${{ steps.commit.outputs.short_sha }} -X main.BuildTime=${{ steps.commit.outputs.date }}" \ -o api-server \ . - name: Create build metadata run: | cat > build-info.json << EOF { "commit": "${{ steps.commit.outputs.sha }}", "short_commit": "${{ steps.commit.outputs.short_sha }}", "branch": "${{ steps.commit.outputs.branch }}", "build_date": "${{ steps.commit.outputs.date }}", "go_version": "${{ env.GO_VERSION }}" } EOF - name: Package artifact run: | mkdir -p artifact-package cp backend/api-server artifact-package/ cp -r backend/migrations artifact-package/ cp build-info.json artifact-package/ tar -czf api-server-${{ steps.commit.outputs.sha }}.tar.gz -C artifact-package . - name: Upload artifact uses: actions/upload-artifact@v3 with: name: api-server-${{ steps.commit.outputs.sha }} path: api-server-${{ steps.commit.outputs.sha }}.tar.gz retention-days: 30 build-frontend: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Get commit info id: commit run: | echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Install dependencies working-directory: ./frontend run: npm ci - name: Build frontend working-directory: ./frontend env: VITE_API_URL: https://api.nitrokite.com run: npm run build - name: Create frontend artifact run: | tar -czf frontend-${{ steps.commit.outputs.sha }}.tar.gz -C frontend/dist . - name: Upload frontend artifact uses: actions/upload-artifact@v3 with: name: frontend-${{ steps.commit.outputs.sha }} path: frontend-${{ steps.commit.outputs.sha }}.tar.gz retention-days: 30 deploy: needs: [build-backend, build-frontend] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Checkout deployment scripts uses: actions/checkout@v4 with: sparse-checkout: | deployment/scripts - name: Get commit SHA id: commit run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Download backend artifact uses: actions/download-artifact@v3 with: name: api-server-${{ steps.commit.outputs.sha }} - name: Download frontend artifact uses: actions/download-artifact@v3 with: name: frontend-${{ steps.commit.outputs.sha }} - name: Extract and deploy backend run: | BUILD_DIR="${{ env.ARTIFACT_DIR }}/builds/${{ steps.commit.outputs.sha }}" mkdir -p "$BUILD_DIR" tar -xzf api-server-${{ steps.commit.outputs.sha }}.tar.gz -C "$BUILD_DIR" chmod +x "$BUILD_DIR/api-server" if [ -f "${{ env.ARTIFACT_DIR }}/config/.env.production" ]; then cp "${{ env.ARTIFACT_DIR }}/config/.env.production" "$BUILD_DIR/.env.production" fi - name: Extract and deploy frontend run: | FRONTEND_STAGING_DIR="/opt/frontend-artifacts/staging/${{ steps.commit.outputs.sha }}" mkdir -p "$FRONTEND_STAGING_DIR" tar -xzf frontend-${{ steps.commit.outputs.sha }}.tar.gz -C "$FRONTEND_STAGING_DIR" chown -R www-data:www-data "$FRONTEND_STAGING_DIR" - name: Run deployment script run: | cd ${{ env.ARTIFACT_DIR }}/scripts ./deploy.sh ${{ steps.commit.outputs.sha }} env: DATABASE_URL: ${{ secrets.DATABASE_URL }} AUTO_MIGRATE: "false" PORT: "8080" - name: Notify deployment status if: always() run: | echo "Deployment staged successfully: ${{ steps.commit.outputs.sha }}" echo "Backend staged at: /opt/api-artifacts/builds/${{ steps.commit.outputs.sha }}" echo "Frontend staged at: /opt/frontend-artifacts/staging/${{ steps.commit.outputs.sha }}" echo "" echo "To promote to production, SSH to server and run:" echo " sudo /opt/api-artifacts/scripts/promote.sh ${{ steps.commit.outputs.sha }}"