Skip to content
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

Adjust scripts/tests to generate Go code coverage data #31

Merged
merged 1 commit into from
Mar 20, 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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ jobs:
.bin/bashbrew --version
echo "$PWD/.bin" >> "$GITHUB_PATH"
- run: .test/test.sh
- uses: actions/upload-artifact@v4
with:
name: coverage
path: .test/coverage**
if-no-files-found: error
- run: git diff --exit-code
# TODO download latest coverage artifacts from HEAD / PR target to emulate Codecov but without another flaky third-party service that's begging for write-access to all our repositories via a GitHub App? 👀
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

5 changes: 3 additions & 2 deletions .go-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ user="$(id -u):$(id -g)"
args=(
--interactive --rm --init
--user "$user"
--mount "type=bind,src=$dir,dst=/app"
--workdir /app
--mount "type=bind,src=$dir,dst=$dir"
--workdir "$dir"
--tmpfs /tmp,exec
--env HOME=/tmp

Expand All @@ -20,6 +20,7 @@ args=(

--env "CGO_ENABLED=${CGO_ENABLED-0}"
--env "GOTOOLCHAIN=${GOTOOLCHAIN-local}"
--env GOCOVERDIR # https://go.dev/doc/build-cover
--env GODEBUG
--env GOFLAGS
--env GOOS --env GOARCH
Expand Down
1 change: 1 addition & 0 deletions .test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage**
79 changes: 79 additions & 0 deletions .test/lookup-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
[
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23",
"size": 946,
"annotations": {
"com.docker.official-images.bashbrew.arch": "windows-amd64",
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23"
},
"platform": {
"architecture": "amd64",
"os": "windows",
"os.version": "10.0.20348.2340"
}
}
],
"annotations": {
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23"
}
},
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57",
"size": 861,
"annotations": {
"com.docker.official-images.bashbrew.arch": "amd64",
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57",
"org.opencontainers.image.revision": "3fb6ebca4163bf5b9cc496ac3e8f11cb1e754aee",
"org.opencontainers.image.source": "https://github.com/docker-library/hello-world.git#3fb6ebca4163bf5b9cc496ac3e8f11cb1e754aee:amd64/hello-world",
"org.opencontainers.image.url": "https://hub.docker.com/_/hello-world",
"org.opencontainers.image.version": "linux"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23",
"size": 946,
"annotations": {
"com.docker.official-images.bashbrew.arch": "windows-amd64",
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23"
},
"platform": {
"architecture": "amd64",
"os": "windows",
"os.version": "10.0.20348.2340"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:3a0bd0fb5ad6dd6528dc78726b3df78e980b39b379e99c5a508904ec17cfafe5",
"size": 946,
"annotations": {
"com.docker.official-images.bashbrew.arch": "windows-amd64",
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:3a0bd0fb5ad6dd6528dc78726b3df78e980b39b379e99c5a508904ec17cfafe5"
},
"platform": {
"architecture": "amd64",
"os": "windows",
"os.version": "10.0.17763.5576"
}
}
],
"annotations": {
"org.opencontainers.image.ref.name": "docker.io/tianon/test@sha256:347290ddd775c1b85a3e381b09edde95242478eb65153e9b17225356f4c072ac"
}
}
]
32 changes: 32 additions & 0 deletions .test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,40 @@ time bashbrew fetch "$@"

time "$dir/../sources.sh" "$@" > "$dir/sources.json"

rm -rf "$dir/coverage"
mkdir -p "$dir/coverage"
export GOCOVERDIR="${GOCOVERDIR:-"$dir/coverage"}"

rm -f "$dir/../bin/builds" # make sure we build with -cover for sure
time "$dir/../builds.sh" --cache "$dir/cache-builds.json" "$dir/sources.json" > "$dir/builds.json"

# test again, but with "--cache=..." instead of "--cache ..." (which also lets us delete the cache and get slightly better coverage reports at the expense of speed / Hub requests)
time "$dir/../builds.sh" --cache="$dir/cache-builds.json" "$dir/sources.json" > "$dir/builds.json"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would having the equal sign or not change behavior?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅 because we're currently punting on choosing a flag-parsing library:

meta-scripts/builds.go

Lines 221 to 228 in 96ed6a9

