Skip to content

Commit c584641

Browse files
feature: Add version command and enhance CLI logging
- Add version command to display CLI version information - Add command execution logging with sensitive data masking - Add version logging to file
1 parent 8062f87 commit c584641

File tree

8 files changed

+226
-14
lines changed

8 files changed

+226
-14
lines changed

.github/workflows/go.yml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@ jobs:
99
steps:
1010
- name: Checkout
1111
uses: actions/checkout@v4
12+
with:
13+
fetch-depth: 0 # Needed for git history
1214
- name: Set up Go
1315
uses: actions/setup-go@v4
14-
- name: Build CLI for Linux
15-
run: |
16-
GOOS=linux GOARCH=amd64 go build -o cli-v2-linux ./cli-v2.go
17-
- name: Build CLI for Windows
18-
run: |
19-
GOOS=windows GOARCH=amd64 go build -o cli-v2.exe ./cli-v2.go
20-
- name: Build CLI for macOS
21-
run: |
22-
GOOS=darwin GOARCH=amd64 go build -o cli-v2-macos ./cli-v2.go
16+
- name: Build CLI for all platforms
17+
run: make build-all
2318
- name: Upload CLI binaries
2419
uses: actions/upload-artifact@v4
2520
with:
@@ -38,7 +33,7 @@ jobs:
3833
uses: actions/setup-go@v4
3934
- name: Install dependencies from .codacy/codacy.yaml
4035
run: |
41-
go build ./cli-v2.go
36+
make build
4237
./cli-v2 install
4338
- name: "Run tests"
4439
run: |

.github/workflows/it-test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
steps:
1717
- name: Checkout code
1818
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0 # Needed for git history
1921

2022
- name: Set up Go
2123
uses: actions/setup-go@v5
@@ -46,7 +48,6 @@ jobs:
4648
if: matrix.os != 'windows-latest'
4749
run: chmod +x cli-v2
4850

49-
5051
- name: Run tool tests
5152
if: matrix.os != 'windows-latest'
5253
id: run_tests

Makefile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.PHONY: build clean build-all build-linux build-darwin build-windows
2+
3+
# Get the version from git describe or fallback to a default version
4+
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "development")
5+
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
6+
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
7+
8+
# Build flags
9+
LDFLAGS := -X 'codacy/cli-v2/version.Version=$(VERSION)' \
10+
-X 'codacy/cli-v2/version.GitCommit=$(COMMIT)' \
11+
-X 'codacy/cli-v2/version.BuildTime=$(BUILD_TIME)'
12+
13+
# Build the CLI for current platform
14+
build:
15+
go build -ldflags "$(LDFLAGS)" -o cli-v2
16+
17+
# Build for Linux
18+
build-linux:
19+
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o cli-v2-linux
20+
21+
# Build for macOS
22+
build-darwin:
23+
GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o cli-v2-macos
24+
25+
# Build for Windows
26+
build-windows:
27+
GOOS=windows GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o cli-v2.exe
28+
29+
# Build for all platforms
30+
build-all: build-linux build-darwin build-windows
31+
32+
# Clean build artifacts
33+
clean:
34+
rm -f cli-v2 cli-v2-linux cli-v2-macos cli-v2.exe

cli-v2.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"codacy/cli-v2/config"
66
config_file "codacy/cli-v2/config-file"
77
"codacy/cli-v2/utils/logger"
8+
"codacy/cli-v2/version"
89
"fmt"
910
"os"
1011
"path/filepath"
@@ -22,8 +23,10 @@ func main() {
2223
fmt.Printf("Failed to initialize logger: %v\n", err)
2324
}
2425

25-
// Log startup message
26-
logger.Debug("Starting Codacy CLI.", logrus.Fields{})
26+
// Log startup message and version
27+
logger.Info("Starting Codacy CLI", logrus.Fields{
28+
"version": version.GetVersion(),
29+
})
2730

2831
// This also setup the config global !
2932
configErr := config_file.ReadConfigFile(config.Config.ProjectConfigFile())

cmd/root.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"strings"
78

89
"codacy/cli-v2/config"
910
"codacy/cli-v2/utils/logger"
11+
"codacy/cli-v2/version"
1012

1113
"github.com/fatih/color"
14+
"github.com/sirupsen/logrus"
1215
"github.com/spf13/cobra"
1316
)
1417

