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
10 changes: 5 additions & 5 deletions .github/workflows/pr-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # ratchet:actions/setup-go@v6.3.0
with:
go-version-file: 'go.mod'
check-latest: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # ratchet:golangci/golangci-lint-action@v9.2.0
with:
version: v1.59
version: latest
govulncheck:
name: govulncheck
runs-on: ubuntu-latest
steps:
- id: govulncheck
uses: golang/govulncheck-action@v1
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # ratchet:golang/govulncheck-action@v1.0.4
with:
go-version-file: 'go.mod'
check-latest: true
Expand Down
15 changes: 5 additions & 10 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
# Refer to golangci-lint's example config file for more options and information:
# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml

version: "2"
run:
timeout: 5m
modules-download-mode: readonly

linters:
enable:
- errcheck
- gofmt
- goimports
- gocyclo
- govet
- misspell
- revive
- staticcheck
formatters:
enable:
- gofmt
- goimports

issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0
46 changes: 28 additions & 18 deletions build/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ showUsage() {
exit 0
}

## install gox if needed
ensureGox() {
if ! which gox &> /dev/null; then
printf "Installing gox ... "
go install github.com/mitchellh/gox@v1
fi
}

## we require module support
export GO111MODULE=on

Expand All @@ -48,7 +40,6 @@ while getopts ":dcri" opt; do
should_exit=true
;;
r)
ensureGox
RELEASE_BUILD=1
;;
i)
Expand All @@ -73,15 +64,34 @@ if [ $RELEASE_BUILD -eq 1 ]; then
## clean dist directory
rm -rf ./dist/

## call gox to build our binaries
CGO_ENABLED=0 gox \
-osarch="linux/amd64 darwin/amd64 freebsd/amd64 openbsd/amd64 windows/amd64 windows/386" \
-ldflags="-X main.appVersion=${RELEASE_VERSION} -s -w" \
-output="./dist/${BUILD_NAME}-${RELEASE_VERSION}-{{.Arch}}-{{.OS}}/${BUILD_NAME}-${RELEASE_VERSION}" \
> /dev/null >&1

## gox return
RETURN_VALUE=$?
## build release binaries with a shell loop instead of gox
RETURN_VALUE=0

for target in \
linux/amd64 \
darwin/amd64 \
freebsd/amd64 \
openbsd/amd64 \
windows/amd64 \
windows/386
do
GOOS="${target%/*}"
GOARCH="${target#*/}"
OUTPUT_DIR="./dist/${BUILD_NAME}-${RELEASE_VERSION}-${GOARCH}-${GOOS}"

mkdir -p "${OUTPUT_DIR}"

CGO_ENABLED=0 GOOS="${GOOS}" GOARCH="${GOARCH}" \
go build \
-ldflags="-X main.appVersion=${RELEASE_VERSION} -s -w" \
-o "${OUTPUT_DIR}/${BUILD_NAME}-${RELEASE_VERSION}" \
> /dev/null 2>&1

RETURN_VALUE=$?
if [ ${RETURN_VALUE} -ne 0 ]; then
break
fi
done

else

Expand Down
3 changes: 1 addition & 2 deletions build/codeCheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
golangci="$(go env GOPATH)/bin/golangci-lint"
if ! ${golangci} version &> /dev/null; then
echo "Installing golangci-lint binary to ${golangci}"
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
sh -s -- -b "$(go env GOPATH)/bin" v1.57.1
curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b $(go env GOPATH)/bin
echo "done"
fi

Expand Down
15 changes: 10 additions & 5 deletions command/check/util.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package check

import (
stderrors "errors"
"flag"
"fmt"
"os"

"github.com/leprechau/ipman/internal"
"github.com/leprechau/ipman/internal/errors"
internalerrors "github.com/leprechau/ipman/internal/errors"
)

