Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/actions/detect-affected/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Detect affected Nx projects
description: List affected projects and expose outputs for skipping nx affected when nothing changed.

outputs:
has_affected:
description: True when at least one project is affected
value: ${{ steps.detect.outputs.has_affected }}
projects:
description: Newline-separated list of affected project names
value: ${{ steps.detect.outputs.projects }}
has_test:
description: True when at least one affected project has a test target
value: ${{ steps.detect.outputs.has_test }}
has_e2e:
description: True when at least one affected project has an e2e target
value: ${{ steps.detect.outputs.has_e2e }}
has_lint:
description: True when at least one affected project has a lint target
value: ${{ steps.detect.outputs.has_lint }}
has_build:
description: True when at least one affected project has a build target
value: ${{ steps.detect.outputs.has_build }}

runs:
using: composite
steps:
- name: Detect affected projects
id: detect
shell: bash
run: |
chmod +x tools/ci/detect-affected.sh
tools/ci/detect-affected.sh
120 changes: 87 additions & 33 deletions .github/workflows/pull-request-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ permissions:
packages: read

jobs:
detect-affected:
name: Detect Affected Projects
runs-on: ubuntu-latest
outputs:
has_affected: ${{ steps.detect-affected.outputs.has_affected }}
projects: ${{ steps.detect-affected.outputs.projects }}
has_test: ${{ steps.detect-affected.outputs.has_test }}
has_e2e: ${{ steps.detect-affected.outputs.has_e2e }}
has_lint: ${{ steps.detect-affected.outputs.has_lint }}
has_build: ${{ steps.detect-affected.outputs.has_build }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Set Nx SHA
uses: nrwl/nx-set-shas@v5

- name: Setup environment
uses: ./.github/actions/setup-env

- name: Detect affected projects
id: detect-affected
uses: ./.github/actions/detect-affected

lint_pull_request:
name: Pull Request Lint
runs-on: ubuntu-latest
Expand Down Expand Up @@ -52,6 +78,7 @@ jobs:
check:
name: Format Check
runs-on: ubuntu-latest
needs: detect-affected
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand All @@ -68,11 +95,18 @@ jobs:
run: npx nx format:check

- name: Nx Lint - Check
run: npx nx affected --target=lint --parallel=3 || echo "No affected projects for lint"
if: needs.detect-affected.outputs.has_lint == 'true'
run: npx nx affected --target=lint --parallel=3

- name: Skip lint (no affected projects)
if: needs.detect-affected.outputs.has_lint != 'true'
run: echo "No affected projects with lint target; skipping nx affected lint."

test:
name: Test
runs-on: ubuntu-latest
needs: detect-affected
if: needs.detect-affected.outputs.has_affected == 'true'
permissions:
contents: read
actions: read
Expand All @@ -91,20 +125,8 @@ jobs:
- name: Setup environment
uses: ./.github/actions/setup-env

- name: Detect affected projects with test target
id: affected
shell: bash
run: |
set -euo pipefail
RAW=$(npx nx show projects --affected --with-target=test 2>/dev/null | sed '/^\s*$/d' || true)
if [ -n "$RAW" ]; then
echo "has=true" >> "$GITHUB_OUTPUT"
else
echo "has=false" >> "$GITHUB_OUTPUT"
fi

- name: Collect base-branch coverage (for PR diff)
if: github.event_name == 'pull_request' && steps.affected.outputs.has == 'true'
if: github.event_name == 'pull_request' && needs.detect-affected.outputs.has_test == 'true'
continue-on-error: true
shell: bash
run: |
Expand All @@ -113,7 +135,7 @@ jobs:
git fetch origin "${{ github.base_ref }}" --depth=1
git checkout "${{ github.event.pull_request.base.sha }}"
rm -rf coverage coverage-base
npx nx affected --target=test --parallel=3 --configuration=ci --skip-nx-cache || true
npx nx affected --target=test --parallel=3 --configuration=ci --skip-nx-cache
if [ -d coverage ]; then
mv coverage coverage-base
else
Expand All @@ -122,26 +144,36 @@ jobs:
git checkout "$PR_SHA"

- name: Ensure coverage-base exists for diff comment
if: github.event_name == 'pull_request' && steps.affected.outputs.has != 'true'
if: github.event_name == 'pull_request' && needs.detect-affected.outputs.has_test != 'true'
run: mkdir -p coverage-base

- name: Run unit tests
run: npx nx affected --target=test --parallel=3 --configuration=ci --skip-nx-cache || echo "No affected projects for test"
if: needs.detect-affected.outputs.has_test == 'true'
run: npx nx affected --target=test --parallel=3 --configuration=ci --skip-nx-cache

- name: Skip unit tests (no affected projects with test target)
if: needs.detect-affected.outputs.has_test != 'true'
run: echo "No affected projects with test target; skipping unit tests."

- name: Report Nx coverage on PR
if: always() && github.event_name == 'pull_request'
uses: dkhunt27/action-nx-code-coverage@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
no-coverage-ran: ${{ steps.affected.outputs.has == 'false' }}
no-coverage-ran: ${{ needs.detect-affected.outputs.has_test != 'true' }}
coverage-folder: coverage
coverage-base-folder: coverage-base
gist-processing: 'false'
hide-coverage-reports: 'false'
hide-unchanged: 'false'

- name: Run end-to-end tests
run: npx nx affected --target=e2e --parallel=3 || echo "No affected projects for e2e"
if: needs.detect-affected.outputs.has_e2e == 'true'
run: npx nx affected --target=e2e --parallel=3

- name: Skip e2e tests (no affected projects with e2e target)
if: needs.detect-affected.outputs.has_e2e != 'true'
run: echo "No affected projects with e2e target; skipping e2e tests."

trivy-filesystem:
name: Trivy Filesystem Scan
Expand Down Expand Up @@ -180,6 +212,8 @@ jobs:
build:
name: Build
runs-on: ubuntu-latest
needs: detect-affected
if: needs.detect-affected.outputs.has_affected == 'true'
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand All @@ -193,12 +227,12 @@ jobs:
uses: ./.github/actions/setup-env

- name: Run build
run: npx nx affected --target=build --parallel=3 || echo "No affected projects for build"
run: npx nx affected --target=build --parallel=3

- name: Run SBOM generation
env:
VERSION: 0.0.0-SNAPSHOT
run: npx nx affected --target=sbom --parallel=1 || echo "No affected projects for sbom generation"
run: npx nx affected --target=sbom --parallel=1

- name: Upload build artifacts
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -240,7 +274,7 @@ jobs:

- name: Build API container images
run: |
npx nx affected --target=api-container-image --configuration=test --parallel=3 || echo "No projects for api container image build"
npx nx affected --target=api-container-image --configuration=test --parallel=3

- name: Scan API container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand Down Expand Up @@ -282,7 +316,7 @@ jobs:

- name: Build Worker container images
run: |
npx nx affected --target=worker-container-image --configuration=test --parallel=3 || echo "No projects for worker container image build"
npx nx affected --target=worker-container-image --configuration=test --parallel=3

- name: Scan Worker container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand Down Expand Up @@ -324,7 +358,7 @@ jobs:

- name: Build VNC container images
run: |
npx nx affected --target=vnc-container-image --configuration=test --parallel=3 || echo "No projects for vnc container image build"
npx nx affected --target=vnc-container-image --configuration=test --parallel=3

- name: Scan VNC container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand Down Expand Up @@ -366,7 +400,7 @@ jobs:

- name: Build SSH container images
run: |
npx nx affected --target=ssh-container-image --configuration=test --parallel=3 || echo "No projects for ssh container image build"
npx nx affected --target=ssh-container-image --configuration=test --parallel=3

- name: Scan SSH container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand Down Expand Up @@ -408,7 +442,7 @@ jobs:

- name: Build AGI container images
run: |
npx nx affected --target=agi-container-image --configuration=test --parallel=3 || echo "No projects for agi container image build"
npx nx affected --target=agi-container-image --configuration=test --parallel=3

- name: Scan AGI container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand Down Expand Up @@ -450,7 +484,7 @@ jobs:

- name: Build Server container images
run: |
npx nx affected --target=server-container-image --configuration=test --parallel=3 || echo "No projects for server container image build"
npx nx affected --target=server-container-image --configuration=test --parallel=3

- name: Scan Server container images with Trivy
uses: ./.github/actions/trivy-scan-local-images
Expand All @@ -467,14 +501,15 @@ jobs:
name: Collect SBOM artifacts
runs-on: ubuntu-latest
needs:
- detect-affected
- build
- build-api-container-images
- build-worker-container-images
- build-vnc-container-images
- build-ssh-container-images
- build-agi-container-images
- build-server-container-images
if: always()
if: always() && needs.detect-affected.outputs.has_affected == 'true'
steps:
- name: Download service SBOMs from build
uses: actions/download-artifact@v8
Expand Down Expand Up @@ -508,6 +543,24 @@ jobs:
compression-level: 6
if-no-files-found: ignore

- name: Fail if required upstream jobs failed
if: always()
env:
BUILD: ${{ needs.build.result }}
API: ${{ needs.build-api-container-images.result }}
WORKER: ${{ needs.build-worker-container-images.result }}
VNC: ${{ needs.build-vnc-container-images.result }}
SSH: ${{ needs.build-ssh-container-images.result }}
AGI: ${{ needs.build-agi-container-images.result }}
SERVER: ${{ needs.build-server-container-images.result }}
run: |
for result in "$BUILD" "$API" "$WORKER" "$VNC" "$SSH" "$AGI" "$SERVER"; do
if [ "$result" = "failure" ]; then
echo "::error::An upstream SBOM build job failed"
exit 1
fi
done

build-scripts-binary:
name: Build Scripts Binaries
runs-on: ubuntu-latest
Expand All @@ -531,7 +584,7 @@ jobs:
uses: ./.github/actions/setup-env

- name: Build binaries
run: npx nx affected --target=scripts-binary --parallel=3 || echo "No projects for scripts binary build"
run: npx nx affected --target=scripts-binary --parallel=3

build-openapi-clients-js:
name: Build OpenAPI JavaScript/TypeScript Clients
Expand Down Expand Up @@ -562,7 +615,7 @@ jobs:

- name: Build JavaScript/TypeScript clients
run: |
npx nx affected --target=openapi-client-js --configuration=test --parallel=3 || echo "No projects for openapi js client build"
npx nx affected --target=openapi-client-js --configuration=test --parallel=3

build-native-applications-linux:
name: Build Linux Applications
Expand Down Expand Up @@ -590,7 +643,7 @@ jobs:
env:
ELECTRON_FORGE_PLATFORM: linux
run: |
xvfb-run -a npx nx affected --target=package --configuration=development-linux --parallel=3 || echo "No projects for native applications build"
xvfb-run -a npx nx affected --target=package --configuration=development-linux --parallel=3

- name: Upload build artifacts
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -632,7 +685,7 @@ jobs:
env:
ELECTRON_FORGE_PLATFORM: win32
run: |
xvfb-run -a npx nx affected --target=package --configuration=development-windows --parallel=3 || echo "No projects for native applications build"
xvfb-run -a npx nx affected --target=package --configuration=development-windows --parallel=3

- name: Upload Windows Electron bundle
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -667,7 +720,6 @@ jobs:

- name: Download Windows Electron bundle
uses: actions/download-artifact@v8
continue-on-error: true
with:
name: windows-electron-bundle
path: windows-electron-bundle
Expand All @@ -689,9 +741,11 @@ jobs:
name: Publish Native Applications
runs-on: ubuntu-latest
needs:
- detect-affected
- build-native-applications-linux
- build-native-applications-windows
- build-native-applications-windows-installer
if: needs.detect-affected.outputs.has_affected == 'true'
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand Down
Loading