1518
var rootCmd = &cobra.Command{
1619
Use: "codacy-cli",
17-
Short: "Codacy CLI - A command line interface for Codacy",
20+
Short: fmt.Sprintf("Codacy CLI v%s - A command line interface for Codacy", version.GetVersion()),
1821
Long: "",
1922
Example: getExampleText(),
2023
PersistentPreRun: func(cmd *cobra.Command, args []string) {
@@ -23,6 +26,16 @@ var rootCmd = &cobra.Command{
2326
if err := logger.Initialize(logsDir); err != nil {
2427
fmt.Printf("Warning: Failed to initialize file logger: %v\n", err)
2528
}
29+
30+
// Create a masked version of the full command for logging
31+
maskedArgs := maskSensitiveArgs(os.Args)
32+
33+
// Log the command being executed with its arguments and flags
34+
logger.Info("Executing CLI command", logrus.Fields{
35+
"command": cmd.Name(),
36+
"full_command": maskedArgs,
37+
"args": args,
38+
})
2639
},
2740
Run: func(cmd *cobra.Command, args []string) {
2841
// Check if .codacy directory exists
@@ -122,3 +135,37 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
122135
https://github.com/codacy/codacy-cli-v2
123136
`)
124137
}
138+
139+
// maskSensitiveArgs creates a copy of the arguments with sensitive values masked
140+
func maskSensitiveArgs(args []string) []string {
141+
maskedArgs := make([]string, len(args))
142+
copy(maskedArgs, args)
143+
144+
sensitiveFlags := map[string]bool{
145+
"--api-token": true,
146+
"--repository-token": true,
147+
"--project-token": true,
148+
"--codacy-api-token": true,
149+
}
150+
151+
for i, arg := range maskedArgs {
152+
// Skip the first argument (program name)
153+
if i == 0 {
154+
continue
155+
}
156+
157+
// Handle --flag=value format
158+
for flag := range sensitiveFlags {
159+
if strings.HasPrefix(arg, flag+"=") {
160+
maskedArgs[i] = flag + "=***"
161+
break
162+
}
163+
}
164+
165+
// Handle --flag value format
166+
if sensitiveFlags[arg] && i < len(maskedArgs)-1 {
167+
maskedArgs[i+1] = "***"
168+
}
169+
}
170+
return maskedArgs
171+
}

cmd/root_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package cmd
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestMaskSensitiveArgs(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
args []string
13+
expected []string
14+
}{
15+
{
16+
name: "no sensitive flags",
17+
args: []string{"codacy-cli", "analyze", "--tool", "eslint"},
18+
expected: []string{"codacy-cli", "analyze", "--tool", "eslint"},
19+
},
20+
{
21+
name: "api token with space",
22+
args: []string{"codacy-cli", "init", "--api-token", "secret123", "--tool", "eslint"},
23+
expected: []string{"codacy-cli", "init", "--api-token", "***", "--tool", "eslint"},
24+
},
25+
{
26+
name: "api token with equals",
27+
args: []string{"codacy-cli", "init", "--api-token=secret123", "--tool", "eslint"},
28+
expected: []string{"codacy-cli", "init", "--api-token=***", "--tool", "eslint"},
29+
},
30+
{
31+
name: "repository token at end with space",
32+
args: []string{"codacy-cli", "init", "--repository-token", "secret123"},
33+
expected: []string{"codacy-cli", "init", "--repository-token", "***"},
34+
},
35+
{
36+
name: "repository token at end with equals",
37+
args: []string{"codacy-cli", "init", "--repository-token=secret123"},
38+
expected: []string{"codacy-cli", "init", "--repository-token=***"},
39+
},
40+
{
41+
name: "project token at start with space",
42+
args: []string{"codacy-cli", "--project-token", "secret123", "analyze"},
43+
expected: []string{"codacy-cli", "--project-token", "***", "analyze"},
44+
},
45+
{
46+
name: "project token at start with equals",
47+
args: []string{"codacy-cli", "--project-token=secret123", "analyze"},
48+
expected: []string{"codacy-cli", "--project-token=***", "analyze"},
49+
},
50+
{
51+
name: "multiple tokens mixed format",
52+
args: []string{"codacy-cli", "--api-token=secret1", "--project-token", "secret2"},
53+
expected: []string{"codacy-cli", "--api-token=***", "--project-token", "***"},
54+
},
55+
{
56+
name: "token flag at end without value",
57+
args: []string{"codacy-cli", "analyze", "--api-token"},
58+
expected: []string{"codacy-cli", "analyze", "--api-token"},
59+
},
60+
{
61+
name: "empty value after equals",
62+
args: []string{"codacy-cli", "--api-token="},
63+
expected: []string{"codacy-cli", "--api-token=***"},
64+
},
65+
}
66+
67+
for _, tt := range tests {
68+
t.Run(tt.name, func(t *testing.T) {
69+
masked := maskSensitiveArgs(tt.args)
70+
assert.Equal(t, tt.expected, masked, "masked arguments should match expected")
71+
})
72+
}
73+
}

cmd/version.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package cmd
2+
3+
import (
4+
"codacy/cli-v2/version"
5+
"fmt"
6+
"runtime"
7+
8+
"github.com/fatih/color"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var versionCmd = &cobra.Command{
13+
Use: "version",
14+
Short: "Display version information",
15+
Run: func(cmd *cobra.Command, args []string) {
16+
bold := color.New(color.Bold)
17+
cyan := color.New(color.FgCyan)
18+
19+
fmt.Println()
20+
bold.Println("Codacy CLI Version Information")
21+
fmt.Println("-----------------------------")
22+
cyan.Printf("Version: ")
23+
fmt.Println(version.Version)
24+
cyan.Printf("Commit: ")
25+
fmt.Println(version.GitCommit)
26+
cyan.Printf("Built: ")
27+
fmt.Println(version.BuildTime)
28+
cyan.Printf("Go version: ")
29+
fmt.Println(runtime.Version())
30+
cyan.Printf("OS/Arch: ")
31+
fmt.Printf("%s/%s\n", runtime.GOOS, runtime.GOARCH)
32+
fmt.Println()
33+
},
34+
}
35+
36+
func init() {
37+
rootCmd.AddCommand(versionCmd)
38+
}

version/version.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package version
2+
3+
// Version information set at build time
4+
var (
5+
// Version is the current version of codacy-cli
6+
Version = "development"
7+
8+
// GitCommit is the git commit hash of the build
9+
GitCommit = "unknown"
10+
11+
// BuildTime is the time the binary was built
12+
BuildTime = "unknown"
13+
)
14+
15+
// GetVersion returns the current version of codacy-cli
16+
func GetVersion() string {
17+
if GitCommit != "unknown" {
18+
return Version + " (" + GitCommit + ") built at " + BuildTime
19+
}
20+
return Version
21+
}

0 commit comments

Comments
 (0)