Skip to content

perf: fix CompileSimpleWorkflow regression by reusing cached git root#25764

Merged
pelikhan merged 4 commits intomainfrom
copilot/fix-performance-regression-compilesimpleworkflow
Apr 11, 2026
Merged

perf: fix CompileSimpleWorkflow regression by reusing cached git root#25764
pelikhan merged 4 commits intomainfrom
copilot/fix-performance-regression-compilesimpleworkflow

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 11, 2026

BenchmarkCompileSimpleWorkflow regressed ~45% because CompileWorkflowData spawns a git rev-parse --show-toplevel subprocess (~1.4ms) on every call via gitutil.ReadFileFromHEAD, despite the compiler already caching gitRoot at construction time.

Changes

  • pkg/gitutil/gitutil.go: Extract ReadFileFromHEADWithRoot(filePath, gitRoot) that accepts a pre-computed git root, skipping the subprocess. ReadFileFromHEAD now delegates to it.
  • pkg/workflow/compiler.go: Add readLockFileFromHEAD helper that uses c.gitRoot; replace the gitutil.ReadFileFromHEAD call in CompileWorkflowData. Add fast-path to normalizeHeredocDelimiters — skip regex when content has no GH_AW_ prefix.
  • pkg/gitutil/gitutil_test.go: Tests for ReadFileFromHEADWithRoot.

Results

Metric Before After Δ
ns/op 5,388 3,514 −35%
allocs/op 12,208 12,059 −149

