Skip to content

Commit 64172ab

Browse files
authored
Merge pull request #188 from pjbgf/forward
v6: Ensure Chmod behaviour across BoundOS and ChrootOS
2 parents 37866f8 + 684be43 commit 64172ab

8 files changed

Lines changed: 389 additions & 33 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
name: Benchmarks
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
pr_number:
7+
description: 'Pull Request number'
8+
required: true
9+
type: number
10+
11+
permissions: {}
12+
13+
jobs:
14+
benchmark:
15+
name: Compare Benchmarks
16+
runs-on: ubuntu-latest
17+
18+
permissions:
19+
contents: read
20+
pull-requests: write
21+
22+
steps:
23+
- name: Get PR base ref
24+
id: pr-info
25+
env:
26+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
run: |
28+
base_ref=$(gh pr view ${{ inputs.pr_number }} --repo ${{ github.repository }} --json baseRefName --jq .baseRefName)
29+
echo "base_ref=$base_ref" >> $GITHUB_OUTPUT
30+
31+
- name: Checkout PR branch
32+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
33+
with:
34+
ref: refs/pull/${{ inputs.pr_number }}/head
35+
path: new
36+
37+
- name: Checkout base branch
38+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
39+
with:
40+
ref: ${{ steps.pr-info.outputs.base_ref }}
41+
path: old
42+
43+
- name: Set up Go
44+
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
45+
with:
46+
go-version: stable
47+
cache-dependency-path: new/go.sum
48+
49+
- name: Install benchstat
50+
# renovate: datasource=go depName=golang.org/x/perf/cmd/benchstat
51+
run: go install golang.org/x/perf/cmd/benchstat@v0.0.0-20260211190930-8161c38c6cdc
52+
53+
- name: Run base branch benchmarks
54+
id: base-bench
55+
working-directory: old
56+
run: go test -run='^$' -bench=. -benchmem -count=1 ./test/... > ../base.txt 2>&1
57+
continue-on-error: true
58+
59+
- name: Run PR branch benchmarks
60+
id: pr-bench
61+
working-directory: new
62+
run: go test -run='^$' -bench=. -benchmem -count=1 ./test/... > ../pr.txt 2>&1
63+
continue-on-error: true
64+
65+
- name: Compare and report
66+
if: always()
67+
env:
68+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69+
PR_NUMBER: ${{ inputs.pr_number }}
70+
REPO: ${{ github.repository }}
71+
BASE_OUTCOME: ${{ steps.base-bench.outcome }}
72+
PR_OUTCOME: ${{ steps.pr-bench.outcome }}
73+
run: |
74+
if [ "$BASE_OUTCOME" != "success" ] || [ "$PR_OUTCOME" != "success" ]; then
75+
{
76+
echo "## ⚠️ Benchmark Run Failed"
77+
echo ""
78+
echo "One or more benchmark runs did not complete successfully."
79+
echo "Please check the workflow logs for details."
80+
echo ""
81+
echo "| Step | Outcome |"
82+
echo "| --- | --- |"
83+
echo "| Base branch benchmarks | \`${BASE_OUTCOME}\` |"
84+
echo "| PR branch benchmarks | \`${PR_OUTCOME}\` |"
85+
} > comment.md
86+
else
87+
benchstat base.txt pr.txt > stat.txt 2>&1
88+
89+
# Extract lines with regressions greater than 5% on any metric.
90+
# Also capture infinite regressions (+∞ / +Inf) that appear when the
91+
# baseline measurement was zero.
92+
awk '
93+
/\+∞/ || /\+Inf/ { print; next }
94+
match($0, /\+[0-9]+\.?[0-9]*%/) {
95+
pct = substr($0, RSTART + 1, RLENGTH - 2)
96+
if (pct + 0 > 5) print
97+
}
98+
' stat.txt > regressions.txt
99+
100+
if [ -s regressions.txt ]; then
101+
{
102+
echo "## ⚠️ Benchmark Regressions Detected (>5%)"
103+
echo ""
104+
echo "The following benchmarks have degraded by more than 5% in time, memory, or allocations:"
105+
echo ""
106+
echo "\`\`\`"
107+
cat regressions.txt
108+
echo "\`\`\`"
109+
echo ""
110+
echo "<details>"
111+
echo "<summary>Full benchmark comparison (<code>benchstat</code>)</summary>"
112+
echo ""
113+
echo "\`\`\`"
114+
cat stat.txt
115+
echo "\`\`\`"
116+
echo "</details>"
117+
} > comment.md
118+
else
119+
{
120+
echo "## ✅ No Benchmark Regressions"
121+
echo ""
122+
echo "No benchmark regressions greater than 5% were detected."
123+
echo ""
124+
echo "<details>"
125+
echo "<summary>Full benchmark comparison (<code>benchstat</code>)</summary>"
126+
echo ""
127+
echo "\`\`\`"
128+
cat stat.txt
129+
echo "\`\`\`"
130+
echo "</details>"
131+
} > comment.md
132+
fi
133+
fi
134+
135+
gh pr comment "$PR_NUMBER" --edit-last --create-if-none --body-file comment.md --repo "$REPO"

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
test:
1111
strategy:
1212
matrix:
13-
go-version: [1.24.x,1.25.x]
13+
go-version: [oldstable, stable]
1414
platform: [ubuntu-latest, macos-latest, windows-latest]
1515
runs-on: ${{ matrix.platform }}
1616
steps:

