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
27 changes: 24 additions & 3 deletions .github/workflows/api-smoke.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
name: API smoke

on:
workflow_call:
inputs:
context_ref:
required: true
type: string
core_ref:
required: true
type: string
compute_ref:
required: true
type: string
web_ref:
required: true
type: string
integration_ref:
required: true
type: string
secrets:
REFINVEST_CI_APP_PRIVATE_KEY:
required: true
pull_request:
push:
branches:
Expand All @@ -27,14 +47,15 @@ permissions:
contents: read

concurrency:
group: api-smoke-${{ github.workflow }}-${{ inputs.context_ref || github.ref }}
group: api-smoke-${{ github.workflow }}-${{ github.event_name }}-${{ inputs.context_ref && github.run_id || github.ref }}
cancel-in-progress: true

jobs:
smoke:
name: Core to Compute API smoke and Web browser acceptance
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
timeout-minutes: 45
services:
postgres:
image: postgres:17-alpine
Expand Down Expand Up @@ -173,14 +194,14 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: api-smoke-and-web-acceptance-compatibility-evidence
name: api-smoke-and-web-acceptance-compatibility-evidence-${{ github.run_attempt }}
path: integration/.integration-data/evidence/compatibility.json
if-no-files-found: warn

- name: Upload integration logs
if: always()
uses: actions/upload-artifact@v4
with:
name: api-smoke-and-web-acceptance-logs
name: api-smoke-and-web-acceptance-logs-${{ github.run_attempt }}
path: integration/.integration-data/logs
if-no-files-found: warn
92 changes: 92 additions & 0 deletions .github/workflows/contract-evidence.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Record candidate contract evidence

on:
workflow_run:
workflows: [Propagate Context snapshots]
types: [completed]

permissions:
contents: read
actions: read

concurrency:
group: contract-evidence-${{ github.event.workflow_run.id }}
cancel-in-progress: false

