Skip to content
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
42 changes: 42 additions & 0 deletions .github/actions/auto-commit/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Auto-commit changes
description: Composite action for auto-committing changes made by jobs
outputs:
changes-detected:
description: Whether changes were detected & committed
value: ${{ steps.auto_commit.outputs.changes_detected }}

commit-hash:
description: SHA hash of the auto-commit
value: ${{ steps.auto_commit.outputs.commit_hash }}

runs:
using: composite
steps:
- name: Auto-commit changes made by job
id: auto_commit
if: github.event_name == 'pull_request'
uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v6.0.1
with:
commit_message: Auto-fix from ${{ github.workflow }} / ${{ github.job }} job
status_options: --untracked-files=no

- name: Comment on PR about the auto-commit
if: github.event_name == 'pull_request' && steps.auto_commit.outputs.changes_detected == 'true'
uses: actions/github-script@v8
with:
script: |
const repositoryUrl = '${{ github.server_url }}/${{ github.repository }}'

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `
**Auto-fix applied from ${{ github.workflow }}** / \`${{ github.job }}\` job

* Workflow run: ${repositoryUrl}/actions/runs/${{ github.run_id }}
* Fix commit: ${repositoryUrl}/commit/${{ steps.auto_commit.outputs.commit_hash }}

@${{ github.event.pull_request.user.login }}: `
+ 'Please check the auto-changes, pull them, squash commits, & force-push to continue the PR review ...'
})
39 changes: 32 additions & 7 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
name: Lint & format
name: Linting
on:
push:
pull_request:

permissions:
contents: write
pull-requests: write

jobs:
lint:
name: Lint w/ golangci-lint ${{ github.event_name == 'pull_request' && '(auto-fix) & reviewdog' || '' }}
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
submodules: recursive

# Avoid merge commits when auto-committing fixes ...
ref: ${{ github.head_ref || github.ref }}

- name: Setup Go environment
uses: actions/setup-go@v6
with:
go-version: 1.25.1

- name: Run go mod tidy
run: go mod tidy
run: |
go mod tidy

- name: Install & run golangci-lint
if: github.event_name == 'push'
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8
with:
install-mode: goinstall
version: latest
install-mode: "goinstall"
args: --fix
args: --default all # ${{ github.event_name == 'pull_request' && '--fix' || '' }}

- name: Install & run golangci-lint w/ reviewdog
if: github.event_name == 'pull_request'
uses: reviewdog/action-golangci-lint@f9bba13753278f6a73b27a56a3ffb1bfda90ed71 # v2.8.0
with:
golangci_lint_flags: --default all --fix

reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
filter_mode: file
level: error
fail_level: any
cache: false

- name: Auto-commit lint fixes
if: github.event_name == 'pull_request' && (success() || failure()) # (golangci-lint succeeds when all is auto-fixed)
uses: ./.github/actions/auto-commit
18 changes: 11 additions & 7 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
name: Test & benchmark

name: Testing
on:
push:
pull_request:

permissions:
contents: write
pull-requests: write

jobs:
test:
name: Test w/ go test
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Setup Go environment
uses: actions/setup-go@v6
with:
go-version: 1.25.1

- name: Run tests
run: |
go mod tidy
go test -v ./...

benchmark:
name: Benchmark w/ go test & benchstat
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
with:
Expand All @@ -37,7 +40,8 @@ jobs:
go-version: 1.25.1

- name: Install benchstat
run: go install golang.org/x/perf/cmd/benchstat@latest
run: |
go install golang.org/x/perf/cmd/benchstat@latest

- name: Run benchmark on base branch
if: github.event_name == 'pull_request'
Expand Down
15 changes: 15 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '2'
linters:
disable:
- wsl # <-- Auto-switches to wsl_v5.

settings:
depguard:
rules:
main:
list-mode: strict
allow:
- $gostd
- github.com/samber/lo
- github.com/stretchr/testify
- github.com/zimmermanncode/go-require
3 changes: 3 additions & 0 deletions pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// Package require provides runtime Go assertions w/ descriptive panics & a fluent API.
package require

import (
Expand All @@ -30,6 +31,7 @@ import (
// // if not nil => panic: assertion failed: My value should be a nil pointer
func NilPtr[T any](name string, value *T) *T {
lo.Assertf(value == nil, "%s should be a nil pointer", name)

return value
}

Expand All @@ -42,5 +44,6 @@ func NilPtr[T any](name string, value *T) *T {
// // if nil => panic: assertion failed: My value should not be a nil pointer
func NotNilPtr[T any](name string, value *T) *T {
lo.Assertf(value != nil, "%s should not be a nil pointer", name)

return value
}
49 changes: 30 additions & 19 deletions pointer_test.go
Original file line number Diff line number Diff line change
@@ -1,61 +1,72 @@
package require
package require_test

import (
"testing"

assert "github.com/stretchr/testify/assert"
"github.com/zimmermanncode/go-require"
)

func TestNilPtr(t *testing.T) {
t.Parallel()
t.Run("should accept nil pointer & return nil", func(t *testing.T) {
var nilPtr *int
assert.Nil(t, NilPtr("Test pointer", nilPtr))
t.Parallel()
assert.Nil(t, require.NilPtr("Test pointer", (*int)(nil)))
})
t.Run("should panic when pointer is not nil", func(t *testing.T) {
value := "test"

t.Parallel()
assert.PanicsWithValue(t, "assertion failed: Test pointer should be a nil pointer", func() {
value := "test"
NilPtr("Test pointer", &value)
require.NilPtr("Test pointer", &value)
})
})
t.Run("should use given name in panic message", func(t *testing.T) {
assert.PanicsWithValue(t, "assertion failed: Other pointer should be a nil pointer", func() {
value := 42
NilPtr("Other pointer", &value)
value := 42

t.Parallel()
assert.PanicsWithValue(t, "assertion failed: Other value should be a nil pointer", func() {
require.NilPtr("Other value", &value)
})
})
}

func TestNotNilPtr(t *testing.T) {
t.Parallel()
t.Run("should accept not-nil pointer & return same pointer", func(t *testing.T) {
value := 42
assert.Same(t, &value, NotNilPtr("Test pointer", &value))

t.Parallel()
assert.Same(t, &value, require.NotNilPtr("Test pointer", &value))
})
t.Run("should panic when pointer is nil", func(t *testing.T) {
t.Parallel()
assert.PanicsWithValue(t, "assertion failed: Test pointer should not be a nil pointer", func() {
var nilPtr *string
NotNilPtr("Test pointer", nilPtr)
require.NotNilPtr("Test pointer", (*string)(nil))
})
})
t.Run("should use given name in panic message", func(t *testing.T) {
assert.PanicsWithValue(t, "assertion failed: Other pointer should not be a nil pointer", func() {
var nilPtr *float64
NotNilPtr("Other pointer", nilPtr)
t.Parallel()
assert.PanicsWithValue(t, "assertion failed: Other value should not be a nil pointer", func() {
require.NotNilPtr("Other value", (*float64)(nil))
})
})
}

func BenchmarkNilPtr(b *testing.B) {
var nilPtr *int
b.ResetTimer()
for i := 0; i < b.N; i++ {
NilPtr("Benchmark pointer", nilPtr)

for range b.N {
require.NilPtr("Benchmark pointer", (*int)(nil))
}
}

func BenchmarkNotNilPtr(b *testing.B) {
value := "benchmark"

b.ResetTimer()
for i := 0; i < b.N; i++ {
NotNilPtr("Benchmark pointer", &value)

for range b.N {
require.NotNilPtr("Benchmark pointer", &value)
}
}
Loading