// setupFlags initializes the instance configuration
Expand All @@ -21,7 +22,8 @@ func (c *Command) setupFlags(args []string) error {

// init flagset
cmdFlags = flag.NewFlagSet("check", flag.ContinueOnError)
cmdFlags.Usage = func() { _, _ = fmt.Fprint(os.Stdout, c.Help()); os.Exit(0) }
cmdFlags.SetOutput(os.Stdout)
cmdFlags.Usage = func() { _, _ = os.Stdout.WriteString(c.Help()) }

// declare flags
cmdFlags.BoolVar(&c.config.v4, "4", false,
Expand All @@ -33,12 +35,15 @@ func (c *Command) setupFlags(args []string) error {

// parse flags and ignore error
if err = cmdFlags.Parse(args); err != nil {
return nil
if stderrors.Is(err, flag.ErrHelp) {
return nil
}
return fmt.Errorf("parse check flags: %w", err)
}

// check for remaining garbage
if cmdFlags.NArg() > 0 {
return errors.ErrUnknownArg
return internalerrors.ErrUnknownArg
}

// default to v4 if not specified
Expand All @@ -48,7 +53,7 @@ func (c *Command) setupFlags(args []string) error {

// init ip backend
if c.ip, err = internal.GetIPBackend(c.config.ipbe); err != nil {
return err
return fmt.Errorf("init ip backend: %w", err)
}

return nil
Expand Down
60 changes: 60 additions & 0 deletions command/check/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package check

import (
"strings"
"testing"

internalerrors "github.com/leprechau/ipman/internal/errors"
)

func TestSetupFlagsDefaultsToIPv4(t *testing.T) {
t.Parallel()

cmd := &Command{Self: "ipman"}

if err := cmd.setupFlags(nil); err != nil {
t.Fatalf("setupFlags() error = %v", err)
}

if !cmd.config.v4 {
t.Fatal("setupFlags() did not default to IPv4")
}

if cmd.config.v6 {
t.Fatal("setupFlags() unexpectedly enabled IPv6")
}

if cmd.ip == nil {
t.Fatal("setupFlags() did not initialize an IP backend")
}
}

func TestSetupFlagsReturnsParseError(t *testing.T) {
t.Parallel()

cmd := &Command{Self: "ipman"}

err := cmd.setupFlags([]string{"-unknown"})
if err == nil {
t.Fatal("setupFlags() error = nil, want parse failure")
}

if !strings.Contains(err.Error(), "parse check flags") {
t.Fatalf("setupFlags() error = %v, want contextual parse error", err)
}
}

func TestSetupFlagsRejectsTrailingArgs(t *testing.T) {
t.Parallel()

cmd := &Command{Self: "ipman"}

err := cmd.setupFlags([]string{"extra"})
if err == nil {
t.Fatal("setupFlags() error = nil, want trailing arg failure")
}

if err != internalerrors.ErrUnknownArg {
t.Fatalf("setupFlags() error = %v, want %v", err, internalerrors.ErrUnknownArg)
}
}
19 changes: 12 additions & 7 deletions command/update/util.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package update

import (
stderrors "errors"
"flag"
"fmt"
"os"

"github.com/leprechau/ipman/internal"
"github.com/leprechau/ipman/internal/errors"
internalerrors "github.com/leprechau/ipman/internal/errors"
)

// setupFlags initializes the instance configuration
Expand All @@ -21,7 +22,8 @@ func (c *Command) setupFlags(args []string) error {

// init flagset
cmdFlags = flag.NewFlagSet("update", flag.ContinueOnError)
cmdFlags.Usage = func() { _, _ = fmt.Fprint(os.Stdout, c.Help()); os.Exit(0) }
cmdFlags.SetOutput(os.Stdout)
cmdFlags.Usage = func() { _, _ = os.Stdout.WriteString(c.Help()) }

// declare flags
cmdFlags.BoolVar(&c.config.v4, "4", false,
Expand All @@ -45,18 +47,21 @@ func (c *Command) setupFlags(args []string) error {

// parse flags and ignore error
if err = cmdFlags.Parse(args); err != nil {
return nil
if stderrors.Is(err, flag.ErrHelp) {
return nil
}
return fmt.Errorf("parse update flags: %w", err)
}

// check for remaining garbage
if cmdFlags.NArg() > 0 {
return errors.ErrUnknownArg
return internalerrors.ErrUnknownArg
}

// check zone and attempt to get from environment
if c.config.zone == "" {
if c.config.zone = os.Getenv("IPMAN_DNS_ZONE"); c.config.zone == "" {
return errors.ErrMissingZone
return internalerrors.ErrMissingZone
}
}

Expand All @@ -77,12 +82,12 @@ func (c *Command) setupFlags(args []string) error {

// init ip backend
if c.ip, err = internal.GetIPBackend(c.config.ipbe); err != nil {
return err
return fmt.Errorf("init ip backend: %w", err)
}

// init dns backend
if c.dns, err = internal.GetDNSBackend(c.config.dnsbe); err != nil {
return err
return fmt.Errorf("init dns backend: %w", err)
}

// set backend access key if needed
Expand Down
60 changes: 60 additions & 0 deletions command/update/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package update

import (
"strings"
"testing"

internalerrors "github.com/leprechau/ipman/internal/errors"
)

func TestSetupFlagsLoadsZoneFromEnv(t *testing.T) {
t.Setenv("IPMAN_DNS_ZONE", "example.com")

cmd := &Command{Self: "ipman"}

if err := cmd.setupFlags(nil); err != nil {
t.Fatalf("setupFlags() error = %v", err)
}

if got := cmd.config.zone; got != "example.com" {
t.Fatalf("setupFlags() zone = %q, want %q", got, "example.com")
}

if !cmd.config.v4 {
t.Fatal("setupFlags() did not default to IPv4")
}

if cmd.dns == nil || cmd.ip == nil {
t.Fatal("setupFlags() did not initialize backends")
}
}

func TestSetupFlagsReturnsParseError(t *testing.T) {
t.Setenv("IPMAN_DNS_ZONE", "example.com")

cmd := &Command{Self: "ipman"}

err := cmd.setupFlags([]string{"-ttl=bad"})
if err == nil {
t.Fatal("setupFlags() error = nil, want parse failure")
}

if !strings.Contains(err.Error(), "parse update flags") {
t.Fatalf("setupFlags() error = %v, want contextual parse error", err)
}
}

func TestSetupFlagsRequiresZoneWhenUnset(t *testing.T) {
t.Parallel()

cmd := &Command{Self: "ipman"}

err := cmd.setupFlags(nil)
if err == nil {
t.Fatal("setupFlags() error = nil, want missing zone failure")
}

if err != internalerrors.ErrMissingZone {
t.Fatalf("setupFlags() error = %v, want %v", err, internalerrors.ErrMissingZone)
}
}
Loading
Loading