Fixes 32693: Encrypt and mask ingestion pipeline secrets #10729
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
| # Copyright 2021 Collate | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| name: PostgreSQL PR RDF E2E Tests | |
| on: | |
| merge_group: | |
| workflow_dispatch: | |
| # `Playwright RDF (Knowledge Graph + Ontology)` is a REQUIRED status check on | |
| # main, so there is deliberately no `paths:` filter here: a path-filtered | |
| # workflow simply never reports on PRs outside the filter, and the required | |
| # context would hang at "Expected — waiting for status" forever (same rationale | |
| # as the `changes` pattern in java-playwright-nightly.yml, PR #32521). Path | |
| # selection lives in the `changes` job below (dorny/paths-filter), which skips | |
| # the expensive build/test jobs while the summary still publishes the required | |
| # check name as green. Same-repo PRs are unprivileged under pull_request; | |
| # merges use merge_group; full dispatch uses workflow_dispatch. | |
| pull_request: | |
| types: | |
| - labeled | |
| - opened | |
| - synchronize | |
| - reopened | |
| - ready_for_review | |
| # Fork PRs need cloud-connector secrets that pull_request events cannot access | |
| # on forks. pull_request_target runs in the base repo's context so those | |
| # secrets resolve, but requires a maintainer to apply the "safe to test" label | |
| # first (enforced by the gate job below). Same-repo PRs already run under | |
| # pull_request above; the gate short-circuits on them via the head-repo check. | |
| pull_request_target: | |
| types: | |
| - labeled | |
| - opened | |
| - synchronize | |
| - reopened | |
| - ready_for_review | |
| permissions: | |
| contents: read | |
| concurrency: | |
| # Include event_name in the group so pull_request and pull_request_target | |
| # runs on the same PR don't cancel each other — one gates false and skips, | |
| # the other does the real work; sharing a group would let the "skip" event | |
| # cancel an in-flight real run. | |
| group: playwright-rdf-pr-postgresql-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: ${{ !contains(fromJSON('["pull_request","pull_request_target"]'), github.event_name) || github.event.action != 'labeled' || (github.event.label.name == 'safe to test' && github.event.pull_request.head.repo.full_name != github.repository) }} | |
| jobs: | |
| # Path selection for the required `Playwright RDF (Knowledge Graph + Ontology)` | |
| # check. The workflow itself has no `paths:` filter (see the trigger comment); | |
| # this job decides whether the RDF-related paths were touched. When they were | |
| # not, build/tests are skipped but the summary still publishes the required | |
| # check as green so branch protection is satisfied. This is the single source | |
| # of truth for "RDF/ontology code changed" — keep the filter list here. | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| outputs: | |
| rdf: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && 'true' || steps.filter.outputs.rdf }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| if: ${{ github.event_name == 'merge_group' }} | |
| with: | |
| fetch-depth: 0 | |
| filter: blob:none | |
| persist-credentials: false | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' || github.event_name == 'merge_group' }} | |
| with: | |
| # Fork PRs under pull_request_target: dorny/paths-filter uses the | |
| # GitHub API to enumerate changed files rather than checking out fork | |
| # code, so no untrusted execution here. | |
| base: ${{ github.event_name == 'merge_group' && github.event.merge_group.base_sha || '' }} | |
| filters: | | |
| rdf: | |
| - '.github/actions/setup-openmetadata-test-environment/action.yml' | |
| - '.github/workflows/playwright-knowledge-graph-postgresql-e2e.yml' | |
| - 'docker/run_local_docker.sh' | |
| - 'docker/run_local_docker_common.sh' | |
| - 'docker/run_local_docker_rdf.sh' | |
| - 'docker/validate_compose.py' | |
| - 'docker/development/docker-compose-fuseki.yml' | |
| - 'docker/development/docker-compose-postgres-fuseki.yml' | |
| - 'docs/rdf-local-development.md' | |
| - 'openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/rdf/**' | |
| - 'openmetadata-service/src/main/java/org/openmetadata/service/rdf/**' | |
| - 'openmetadata-service/src/main/java/org/openmetadata/service/resources/glossary/**' | |
| - 'openmetadata-service/src/main/java/org/openmetadata/service/resources/rdf/**' | |
| - 'openmetadata-service/src/test/java/org/openmetadata/service/apps/bundles/rdf/**' | |
| - 'openmetadata-service/src/test/java/org/openmetadata/service/rdf/**' | |
| - 'openmetadata-service/src/test/java/org/openmetadata/service/resources/rdf/**' | |
| - 'openmetadata-spec/src/main/resources/json/schema/api/data/createGlossaryTerm.json' | |
| - 'openmetadata-spec/src/main/resources/json/schema/configuration/glossaryTermRelationSettings.json' | |
| - 'openmetadata-spec/src/main/resources/json/schema/entity/data/glossary.json' | |
| - 'openmetadata-spec/src/main/resources/json/schema/entity/data/glossaryTerm.json' | |
| - 'openmetadata-spec/src/main/resources/rdf/**' | |
| - 'openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/KnowledgeGraph.spec.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/OntologyExplorerRdf.spec.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/OntologyImportRdf.spec.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/playwright.config.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/**' | |
| - 'openmetadata-ui/src/main/resources/ui/src/components/Glossary/ImportOntologyModal/**' | |
| - 'openmetadata-ui/src/main/resources/ui/src/components/KnowledgeGraph3D/**' | |
| - 'openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/**' | |
| - 'openmetadata-ui/src/main/resources/ui/src/rest/importExportAPI.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/src/rest/rdfAPI.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/src/types/knowledgeGraph.types.ts' | |
| - 'openmetadata-ui/src/main/resources/ui/src/utils/TableUtils.tsx' | |
| # Fork-vs-same-repo PR arbitration. Same pattern as | |
| # playwright-postgresql-e2e.yml (established by #30485): | |
| # merge_group / workflow_dispatch → always run | |
| # drafts → never run | |
| # labeled event with label != "safe to test" → skip | |
| # same-repo PR + pull_request → run | |
| # fork PR + pull_request_target + "safe to test" (reconciled) → run | |
| # everything else → skip | |
| # `should_run` only encodes the fork/label/authoritative-event decision. | |
| # The paths decision comes from the `changes` job above; build/tests need | |
| # both to be true. | |
| gate: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| checks: read | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| should_run: ${{ steps.gate.outputs.should_run }} | |
| steps: | |
| # Team Label atomically removes stale fork approval on synchronize and | |
| # re-adds it only for allowlisted authors. Wait for that reconciliation | |
| # instead of relying on another labeled event: GITHUB_TOKEN label writes | |
| # intentionally do not trigger a new workflow run. | |
| - name: Wait for fork label reconciliation | |
| if: | | |
| github.event_name == 'pull_request_target' && | |
| github.event.pull_request.head.repo.full_name != github.repository | |
| uses: lewagon/wait-on-check-action@9312864dfbc9fd208e9c0417843430751c042800 # v1.7.0 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| check-name: Team Label | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| wait-interval: 10 | |
| - name: Read reconciled fork labels | |
| id: fork-labels | |
| if: | | |
| github.event_name == 'pull_request_target' && | |
| github.event.pull_request.head.repo.full_name != github.repository | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| labels=$(gh api "/repos/${REPO}/pulls/${PR_NUMBER}" \ | |
| --jq '[.labels[].name] | @json') | |
| echo "labels=$labels" >> "$GITHUB_OUTPUT" | |
| - name: Compute gate decision | |
| id: gate | |
| env: | |
| EVENT: ${{ github.event_name }} | |
| ACTION: ${{ github.event.action }} | |
| LABEL: ${{ github.event.label.name }} | |
| HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| BASE_REPO: ${{ github.repository }} | |
| LABELS_JSON: ${{ steps.fork-labels.outputs.labels || toJSON(github.event.pull_request.labels.*.name) }} | |
| IS_DRAFT: ${{ github.event.pull_request.draft }} | |
| run: | | |
| set -euo pipefail | |
| decide() { echo "should_run=$1" >> "$GITHUB_OUTPUT"; exit 0; } | |
| case "$EVENT" in | |
| merge_group|workflow_dispatch) decide true ;; | |
| esac | |
| if [[ "$IS_DRAFT" == "true" ]]; then decide false; fi | |
| if [[ "$ACTION" == "labeled" && "$LABEL" != "safe to test" ]]; then decide false; fi | |
| if [[ "$HEAD_REPO" == "$BASE_REPO" ]]; then | |
| if [[ "$EVENT" == "pull_request" ]]; then decide true; else decide false; fi | |
| fi | |
| # Fork PR — pull_request_target must fire and the reconciled labels | |
| # for the current head SHA must include "safe to test". | |
| if [[ "$EVENT" == "pull_request_target" ]] && \ | |
| echo "$LABELS_JSON" | jq -e '. | index("safe to test")' >/dev/null; then | |
| decide true | |
| fi | |
| decide false | |
| build: | |
| needs: [gate, changes] | |
| runs-on: ubuntu-latest | |
| if: ${{ needs.gate.outputs.should_run == 'true' && needs.changes.outputs.rdf == 'true' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| # pull_request_target runs in the base repo's context, so | |
| # github.sha is the base tip. Explicitly check out the fork's | |
| # PR head SHA under that event so we test the PR's code, not | |
| # the base. actions/checkout@v7 refuses this by default under | |
| # pull_request_target — allow-unsafe-pr-checkout: true opts in; | |
| # build/test steps below run inside docker containers so the | |
| # fork code cannot exfiltrate GITHUB_TOKEN or secrets. | |
| ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} | |
| allow-unsafe-pr-checkout: true | |
| - name: Setup JDK 21 | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: 'temurin' | |
| - name: Restore Maven Dependencies | |
| id: maven-cache | |
| uses: actions/cache/restore@v6 | |
| with: | |
| path: ~/.m2 | |
| key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-maven- | |
| - name: Install antlr cli | |
| run: sudo make install_antlr_cli | |
| - name: Restore openmetadata-ui dist cache | |
| # Skip cache on fork-PR-via-pull_request_target: that combination | |
| # runs base-branch privileged with untrusted checked-out code, so a | |
| # cache save would poison the default-branch cache scope (CodeQL | |
| # `actions/actions/cache-poisoning`). The same guard lives inside | |
| # the composite action as defence in depth, but CodeQL is a static | |
| # analyser and needs to see it here at the workflow level. | |
| if: >- | |
| !(github.event_name == 'pull_request_target' && | |
| github.event.pull_request.head.repo.full_name != github.repository) | |
| uses: ./.github/actions/cache-ui-dist | |
| - name: Build with Maven | |
| run: mvn -DskipTests clean package | |
| - name: Save Maven Dependencies | |
| # Fork PRs under pull_request_target skip the save — actions/cache-poisoning. | |
| # The restore above stays ungated so forks are not forced into a cold | |
| # ~/.m2 download; only the write into main's cache scope is blocked. | |
| if: >- | |
| steps.maven-cache.outputs.cache-hit != 'true' && | |
| !(github.event_name == 'pull_request_target' && | |
| github.event.pull_request.head.repo.full_name != github.repository) | |
| continue-on-error: true | |
| uses: actions/cache/save@v6 | |
| with: | |
| path: ~/.m2 | |
| key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | |
| - name: Upload OpenMetadata distribution | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: openmetadata-distribution | |
| overwrite: true | |
| path: openmetadata-dist/target/openmetadata-*.tar.gz | |
| retention-days: 1 | |
| playwright-rdf-postgresql: | |
| # Internal display name only. The required-check status | |
| # `Playwright RDF (Knowledge Graph + Ontology)` is published by the | |
| # `playwright-rdf-summary` job below (which uses a dynamic name | |
| # expression), so a redundant sibling event's synthetic-green cannot | |
| # satisfy branch protection before the real pipeline finishes. | |
| name: RDF Playwright execution | |
| needs: [gate, changes, build] | |
| runs-on: ubuntu-latest | |
| # The previous fork short-circuit (`!github.event.pull_request.head.repo.fork`) | |
| # is now handled by the gate — fork PRs only reach this point when | |
| # pull_request_target fires AND the reconciled labels include | |
| # "safe to test", so it is safe to run the pipeline with secrets. | |
| if: ${{ !cancelled() && needs.gate.outputs.should_run == 'true' && needs.changes.outputs.rdf == 'true' && needs.build.result == 'success' }} | |
| environment: test | |
| steps: | |
| - name: Free Disk Space (Ubuntu) | |
| uses: jlumbroso/free-disk-space@main | |
| with: | |
| tool-cache: false | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: false | |
| swap-storage: true | |
| docker-images: false | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| # Same head.sha vs base.sha routing as the build job above. | |
| ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} | |
| allow-unsafe-pr-checkout: true | |
| - name: Prepare temporary distribution directory | |
| run: mkdir -p "${{ runner.temp }}/openmetadata-distribution" | |
| - name: Download OpenMetadata distribution | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: openmetadata-distribution | |
| path: ${{ runner.temp }}/openmetadata-distribution | |
| - name: Copy OpenMetadata distribution into workspace | |
| run: | | |
| mkdir -p openmetadata-dist/target | |
| cp -a "${{ runner.temp }}/openmetadata-distribution/." openmetadata-dist/target/ | |
| - name: Setup Openmetadata Test Environment | |
| uses: ./.github/actions/setup-openmetadata-test-environment | |
| with: | |
| python-version: "3.10" | |
| args: "-d postgresql -s true" | |
| startup-script: "./docker/run_local_docker_rdf.sh" | |
| ingestion_dependency: "all" | |
| install-test-dependencies: "false" | |
| - name: Wait for Fuseki to be healthy | |
| run: | | |
| echo "Verifying Fuseki is healthy before running tests..." | |
| for i in $(seq 1 30); do | |
| if curl -sf "http://localhost:3030/\$/ping" > /dev/null 2>&1; then | |
| echo "Fuseki is healthy" | |
| exit 0 | |
| fi | |
| echo "Waiting for Fuseki ($i/30)..." | |
| sleep 10 | |
| done | |
| echo "Fuseki failed health check. Container logs:" | |
| docker logs openmetadata-fuseki --tail 100 | |
| exit 1 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version-file: "openmetadata-ui/src/main/resources/ui/.nvmrc" | |
| - name: Install dependencies | |
| working-directory: openmetadata-ui/src/main/resources/ui/ | |
| run: yarn --ignore-scripts --frozen-lockfile | |
| - name: Install Playwright Browsers | |
| run: npx playwright@1.57.0 install chromium --with-deps | |
| - name: Run RDF Playwright tests | |
| working-directory: openmetadata-ui/src/main/resources/ui/ | |
| run: >- | |
| npx playwright test | |
| --project="Knowledge Graph" | |
| --project="Ontology RDF" | |
| env: | |
| PLAYWRIGHT_IS_OSS: true | |
| PLAYWRIGHT_SNOWFLAKE_USERNAME: ${{ secrets.TEST_SNOWFLAKE_USERNAME }} | |
| PLAYWRIGHT_SNOWFLAKE_PASSWORD: ${{ secrets.TEST_SNOWFLAKE_PASSWORD }} | |
| PLAYWRIGHT_SNOWFLAKE_ACCOUNT: ${{ secrets.TEST_SNOWFLAKE_ACCOUNT }} | |
| PLAYWRIGHT_SNOWFLAKE_DATABASE: ${{ secrets.TEST_SNOWFLAKE_DATABASE }} | |
| PLAYWRIGHT_SNOWFLAKE_WAREHOUSE: ${{ secrets.TEST_SNOWFLAKE_WAREHOUSE }} | |
| PLAYWRIGHT_SNOWFLAKE_PASSPHRASE: ${{ secrets.TEST_SNOWFLAKE_PASSPHRASE }} | |
| PLAYWRIGHT_BQ_PRIVATE_KEY: ${{ secrets.TEST_BQ_PRIVATE_KEY }} | |
| PLAYWRIGHT_BQ_PROJECT_ID: ${{ secrets.PLAYWRIGHT_BQ_PROJECT_ID }} | |
| PLAYWRIGHT_BQ_PRIVATE_KEY_ID: ${{ secrets.TEST_BQ_PRIVATE_KEY_ID }} | |
| PLAYWRIGHT_BQ_PROJECT_ID_TAXONOMY: ${{ secrets.TEST_BQ_PROJECT_ID_TAXONOMY }} | |
| PLAYWRIGHT_BQ_CLIENT_EMAIL: ${{ secrets.TEST_BQ_CLIENT_EMAIL }} | |
| PLAYWRIGHT_BQ_CLIENT_ID: ${{ secrets.TEST_BQ_CLIENT_ID }} | |
| PLAYWRIGHT_REDSHIFT_HOST: ${{ secrets.E2E_REDSHIFT_HOST_PORT }} | |
| PLAYWRIGHT_REDSHIFT_USERNAME: ${{ secrets.E2E_REDSHIFT_USERNAME }} | |
| PLAYWRIGHT_REDSHIFT_PASSWORD: ${{ secrets.E2E_REDSHIFT_PASSWORD }} | |
| PLAYWRIGHT_REDSHIFT_DATABASE: ${{ secrets.TEST_REDSHIFT_DATABASE }} | |
| PLAYWRIGHT_METABASE_USERNAME: ${{ secrets.TEST_METABASE_USERNAME }} | |
| PLAYWRIGHT_METABASE_PASSWORD: ${{ secrets.TEST_METABASE_PASSWORD }} | |
| PLAYWRIGHT_METABASE_DB_SERVICE_NAME: ${{ secrets.TEST_METABASE_DB_SERVICE_NAME }} | |
| PLAYWRIGHT_METABASE_HOST_PORT: ${{ secrets.TEST_METABASE_HOST_PORT }} | |
| PLAYWRIGHT_SUPERSET_USERNAME: ${{ secrets.TEST_SUPERSET_USERNAME }} | |
| PLAYWRIGHT_SUPERSET_PASSWORD: ${{ secrets.TEST_SUPERSET_PASSWORD }} | |
| PLAYWRIGHT_SUPERSET_HOST_PORT: ${{ secrets.TEST_SUPERSET_HOST_PORT }} | |
| PLAYWRIGHT_KAFKA_BOOTSTRAP_SERVERS: ${{ secrets.TEST_KAFKA_BOOTSTRAP_SERVERS }} | |
| PLAYWRIGHT_KAFKA_SCHEMA_REGISTRY_URL: ${{ secrets.TEST_KAFKA_SCHEMA_REGISTRY_URL }} | |
| PLAYWRIGHT_GLUE_ACCESS_KEY: ${{ secrets.TEST_GLUE_ACCESS_KEY }} | |
| PLAYWRIGHT_GLUE_SECRET_KEY: ${{ secrets.TEST_GLUE_SECRET_KEY }} | |
| PLAYWRIGHT_GLUE_AWS_REGION: ${{ secrets.TEST_GLUE_AWS_REGION }} | |
| PLAYWRIGHT_GLUE_ENDPOINT: ${{ secrets.TEST_GLUE_ENDPOINT }} | |
| PLAYWRIGHT_GLUE_STORAGE_SERVICE: ${{ secrets.TEST_GLUE_STORAGE_SERVICE }} | |
| PLAYWRIGHT_MYSQL_USERNAME: ${{ secrets.TEST_MYSQL_USERNAME }} | |
| PLAYWRIGHT_MYSQL_PASSWORD: ${{ secrets.TEST_MYSQL_PASSWORD }} | |
| PLAYWRIGHT_MYSQL_HOST_PORT: ${{ secrets.TEST_MYSQL_HOST_PORT }} | |
| PLAYWRIGHT_MYSQL_DATABASE_SCHEMA: ${{ secrets.TEST_MYSQL_DATABASE_SCHEMA }} | |
| PLAYWRIGHT_POSTGRES_USERNAME: ${{ secrets.TEST_POSTGRES_USERNAME }} | |
| PLAYWRIGHT_POSTGRES_PASSWORD: ${{ secrets.TEST_POSTGRES_PASSWORD }} | |
| PLAYWRIGHT_POSTGRES_HOST_PORT: ${{ secrets.TEST_POSTGRES_HOST_PORT }} | |
| PLAYWRIGHT_POSTGRES_DATABASE: ${{ secrets.TEST_POSTGRES_DATABASE }} | |
| PLAYWRIGHT_AIRFLOW_HOST_PORT: ${{ secrets.TEST_AIRFLOW_HOST_PORT }} | |
| PLAYWRIGHT_ML_MODEL_TRACKING_URI: ${{ secrets.TEST_ML_MODEL_TRACKING_URI }} | |
| PLAYWRIGHT_ML_MODEL_REGISTRY_URI: ${{ secrets.TEST_ML_MODEL_REGISTRY_URI }} | |
| PLAYWRIGHT_S3_STORAGE_ACCESS_KEY_ID: ${{ secrets.TEST_S3_STORAGE_ACCESS_KEY_ID }} | |
| PLAYWRIGHT_S3_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.TEST_S3_STORAGE_SECRET_ACCESS_KEY }} | |
| PLAYWRIGHT_S3_STORAGE_END_POINT_URL: ${{ secrets.TEST_S3_STORAGE_END_POINT_URL }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload Playwright diagnostics | |
| uses: actions/upload-artifact@v7 | |
| if: failure() || cancelled() | |
| continue-on-error: true | |
| with: | |
| name: playwright-rdf-report | |
| path: | | |
| openmetadata-ui/src/main/resources/ui/playwright/output/playwright-report | |
| openmetadata-ui/src/main/resources/ui/playwright/output/test-results | |
| retention-days: 5 | |
| if-no-files-found: ignore | |
| - name: Clean Up | |
| if: always() | |
| continue-on-error: true | |
| run: | | |
| docker compose -f docker/development/docker-compose-postgres.yml -f docker/development/docker-compose-fuseki.yml down --remove-orphans || true | |
| docker compose -f docker/development/docker-compose-postgres.yml down --remove-orphans || true | |
| sudo rm -rf "${PWD}/docker/development/docker-volume" | |
| # Publishes the required branch-protection check name | |
| # `Playwright RDF (Knowledge Graph + Ontology)` ONLY when this run is | |
| # authorised by the gate. Every other case (redundant sibling event | |
| # for a same-repo PR, fork PR without safe-to-test, draft, spurious | |
| # non-safe-to-test labeled event) publishes a differently-named check | |
| # so branch protection can distinguish "authoritative for this PR | |
| # shape" from "synthetic green / skipped". Without this, GitHub's | |
| # protection UI picks the most-recently-completed run of the required | |
| # name — and the pull_request_target sibling of a same-repo PR would | |
| # finish in ~15s with a green skip while the real pull_request run is | |
| # still compiling, making the PR appear mergeable before tests run. | |
| # | |
| # Decision tree (mirrors the gate + playwright-postgresql-e2e.yml | |
| # pattern from #30476): | |
| # gate succeeds with should_run=true → 'Playwright RDF (Knowledge Graph + Ontology)' | |
| # gate fails (crash / cancelled) → 'Playwright RDF (Knowledge Graph + Ontology)' + hard fail | |
| # labeled event with non-'safe to test' label → '... (label ignored)' | |
| # gate succeeds with should_run=false → '... (skipped)' | |
| playwright-rdf-summary: | |
| name: >- | |
| ${{ | |
| ( | |
| needs.gate.result != 'success' | |
| || needs.gate.outputs.should_run == 'true' | |
| ) | |
| && 'Playwright RDF (Knowledge Graph + Ontology)' | |
| || ( | |
| github.event.action == 'labeled' | |
| && github.event.label.name != 'safe to test' | |
| && 'Playwright RDF (Knowledge Graph + Ontology) (label ignored)' | |
| || 'Playwright RDF (Knowledge Graph + Ontology) (skipped)' | |
| ) | |
| }} | |
| if: ${{ always() && !cancelled() }} | |
| needs: [gate, changes, build, playwright-rdf-postgresql] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| # If gate itself didn't produce a valid decision (crash, cancelled, | |
| # unknown), FAIL loudly rather than silently reporting green. | |
| # Without this guard, `should_run != 'true'` on an unset output | |
| # would fall into the label-ignored/skipped branch above and mask | |
| # the gate failure. | |
| - name: Guard against missing gate decision | |
| if: ${{ needs.gate.result != 'success' }} | |
| run: | | |
| echo "::error::gate did not succeed (result=${{ needs.gate.result }}, should_run=${{ needs.gate.outputs.should_run }}). Refusing synthetic green." | |
| exit 1 | |
| # Same treatment for the paths detector: an unset `rdf` output would | |
| # look like "no paths changed" and silently pass without ever running | |
| # the tests. | |
| - name: Guard against missing changes decision | |
| if: ${{ needs.changes.result != 'success' }} | |
| run: | | |
| echo "::error::changes did not succeed (result=${{ needs.changes.result }}, rdf=${{ needs.changes.outputs.rdf }}). Refusing synthetic green." | |
| exit 1 | |
| # Short-circuit when gate decided should_run=false. The underlying | |
| # jobs are skipped in that case (redundant pull_request_target for | |
| # a same-repo PR, or fork PR without safe-to-test), so there's | |
| # nothing to summarise. The dynamic job name above already routes | |
| # this run to a non-required check name; this step just keeps the | |
| # job outcome at ✅. | |
| - name: Report gate-skipped run as green | |
| if: ${{ needs.gate.outputs.should_run == 'false' }} | |
| run: | | |
| echo "Gate decided should_run=false for event=${{ github.event_name }}." | |
| echo "This run is intentionally skipped; the authoritative required check comes from the sibling event's run." | |
| # Authoritative event but no RDF/ontology paths changed. Build and | |
| # tests were skipped by design; publish the required check name as | |
| # green so branch protection is satisfied on PRs unrelated to RDF. | |
| - name: Report no-paths-changed run as green | |
| if: ${{ needs.gate.outputs.should_run == 'true' && needs.changes.outputs.rdf != 'true' }} | |
| run: | | |
| echo "No RDF/ontology paths changed for event=${{ github.event_name }}." | |
| echo "Build and Playwright execution were skipped; required check reports green." | |
| # Propagate real upstream failures under the required check name | |
| # so the PR fails visibly rather than falling through to green. | |
| # Only fires when we actually asked the pipeline to run. | |
| - name: Fail on upstream failure | |
| if: | | |
| needs.gate.outputs.should_run == 'true' && needs.changes.outputs.rdf == 'true' && ( | |
| needs.build.result != 'success' || | |
| needs.playwright-rdf-postgresql.result != 'success' | |
| ) | |
| run: | | |
| echo "::error::Upstream job failure — build=${{ needs.build.result }}, execution=${{ needs.playwright-rdf-postgresql.result }}." | |
| exit 1 |