.github/workflows/test_wasip1.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
test:
1212
strategy:
1313
matrix:
14-
go-version: [1.24.x,1.25.x]
14+
go-version: [oldstable, stable]
1515
runs-on: ubuntu-latest
1616
steps:
1717
- name: Checkout code

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ COVERAGE_REPORT := coverage.out
88
COVERAGE_MODE := count
99

1010
# renovate: datasource=github-tags depName=golangci/golangci-lint
11-
GOLANGCI_VERSION ?= v2.8.0
11+
GOLANGCI_VERSION ?= v2.10.0
1212
TOOLS_BIN := $(shell mkdir -p build/tools && realpath build/tools)
1313

1414
GOLANGCI = $(TOOLS_BIN)/golangci-lint-$(GOLANGCI_VERSION)

helper/polyfill/polyfill_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ func TestChroot(t *testing.T) {
4646
assert.ErrorIs(t, err, billy.ErrNotSupported)
4747
}
4848

49+
func TestChmod(t *testing.T) {
50+
ch, ok := helper.(billy.Chmod)
51+
assert.True(t, ok)
52+
53+
err := ch.Chmod("", 0o444)
54+
assert.ErrorIs(t, err, billy.ErrNotSupported)
55+
}
56+
4957
func TestRoot(t *testing.T) {
5058
assert.Equal(t, string(filepath.Separator), helper.Root())
5159
}

osfs/os_bound.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ func (fs *BoundOS) TempFile(dir, prefix string) (billy.File, error) {
153153
if err != nil {
154154
return nil, err
155155
}
156+
157+
_, err = os.Stat(dir)
158+
if err != nil && os.IsNotExist(err) {
159+
err = os.MkdirAll(dir, defaultDirectoryMode)
160+
if err != nil {
161+
return nil, err
162+
}
163+
}
156164
}
157165

158166
return tempFile(dir, prefix)

osfs/os_bound_test.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,18 +279,22 @@ func TestTempFile(t *testing.T) {
279279
require.NoError(t, f.Close())
280280

281281
f, err = fs.TempFile("/above/cwd", "prefix")
282-
require.ErrorContains(t, err, fmt.Sprint(dir, filepath.FromSlash("/above/cwd/prefix")))
283-
assert.Nil(f)
282+
require.NoError(t, err)
283+
assert.NotNil(f)
284+
assert.Contains(f.Name(), filepath.Join(dir, "/above/cwd", "prefix"))
285+
require.NoError(t, f.Close())
284286

285-
tempDir := os.TempDir()
287+
dir = os.TempDir()
286288
// For windows, volume name must be removed.
287-
if v := filepath.VolumeName(tempDir); v != "" {
288-
tempDir = strings.TrimPrefix(tempDir, v)
289+
if v := filepath.VolumeName(dir); v != "" {
290+
dir = strings.TrimPrefix(dir, v)
289291
}
290292

291-
f, err = fs.TempFile(tempDir, "prefix")
292-
require.ErrorContains(t, err, filepath.Join(dir, tempDir, "prefix"))
293-
assert.Nil(f)
293+
f, err = fs.TempFile(dir, "prefix")
294+
require.NoError(t, err)
295+
assert.NotNil(f)
296+
assert.Contains(f.Name(), filepath.Join(dir, "prefix"))
297+
require.NoError(t, f.Close())
294298
}
295299

296300
func TestChroot(t *testing.T) {

0 commit comments

Comments
 (0)