jobs:
record:
if: >-
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.repository.full_name == github.repository &&
(github.event.workflow_run.event == 'workflow_dispatch' ||
github.event.workflow_run.event == 'repository_dispatch')
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
# Never check out the candidate or execute files from downloaded artifacts.
- name: Checkout trusted default branch
uses: actions/checkout@v4
with:
ref: refs/heads/main
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Create read-only Context token
id: context-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.REFINVEST_CI_APP_CLIENT_ID }}
private-key: ${{ secrets.REFINVEST_CI_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: context
permission-contents: read

- name: Create evidence PR token
id: pr-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.REFINVEST_CI_APP_CLIENT_ID }}
private-key: ${{ secrets.REFINVEST_CI_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
integration
core-api
compute-api
web
permission-contents: read
permission-pull-requests: write

- name: Collect completed jobs and link PR evidence
env:
GH_TOKEN: ${{ steps.pr-token.outputs.token }}
GH_CONTEXT_TOKEN: ${{ steps.context-token.outputs.token }}
GH_ACTIONS_TOKEN: ${{ github.token }}
SOURCE_REPOSITORY: ${{ github.repository }}
SOURCE_RUN_ID: ${{ github.event.workflow_run.id }}
SOURCE_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
CONTRACT_REPORT_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
python -B scripts/contract_evidence.py \
--repository "$SOURCE_REPOSITORY" --run-id "$SOURCE_RUN_ID" \
--attempt "$SOURCE_ATTEMPT" --output "$RUNNER_TEMP/contract-evidence"

- name: Publish evidence summary
if: always()
run: |
if [ -f "$RUNNER_TEMP/contract-evidence/contract-candidate-evidence.md" ]; then
cat "$RUNNER_TEMP/contract-evidence/contract-candidate-evidence.md" >> "$GITHUB_STEP_SUMMARY"
else
echo '후보 검증 증거를 수집하지 못했습니다. 성공으로 간주하지 말고 이 실행의 로그를 확인하세요.' >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload final candidate evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: contract-candidate-evidence-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}
path: ${{ runner.temp }}/contract-evidence/
if-no-files-found: warn
62 changes: 36 additions & 26 deletions .github/workflows/contract-propagation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ concurrency:

jobs:
propagate:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 15
outputs:
context_ref: ${{ steps.propagate.outputs.context_ref }}
core_ref: ${{ steps.propagate.outputs.core_ref }}
compute_ref: ${{ steps.propagate.outputs.compute_ref }}
web_ref: ${{ steps.propagate.outputs.web_ref }}
integration_ref: ${{ steps.propagate.outputs.integration_ref }}
steps:
- name: Create read-only Context token
id: context-token
Expand All @@ -45,14 +53,14 @@ jobs:
web
permission-contents: write
permission-pull-requests: write
permission-actions: write

- name: Checkout integration
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/integration
token: ${{ steps.propagation-token.outputs.token }}
path: integration
ref: ${{ github.sha }}
fetch-depth: 0

- name: Checkout Context
Expand Down Expand Up @@ -109,35 +117,37 @@ jobs:
echo "compute_ref=$(jq -r '.heads.computeApi' "$RUNNER_TEMP/contract-propagation.json")" >> "$GITHUB_OUTPUT"
echo "web_ref=$(jq -r '.heads.web' "$RUNNER_TEMP/contract-propagation.json")" >> "$GITHUB_OUTPUT"
echo "integration_ref=$(jq -r '.heads.integration' "$RUNNER_TEMP/contract-propagation.json")" >> "$GITHUB_OUTPUT"
echo "run_api_smoke=$(jq -r '.runApiSmoke' "$RUNNER_TEMP/contract-propagation.json")" >> "$GITHUB_OUTPUT"

- name: Dispatch candidate contract verification
env:
GH_TOKEN: ${{ steps.propagation-token.outputs.token }}
run: |
gh workflow run contract-sync.yml --repo '${{ github.repository_owner }}/integration' \
-f context_ref='${{ steps.propagate.outputs.context_ref }}' \
-f core_ref='${{ steps.propagate.outputs.core_ref }}' \
-f compute_ref='${{ steps.propagate.outputs.compute_ref }}' \
-f web_ref='${{ steps.propagate.outputs.web_ref }}' \
-f integration_ref='${{ steps.propagate.outputs.integration_ref }}'

- name: Dispatch candidate API smoke
if: steps.propagate.outputs.run_api_smoke == 'true'
env:
GH_TOKEN: ${{ steps.propagation-token.outputs.token }}
run: |
gh workflow run api-smoke.yml --repo '${{ github.repository_owner }}/integration' \
-f context_ref='${{ steps.propagate.outputs.context_ref }}' \
-f core_ref='${{ steps.propagate.outputs.core_ref }}' \
-f compute_ref='${{ steps.propagate.outputs.compute_ref }}' \
-f web_ref='${{ steps.propagate.outputs.web_ref }}' \
-f integration_ref='${{ steps.propagate.outputs.integration_ref }}'

- name: Upload propagation result
if: always()
uses: actions/upload-artifact@v4
with:
name: contract-propagation-result
name: contract-propagation-result-${{ github.run_attempt }}
path: ${{ runner.temp }}/contract-propagation.json
if-no-files-found: ignore

candidate-sync:
name: candidate-sync
needs: propagate
uses: ./.github/workflows/contract-sync.yml
with:
context_ref: ${{ needs.propagate.outputs.context_ref }}
core_ref: ${{ needs.propagate.outputs.core_ref }}
compute_ref: ${{ needs.propagate.outputs.compute_ref }}
web_ref: ${{ needs.propagate.outputs.web_ref }}
integration_ref: ${{ needs.propagate.outputs.integration_ref }}
secrets:
REFINVEST_CI_APP_PRIVATE_KEY: ${{ secrets.REFINVEST_CI_APP_PRIVATE_KEY }}

candidate-smoke:
name: candidate-smoke
needs: [propagate, candidate-sync]
uses: ./.github/workflows/api-smoke.yml
with:
context_ref: ${{ needs.propagate.outputs.context_ref }}
core_ref: ${{ needs.propagate.outputs.core_ref }}
compute_ref: ${{ needs.propagate.outputs.compute_ref }}
web_ref: ${{ needs.propagate.outputs.web_ref }}
integration_ref: ${{ needs.propagate.outputs.integration_ref }}
secrets:
REFINVEST_CI_APP_PRIVATE_KEY: ${{ secrets.REFINVEST_CI_APP_PRIVATE_KEY }}
28 changes: 27 additions & 1 deletion .github/workflows/contract-sync.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
name: Contract sync

on:
workflow_call:
inputs:
context_ref:
required: true
type: string
core_ref:
required: true
type: string
compute_ref:
required: true
type: string
web_ref:
required: true
type: string
integration_ref:
required: true
type: string
secrets:
REFINVEST_CI_APP_PRIVATE_KEY:
required: true
pull_request:
push:
branches:
Expand Down Expand Up @@ -33,6 +53,7 @@ jobs:
name: Verify Context/Core/Compute/Web snapshots
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout integration
uses: actions/checkout@v4
Expand Down Expand Up @@ -95,6 +116,11 @@ jobs:
- name: Install Analytics contract verifier dependencies
run: python -m pip install -r integration/scripts/requirements-contract-sync.txt

- name: Test propagation policy and evidence binding
run: |
python -B -m unittest discover -s integration/scripts -p 'test_contract_*.py'
python -B -m unittest discover -s integration/scripts -p 'test_publish_contract_sync.py'

- name: Verify OpenAPI snapshots
id: contract-sync
shell: pwsh
Expand Down Expand Up @@ -146,6 +172,6 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: contract-sync-compatibility-evidence
name: contract-sync-compatibility-evidence-${{ github.run_attempt }}
path: integration/.integration-data/evidence/compatibility.json
if-no-files-found: warn
Loading
Loading