// support "--cache foo.json" and "--cache=foo.json"
if sourcesJsonFile == "--cache" && len(os.Args) >= 4 {
cacheFile = os.Args[2]
sourcesJsonFile = os.Args[3]
} else if cf, ok := strings.CutPrefix(sourcesJsonFile, "--cache="); ok && len(os.Args) >= 3 {
cacheFile = cf
sourcesJsonFile = os.Args[2]
}

Also though, running it a second time should give us slightly different coverage in the case of "totally fresh cache" which is useful for testing locally and has minimal impact in general thanks to our cache file).


# test "lookup" code for more edge cases
"$dir/../.go-env.sh" go build -cover -trimpath -o "$dir/../bin/lookup" ./cmd/lookup
lookup=(
# force a config blob lookup for platform object creation (and top-level Docker media type!)
'tianon/test@sha256:2f19ce27632e6baf4ebb1b582960d68948e52902c8cfac10133da0058f1dab23'
# (this is the first Windows manifest of "tianon/test:index-no-platform-smaller" referenced below)

# tianon/test:index-no-platform-smaller - a "broken" index with *zero* platform objects in it (so every manifest requires a platform lookup)
'tianon/test@sha256:347290ddd775c1b85a3e381b09edde95242478eb65153e9b17225356f4c072ac'
# (doing these in the same run means the manifest from above should be cached and exercise more codepaths for better coverage)
)
"$dir/../bin/lookup" "${lookup[@]}" | jq -s > "$dir/lookup-test.json"

# don't leave around the "-cover" versions of these binaries
rm -f "$dir/../bin/builds" "$dir/../bin/lookup"

# Go tests
"$dir/../.go-env.sh" go test -cover ./... -args -test.gocoverdir="$GOCOVERDIR"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Odd that go test would not pick up the GOCOVERDIR environment variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, 100%! That "didn't make it into the feature in 1.20", but also doesn't seem to have made it in 1.21 or 1.22 either! (golang/go#51430 (comment))


# combine the coverage data into the "legacy" coverage format (understood by "go tool cover") and pre-generate HTML for easier digestion of the data
"$dir/../.go-env.sh" go tool covdata textfmt -i "$GOCOVERDIR" -o "$dir/coverage.txt"
"$dir/../.go-env.sh" go tool cover -html "$dir/coverage.txt" -o "$dir/coverage.html"
"$dir/../.go-env.sh" go tool cover -func "$dir/coverage.txt"

# generate an "example commands" file so that changes to generated commands are easier to review
SOURCE_DATE_EPOCH=0 jq -r -L "$dir/.." '
include "meta";
Expand Down
2 changes: 2 additions & 0 deletions bin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**
!.gitignore
13 changes: 7 additions & 6 deletions builds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ export BASHBREW_STAGING_TEMPLATE

dir="$(dirname "$BASH_SOURCE")"
dir="$(readlink -ve "$dir")"
if ( cd "$dir" && ./.any-go-nt.sh builds ); then
bin="$dir/bin/builds"
if ( cd "$dir" && ./.any-go-nt.sh "$bin" ); then
{
echo "building '$dir/builds' from 'builds.go'"
"$dir/.go-env.sh" go build -v -o builds builds.go
ls -l "$dir/builds"
echo "building '$bin'"
"$dir/.go-env.sh" go build ${GOCOVERDIR:+-cover} -v -trimpath -o "$bin" ./cmd/builds
ls -l "$bin"
} >&2
fi
[ -x "$dir/builds" ]
[ -x "$bin" ]

"$dir/builds" "$@" | jq .
"$bin" "$@" | jq .
File renamed without changes.
32 changes: 16 additions & 16 deletions lookup.go → cmd/lookup/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()

img := os.Args[1]

ref, err := registry.ParseRefNormalized(img)
if err != nil {
panic(err)
}

index, err := registry.SynthesizeIndex(ctx, ref)
if err != nil {
panic(err)
}

e := json.NewEncoder(os.Stdout)
e.SetIndent("", "\t")
if err := e.Encode(index); err != nil {
panic(err)
for _, img := range os.Args[1:] {
ref, err := registry.ParseRefNormalized(img)
if err != nil {
panic(err)
}

index, err := registry.SynthesizeIndex(ctx, ref)
if err != nil {
panic(err)
}

e := json.NewEncoder(os.Stdout)
e.SetIndent("", "\t")
if err := e.Encode(index); err != nil {
panic(err)
}
}
}