Skip to content

Code and Documentation Coverage (Deploy) #695

Code and Documentation Coverage (Deploy)

Code and Documentation Coverage (Deploy) #695

name: "Code and Documentation Coverage (Deploy)"
# see https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
on:
workflow_run:
workflows: ["Code and Documentation Coverage (PR)"]
types:
- completed
# see https://github.com/JamesIves/github-pages-deploy-action/tree/dev
permissions:
contents: write
env:
rust_release: nightly
jobs:
deploy-coverage:
name: "Info: Code Coverage"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set shas
id: sha
uses: actions/github-script@v6
with:
result-encoding: string
script: |
const {data: callee_run } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
console.log(callee_run);
// from manual inspection in jq, seems to hold head.sha for PR, not
// whatever GITHUB_SHA is.
return callee_run.head_sha;
- name: Download artifact
uses: dawidd6/action-download-artifact@v2
with:
name: code-coverage-${{ steps.sha.outputs.result }}
workflow: code-coverage.yml
path: ./deploy
- name: Deploy to Github Pages
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: ./deploy
target-folder: "coverage/${{ steps.sha.outputs.result }}"
branch: gh-pages
commit-message: "Actions: Code Coverage for ${{ steps.sha.outputs.result }}"
indexes:
needs: deploy-coverage
name: "Regenerate indexes for coverage"
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v2
- name: Checkout the pages repository
uses: actions/checkout@v2
with:
ref: "gh-pages"
path: "pages"
- name: Set shas
id: sha
uses: actions/github-script@v6
with:
result-encoding: string
script: |
const {data: callee_run } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
console.log(callee_run);
return callee_run.head_sha;
- name: "Generate indexes"
run: |
./tools/ci/genindex.py pages/coverage/
- uses: JamesIves/github-pages-deploy-action@v4
with:
folder: ./pages/coverage/
target-folder: ./coverage/
branch: gh-pages
commit-message: "Actions: Update coverage indexes"
comment:
permissions: write-all
needs: deploy-coverage
runs-on: ubuntu-latest
steps:
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
solvers/minion/vendor
solvers/chuffed/vendor
key: ${{ runner.os }}-${{ env.rust_release }}-${{ github.event.repository.updated_at }}
restore-keys: ${{ runner.os }}-${{ env.rust_release }}
- name: Set shas
id: sha
uses: actions/github-script@v6
with:
result-encoding: string
script: |
const {data: callee_run } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
console.log(callee_run);
// from manual inspection in jq, seems to hold head.sha for PR, not
// whatever GITHUB_SHA is.
return callee_run.head_sha;
- name: Download artifact
uses: dawidd6/action-download-artifact@v2
with:
name: code-coverage-${{ steps.sha.outputs.result }}
workflow: code-coverage.yml
path: ./deploy
- name: Get PR number
id: prnum
run: |
echo "num=$(cat deploy/prnumber)" > $GITHUB_OUTPUT
- name: Retrieve list of artifacts for the PR
id: find_artifacts
uses: actions/github-script@v6
with:
script: |
const prNum = process.env.num;
const artifacts = await github.rest.actions.listArtifactsForRepo({
owner: context.repo.owner,
repo: context.repo.repo
});
// Filter artifacts by PR number in their name
const artifactList = artifacts.data.artifacts.filter(artifact => artifact.name.includes(`coverage-${prNum}-`));
return artifactList.map((artifact) => ({
id: artifact.id,
name: artifact.name,
created_at: artifact.created_at
}));
# WARNING: Artifacts are deleted after 90 days (or per configured retention policy)
- name: Find previous artifact
id: previous-artifact
if: steps.find_artifacts.outputs.result != '[]'
uses: actions/github-script@v6
with:
result-encoding: string
script: |
// parse the output from the previous step into a JSON array
previous_artifacts = ${{ fromJson(steps.find_artifacts.outputs.result) }}
// assuming filtered and sorted the previous_artifacts by creation date in descending order
if (previous_artifacts.length > 1) {
// get the second latest artifact (since the latest would be the current one)
return previous_artifacts[1].id
}
- run: |
echo "previous_artifact_id=${{steps.previous-artifact.outputs.result}}" >> $GITHUB_ENV
- name: Install rust ${{ env.rust_release }}
run: rustup update ${{ env.rust_release }} && rustup default ${{ env.rust_release }}
- name: Generate lcov summary for main and pr
continue-on-error: true
id: lcov
run: |
sudo apt-get install -y lcov
wget https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/main/lcov.info
lcov --summary lcov.info > cov.txt
echo "main<<EOFABC" >> $GITHUB_OUTPUT
echo "$(cat cov.txt | tail -n +3)" >> $GITHUB_OUTPUT
echo 'EOFABC' >> $GITHUB_OUTPUT
lcov --summary ./deploy/lcov.info > cov.txt
echo "pr<<EOFABC" >> $GITHUB_OUTPUT
echo "$(cat cov.txt | tail -n +3)" >> $GITHUB_OUTPUT
echo 'EOFABC' >> $GITHUB_OUTPUT
- name: Get doc-coverage for main and pr
id: doccov
run: |
wget https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/main/doc-coverage.txt
echo "main<<EOFABC" >> $GITHUB_OUTPUT
echo "$(cat doc-coverage.txt)" >> $GITHUB_OUTPUT
echo 'EOFABC' >> $GITHUB_OUTPUT
echo "pr<<EOFABC" >> $GITHUB_OUTPUT
echo "$(cat ./deploy/doc-coverage.txt)" >> $GITHUB_OUTPUT
echo 'EOFABC' >> $GITHUB_OUTPUT
- name: Find coverage comment
uses: peter-evans/find-comment@v1
continue-on-error: true
id: fc
with:
issue-number: ${{steps.prnum.outputs.num}}
comment-author: "github-actions[bot]"
body-includes: "## Documentation Coverage"
- name: Delete coverage comment if it exists
if: steps.fc.outputs.comment-id != ''
uses: actions/github-script@v6
with:
script: |
github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: ${{ steps.fc.outputs.comment-id }}
})
- name: Download the previous lcov.info (historical) file
uses: actions/download-artifact@v2
with: |
name: code-coverage-${{ env.num }}-${{ env.previous_artifact_id }}
path: ./tools/code-coverage-diff/deploy-prev
# this will be used for future visualizations in the coverage report (requiring external python libs)
- name: Install python dependencies
run: |
pip install -r tools/code-coverage-diff/requirements.txt
- name: Calculate current coverage difference PR <> main
id: coveragediff
run: |
# pipeline lcov relevant stats to python script
python ./tools/code-coverage-diff/calculate_coverage_difference.py ${{ steps.lcov.outputs.main }} ${{ steps.lcov.outputs.pr }} > ./tools/code-coverage-diff/lcov/coverage_diff.txt
# store into environment variable
echo "diff<<EOFABC" >> $GITHUB_OUTPUT
cat ./tools/code-coverage-diff/lcov/coverage_diff.txt >> $GITHUB_ENV
echo 'EOFABC' >> $GITHUB_OUTPUT
# create summary of previous (historical) lcov summary for main and pr
lcov --summary ./tools/code-coverage-diff/deploy-prev/code-coverage-${{ env.num }}-${{ env.previous_artifact_id }} > historical_coverage_lcov.txt
echo "hist_main_summary<<EOFABC" >> $GITHUB_OUTPUT
echo "$(cat historical_coverage_lcov.txt | tail -n +3)" >> $GITHUB_OUTPUT
echo 'EOFABC' >> $GITHUB_OUTPUT
- name: Calculate coverage difference with previous historical lcov artifact
id: historicalcoveragediff
run: |
# call python script to compare historical previous main coverage with current main coverage
python ./tools/code-coverage-diff/calculate_coverage_difference.py ${{ steps.lcov.outputs.main }} ${{ steps.coveragediff.outputs.hist_main_summary }} > ./tools/code-coverage-diff/lcov/hist_coverage_diff.txt
# store into output variable for comment display
echo "hist_diff<<EOFABC" >> $GITHUB_OUTPUT
cat ./tools/code-coverage-diff/lcov/hist_coverage_diff.txt >> $GITHUB_ENV
echo 'EOFABC' >> $GITHUB_OUTPUT
- name: Create coverage comment
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ steps.prnum.outputs.num }}
body: |
## Code and Documentation Coverage Report
### Documentation Coverage
<details>
<summary>Click to view documentation coverage for this PR</summary>
```
${{ steps.doccov.outputs.pr }}
```
</details>
<details>
<summary>Click to view documentation coverage for main</summary>
```
${{ steps.doccov.outputs.main }}
```
</details>
### Code Coverage Summary
**This PR**: [Detailed Report](https://${{ github.repository_owner }}.github.io/conjure-oxide/coverage/${{ steps.sha.outputs.result }}/index.html)
```
${{ steps.lcov.outputs.pr }}
```
**Main**: [Detailed Report](https://${{ github.repository_owner }}.github.io/conjure-oxide/coverage/main/index.html)
```
${{ steps.lcov.outputs.main }}
```
### Coverage Main & PR Coverage Change
```diff
${{ steps.coveragediff.outputs.diff }}
```
### Previous Main Coverage Change
```diff
${{ steps.historicalcoveragediff.outputs.hist_diff }}
```