Skip to content

feat: add incremental coverage basic support #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 15, 2024
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.vscode
cover.out
*.out
cover.txt
cover.html
21 changes: 16 additions & 5 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,51 @@ runs:
path: go-cover
token: ${{ inputs.token }}

- id : 'normalize-path'
name: Normalize Input Path
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const script = require(`${process.env.GITHUB_ACTION_PATH}/src/normalize-path.js`)
return script('${{ inputs.path }}')

- name: Checkout Coverage Branch
shell: bash
run: |
export INPUTS_BRANCH="${{ inputs.branch }}"
export INPUTS_PATH="${{ steps.normalize-path.outputs.result }}"
${GITHUB_ACTION_PATH}/scripts/pull.sh

- name: Push Coverage
shell: bash
run: |
export REVISION="${{ github.event.pull_request.head.sha || github.sha }}"
export INPUTS_PATH="${{ inputs.path }}"
export INPUTS_PATH="${{ steps.normalize-path.outputs.result }}"
export INPUTS_BRANCH="${{ inputs.branch }}"
export REF_NAME="${{ github.ref_name }}"
${GITHUB_ACTION_PATH}/scripts/push.sh

- name: Post Code Coverage Comment
if: ${{ github.event_name == 'pull_request' }}
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
github-token: ${{ inputs.token }}
script: |
const script = require(`${process.env.GITHUB_ACTION_PATH}/src/update-comment.js`)
const revision = '${{ github.event.pull_request.head.sha || github.sha }}'
const path = '${{ inputs.path }}'
const threshold = parseFloat('${{ inputs.threshold }}', 10)
const path = '${{ steps.normalize-path.outputs.result }}'
await script({ context, github, path, revision, threshold })

