mirror of
https://github.com/LukeHagar/slinky.git
synced 2025-12-06 04:21:20 +00:00
Refactor entrypoint.sh, check.go, and run.go to support positional targets for URL scanning, enhancing flexibility. Update README.md to reflect changes in target handling and provide clearer usage instructions.
This commit is contained in:
16
README.md
16
README.md
@@ -51,14 +51,18 @@ go build -o slinky ./
|
|||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
slinky check . --patterns "docs/**/*.md" --patterns "**/*.go" --md-out results.md --json-out results.json
|
# Headless: provide one or more targets (files, dirs, or globs)
|
||||||
|
slinky check **/*
|
||||||
|
slinky check ./docs/**/* ./markdown/**/*
|
||||||
|
|
||||||
|
# TUI mode: same targets
|
||||||
|
slinky run **/*
|
||||||
```
|
```
|
||||||
|
|
||||||
TUI mode:
|
Notes:
|
||||||
|
- Targets can be files, directories, or doublestar globs. Multiple targets are allowed.
|
||||||
```bash
|
- If no targets are provided, the default is `**/*` relative to the current working directory.
|
||||||
slinky run . --patterns "**/*"
|
- Legacy flags `--glob` and `--patterns` are still supported, but positional targets are preferred.
|
||||||
```
|
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
|
|||||||
68
cmd/check.go
68
cmd/check.go
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -29,24 +30,31 @@ type SerializableResult struct {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
checkCmd := &cobra.Command{
|
checkCmd := &cobra.Command{
|
||||||
Use: "check [path]",
|
Use: "check [targets...]",
|
||||||
Short: "Scan a directory for URLs and validate them (headless)",
|
Short: "Scan for URLs and validate them (headless)",
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.ArbitraryArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
path := "."
|
path := "."
|
||||||
if len(args) == 1 {
|
|
||||||
path = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
var gl []string
|
var gl []string
|
||||||
if len(patterns) > 0 {
|
if len(args) > 0 {
|
||||||
gl = append(gl, patterns...)
|
for _, a := range args {
|
||||||
} else if globPat != "" {
|
for _, part := range strings.Split(a, ",") {
|
||||||
gl = strings.Split(globPat, ",")
|
p := strings.TrimSpace(part)
|
||||||
|
if p != "" {
|
||||||
|
gl = append(gl, toSlash(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gl = []string{"**/*"}
|
gl = []string{"**/*"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gl = expandDirectories(path, gl)
|
||||||
|
|
||||||
|
// Emit normalized patterns for debugging
|
||||||
|
fmt.Printf("::debug:: Effective patterns: %s\n", strings.Join(gl, ","))
|
||||||
|
|
||||||
timeout := time.Duration(timeoutSeconds) * time.Second
|
timeout := time.Duration(timeoutSeconds) * time.Second
|
||||||
cfg := web.Config{MaxConcurrency: maxConcurrency, RequestTimeout: timeout}
|
cfg := web.Config{MaxConcurrency: maxConcurrency, RequestTimeout: timeout}
|
||||||
|
|
||||||
@@ -149,8 +157,6 @@ func init() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
checkCmd.Flags().StringVar(&globPat, "glob", "", "comma-separated glob patterns for files (doublestar); empty = all files")
|
|
||||||
checkCmd.Flags().StringSliceVar(&patterns, "patterns", nil, "file match patterns (doublestar). Examples: docs/**/*.md,**/*.go; defaults to **/*")
|
|
||||||
checkCmd.Flags().IntVar(&maxConcurrency, "concurrency", 16, "maximum concurrent requests")
|
checkCmd.Flags().IntVar(&maxConcurrency, "concurrency", 16, "maximum concurrent requests")
|
||||||
checkCmd.Flags().StringVar(&jsonOut, "json-out", "", "path to write full JSON results (array)")
|
checkCmd.Flags().StringVar(&jsonOut, "json-out", "", "path to write full JSON results (array)")
|
||||||
checkCmd.Flags().StringVar(&mdOut, "md-out", "", "path to write Markdown report for PR comment")
|
checkCmd.Flags().StringVar(&mdOut, "md-out", "", "path to write Markdown report for PR comment")
|
||||||
@@ -165,7 +171,43 @@ func init() {
|
|||||||
var (
|
var (
|
||||||
timeoutSeconds int
|
timeoutSeconds int
|
||||||
failOnFailures bool
|
failOnFailures bool
|
||||||
patterns []string
|
|
||||||
repoBlobBase string
|
repoBlobBase string
|
||||||
respectGitignore bool
|
respectGitignore bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func toSlash(p string) string {
|
||||||
|
p = strings.TrimSpace(p)
|
||||||
|
if p == "" {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p = filepath.ToSlash(p)
|
||||||
|
if after, ok := strings.CutPrefix(p, "./"); ok {
|
||||||
|
p = after
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasGlobMeta(s string) bool {
|
||||||
|
return strings.ContainsAny(s, "*?[")
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandDirectories(root string, pats []string) []string {
|
||||||
|
var out []string
|
||||||
|
for _, p := range pats {
|
||||||
|
pp := strings.TrimSpace(p)
|
||||||
|
if pp == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if hasGlobMeta(pp) {
|
||||||
|
out = append(out, pp)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
abs := filepath.Join(root, filepath.FromSlash(pp))
|
||||||
|
if fi, err := os.Stat(abs); err == nil && fi.IsDir() {
|
||||||
|
out = append(out, strings.TrimSuffix(pp, "/")+"/**/*")
|
||||||
|
} else {
|
||||||
|
out = append(out, pp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
26
cmd/run.go
26
cmd/run.go
@@ -11,29 +11,28 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runCmd := &cobra.Command{
|
runCmd := &cobra.Command{
|
||||||
Use: "run [path]",
|
Use: "run [targets...]",
|
||||||
Short: "Scan a directory/repo for URLs in files and validate them (TUI)",
|
Short: "Scan a directory/repo for URLs in files and validate them (TUI)",
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.ArbitraryArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
path := "."
|
|
||||||
if len(args) == 1 {
|
|
||||||
path = args[0]
|
|
||||||
}
|
|
||||||
cfg := web.Config{MaxConcurrency: maxConcurrency}
|
cfg := web.Config{MaxConcurrency: maxConcurrency}
|
||||||
var gl []string
|
var gl []string
|
||||||
if len(patterns) > 0 {
|
if len(args) > 0 {
|
||||||
gl = append(gl, patterns...)
|
for _, a := range args {
|
||||||
} else if globPat != "" {
|
for _, part := range strings.Split(a, ",") {
|
||||||
gl = strings.Split(globPat, ",")
|
p := strings.TrimSpace(part)
|
||||||
|
if p != "" {
|
||||||
|
gl = append(gl, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gl = []string{"**/*"}
|
gl = []string{"**/*"}
|
||||||
}
|
}
|
||||||
return tui.Run(path, gl, cfg, jsonOut, mdOut)
|
return tui.Run(".", gl, cfg, jsonOut, mdOut)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runCmd.Flags().StringVar(&globPat, "glob", "", "comma-separated glob patterns for files (doublestar); empty = all files")
|
|
||||||
runCmd.Flags().StringSliceVar(&patterns, "patterns", nil, "file match patterns (doublestar). Examples: docs/**/*.md,**/*.go; defaults to **/*")
|
|
||||||
runCmd.Flags().IntVar(&maxConcurrency, "concurrency", 16, "maximum concurrent requests")
|
runCmd.Flags().IntVar(&maxConcurrency, "concurrency", 16, "maximum concurrent requests")
|
||||||
runCmd.Flags().StringVar(&jsonOut, "json-out", "", "path to write full JSON results (array)")
|
runCmd.Flags().StringVar(&jsonOut, "json-out", "", "path to write full JSON results (array)")
|
||||||
runCmd.Flags().StringVar(&mdOut, "md-out", "", "path to write Markdown report for PR comment")
|
runCmd.Flags().StringVar(&mdOut, "md-out", "", "path to write Markdown report for PR comment")
|
||||||
@@ -44,6 +43,5 @@ func init() {
|
|||||||
var (
|
var (
|
||||||
maxConcurrency int
|
maxConcurrency int
|
||||||
jsonOut string
|
jsonOut string
|
||||||
globPat string
|
|
||||||
mdOut string
|
mdOut string
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ COMMENT_PR_ARG="${INPUT_COMMENT_PR:-true}"
|
|||||||
STEP_SUMMARY_ARG="${INPUT_STEP_SUMMARY:-true}"
|
STEP_SUMMARY_ARG="${INPUT_STEP_SUMMARY:-true}"
|
||||||
|
|
||||||
# Build argv safely
|
# Build argv safely
|
||||||
set -- check "$PATH_ARG" --concurrency "$CONCURRENCY_ARG" --timeout "$TIMEOUT_ARG"
|
set -- check --concurrency "$CONCURRENCY_ARG" --timeout "$TIMEOUT_ARG"
|
||||||
if [ "${FAIL_ON_FAILURES_ARG}" = "true" ]; then
|
if [ "${FAIL_ON_FAILURES_ARG}" = "true" ]; then
|
||||||
set -- "$@" --fail-on-failures=true
|
set -- "$@" --fail-on-failures=true
|
||||||
else
|
else
|
||||||
@@ -22,12 +22,9 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${PATTERNS_ARG}" ]; then
|
if [ -n "${PATTERNS_ARG}" ]; then
|
||||||
NORM_PATTERNS=$(printf "%s" "${PATTERNS_ARG}" | sed 's/,[[:space:]]*/,/g')
|
set -- "$@" "$PATTERNS_ARG"
|
||||||
IFS=','
|
else
|
||||||
for pat in $NORM_PATTERNS; do
|
set -- "$@" "**/*"
|
||||||
set -- "$@" --patterns "$pat"
|
|
||||||
done
|
|
||||||
unset IFS
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${JSON_OUT_ARG}" ]; then
|
if [ -n "${JSON_OUT_ARG}" ]; then
|
||||||
@@ -60,8 +57,9 @@ fi
|
|||||||
|
|
||||||
# Emit consolidated config at start (visible with ACTIONS_STEP_DEBUG=true)
|
# Emit consolidated config at start (visible with ACTIONS_STEP_DEBUG=true)
|
||||||
EFFECTIVE_REPO_BLOB_BASE="${SLINKY_REPO_BLOB_BASE_URL:-$REPO_BLOB_BASE_ARG}"
|
EFFECTIVE_REPO_BLOB_BASE="${SLINKY_REPO_BLOB_BASE_URL:-$REPO_BLOB_BASE_ARG}"
|
||||||
printf "::debug:: Config: path=%s patterns=%s concurrency=%s timeout=%s respect_gitignore=%s json_out=%s md_out=%s fail_on_failures=%s comment_pr=%s step_summary=%s repo_blob_base_url=%s\n" \
|
TARGETS_DEBUG="${PATTERNS_ARG:-**/*}"
|
||||||
"$PATH_ARG" "$PATTERNS_ARG" "$CONCURRENCY_ARG" "$TIMEOUT_ARG" "$RESPECT_GITIGNORE_ARG" "$JSON_OUT_ARG" "$MD_OUT_ARG" \
|
printf "::debug:: Config: targets=%s concurrency=%s timeout=%s respect_gitignore=%s json_out=%s md_out=%s fail_on_failures=%s comment_pr=%s step_summary=%s repo_blob_base_url=%s\n" \
|
||||||
|
"$TARGETS_DEBUG" "$CONCURRENCY_ARG" "$TIMEOUT_ARG" "$RESPECT_GITIGNORE_ARG" "$JSON_OUT_ARG" "$MD_OUT_ARG" \
|
||||||
"$FAIL_ON_FAILURES_ARG" "$COMMENT_PR_ARG" "$STEP_SUMMARY_ARG" "$EFFECTIVE_REPO_BLOB_BASE"
|
"$FAIL_ON_FAILURES_ARG" "$COMMENT_PR_ARG" "$STEP_SUMMARY_ARG" "$EFFECTIVE_REPO_BLOB_BASE"
|
||||||
printf "::debug:: CLI Args: slinky %s\n" "$*"
|
printf "::debug:: CLI Args: slinky %s\n" "$*"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user