chore: remove stray committed files and extend .gitignore #283
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: Cardano Ecosystem CI | |
| # Thin orchestrator. | |
| # | |
| # Most of the work — installing toolchains, the matrix shape, the | |
| # upload/download artifact pattern — lives in reusable workflows under | |
| # .github/workflows/_*.yml and composite actions under .github/actions/. | |
| # | |
| # Off-chain tests run in a cross-product: each off-chain framework is tested | |
| # against every on-chain framework whose example set it shares. The discover job | |
| # computes that cross-product as `offchain-matrix` (in local-test-discovery.sh), | |
| # and a single matrix-driven `test-offchain` job runs every combo through the | |
| # runtime-generic reusable workflow `_test-offchain.yml`. | |
| # Artifact and log naming: plutus-<onchain>-<example> / logs-<prefix>-<onchain>-<example> | |
| # so the dashboard generator can correlate them automatically. | |
| # | |
| # Adding a new OFF-CHAIN framework: | |
| # 1. Add it to frameworks.json (kind: offchain, with runtime/subdir/entryGlob). | |
| # It flows into `offchain-matrix` automatically — no YAML changes here. | |
| # | |
| # Adding a new ON-CHAIN framework: | |
| # 1. Add it to frameworks.json (kind: onchain). | |
| # 2. Add a compile-<id> job below pointing at the right reusable compile workflow, | |
| # and add it to test-offchain's `needs` + the report-and-dashboard `needs`. | |
| # (Off-chain combos against it appear in `offchain-matrix` automatically.) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| schedule: | |
| - cron: '0 2 * * *' # 2am UTC daily | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| AIKEN_VERSION: v1.1.21 | |
| SCALUS_JAVA_VERSION: '21' | |
| CACHE_VERSION: v1 | |
| jobs: | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| # Discovery | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| discover: | |
| name: Discover Examples | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| # On-chain example lists drive the compile jobs; offchain-matrix is the | |
| # off-chain × on-chain cross-product that drives the single test job. | |
| aiken-examples: ${{ steps.discovery.outputs.aiken-examples }} | |
| scalus-examples: ${{ steps.discovery.outputs.scalus-examples }} | |
| offchain-matrix: ${{ steps.discovery.outputs.offchain-matrix }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Run discovery script | |
| id: discovery | |
| run: | | |
| chmod +x scripts/local-test-discovery.sh | |
| scripts/local-test-discovery.sh | |
| # (Cross-product example lists are now computed in local-test-discovery.sh and | |
| # exposed as the single `offchain-matrix` output of the discover job.) | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| # Toolchain prepare | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| prepare-toolchains: | |
| name: Prepare toolchains | |
| needs: discover | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Aiken | |
| if: needs.discover.outputs.aiken-examples != '[]' | |
| uses: ./.github/actions/setup-aiken | |
| with: | |
| aiken-version: ${{ env.AIKEN_VERSION }} | |
| cache-version: ${{ env.CACHE_VERSION }} | |
| - name: Setup SBT | |
| if: needs.discover.outputs.scalus-examples != '[]' | |
| uses: ./.github/actions/setup-sbt | |
| with: | |
| java-version: ${{ env.SCALUS_JAVA_VERSION }} | |
| cache-version: ${{ env.CACHE_VERSION }} | |
| - name: Setup JBang + Java | |
| if: contains(needs.discover.outputs.offchain-matrix, '"runtime":"jbang"') | |
| uses: ./.github/actions/setup-jbang-java | |
| with: | |
| cache-version: ${{ env.CACHE_VERSION }} | |
| - name: Setup Yaci DevKit (install only) | |
| if: needs.discover.outputs.offchain-matrix != '[]' | |
| uses: ./.github/actions/setup-yaci-devkit | |
| with: | |
| start: 'false' | |
| cache-version: ${{ env.CACHE_VERSION }} | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| # On-chain compile | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| compile-aiken: | |
| needs: [discover, prepare-toolchains] | |
| if: needs.discover.outputs.aiken-examples != '[]' | |
| uses: ./.github/workflows/_compile-aiken.yml | |
| with: | |
| examples: ${{ needs.discover.outputs.aiken-examples }} | |
| aiken-version: v1.1.21 | |
| cache-version: v1 | |
| compile-scalus: | |
| needs: [discover, prepare-toolchains] | |
| if: needs.discover.outputs.scalus-examples != '[]' | |
| uses: ./.github/workflows/_compile-scalus.yml | |
| with: | |
| examples: ${{ needs.discover.outputs.scalus-examples }} | |
| java-version: '21' | |
| cache-version: v1 | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| # Off-chain tests — one matrix-driven job over the off-chain × on-chain | |
| # cross-product computed by discover (`offchain-matrix`). Each matrix row is a | |
| # {framework-id, status-prefix, subdir, runtime, onchain, examples} combo run | |
| # through the runtime-generic reusable workflow. Adding a framework adds rows | |
| # to the matrix automatically — no new jobs here. | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| test-offchain: | |
| needs: [discover, prepare-toolchains, compile-aiken, compile-scalus] | |
| # Run whenever the matrix is non-empty and no prerequisite *failed*. A | |
| # conditionally-skipped compile job (e.g. no scalus examples) must not block | |
| # the aiken combos, so we allow 'skipped'/'success' but not 'failure'. | |
| if: >- | |
| ${{ !cancelled() | |
| && needs.discover.outputs.offchain-matrix != '[]' | |
| && needs.compile-aiken.result != 'failure' | |
| && needs.compile-scalus.result != 'failure' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: ${{ fromJson(needs.discover.outputs.offchain-matrix) }} | |
| uses: ./.github/workflows/_test-offchain.yml | |
| with: | |
| framework-id: ${{ matrix.framework-id }} | |
| status-prefix: ${{ matrix.status-prefix }} | |
| subdir: ${{ matrix.subdir }} | |
| runtime: ${{ matrix.runtime }} | |
| examples: ${{ toJson(matrix.examples) }} | |
| onchain-framework: ${{ matrix.onchain }} | |
| cache-version: v1 | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| # Report & Dashboard | |
| # ─────────────────────────────────────────────────────────────────────────── | |
| report-and-dashboard: | |
| name: Report & Dashboard | |
| needs: | |
| - compile-aiken | |
| - compile-scalus | |
| - test-offchain | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| # Publishing the dashboard needs to push commits and open PRs. | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 | |
| ref: ${{ github.head_ref || github.ref }} | |
| - name: Install jq | |
| run: sudo apt-get install -y jq | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts/ | |
| - name: Reconstruct status files from artifacts | |
| run: | | |
| mkdir -p .local-test-results | |
| # Onchain compile status: plutus-<onchain>-<example> → <onchain>-<example>-status.txt | |
| for d in artifacts/plutus-*/; do | |
| [ -d "$d" ] || continue | |
| # Strip "plutus-" prefix → e.g. "aiken-payment-splitter" or "scalus-auction" | |
| rest=$(basename "$d" | sed 's/^plutus-//') | |
| if [ -f "$d/plutus.json" ]; then | |
| echo "success" > ".local-test-results/${rest}-status.txt" | |
| else | |
| echo "failed" > ".local-test-results/${rest}-status.txt" | |
| fi | |
| done | |
| # Off-chain test status from logs-<prefix>-<onchain>-<example> artifacts. | |
| # The example name is everything after "logs-<prefix>-", so it naturally | |
| # becomes "<onchain>-<example>" which is what generate-dashboard.sh expects. | |
| resolve_status() { | |
| local prefix="$1" log_pattern="$2" | |
| for d in artifacts/logs-${prefix}-*/; do | |
| [ -d "$d" ] || continue | |
| local rest | |
| rest=$(basename "$d" | sed "s/^logs-${prefix}-//") | |
| local out=".local-test-results/${prefix}-${rest}-status.txt" | |
| if [ -f "$d/test-status.txt" ]; then | |
| cp "$d/test-status.txt" "$out" | |
| elif [ -f "$d/test-output.log" ] && grep -qE "$log_pattern" "$d/test-output.log" 2>/dev/null; then | |
| echo "failed" > "$out" | |
| elif [ -f "$d/test-output.log" ]; then | |
| echo "success" > "$out" | |
| else | |
| echo "failed" > "$out" | |
| fi | |
| done | |
| } | |
| resolve_status ccl "AssertionError|BUILD FAILED|Exception in thread" | |
| resolve_status mesh "Uncaught|AssertionError|TypeError:|ReferenceError:|SyntaxError:|^error:" | |
| resolve_status evosdk "Uncaught|AssertionError|TypeError:|ReferenceError:|SyntaxError:|^error:" | |
| resolve_status pycardano "Traceback|Error:|Exception:" | |
| - name: Generate markdown report | |
| env: | |
| REPO: ${{ github.repository }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| echo "# Cardano Ecosystem Test Report" > report.md | |
| echo "" >> report.md | |
| echo "**Generated**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> report.md | |
| echo "**Workflow Run**: https://github.com/${REPO}/actions/runs/${RUN_ID}" >> report.md | |
| echo "" >> report.md | |
| echo "## Summary" >> report.md | |
| echo "" >> report.md | |
| AIKEN_COUNT=$(find artifacts -name "plutus-aiken-*" -type d 2>/dev/null | wc -l) | |
| SCALUS_COUNT=$(find artifacts -name "plutus-scalus-*" -type d 2>/dev/null | wc -l) | |
| CCL_COUNT=$(find artifacts -name "logs-ccl-*" -type d 2>/dev/null | wc -l) | |
| MESH_COUNT=$(find artifacts -name "logs-mesh-*" -type d 2>/dev/null | wc -l) | |
| EVOSDK_COUNT=$(find artifacts -name "logs-evosdk-*" -type d 2>/dev/null | wc -l) | |
| PYCARDANO_COUNT=$(find artifacts -name "logs-pycardano-*" -type d 2>/dev/null | wc -l) | |
| echo "- **Aiken Examples Compiled**: $AIKEN_COUNT" >> report.md | |
| echo "- **Scalus Examples Compiled**: $SCALUS_COUNT" >> report.md | |
| echo "- **CCL Java Tests**: $CCL_COUNT" >> report.md | |
| echo "- **Mesh.js Tests**: $MESH_COUNT" >> report.md | |
| echo "- **Evolution SDK Tests**: $EVOSDK_COUNT" >> report.md | |
| echo "- **PyCardano Tests**: $PYCARDANO_COUNT" >> report.md | |
| echo "" >> report.md | |
| echo "All test logs and build artifacts are available in the workflow artifacts." >> report.md | |
| - name: Run version check | |
| run: bash scripts/check-library-versions.sh | |
| - name: Generate dashboard | |
| run: bash scripts/generate-dashboard.sh | |
| - name: Add report and version status to job summary | |
| if: always() | |
| run: | | |
| cat report.md >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -f .local-test-results/version-report.md ]; then | |
| cat .local-test-results/version-report.md >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Upload reports artifact | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: reports | |
| path: | | |
| report.md | |
| .local-test-results/version-report.json | |
| .local-test-results/version-report.md | |
| retention-days: 30 | |
| # Only comment on the PR when the version check flagged outdated libraries — | |
| # avoids posting a report on every run when there's nothing actionable. | |
| - name: Post PR comment | |
| if: github.event_name == 'pull_request' && env.VERSIONS_OUTDATED == 'true' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const report = fs.readFileSync('report.md', 'utf8'); | |
| const versionReport = fs.existsSync('.local-test-results/version-report.md') | |
| ? '\n\n' + fs.readFileSync('.local-test-results/version-report.md', 'utf8') | |
| : ''; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: report + versionReport | |
| }); | |
| # Publish the dashboard resiliently: | |
| # • only when dashboard.json *meaningfully* changed (lastUpdated ignored); | |
| # • on the default branch → open a PR (never a direct commit to main); | |
| # • on any other branch (e.g. a PR's head branch) → commit directly; | |
| # • never fail the build if publishing can't push/open a PR. | |
| - name: Detect dashboard change | |
| id: dash | |
| env: | |
| BRANCH: ${{ github.head_ref || github.ref_name }} | |
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| changed=false | |
| if [ ! -f dashboard/dashboard.json ]; then | |
| echo "dashboard/dashboard.json missing — nothing to publish" | |
| else | |
| CURR=$(jq -S 'del(.lastUpdated)' dashboard/dashboard.json 2>/dev/null || echo '') | |
| PREV=$(git show HEAD:dashboard/dashboard.json 2>/dev/null \ | |
| | jq -S 'del(.lastUpdated)' 2>/dev/null || echo '') | |
| if [ "$CURR" = "$PREV" ]; then | |
| echo "No meaningful change (lastUpdated ignored) — discarding timestamp-only churn" | |
| git checkout -- dashboard/dashboard.json 2>/dev/null || true | |
| else | |
| echo "Dashboard changed — will publish" | |
| changed=true | |
| fi | |
| fi | |
| echo "changed=$changed" >> "$GITHUB_OUTPUT" | |
| if [ "$BRANCH" = "$DEFAULT_BRANCH" ]; then | |
| echo "on default branch ($BRANCH) → PR" | |
| echo "is_default=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "on branch ($BRANCH) → direct commit" | |
| echo "is_default=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Commit dashboard.json to branch | |
| if: steps.dash.outputs.changed == 'true' && steps.dash.outputs.is_default != 'true' | |
| continue-on-error: true | |
| env: | |
| BRANCH: ${{ github.head_ref || github.ref_name }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add dashboard/dashboard.json | |
| git commit -m "chore: update dashboard.json [skip ci]" | |
| git push origin "HEAD:${BRANCH}" | |
| - name: Open dashboard PR (default branch) | |
| if: steps.dash.outputs.changed == 'true' && steps.dash.outputs.is_default == 'true' | |
| continue-on-error: true | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| base: ${{ github.event.repository.default_branch }} | |
| branch: automated/dashboard-update | |
| delete-branch: true | |
| add-paths: dashboard/dashboard.json | |
| title: "chore: update dashboard.json" | |
| commit-message: "chore: update dashboard.json [skip ci]" | |
| body: | | |
| ## Automated dashboard update | |
| The ecosystem CI detected a change in the cross-check matrix. | |
| This PR updates `dashboard/dashboard.json` (the `lastUpdated` | |
| timestamp alone never triggers it). | |
| --- | |
| _Generated by the ecosystem CI workflow_ | |
| - name: Update versions.json from upstream | |
| if: github.event_name == 'schedule' && env.VERSIONS_OUTDATED == 'true' | |
| run: | | |
| jq '.libraries | to_entries | map({key: .key, value: .value.latest}) | from_entries' \ | |
| .local-test-results/version-report.json > versions.json.new | |
| mv versions.json.new versions.json | |
| echo "Updated versions.json:" | |
| cat versions.json | |
| - name: Apply version sync | |
| if: github.event_name == 'schedule' && env.VERSIONS_OUTDATED == 'true' | |
| run: bash scripts/sync-versions.sh | |
| - name: Create version-bump PR | |
| if: github.event_name == 'schedule' && env.VERSIONS_OUTDATED == 'true' | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| branch: automated/version-bump | |
| delete-branch: true | |
| # Only the files the version sync actually touches — the workspace | |
| # also holds downloaded artifacts/ and the generated report.md, | |
| # which must never end up in the PR. | |
| add-paths: | | |
| versions.json | |
| **/aiken.toml | |
| **/offchain/meshjs/deno.json | |
| **/offchain/evolutionsdk/deno.json | |
| **/offchain/ccl-java/*.java | |
| **/offchain/pycardano/requirements.txt | |
| title: "chore: update library versions to latest" | |
| labels: ${{ env.VERSION_BUMP_LABEL }} | |
| body: | | |
| ## Automated Version Bump | |
| The version check detected outdated libraries. | |
| This PR updates all dependency files to the latest versions. | |
| See the `reports` artifact from the workflow run for details. | |
| --- | |
| _Generated by the ecosystem CI workflow_ | |
| commit-message: "chore: bump library versions to latest" |