feat(team-tracker): spreadsheet-style column filters on People Direct… #14
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: Build & Push Core Images | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'server/**' | |
| - 'modules/team-tracker/**' | |
| - 'shared/**' | |
| - 'src/**' | |
| - 'deploy/core.*.Dockerfile' | |
| - 'deploy/nginx-default.conf' | |
| - 'deploy/openshift/base/**' | |
| - 'package*.json' | |
| - 'vite.config.mjs' | |
| - 'tailwind.config.mjs' | |
| - 'postcss.config.mjs' | |
| - 'index.html' | |
| - 'tests/smoke/**' | |
| - 'playwright.config.js' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: build-images-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| env: | |
| CORE_BACKEND_IMAGE: quay.io/org-pulse/org-pulse-core-backend | |
| CORE_FRONTEND_IMAGE: quay.io/org-pulse/org-pulse-core-frontend | |
| jobs: | |
| detect-changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| backend: ${{ steps.changes.outputs.backend }} | |
| frontend: ${{ steps.changes.outputs.frontend }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 2 | |
| - name: Detect changed paths | |
| id: changes | |
| run: | | |
| CHANGED=$(git diff --name-only HEAD~1 HEAD) | |
| echo "Changed files:" | |
| echo "$CHANGED" | |
| BACKEND=false | |
| FRONTEND=false | |
| if echo "$CHANGED" | grep -qE '^(server/|modules/team-tracker/(server/|module\.json)|shared/server/|deploy/core\.backend\.Dockerfile|package)'; then | |
| BACKEND=true | |
| fi | |
| if echo "$CHANGED" | grep -qE '^(src/|modules/team-tracker/(client/|module\.json)|shared/client/|index\.html|vite\.config|tailwind\.config|postcss\.config|deploy/core\.frontend.*\.Dockerfile|deploy/nginx-default\.conf|deploy/openshift/base/nginx-app\.conf\.template|tests/smoke/|playwright\.config|package)'; then | |
| FRONTEND=true | |
| fi | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| BACKEND=true | |
| FRONTEND=true | |
| fi | |
| echo "backend=$BACKEND" >> "$GITHUB_OUTPUT" | |
| echo "frontend=$FRONTEND" >> "$GITHUB_OUTPUT" | |
| echo "Backend: $BACKEND, Frontend: $FRONTEND" | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - run: npm ci | |
| - run: npm run lint | |
| - run: npm test | |
| - run: npm run build | |
| version-bump: | |
| name: Bump Version | |
| needs: [test, detect-changes] | |
| if: | | |
| github.ref == 'refs/heads/main' && | |
| (needs.detect-changes.outputs.backend == 'true' || needs.detect-changes.outputs.frontend == 'true') | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.bump.outputs.version }} | |
| build_sha: ${{ steps.push.outputs.build_sha }} | |
| steps: | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| app-id: ${{ secrets.APP_ID }} | |
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: main | |
| token: ${{ steps.app-token.outputs.token }} | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| - name: Bump patch version | |
| id: bump | |
| run: | | |
| CURRENT=$(node -p "require('./package.json').version") | |
| NEW=$(npm version patch --no-git-tag-version) | |
| while git ls-remote --tags origin "refs/tags/${NEW}" | grep -q .; do | |
| echo "Tag ${NEW} already exists, bumping again..." | |
| NEW=$(npm version patch --no-git-tag-version) | |
| done | |
| echo "Bumped ${CURRENT} -> ${NEW}" | |
| echo "version=${NEW}" >> "$GITHUB_OUTPUT" | |
| - name: Commit and tag | |
| id: push | |
| run: | | |
| VERSION=${{ steps.bump.outputs.version }} | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add package.json package-lock.json | |
| git commit -m "release: ${VERSION} [skip ci]" | |
| git tag "${VERSION}" | |
| git push origin main --tags | |
| BUILD_SHA=$(git rev-parse HEAD) | |
| echo "build_sha=${BUILD_SHA}" >> "$GITHUB_OUTPUT" | |
| echo "Build SHA: ${BUILD_SHA}" | |
| build-core-backend: | |
| name: Build Core Backend | |
| needs: [test, detect-changes, version-bump] | |
| if: | | |
| always() && | |
| needs.test.result == 'success' && | |
| needs.detect-changes.outputs.backend == 'true' && | |
| (needs.version-bump.result == 'success' || needs.version-bump.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| - name: Build core backend image | |
| run: | | |
| docker build \ | |
| -f deploy/core.backend.Dockerfile \ | |
| --build-arg GIT_SHA=${BUILD_SHA} \ | |
| --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ | |
| -t ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} \ | |
| . | |
| - name: Smoke test core backend | |
| run: | | |
| docker run -d --name core-backend-smoke -p 3001:3001 \ | |
| -e DEMO_MODE=true \ | |
| ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} | |
| echo "Waiting for core backend to start..." | |
| sleep 5 | |
| if curl -sf --max-time 5 http://localhost:3001/api/healthz > /dev/null 2>&1; then | |
| echo "Core backend smoke test passed" | |
| else | |
| echo "Core backend smoke test failed" | |
| docker logs core-backend-smoke | |
| docker stop core-backend-smoke | |
| exit 1 | |
| fi | |
| docker stop core-backend-smoke | |
| - name: Save image artifact | |
| run: docker save ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} -o /tmp/core-backend.tar | |
| - name: Upload image artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: core-backend-image | |
| path: /tmp/core-backend.tar | |
| retention-days: 1 | |
| build-core-frontend: | |
| name: Build Core Frontend | |
| needs: [test, detect-changes, version-bump] | |
| if: | | |
| always() && | |
| needs.test.result == 'success' && | |
| needs.detect-changes.outputs.frontend == 'true' && | |
| (needs.version-bump.result == 'success' || needs.version-bump.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| - name: Build core frontend image | |
| run: | | |
| docker build \ | |
| -f deploy/core.frontend.Dockerfile \ | |
| -t ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} \ | |
| . | |
| - name: Save image artifact | |
| run: docker save ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} -o /tmp/core-frontend.tar | |
| - name: Upload image artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: core-frontend-image | |
| path: /tmp/core-frontend.tar | |
| retention-days: 1 | |
| build-core-frontend-builder: | |
| name: Build Core Frontend Builder | |
| needs: [test, detect-changes, version-bump] | |
| if: | | |
| always() && | |
| needs.test.result == 'success' && | |
| needs.detect-changes.outputs.frontend == 'true' && | |
| (needs.version-bump.result == 'success' || needs.version-bump.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| - name: Build core frontend builder image | |
| run: | | |
| docker build \ | |
| -f deploy/core.frontend-builder.Dockerfile \ | |
| -t ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_SHA} \ | |
| . | |
| - name: Login to Quay.io | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Push core frontend builder image | |
| run: | | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}-builder:latest | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_SHA} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-builder:latest | |
| if [ -n "${BUILD_VERSION}" ]; then | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_VERSION} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-builder:${BUILD_VERSION} | |
| fi | |
| build-core-frontend-runtime: | |
| name: Build Core Frontend Runtime | |
| needs: [test, detect-changes, version-bump] | |
| if: | | |
| always() && | |
| needs.test.result == 'success' && | |
| needs.detect-changes.outputs.frontend == 'true' && | |
| (needs.version-bump.result == 'success' || needs.version-bump.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| - name: Build core frontend runtime image | |
| run: | | |
| docker build \ | |
| -f deploy/core.frontend-runtime.Dockerfile \ | |
| -t ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_SHA} \ | |
| . | |
| - name: Login to Quay.io | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Push core frontend runtime image | |
| run: | | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}-runtime:latest | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_SHA} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-runtime:latest | |
| if [ -n "${BUILD_VERSION}" ]; then | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_VERSION} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}-runtime:${BUILD_VERSION} | |
| fi | |
| smoke-test-core: | |
| name: Core Smoke Tests | |
| needs: [build-core-backend, build-core-frontend, version-bump] | |
| if: | | |
| always() && | |
| needs.build-core-backend.result == 'success' && | |
| needs.build-core-frontend.result == 'success' | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| - name: Download backend image | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: core-backend-image | |
| path: /tmp | |
| - name: Download frontend image | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: core-frontend-image | |
| path: /tmp | |
| - name: Load images | |
| run: | | |
| docker load -i /tmp/core-backend.tar | |
| docker load -i /tmp/core-frontend.tar | |
| - name: Run smoke tests against core images | |
| run: | | |
| make smoke-test-core \ | |
| CONTAINER_RUNTIME=docker \ | |
| CORE_BACKEND_IMAGE=${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} \ | |
| CORE_FRONTEND_IMAGE=${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} | |
| push-core-images: | |
| name: Push Core Images | |
| needs: [smoke-test-core, build-core-backend, build-core-frontend, detect-changes, version-bump] | |
| if: | | |
| always() && | |
| (needs.smoke-test-core.result == 'success' || needs.smoke-test-core.result == 'skipped') && | |
| needs.build-core-backend.result != 'failure' && | |
| needs.build-core-frontend.result != 'failure' && | |
| (needs.build-core-backend.result == 'success' || needs.build-core-frontend.result == 'success') | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - name: Download backend image | |
| if: needs.build-core-backend.result == 'success' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: core-backend-image | |
| path: /tmp | |
| - name: Download frontend image | |
| if: needs.build-core-frontend.result == 'success' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: core-frontend-image | |
| path: /tmp | |
| - name: Load images | |
| run: | | |
| if [ -f /tmp/core-backend.tar ]; then docker load -i /tmp/core-backend.tar; fi | |
| if [ -f /tmp/core-frontend.tar ]; then docker load -i /tmp/core-frontend.tar; fi | |
| - name: Login to Quay.io | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Push backend image | |
| if: needs.build-core-backend.result == 'success' | |
| run: | | |
| docker tag ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} ${{ env.CORE_BACKEND_IMAGE }}:latest | |
| docker push ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} | |
| docker push ${{ env.CORE_BACKEND_IMAGE }}:latest | |
| if [ -n "${BUILD_VERSION}" ]; then | |
| docker tag ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_VERSION} | |
| docker push ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_VERSION} | |
| fi | |
| - name: Push frontend image | |
| if: needs.build-core-frontend.result == 'success' | |
| run: | | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}:latest | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}:latest | |
| if [ -n "${BUILD_VERSION}" ]; then | |
| docker tag ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_VERSION} | |
| docker push ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_VERSION} | |
| fi | |
| publish-package: | |
| name: Publish npm Package | |
| needs: [test, version-bump] | |
| if: needs.version-bump.result == 'success' | |
| runs-on: ubuntu-latest | |
| environment: npm-publish | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha }} | |
| BUILD_VERSION: ${{ needs.version-bump.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ env.BUILD_SHA }} | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| registry-url: 'https://registry.npmjs.org' | |
| - run: npm install -g npm@11.17.0 | |
| - run: npm ci | |
| - name: Publish | |
| run: npm publish --provenance --access public | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: ${{ env.BUILD_VERSION }} | |
| generate_release_notes: true | |
| update-deploy-image: | |
| name: Update Deploy Image Tags | |
| needs: [detect-changes, push-core-images, build-core-backend, build-core-frontend, version-bump] | |
| if: | | |
| always() && | |
| github.ref == 'refs/heads/main' && | |
| needs.push-core-images.result == 'success' | |
| runs-on: ubuntu-latest | |
| env: | |
| BUILD_SHA: ${{ needs.version-bump.outputs.build_sha || github.sha }} | |
| steps: | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| app-id: ${{ secrets.APP_ID }} | |
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: main | |
| token: ${{ steps.app-token.outputs.token }} | |
| - name: Install kustomize | |
| uses: imranismail/setup-kustomize@v3 | |
| with: | |
| kustomize-version: '5.8.1' | |
| - name: Update backend image tag | |
| if: needs.build-core-backend.result == 'success' | |
| working-directory: deploy/openshift/base | |
| run: | | |
| kustomize edit set image ${{ env.CORE_BACKEND_IMAGE }}:${BUILD_SHA} | |
| - name: Update frontend image tag | |
| if: needs.build-core-frontend.result == 'success' | |
| working-directory: deploy/openshift/base | |
| run: | | |
| kustomize edit set image ${{ env.CORE_FRONTEND_IMAGE }}:${BUILD_SHA} | |
| - name: Validate kustomize build | |
| run: kustomize build deploy/openshift/base > /dev/null | |
| - name: Push deploy commit | |
| run: | | |
| VERSION=${{ needs.version-bump.outputs.version || 'unknown' }} | |
| PARTS="" | |
| if [ "${{ needs.build-core-backend.result }}" = "success" ]; then | |
| PARTS="backend" | |
| fi | |
| if [ "${{ needs.build-core-frontend.result }}" = "success" ]; then | |
| [ -n "$PARTS" ] && PARTS="$PARTS + " | |
| PARTS="${PARTS}frontend" | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add deploy/openshift/base/kustomization.yaml | |
| git diff --cached --quiet && { echo "No changes to commit"; exit 0; } | |
| git commit -m "deploy: update ${PARTS} image to ${VERSION} (${BUILD_SHA}) [skip ci]" | |
| git push origin main |