- name: Check Coverage Threshold
if: ${{ github.event_name == 'pull_request' }}
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
github-token: ${{ inputs.token }}
script: |
const script = require(`${process.env.GITHUB_ACTION_PATH}/src/check-threshold.js`)
const revision = '${{ github.event.pull_request.head.sha || github.sha }}'
const threshold = parseFloat('${{ inputs.threshold }}', 10)
await script({ threshold, revision })
const path = '${{ steps.normalize-path.outputs.result }}'
await script({ threshold, path, revision })
2 changes: 1 addition & 1 deletion assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
async function loadContent() {
const spinner = document.getElementById("spinner");
const hash = getHashFromQueryString();
const fileUrl = `${hash}.html`;
const fileUrl = `revisions/${hash}.html`;

spinner.style.display = "block";

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion assets/nord.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

body {
background: var(--nord0) !important;
color: var(--nord4) !important;
color: var(--nord3) !important;
}

#topbar {
Expand Down
12 changes: 12 additions & 0 deletions go-test-app-01/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import (
"math/rand"
)

const side = "right"

func main() {
if tossCoin() == "heads" {
fmt.Println("Heads")
} else {
fmt.Println("Tails")
}

fmt.Println("Maybe:", maybe())
}

func tossCoin() string {
Expand All @@ -20,3 +24,11 @@ func tossCoin() string {
return "tails"
}
}

func maybe() bool {
if side == "right" {
return true
} else {
return false
}
}
6 changes: 5 additions & 1 deletion scripts/pull.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

set -eo pipefail
set -xeo pipefail

cd go-cover
git fetch origin
Expand All @@ -13,4 +13,8 @@ else
git checkout --orphan "${INPUTS_BRANCH}"
rm .git/index
git clean -fdx
mkdir -p "./${INPUTS_PATH}/head"
touch "./${INPUTS_PATH}/head/head.html"
touch "./${INPUTS_PATH}/head/head.txt"
echo "mode: set" > "./${INPUTS_PATH}/head/head.out"
fi
53 changes: 38 additions & 15 deletions scripts/push.sh
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
#!/bin/bash

set -eo pipefail
set -xeo pipefail

# create cover directory

cover_dir="${GITHUB_WORKSPACE}/go-cover/./${INPUTS_PATH}"
mkdir -p "${cover_dir}/revisions"
mkdir -p "${cover_dir}/head"

# generate coverage files
cd "${INPUTS_PATH}"
go tool cover -html=cover.out -o "${GITHUB_WORKSPACE}/go-cover/${REVISION}.html"
go tool cover -func=cover.out -o "${GITHUB_WORKSPACE}/go-cover/${REVISION}.txt"
cp cover.out "${GITHUB_WORKSPACE}/go-cover/${REVISION}.out"

# if we are on the main branch, copy files to main.*
if [ "${REF_NAME}" = "main" ]; then
cp "${GITHUB_WORKSPACE}/go-cover/${REVISION}.html" "${GITHUB_WORKSPACE}/go-cover/main.html"
cp "${GITHUB_WORKSPACE}/go-cover/${REVISION}.txt" "${GITHUB_WORKSPACE}/go-cover/main.txt"
cp "${GITHUB_WORKSPACE}/go-cover/${REVISION}.out" "${GITHUB_WORKSPACE}/go-cover/main.out"
fi
# generate coverage files

go tool cover -html=cover.out -o "${cover_dir}/revisions/${REVISION}.html"
go tool cover -func=cover.out -o "${cover_dir}/revisions/${REVISION}.txt"
cp cover.out "${cover_dir}/revisions/${REVISION}.out"

# generate incremental coverage files

cd "${GITHUB_WORKSPACE}/go-cover"
echo "mode: set" > incremental.out
# grep exits with 1 if no lines are found, so we need to ignore that
grep -F -v -x -f "${GITHUB_WORKSPACE}/go-cover/head/head.out" cover.out >> incremental.out || true
go tool cover -html=incremental.out -o "${cover_dir}/revisions/${REVISION}-inc.html"
go tool cover -func=incremental.out -o "${cover_dir}/revisions/${REVISION}-inc.txt"
cp incremental.out "${cover_dir}/revisions/${REVISION}-inc.out"

cd "${cover_dir}"

# beautify html
ex -sc '%s/<style>/<style>@import url("nord.css");/' -c 'x' "${REVISION}.html"
ex -sc '%s/<\/script>/<\/script><script src="ln.js"><\/script>/' -c 'x' "${REVISION}.html"

for file in "revisions/${REVISION}.html" "revisions/${REVISION}-inc.html"; do
ex -sc '%s/<style>/<style>@import url("..\/nord.css");/' -c 'x' "${file}"
ex -sc '%s/<\/script>/<\/script><script src="..\/index.js"><\/script>/' -c 'x' "${file}"
done

# if we are on the main branch, copy files to main.*

if [ "${REF_NAME}" = "main" ]; then
cp "revisions/${REVISION}.html" "${cover_dir}/head/head.html"
cp "revisions/${REVISION}.txt" "${cover_dir}/head/head.txt"
cp "revisions/${REVISION}.out" "${cover_dir}/head/head.out"
fi

# copy assets
cp "${GITHUB_ACTION_PATH}"/assets/* .

cp "${GITHUB_ACTION_PATH}"/assets/* "${cover_dir}"

# push to branch

git add .
git config user.email "go-coverage-action@github.com"
git config user.name "go-coverage-action"
Expand Down
7 changes: 5 additions & 2 deletions src/check-threshold.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const fs = require('fs')
const normalizePath = require('./normalize-path')

const checkThreshold = module.exports = async ({ threshold, revision }) => {
const coverageText = fs.readFileSync(`go-cover/${revision}.txt`, 'utf8').split('\n').slice(0, -1)
const checkThreshold = module.exports = async ({ threshold, path, revision }) => {
path = normalizePath(path)

const coverageText = fs.readFileSync(`go-cover/${path}/revisions/${revision}.txt`, 'utf8').split('\n').slice(0, -1)
const coverageTextSummary = coverageText[coverageText.length-1].split('\t').pop()

const coverage = parseFloat(coverageTextSummary.replace('%', ''), 10)
Expand Down
62 changes: 62 additions & 0 deletions src/normalize-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const path = require('path')

const normalizePath = module.exports = (dir) => {
dir = path.normalize(dir)

if (dir === '/' || dir === './' || dir === '.') {
return ''
}

if (dir.startsWith('./')) {
dir = dir.substring(2)
}

if (dir.startsWith('/')) {
dir = dir.substring(1)
}

if (dir.endsWith('/')) {
dir = dir.substring(0, dir.length - 1)
}

return dir
}

const test = async () => {
let pass = true

const tests = [
{ input: '/', expected: '' },
{ input: '/foo', expected: 'foo' },

{ input: './', expected: '' },
{ input: './foo', expected: 'foo' },
{ input: './foo/', expected: 'foo' },
{ input: './foo/bar', expected: 'foo/bar' },
{ input: './foo/bar/', expected: 'foo/bar' },

{ input: '', expected: '' },
{ input: 'foo', expected: 'foo' },
{ input: 'foo/', expected: 'foo' },
{ input: 'foo/bar', expected: 'foo/bar' },
{ input: 'foo/bar/', expected: 'foo/bar' },
]

for (const { input, expected } of tests) {
const result = normalizePath(input)
if (result !== expected) {
console.error(`error("${input}"): expected "${expected}" but got "${result}"`)
pass = false
}
}

if (!pass) {
process.exit(1)
} else {
console.log('All tests passed')
}
}

if (require.main === module) {
test()
}
11 changes: 8 additions & 3 deletions src/update-comment.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const fs = require('fs')
const normalizePath = require('./normalize-path')
const join = require('path').join

const updateCodeCoverageComment = module.exports = async ({ context, github, path, revision, threshold }) => {
const comments = await github.rest.issues.listComments({
Expand All @@ -8,19 +10,22 @@ const updateCodeCoverageComment = module.exports = async ({ context, github, pat
per_page: 100
})

path = normalizePath(path)

const coverageComment = comments.data.find((comment) => {
return comment.body.startsWith(`<!-- coverage (${path})-->`)
}) || {}

const coverageText = fs.readFileSync(`go-cover/${revision}.txt`, 'utf8').split('\n').slice(0, -1)
const coverageText = fs.readFileSync(join('go-cover', path, 'revisions', `${revision}.txt`), 'utf8').split('\n').slice(0, -1)
const coverageTextSummary = coverageText[coverageText.length-1].split('\t').pop()
const coverage = parseFloat(coverageTextSummary.replace('%', ''), 10)
const coverageEmoji = coverage >= threshold ? '' : `<kbd>🔻 ${(coverage - threshold).toFixed(1)}%</kbd> `
const pathText = (path !== './' ? ` for <kbd>${path}/</kbd>` : '').replace('//', '/')
const pathText = (path !== '' ? ` for <kbd>${path}/</kbd>` : '')
const url = `https://${context.repo.owner}.github.io/${join(context.repo.repo, path)}?hash=${revision}`

const commentBody = [
`<!-- coverage (${path})-->`,
`##### ${coverageEmoji}<kbd>[🔗 Code Coverage Report](https://${context.repo.owner}.github.io/${context.repo.repo}/?hash=${revision})</kbd>${pathText} at <kbd>${revision}</kbd>`,
`##### ${coverageEmoji}<kbd>[🔗 Code Coverage Report](${url})</kbd>${pathText} at <kbd>${revision}</kbd>`,
'```',
`📔 Total: ${coverageTextSummary}`,
]
Expand Down
Loading