All 187 workflows recompile with no lock file diff.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw --gdwarf2 --64 64/pkg/tool/linux_amd64/vet -W -I /tmp/go-build2802642204/b186/ 64/pkg/tool/linux_amd64/vet . --gdwarf2 --64 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw --gdwarf2 --64 64/pkg/tool/linux_amd64/vet -W -I /tmp/go-build2802642204/b186/ 64/pkg/tool/linux_amd64/compile . --gdwarf2 --64 64/pkg/tool/linux_amd64/compile (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name ck '**/*.cjs' '*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha user.email test@example.com /opt/hostedtoolcache/node/24.14.1/x64/bin/node -json GO111MODULE x_amd64/link /opt/hostedtoolcache/node/24.14.1/x64/bin/node /tmp�� GOMODCACHE x_amd64/link /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha /tmp/gh-aw-test-runs/20260411-061347-49238/test-4251296757/.github/workflows rev-parse /usr/bin/git ck 'scripts/**/*git GO111MODULE 64/bin/go git -C /tmp/gh-aw-test-runs/20260411-061347-49238/test-764001117/.github/workflows l /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git -json GO111MODULE ache/go/1.25.8/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git runs/20260411-06git GO111MODULE /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel go /usr/bin/git runs/20260411-06git GO111MODULE .cfg git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/src/cmd/internal/disasm/disasm.go /usr/bin/git se 2107591/b033/vet--norc .cfg git rev-�� --show-toplevel ache/go/1.25.8/x-trimpath /usr/bin/git se 2107591/b077/vet--norc ache/go/1.25.8/x--noprofile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr-u /usr/bin/git se 2107591/b052/vettest .cfg git rev-�� 1 1 ache/go/1.25.8/x./pkg/workflow/ /usr/bin/git se 2107591/b169/vet-rn ache/go/1.25.8/xnormalizeHeredocDelimiters\|normalizeContainerPins git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git se 2107591/b164/vetrev-parse .cfg git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git --abbrev-ref HEAD ache/go/1.25.8/x--noprofile git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/link /usr/bin/git eutil.test GO111MODULE x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git -json GO111MODULE g_.a git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/src/cmd/vendor/github.com/google/pprof/internal/report/package.go /usr/bin/git se 2107591/b060/vet--norc .cfg git rev-�� --show-toplevel ache/go/1.25.8/x-trimpath /usr/bin/git se 2107591/b172/vet--norc ache/go/1.25.8/x--noprofile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha --show-toplevel /tmp/go-build72030990/b203/embedcfg /usr/bin/git se 2107591/b065/vet-V=full .cfg git rev-�� --show-toplevel ache/go/1.25.8/x-trimpath /usr/bin/git set-url origin ache/go/1.25.8/x--noprofile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git se 2107591/b177/vetrev-parse .cfg git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git se 2107591/b192/vet--norc (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgrap-rn /usr/bin/git se 2107591/b047/vet--norc .cfg git rev-�� --show-toplevel ache/go/1.25.8/x-trimpath /usr/bin/git se 2107591/b171/vet--norc ache/go/1.25.8/x--noprofile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha ../../../.pretti/tmp/gh-aw-test-runs/20260411-061347-49238/test-420117250 go /usr/bin/git repo3355132576/0git GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git m/workflows GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha g_.a git x_amd64/vet --show-toplevel go n-dir/node x_amd64/vet ache�� ache/go/1.25.8/x-p git 64/pkg/tool/linu-lang=go1.25 HH5svbNKI /opt/hostedtoolc-atomic /usr/bin/git 64/pkg/tool/linu-buildtags (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin--norc /usr/bin/git se 2107591/b040/vet--norc .cfg git rev-�� --show-toplevel ache/go/1.25.8/x-trimpath /usr/bin/git set-url origin ache/go/1.25.8/x--noprofile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha add upstream /opt/hostedtoolcache/node/24.14.1/x64/bin/node ted/golang/pkg/fgit GO111MODULE x_amd64/cgo node /tmp�� /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/ai-moderator.md x_amd64/cgo /usr/bin/git m/workflows GO111MODULE x_amd64/vet git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha g_.a git x_amd64/vet --show-toplevel go 1/x64/bin/npm x_amd64/vet 2642�� ache/go/1.25.8/x-p ache/go/1.25.8/xgo.yaml.in/yaml/v3 u/13/cc1 WfFTguxa7 ache/go/1.25.8/x-atomic /usr/bin/git u/13/cc1 (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha -test.paniconexit0 -test.v=true ache/node/24.14.1/x64/bin/node -test.timeout=10git -test.run=^Test -test.short=true--show-toplevel /usr/lib/git-core/git t-24�� sistency_GoAndJavaScript3482651312/001/test-inlined-imports-enabled-with-env-template-expressiongit --format=%(objectname) /usr/bin/git ck '**/*.cjs' '*git GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha 1347-49238/test-3023420086/.gith@{u} GO111MODULE k/_temp/uv-python-dir/bash GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE e/git GOINSECURE GOMOD GOMODCACHE cUPri2m/J2Vr8-notXFkLdl0N6mo (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha RequiresMinIntegrity3397617581/001 GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile env t.go t_test.go 1/x64/bin/node GOINSECURE b/gh-aw/pkg/consrev-parse GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha 1347-49238/test-420117250 GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env kflows/test.lock.yml GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha /opt/hostedtoolcache/go/1.25.8/x64/src/net 8830389/b136/ nfig/composer/vendor/bin/as --gdwarf-5 --64 -o al_fold_amd64.o om/s�� ache/go/1.25.8/x64/src/os/user /tmp/go-build2802642204/b060/vet.cfg .cfg 64/bin/go go /usr/bin/git ache/go/1.25.8/x64/pkg/tool/linux_amd64/asm (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha /opt/hostedtoolcache/go/1.25.8/x64/src/net 8830389/b136/ 8JXZCFnoz --gdwarf-5 --64 -o /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet 8830�� ache/go/1.25.8/x64/src/os/user ortcfg .cfg go ions =0 ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile (http block)
  • https://api.github.com/repos/docker/build-push-action/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v7 --jq .object.sha -I 8830389/b277/importcfg $name) { hasDiscussionsEnabled } } . --gdwarf2 --64 /opt/hostedtoolc-f -o /tmp/go-build311-f -trimpath r: $owner, name:-f -p image/png -lang=go1.25 /opt/hostedtoolcconfig (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v7 --jq .object.sha -I 8830389/b152/importcfg es . --gdwarf2 --64 /opt/hostedtoolcache/go/1.25.8/x-f -o /tmp/go-build3118830389/b291/_pk-f -trimpath 8830389/b370/vet.cfg -p charm.land/huh/vshow -lang=go1.25 /opt/hostedtoolcache/go/1.25.8/xconfig (http block)
  • https://api.github.com/repos/docker/metadata-action/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v6 --jq .object.sha 8830389/b370/_pkg_.a 8830389/b281/importcfg r: $owner, name: $name) { hasDiscussionsEnabled } } . b/gh-aw/pkg/work-C --64 /opt/hostedtoolcrev-parse -o /tmp/go-build3118830389/b282/_pkg_.a -trimpath qhnY/vfRDi85yMI3RzB5-qhnY -p github.com/dustiapi -lang=go1.16 /opt/hostedtoolc-f (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v6 --jq .object.sha -I 8830389/b293/impowner=github ptables . --gdwarf2 --64 /opt/hostedtoolcconfig -o /tmp/go-build311remote.origin.url -trimpath /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -p github.com/catpp-C -lang=go1.19 /opt/hostedtoolcconfig (http block)
  • https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v4 --jq .object.sha -I 8830389/b274/impowner=github /opt/hostedtoolc-f . --gdwarf2 --64 /opt/hostedtoolc-f -o /tmp/go-build311-f -trimpath 8830389/b342/vet-f -p hash/maphash -lang=go1.25 /opt/hostedtoolcache/go/1.25.8/xconfig (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v4 --jq .object.sha 8830389/b001/_pkg_.a 8830389/b161/importcfg ptables . --gdwarf2 --64 /opt/hostedtoolcache/go/1.25.8/xconfig -o /tmp/go-build3118830389/b286/_pkremote.origin.url -trimpath Z8HB/E8Cijxv7KMbVCL03Z8HB -p charm.land/bubblapi -lang=go1.25 /opt/hostedtoolc-f (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .visibility /opt/hostedtoolcremote.origin.url 8830389/b365/importcfg r: $owner, name: $name) { hasDiscussionsEnabled } } --gdwarf-5 --64 -o /opt/hostedtoolcconfig -o /tmp/go-build311remote.origin.url -trimpath /opt/hostedtoolcache/go/1.25.8/x-f -p golang.org/x/tex-1 -lang=go1.25 /opt/hostedtoolcache/go/1.25.8/x-f (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha HEAD .github/workflows/test.md /usr/bin/git ub/workflows GO111MODULE 64/bin/go git conf�� user.name Test User /usr/bin/git b/workflows GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha sistency_GoAndJavaScript3482651312/001/test-empty-frontmatter.md -buildtags /usr/lib/git-core/git -errorsas -ifaceassert -nilfunc /usr/lib/git-core/git pack�� r-test1920496253/test1.md r-test1920496253/test2.lock.yml /usr/bin/git --thin --delta-base-offrev-parse -q git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha 1240353/b431/_pkg_.a -trimpath 1240353/b431=> -p b/gh-aw/pkg/slicrev-parse -lang=go1.25 /bin/sh -c mKXx/M289NJ7fl33W_GzsmKXx git-receive-pack '/tmp/TestParseDefaultBranchFromLsRemoteWithRealGitbranch_with_hyphen1990713763rev-parse /usr/bin/git 4325916/001' 4325916/001' -nolocalimports 1240353/b431/importcfg (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/1/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 420117250 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE 1/x64/bin/bash GOINSECURE GOMOD GOMODCACHE ylQP4Z8/vCNYLdc7D8RXanEmFBss env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12345/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ithub/workflows GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/pkg/tool/linux_amd64/link GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/link (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ithub/workflows GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link (http block)
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/2/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 420117250 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/3/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE de/node/bin/bash GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/4/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 420117250 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE 64/bin/bash GOINSECURE GOMOD GOMODCACHE go env 1102951311/.github/workflows GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/5/artifacts --jq .artifacts[].name GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/pkg/tool/linux_amd64/link GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/link (http block)
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path GoFiles,Export,DGOINSECURE GO111MODULE 64/bin/go GOINSECURE erignore GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE node /opt�� prettier --check 64/bin/go **/*.ts **/*.json --ignore-path go (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE go env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel go /usr/bin/git efaultBranchFrom/bin/sh efaultBranchFrom-c ache/go/1.25.8/xgit-upload-pack 'origin' git (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha edOutput2713578899/001 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env plorer.md GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha mfg1/dqv16HYODI1-s GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 9069815/b378/imp/tmp/TestParseDefaultBranchFromLsRemoteWithRealGitbranch_with_hyphen1990713763/002/work -c k/gh-aw/gh-aw/cmd/gh-aw/main.go k/gh-aw/gh-aw/cmd/gh-aw/capitaliGOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go iE8t3kR/-pSRkXIpremote (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha 2YlW/0Xo6z-ZpEVe-s GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 9069815/b428/imp-extld=gcc -c che/go-build/79/79ea474aaf445363GOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c "prettier" --che-c=4 GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c "prettier" --che-errorsas GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c "prettier" --check '**/*.cjs' '*GOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
  • https://api.github.com/repos/githubnext/agentics/git/ref/tags/-
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/- --jq .object.sha 8830389/b260/_pkg_.a -trimpath .cfg -p erhouse/uax29/v2show -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -ato�� -bool -buildtags ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc ache/go/1.25.8/xconfig (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo -nolocalimports -importcfg /tmp/go-build1231240353/b412/importcfg -pack /tmp/go-build1231240353/b412/_testmain.go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build1231240353/b397/cli.test /tmp/go-build1231240353/b397/cli.test -test.testlogfile=/tmp/go-build1231240353/b397/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE go env ck '**/*.cjs' '*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name ck '**/*.cjs' '*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 2 commits April 11, 2026 06:22
… git root

Two optimizations to address the ~45% regression in BenchmarkCompileSimpleWorkflow:

1. Use the compiler's cached gitRoot instead of spawning a new `git rev-parse
   --show-toplevel` subprocess on every CompileWorkflowData call. Added
   ReadFileFromHEADWithRoot to gitutil that accepts a pre-computed git root.

2. Add fast-path to normalizeHeredocDelimiters: skip regex scan when content
   contains no "GH_AW_" prefix (common in benchmarks and first-time compilations).

Before: ~5,388 ns/op, 12,208 allocs/op
After:  ~3,514 ns/op, 12,059 allocs/op (~35% faster, 149 fewer allocations)

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/be98dc1c-94b9-4ee5-b58d-b24829a625d1

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix performance regression in CompileSimpleWorkflow perf: fix CompileSimpleWorkflow regression by reusing cached git root Apr 11, 2026
Copilot AI requested a review from pelikhan April 11, 2026 06:23
@github-actions github-actions Bot mentioned this pull request Apr 11, 2026
@pelikhan pelikhan marked this pull request as ready for review April 11, 2026 09:05
Copilot AI review requested due to automatic review settings April 11, 2026 09:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves compilation performance by avoiding repeated git rev-parse --show-toplevel calls during workflow compilation, reusing the compiler’s cached git root.

Changes:

  • Added gitutil.ReadFileFromHEADWithRoot(filePath, gitRoot) and updated ReadFileFromHEAD to delegate to it.
  • Updated the workflow compiler to read committed lock files via cached c.gitRoot and added a fast-path in heredoc delimiter normalization.
  • Added unit tests covering ReadFileFromHEADWithRoot.
Show a summary per file
File Description
pkg/gitutil/gitutil.go Introduces root-accepting ReadFileFromHEADWithRoot and refactors ReadFileFromHEAD to reuse it.
pkg/workflow/compiler.go Uses cached compiler git root when reading lock files from HEAD; optimizes heredoc normalization.
pkg/gitutil/gitutil_test.go Adds tests for the new ReadFileFromHEADWithRoot helper.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

pkg/gitutil/gitutil.go:119

  • ReadFileFromHEADWithRoot should validate gitRoot up front (e.g., non-empty and ideally absolute/clean). As-is, an empty or relative gitRoot yields confusing errors like "outside the git repository root """ and can produce surprising filepath.Rel results.
// ReadFileFromHEADWithRoot is like ReadFileFromHEAD but accepts a pre-computed git
// repository root, avoiding the subprocess overhead of calling FindGitRoot().
// Use this when the caller already knows the git root (e.g. from a cached value).
func ReadFileFromHEADWithRoot(filePath, gitRoot string) (string, error) {
	absPath, err := filepath.Abs(filePath)
	if err != nil {
		return "", fmt.Errorf("cannot resolve absolute path for %q: %w", filePath, err)
	}

	// git show requires the path to be relative to the repository root and to use
	// forward slashes even on Windows.
	relPath, err := filepath.Rel(gitRoot, absPath)
	if err != nil {
		return "", fmt.Errorf("cannot compute path of %q relative to git root %q: %w", absPath, gitRoot, err)
	}
  • Files reviewed: 3/3 changed files
  • Comments generated: 2

Comment on lines +284 to +290
t.Run("returns error for path outside git root", func(t *testing.T) {
gitRoot, err := FindGitRoot()
require.NoError(t, err, "must be inside a git repository")

_, err = ReadFileFromHEADWithRoot("/tmp/not-in-repo/file.yml", gitRoot)
require.Error(t, err, "should fail for a file outside the git root")
assert.Contains(t, err.Error(), "outside the git repository root", "error should mention path is outside repo")
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

This test uses a hard-coded Unix-y absolute path (/tmp/not-in-repo/file.yml) to represent a file outside the repo. On Windows (and for developers cloning into paths like C:\tmp), this can become a path under the same drive and may not be guaranteed to be outside gitRoot. Prefer constructing a path that is definitively outside gitRoot (e.g., under filepath.Dir(gitRoot) or using t.TempDir() with a guard to ensure it’s not nested under gitRoot).

Copilot uses AI. Check for mistakes.
Comment thread pkg/gitutil/gitutil.go
Comment on lines +108 to 111
func ReadFileFromHEADWithRoot(filePath, gitRoot string) (string, error) {
absPath, err := filepath.Abs(filePath)
if err != nil {
return "", fmt.Errorf("cannot resolve absolute path for %q: %w", filePath, err)
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

Since this variant accepts an explicit gitRoot, it should also execute the underlying git show within that repository context (e.g., git -C <gitRoot> show ... or cmd.Dir = gitRoot). Otherwise calls can fail if the process CWD is not inside the repo even though the root was provided.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100

Excellent

Metric Value
New/modified tests analyzed 3 sub-tests (TestReadFileFromHEADWithRoot)
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 2 (67%)
Duplicate test clusters 0
Test inflation detected ⚠️ Yes — 33 test lines added vs 7 production lines (4.7:1 ratio)
🚨 Coding-guideline violations None

Test Classification Details

Test File Classification Issues Detected
TestReadFileFromHEADWithRoot / reads a committed file with pre-computed root pkg/gitutil/gitutil_test.go:272 ✅ Design Happy path only; no error assertion in this sub-test
TestReadFileFromHEADWithRoot / returns error for path outside git root pkg/gitutil/gitutil_test.go:280 ✅ Design Error path covered; error message content asserted
TestReadFileFromHEADWithRoot / returns same result as ReadFileFromHEAD pkg/gitutil/gitutil_test.go:288 ✅ Design Behavioral parity/regression guard between old and new API

Notable Observations

⚠️ Test Inflation (4.7:1 ratio)

File: pkg/gitutil/gitutil_test.go vs pkg/gitutil/gitutil.go

  • Test lines added: 33
  • Production lines added: 7
  • Ratio: 4.7:1 (threshold: 2:1)

This is a mechanical flag. The underlying cause is that the production change is small (extracting a helper) while the tests are genuinely thorough — three well-structured sub-tests covering happy path, error path, and parity. The flag is noted for transparency but is not a real concern here.

✅ Assertion Quality

All assertions include descriptive messages — e.g., "go.mod should be readable from HEAD with pre-computed root", "error should mention path is outside repo". This is consistent with the project guideline.

✅ Build Tag Present

pkg/gitutil/gitutil_test.go correctly has //go:build !integration on line 1.

✅ No Mock Usage

No gomock, testify/mock, .EXPECT(), or .On() usage. Tests interact with real git subprocess (consistent with project guidelines).

💡 Minor Suggestion

The third sub-test (returns same result as ReadFileFromHEAD) is an excellent regression guard, but the assertion argument order follows the (got, want) pattern in places — e.g., assert.Equal(t, err1, err2, ...). The testify convention is assert.Equal(t, expected, actual, ...). This is cosmetic but worth noting for consistency.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 3 sub-tests within TestReadFileFromHEADWithRoot — unit (//go:build !integration)
  • 🟨 JavaScript (*.test.cjs, *.test.js): 0 tests (no JS test files changed)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All three sub-tests verify observable behavioral contracts of the new ReadFileFromHEADWithRoot API. The test inflation flag (4.7:1) is a mechanical artifact of a well-tested small refactor and does not reflect poor quality.


📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

🧪 Test quality analysis by Test Quality Sentinel · ● 424.5K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 80/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All three new sub-tests in TestReadFileFromHEADWithRoot verify behavioral contracts of the new API, include proper assertion messages, cover both the happy path and the error path, and include a parity regression guard against the original ReadFileFromHEAD.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments

… test paths

- Validate gitRoot is non-empty in ReadFileFromHEADWithRoot up front
- Use `git -C gitRoot` so git show runs in the correct repo context
  regardless of process CWD
- Replace hardcoded /tmp path with t.TempDir() for cross-platform test
  portability
- Add test case for empty gitRoot validation

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/4ce6724a-918f-4ade-ac10-bf18171978e5

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 11, 2026

@copilot review all comments

Addressed all three review comments in 718d9aa:

  1. ReadFileFromHEADWithRoot validates gitRoot — returns a clear error when empty, instead of producing confusing filepath.Rel errors.
  2. git -C gitRoot for repo contextgit show now runs in the correct repository even when the process CWD is outside the repo.
  3. Portable test path — replaced hardcoded /tmp/not-in-repo/file.yml with t.TempDir() so the test works cross-platform.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@pelikhan pelikhan merged commit 78aaf3b into main Apr 11, 2026
53 of 56 checks passed
@pelikhan pelikhan deleted the copilot/fix-performance-regression-compilesimpleworkflow branch April 11, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[performance] Regression in CompileSimpleWorkflow: 45.5% slower

3 participants