--- # DESCRIPTION: Github actions config # This name is key to badges in README.rst, so we use the name build # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 name: RTLMeter on: workflow_dispatch: schedule: - cron: '0 2 * * *' # Daily, starting at 02:00 UTC pull_request: types: [opened, synchronize, reopened, labeled, unlabeled] push: branches: ['ci-rtlmeter/**'] permissions: contents: read defaults: run: shell: bash concurrency: # At most 1 job per branch. Auto cancel all but scheduled jobs group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name != 'schedule' }} jobs: start: name: Start # Only run scheduled jobs if explicitly enabled for that repo (e.g.: not on forks) # Only run pull request jobs if labelled as needing an RTLMeter run # Always run workflow dispatch jobs if: | (github.event_name == 'schedule' && vars.ENABLE_SCHEDULED_JOBS == 'true') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pr: rtlmeter')) || (github.event_name == 'workflow_dispatch') || (github.event_name == 'push') runs-on: ubuntu-24.04 outputs: old-sha: ${{ steps.start.outputs.old-sha }} cases: ${{ steps.cases.outputs.cases }} steps: - name: Checkout uses: actions/checkout@v6 - name: Startup id: start env: GH_TOKEN: ${{ github.token }} run: | [[ "${{ github.event_name }}" == 'pull_request' ]] || exit 0 # For a pull request, 'github.sha' is the test merge commit. Its # first parent is the target branch commit it was merged with for this run. OLD_SHA="$(gh api "repos/${{ github.repository }}/commits/${{ github.sha }}" --jq '.parents[0].sha')" echo "old-sha=$OLD_SHA" >> "$GITHUB_OUTPUT" - name: Load RTLMeter cases id: cases run: echo "cases=$(ci/ci-rtlmeter-cases.py --event-name ${{ github.event_name }})" >> "$GITHUB_OUTPUT" build-gcc-new: name: Build New Verilator - GCC needs: start uses: ./.github/workflows/reusable-rtlmeter-build.yml with: runs-on: ubuntu-24.04 cc: gcc sha: ${{ github.sha }} build-clang-new: name: Build New Verilator - Clang needs: start uses: ./.github/workflows/reusable-rtlmeter-build.yml with: runs-on: ubuntu-24.04 cc: clang sha: ${{ github.sha }} build-gcc-old: name: Build Old Verilator - GCC needs: start if: ${{ needs.start.outputs.old-sha != '' }} uses: ./.github/workflows/reusable-rtlmeter-build.yml with: runs-on: ubuntu-24.04 cc: gcc sha: ${{ needs.start.outputs.old-sha }} build-clang-old: name: Build Old Verilator - Clang needs: start if: ${{ needs.start.outputs.old-sha != '' }} uses: ./.github/workflows/reusable-rtlmeter-build.yml with: runs-on: ubuntu-24.04 cc: clang sha: ${{ needs.start.outputs.old-sha }} run-gcc: name: Run GCC | ${{ matrix.cases }} needs: - start - build-gcc-new - build-gcc-old # Run even if 'build-*-old' was skipped (no old SHA), but not if any # dependency failed, the workflow was cancelled, or 'start' was skipped # (e.g. the workflow was not enabled, so there is nothing to run against). if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }} uses: ./.github/workflows/reusable-rtlmeter-run.yml with: tag: gcc runs-on: ubuntu-24.04 cc: gcc verilator-archive-new: ${{ needs.build-gcc-new.outputs.archive }} verilator-archive-old: ${{ needs.build-gcc-old.outputs.archive }} cases: ${{ matrix.cases }} run-name: "gcc" compileArgs: "" executeArgs: "" strategy: fail-fast: ${{ github.event_name == 'pull_request' }} max-parallel: 7 matrix: cases: ${{ fromJSON(needs.start.outputs.cases)['gcc'] }} run-clang: name: Run Clang | ${{ matrix.cases }} needs: - start - build-clang-new - build-clang-old # Run even if 'build-*-old' was skipped (no old SHA), but not if any # dependency failed, the workflow was cancelled, or 'start' was skipped # (e.g. the workflow was not enabled, so there is nothing to run against). if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }} uses: ./.github/workflows/reusable-rtlmeter-run.yml with: tag: clang runs-on: ubuntu-24.04 cc: clang verilator-archive-new: ${{ needs.build-clang-new.outputs.archive }} verilator-archive-old: ${{ needs.build-clang-old.outputs.archive }} cases: ${{ matrix.cases }} run-name: "clang --threads 4" compileArgs: "--threads 4" executeArgs: "" strategy: fail-fast: ${{ github.event_name == 'pull_request' }} max-parallel: 7 matrix: cases: ${{ fromJSON(needs.start.outputs.cases)['clang'] }} run-gcc-hier: name: Run GCC hier | ${{ matrix.cases }} needs: - start - build-gcc-new - build-gcc-old # Run even if 'build-*-old' was skipped (no old SHA), but not if any # dependency failed, the workflow was cancelled, or 'start' was skipped # (e.g. the workflow was not enabled, so there is nothing to run against). if: ${{ !failure() && !cancelled() && needs.start.result == 'success' }} uses: ./.github/workflows/reusable-rtlmeter-run.yml with: tag: gcc-hier runs-on: ubuntu-24.04 cc: gcc verilator-archive-new: ${{ needs.build-gcc-new.outputs.archive }} verilator-archive-old: ${{ needs.build-gcc-old.outputs.archive }} cases: ${{ matrix.cases }} run-name: "gcc --hierarchical" compileArgs: "--hierarchical" executeArgs: "" strategy: fail-fast: ${{ github.event_name == 'pull_request' }} max-parallel: 6 matrix: cases: ${{ fromJSON(needs.start.outputs.cases)['gcc-hier'] }} combine-results: name: Combine results needs: [run-gcc, run-clang, run-gcc-hier] # Skip if cancelled. # On PRs, run if something succeeded and nothing failed. # On non-PRs, run if anything succeeded or failed (so partial results are still published). if: >- ${{ !cancelled() && ( (github.event_name == 'pull_request' && (contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure'))) || (github.event_name != 'pull_request' && (contains(needs.*.result, 'success') || contains(needs.*.result, 'failure'))) )}} runs-on: ubuntu-24.04 outputs: # The run tags, derived from the 'run-*' dependency job names run-tags: ${{ steps.tags.outputs.tags }} env: GH_TOKEN: ${{ github.token }} # 'gh' resolves the repo from git otherwise, but this job has no checkout # of this repo at the workspace root GH_REPO: ${{ github.repository }} steps: # Derive the run tags from the dependency job names ('run-') - name: Determine run tags id: tags run: echo "tags=$(jq -r 'keys | map(sub("^run-"; "")) | join(" ")' <<< '${{ toJSON(needs) }}')" >> "$GITHUB_OUTPUT" - name: Checkout RTLMeter uses: actions/checkout@v6 with: repository: "verilator/rtlmeter" path: rtlmeter - name: Setup RTLMeter venv working-directory: rtlmeter run: make venv - name: Download all results run: | for tag in ${{ steps.tags.outputs.tags }}; do mkdir artifacts all-results-$tag gh run download ${{ github.run_id }} --pattern "rtlmeter-$tag-results-*" --dir artifacts mv $(find artifacts -name "*.json") all-results-$tag/ rm -rf artifacts done - name: Combine results working-directory: rtlmeter run: | for tag in ${{ steps.tags.outputs.tags }}; do ./rtlmeter collate ../all-results-$tag/*.json > ../all-results-$tag.json done - name: Upload combined results uses: actions/upload-artifact@v7 with: path: all-results-*.json name: all-results overwrite: true retention-days: 30 # The reference (old) results only exist for pull requests, where the # 'build-*-old' jobs run and the run jobs produce '*-reference-*' artifacts. - name: Download reference results if: ${{ github.event_name == 'pull_request' }} run: | for tag in ${{ steps.tags.outputs.tags }}; do mkdir artifacts all-reference-$tag gh run download ${{ github.run_id }} --pattern "rtlmeter-$tag-reference-*" --dir artifacts mv $(find artifacts -name "*.json") all-reference-$tag/ rm -rf artifacts done - name: Combine reference results if: ${{ github.event_name == 'pull_request' }} working-directory: rtlmeter run: | for tag in ${{ steps.tags.outputs.tags }}; do ./rtlmeter collate ../all-reference-$tag/*.json > ../all-reference-$tag.json done - name: Upload reference results if: ${{ github.event_name == 'pull_request' }} uses: actions/upload-artifact@v7 with: path: all-reference-*.json name: all-reference overwrite: true retention-days: 30 publish-scheduled-results: name: Publish results to verilator/verilator-rtlmeter-results needs: combine-results # Only run on scheduled builds on the main repository. We also restrict # the publishing to run only on the first run_attempt. This is required # to prevent multiple uploads the same day (if rerunning), as the # dashboard UI currently assumes there is only one data point per # calendar day. Results from reruns can be imported manually if needed. if: ${{ github.event_name == 'schedule' && github.repository == 'verilator/verilator' && github.run_attempt == 1 && contains(needs.*.result, 'success') && !cancelled() }} runs-on: ubuntu-24.04 steps: - name: Download combined results uses: actions/download-artifact@v8 with: name: all-results path: results - name: Upload published results uses: actions/upload-artifact@v7 with: path: results/*.json name: published-results # Pushing to verilator/verilator-rtlmeter-results requires elevated permissions - name: Generate access token id: generate-token uses: actions/create-github-app-token@v3.2.0 with: client-id: ${{ vars.VERILATOR_CI_ID }} private-key: ${{ secrets.VERILATOR_CI_KEY }} owner: verilator repositories: verilator-rtlmeter-results permission-contents: write - name: Checkout verilator-rtlmeter-results uses: actions/checkout@v6 with: repository: "verilator/verilator-rtlmeter-results" token: ${{ steps.generate-token.outputs.token }} path: verilator-rtlmeter-results - name: Import results id: import-results working-directory: verilator-rtlmeter-results run: | for f in $(find ../results -name "*.json"); do \ echo "Importing $f"; \ ./bin/add-rtlmeter-result $f; \ done test -z "$(git status --porcelain)" || echo "valid=1" >> "$GITHUB_OUTPUT" - name: Push to verilator-rtlmeter-results if: ${{ steps.import-results.outputs.valid }} working-directory: verilator-rtlmeter-results run: | git config --global user.email "action@example.com" git config --global user.name "github action" git add . git commit -m "Verilator CI: Results of 'RTLMeter' workflow run #${{ github.run_number }}" git push origin prepare-pr-results: name: Prepare Pull Request results needs: combine-results if: ${{ github.event_name == 'pull_request' && github.repository == 'verilator/verilator' && needs.combine-results.result == 'success' }} runs-on: ubuntu-24.04 permissions: actions: read steps: - name: Checkout RTLMeter uses: actions/checkout@v6 with: repository: "verilator/rtlmeter" path: rtlmeter - name: Setup RTLMeter venv working-directory: rtlmeter run: make venv - name: Checkout Verilator uses: actions/checkout@v6 with: path: verilator - name: Create report id: report working-directory: verilator env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | ln -s ../rtlmeter rtlmeter gh repo set-default ${{ github.repository }} # Create run report - save status to fail job if the script did STATUS=0 ci/ci-rtlmeter-report.bash ${{ github.run_id }} ${{ github.sha }} ${{ needs.combine-results.outputs.run-tags }} || STATUS=$? echo "status=$STATUS" >> "$GITHUB_OUTPUT" # Create the report artifact mkdir ../report-artifact mv rtlmeter-report/report ../report-artifact/ echo ${{ github.event.number }} > ../report-artifact/pr-number.txt # Create the notification artifact mkdir ../notification-artifact mv rtlmeter-report/notification.txt ../notification-artifact/body.txt echo ${{ github.event.number }} > ../notification-artifact/pr-number.txt - name: Upload report uses: actions/upload-artifact@v7 with: path: report-artifact name: rtlmeter-report - name: Upload notification uses: actions/upload-artifact@v7 with: path: notification-artifact name: pr-notification - name: Report status run: exit ${{ steps.report.outputs.status }} # Create GitHub issue for failed scheduled jobs # This should always be the last job (we want an issue if anything breaks) create-issue: name: Create issue on failure needs: publish-scheduled-results if: ${{ github.event_name == 'schedule' && github.repository == 'verilator/verilator' && github.run_attempt == 1 && failure() && !cancelled() }} runs-on: ubuntu-24.04 steps: # Creating issues requires elevated privilege - name: Generate access token id: generate-token uses: actions/create-github-app-token@v3.2.0 with: client-id: ${{ vars.VERILATOR_CI_ID }} private-key: ${{ secrets.VERILATOR_CI_KEY }} owner: verilator repositories: verilator permission-issues: write - name: Create issue env: GH_TOKEN: ${{ steps.generate-token.outputs.token }} run: |- echo "This issue was created automatically by the GitHub Actions CI due to the failure of a scheduled RTLMeter run." >> body.txt echo "" >> body.txt echo "Workflow status: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> body.txt gh issue --repo ${{ github.repository }} create \ --title "RTLMeter run #${{ github.run_number }} Failed" \ --body-file body.txt \ --label new \ --assignee gezalore,wsnyder