Skip to content

Commit 5c7ba12

Browse files
authored
feat: introduce version command (#11)
1 parent 98dd391 commit 5c7ba12

12 files changed

Lines changed: 250 additions & 2 deletions

File tree

.golangci.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
version: "2"
2+
3+
linters:
4+
default: none
5+
enable:
6+
- asasalint # checks for pass []any as any in variadic func(...any)
7+
- asciicheck # checks that your code does not contain non-ASCII identifiers
8+
- bidichk # checks for dangerous unicode character sequences
9+
- bodyclose # checks whether HTTP response body is closed successfully
10+
- copyloopvar # detects places where loop variables are copied (Go 1.22+)
11+
- durationcheck # checks for two durations multiplied together
12+
- exptostd # detects functions from golang.org/x/exp/ that can be replaced by std functions
13+
- fatcontext # detects nested contexts in loops
14+
- gocheckcompilerdirectives # validates go compiler directive comments (//go:)
15+
- gochecksumtype # checks exhaustiveness on Go "sum types"
16+
- gocritic # provides diagnostics that check for bugs, performance and style issues
17+
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
18+
- goprintffuncname # checks that printf-like functions are named with f at the end
19+
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
20+
- ineffassign # detects when assignments to existing variables are not used
21+
- nilerr # finds the code that returns nil even if it checks that the error is not nil
22+
- nolintlint # reports ill-formed or insufficient nolint directives
23+
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
24+
- reassign # checks that package variables are not reassigned
25+
- unused # checks for unused constants, variables, functions and types
26+
- gosec
27+
- staticcheck
28+
# To enable later due to too many issues, and confirm we need them:
29+
# - errcheck
30+
31+
exclusions:
32+
paths:
33+
- third-party
34+
rules:
35+
- path: _test\.go$
36+
linters:
37+
- bodyclose
38+
- gosec
39+
40+
settings:
41+
gocritic:
42+
disabled-checks:
43+
- appendAssign
44+
disabled-tags:
45+
- style
46+
47+
formatters:
48+
enable:
49+
- gofmt
50+
exclusions:
51+
paths:
52+
- third-party
53+
54+
issues:
55+
max-issues-per-linter: 0
56+
max-same-issues: 0

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Binary & paths
2-
BINARY_NAME := deeplink
2+
BINARY_NAME := linkctl
33
CMD_DIR := ./cmd
44
BUILD_DIR := build
55
DIST_DIR := dist

cmd/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
package main
22

3-
func main() {}
3+
import (
4+
"os"
5+
6+
"github.com/space-code/linkctl/internal/cmd"
7+
)
8+
9+
func main() {
10+
code := cmd.Main()
11+
os.Exit(int(code))
12+
}

go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
module github.com/space-code/linkctl
22

33
go 1.26.0
4+
5+
require github.com/spf13/cobra v1.10.2
6+
7+
require (
8+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
9+
github.com/spf13/pflag v1.0.9 // indirect
10+
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
2+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
3+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
4+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
5+
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
6+
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
7+
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
8+
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
9+
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
10+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/build/build.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package build
2+
3+
import "runtime/debug"
4+
5+
var Version = ""
6+
7+
func init() {
8+
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "(devel)" {
9+
Version = info.Main.Version
10+
}
11+
}

internal/cmd/cmd.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/space-code/linkctl/internal/build"
8+
"github.com/space-code/linkctl/pkg/cmd/factory"
9+
"github.com/space-code/linkctl/pkg/cmd/root"
10+
)
11+
12+
type exitCode int
13+
14+
const (
15+
exitOK exitCode = 0
16+
exitError exitCode = 1
17+
)
18+
19+
func Main() exitCode {
20+
buildVersion := build.Version
21+
22+
cmdFactory := factory.New(buildVersion)
23+
stderr := cmdFactory.IOStreams.ErrOut
24+
25+
ctx := context.Background()
26+
27+
rootCmd, err := root.NewCmdRoot(cmdFactory, buildVersion)
28+
if err != nil {
29+
fmt.Fprintf(stderr, "failed to create root command: %s\n", err)
30+
return exitError
31+
}
32+
33+
if _, err := rootCmd.ExecuteContextC(ctx); err != nil {
34+
fmt.Fprintf(stderr, "error: %s\n", err)
35+
return exitError
36+
}
37+
38+
return exitOK
39+
}

pkg/cmd/factory/default.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package factory
2+
3+
import (
4+
"github.com/space-code/linkctl/pkg/cmdutil"
5+
"github.com/space-code/linkctl/pkg/iostreams"
6+
)
7+
8+
func New(appVersion string) *cmdutil.Factory {
9+
f := &cmdutil.Factory{
10+
AppVersion: appVersion,
11+
ExecutableName: "linkctl",
12+
}
13+
14+
f.IOStreams = ioStreams()
15+
16+
return f
17+
}
18+
19+
func ioStreams() *iostreams.IOStreams {
20+
io := iostreams.System()
21+
return io
22+
}

pkg/cmd/root/root.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package root
2+
3+
import (
4+
versionCmd "github.com/space-code/linkctl/pkg/cmd/version"
5+
"github.com/space-code/linkctl/pkg/cmdutil"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
func NewCmdRoot(f *cmdutil.Factory, appVersion string) (*cobra.Command, error) {
10+
cmd := &cobra.Command{
11+
Use: "linkctl",
12+
Short: "Mobile Deep Link Debugger",
13+
Long: "linkctl - debug universal links, deeplinks, and app links.",
14+
Annotations: map[string]string{
15+
"versionInfo": versionCmd.Format(appVersion),
16+
},
17+
}
18+
19+
cmd.AddCommand(versionCmd.NewCmdVersion(f))
20+
21+
return cmd, nil
22+
}

pkg/cmd/version/version.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package version
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strings"
7+
8+
"github.com/space-code/linkctl/pkg/cmdutil"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func NewCmdVersion(f *cmdutil.Factory) *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "version",
15+
Short: "Show linkctl version information",
16+
Hidden: true,
17+
Run: func(cmd *cobra.Command, args []string) {
18+
fmt.Fprint(f.IOStreams.Out, cmd.Root().Annotations["versionInfo"])
19+
},
20+
}
21+
22+
return cmd
23+
}
24+
25+
func Format(version string) string {
26+
version = strings.TrimPrefix(version, "v")
27+
28+
return fmt.Sprintf("linkctl version %s\n%s\n", version, changelogURL(version))
29+
}
30+
31+
func changelogURL(version string) string {
32+
path := "https://github.com/space-code/linkctl"
33+
r := regexp.MustCompile(`^v?\d+\.\d+\.\d+(-[\w.]+)?$`)
34+
if !r.MatchString(version) {
35+
return fmt.Sprintf("%s/releases/latest", path)
36+
}
37+
38+
url := fmt.Sprintf("%s/releases/tag/v%s", path, strings.TrimPrefix(version, "v"))
39+
return url
40+
}

0 commit comments

Comments
 (0)