1- package cmd
1+ // Package actioncmd implements the gosqlx action subcommand for GitHub Actions CI.
2+ package actioncmd
23
34import (
45 "fmt"
@@ -26,12 +27,12 @@ var (
2627 actionTimeout int
2728)
2829
29- // actionCmd implements the GitHub Actions entrypoint as a Go subcommand .
30- // It finds SQL files, runs lint + validate, and outputs GitHub Actions annotations.
31- var actionCmd = & cobra.Command {
32- Use : "action" ,
33- Short : "Run GoSQLX checks for GitHub Actions CI" ,
34- Long : `Run SQL validation and linting with GitHub Actions annotation output.
30+ // NewCmd returns the action cobra.Command .
31+ func NewCmd () * cobra. Command {
32+ cmd : = & cobra.Command {
33+ Use : "action" ,
34+ Short : "Run GoSQLX checks for GitHub Actions CI" ,
35+ Long : `Run SQL validation and linting with GitHub Actions annotation output.
3536
3637This command replaces the shell-based entrypoint for the GoSQLX GitHub Action.
3738It finds SQL files matching a glob pattern, runs validation and linting on each,
@@ -43,20 +44,18 @@ Environment variables (also settable via flags):
4344 SEVERITY - threshold: error, warning, info (default: warning)
4445 CONFIG - path to .gosqlx.yml config file
4546 TIMEOUT - per-file timeout in seconds (default: 600)` ,
46- RunE : runAction ,
47- }
47+ RunE : runAction ,
48+ }
4849
49- func init () {
50- actionCmd .Flags ().StringVar (& actionFiles , "files" , "" , "glob pattern for SQL files (env: SQL_FILES)" )
51- actionCmd .Flags ().StringVar (& actionRules , "rules" , "" , "comma-separated lint rules (env: RULES)" )
52- actionCmd .Flags ().StringVar (& actionSeverity , "severity" , "" , "severity threshold: error, warning, info (env: SEVERITY)" )
53- actionCmd .Flags ().StringVar (& actionConfig , "config" , "" , "path to config file (env: CONFIG)" )
54- actionCmd .Flags ().IntVar (& actionTimeout , "timeout" , 0 , "per-file timeout in seconds (env: TIMEOUT)" )
50+ cmd .Flags ().StringVar (& actionFiles , "files" , "" , "glob pattern for SQL files (env: SQL_FILES)" )
51+ cmd .Flags ().StringVar (& actionRules , "rules" , "" , "comma-separated lint rules (env: RULES)" )
52+ cmd .Flags ().StringVar (& actionSeverity , "severity" , "" , "severity threshold: error, warning, info (env: SEVERITY)" )
53+ cmd .Flags ().StringVar (& actionConfig , "config" , "" , "path to config file (env: CONFIG)" )
54+ cmd .Flags ().IntVar (& actionTimeout , "timeout" , 0 , "per-file timeout in seconds (env: TIMEOUT)" )
5555
56- rootCmd . AddCommand ( actionCmd )
56+ return cmd
5757}
5858
59- // envDefault returns the flag value if non-empty, otherwise the env var, otherwise the fallback.
6059func envDefault (flagVal , envKey , fallback string ) string {
6160 if flagVal != "" {
6261 return flagVal
@@ -99,7 +98,6 @@ func runAction(_ *cobra.Command, _ []string) error {
9998 }
10099 }
101100
102- // Find SQL files
103101 files , err := findSQLFiles (pattern )
104102 if err != nil {
105103 return fmt .Errorf ("finding SQL files: %w" , err )
@@ -110,7 +108,6 @@ func runAction(_ *cobra.Command, _ []string) error {
110108 }
111109 fmt .Printf ("Found %d SQL file(s)\n " , len (files ))
112110
113- // Parse rules
114111 var ruleList []string
115112 if rules != "" {
116113 for _ , r := range strings .Split (rules , "," ) {
@@ -134,7 +131,6 @@ func runAction(_ *cobra.Command, _ []string) error {
134131 for _ , file := range files {
135132 displayFile := strings .TrimPrefix (file , "./" )
136133
137- // Validate
138134 vErr := validateFileWithTimeout (file , timeout )
139135 if vErr != nil {
140136 validateErrors ++
@@ -154,7 +150,6 @@ func runAction(_ *cobra.Command, _ []string) error {
154150 totalValid ++
155151 }
156152
157- // Lint
158153 violations := lintFile (file , ruleList )
159154 for _ , v := range violations {
160155 level := "notice"
@@ -169,7 +164,6 @@ func runAction(_ *cobra.Command, _ []string) error {
169164 }
170165 }
171166
172- // Summary
173167 fmt .Println ()
174168 fmt .Println ("==============================" )
175169 fmt .Println (" GoSQLX Results Summary" )
@@ -181,12 +175,10 @@ func runAction(_ *cobra.Command, _ []string) error {
181175 fmt .Printf (" Lint warnings: %d\n " , lintWarnings )
182176 fmt .Println ("==============================" )
183177
184- // GitHub step summary
185178 if summaryPath := os .Getenv ("GITHUB_STEP_SUMMARY" ); summaryPath != "" {
186179 writeStepSummary (summaryPath , len (files ), totalValid , validateErrors , lintErrors , lintWarnings )
187180 }
188181
189- // Exit code based on severity
190182 fail := false
191183 switch severity {
192184 case "error" :
@@ -201,7 +193,6 @@ func runAction(_ *cobra.Command, _ []string) error {
201193 return nil
202194}
203195
204- // ghAnnotation prints a GitHub Actions annotation.
205196func ghAnnotation (level , file string , line int , msg string ) {
206197 params := ""
207198 if file != "" {
@@ -217,7 +208,6 @@ func ghAnnotation(level, file string, line int, msg string) {
217208 }
218209}
219210
220- // extractLineNumber extracts a line number from text matching "line N".
221211func extractLineNumber (re * regexp.Regexp , text string ) int {
222212 m := re .FindStringSubmatch (text )
223213 if len (m ) >= 2 {
@@ -227,15 +217,14 @@ func extractLineNumber(re *regexp.Regexp, text string) int {
227217 return 0
228218}
229219
230- // findSQLFiles locates SQL files matching the given glob pattern.
231220func findSQLFiles (pattern string ) ([]string , error ) {
232221 var files []string
233222
234223 switch {
235224 case pattern == "**/*.sql" :
236225 err := filepath .Walk ("." , func (path string , info os.FileInfo , err error ) error {
237226 if err != nil {
238- return nil // skip errors
227+ return nil
239228 }
240229 if ! info .IsDir () && strings .HasSuffix (strings .ToLower (path ), ".sql" ) {
241230 files = append (files , path )
@@ -256,7 +245,6 @@ func findSQLFiles(pattern string) ([]string, error) {
256245 }
257246 }
258247 default :
259- // Try filepath.Glob first, fall back to Walk with path matching
260248 matched , err := filepath .Glob (pattern )
261249 if err == nil && len (matched ) > 0 {
262250 for _ , m := range matched {
@@ -266,7 +254,6 @@ func findSQLFiles(pattern string) ([]string, error) {
266254 }
267255 }
268256 } else {
269- // Walk and match with filepath.Match
270257 err = filepath .Walk ("." , func (path string , info os.FileInfo , walkErr error ) error {
271258 if walkErr != nil {
272259 return nil
@@ -286,14 +273,12 @@ func findSQLFiles(pattern string) ([]string, error) {
286273 return files , nil
287274}
288275
289- // lintViolation represents a single lint finding.
290276type lintViolation struct {
291277 Line int
292278 Severity string
293279 Message string
294280}
295281
296- // defaultLinter creates a linter with standard rules.
297282func defaultLinter () * linter.Linter {
298283 return linter .New (
299284 whitespace .NewTrailingWhitespaceRule (),
@@ -303,7 +288,6 @@ func defaultLinter() *linter.Linter {
303288 )
304289}
305290
306- // lintFile runs the linter on a file and returns violations.
307291func lintFile (filePath string , _ []string ) []lintViolation {
308292 l := defaultLinter ()
309293 result := l .LintFile (filePath )
@@ -327,7 +311,6 @@ func lintFile(filePath string, _ []string) []lintViolation {
327311 return violations
328312}
329313
330- // validateFileWithTimeout validates a SQL file with a timeout.
331314func validateFileWithTimeout (filePath string , timeout time.Duration ) error {
332315 type result struct {
333316 err error
@@ -351,7 +334,6 @@ func validateFileWithTimeout(filePath string, timeout time.Duration) error {
351334 }
352335}
353336
354- // writeStepSummary appends a markdown summary to the GitHub step summary file.
355337func writeStepSummary (path string , total , valid , valErrors , lintErrors , lintWarnings int ) {
356338 f , err := os .OpenFile (filepath .Clean (path ), os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0o600 )
357339 if err != nil {
0 commit comments