diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 4f4a69a3e5..3be5ab9acd 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2241,7 +2241,7 @@ jobs: path: /tmp/gh-aw/aw_info.json if-no-files-found: warn - name: Run AI Inference - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v1 + uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 env: GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 8433f151f1..ce61da11ec 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6056,13 +6056,13 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.10 + uses: anchore/sbom-action@43a17d6e7add2b5535efe4dcae9952337c479a93 # v0.20.11 with: artifact-name: sbom.cdx.json format: cyclonedx-json @@ -6261,7 +6261,7 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Release with gh-extension-precompile - uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2 + uses: cli/gh-extension-precompile@9e2237c30f869ad3bcaed6a4be2cd43564dd421b # v2.1.0 with: build_script_override: scripts/build-release.sh go_version_file: go.mod diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index a8cd91dcd0..21caadf429 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -176,7 +176,7 @@ jobs: ORGANIZATION: ${{ env.ORGANIZATION }} id: stale-repos name: Run stale_repos tool - uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3 + uses: github/stale-repos@a21e55567b83cf3c3f3f9085d3038dc6cee02598 # v3.0.2 - env: INACTIVE_REPOS: ${{ steps.stale-repos.outputs.inactiveRepos }} name: Save stale repos output diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index b15660af2f..4c2fde522c 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -6189,7 +6189,7 @@ jobs: persist-credentials: false - name: Super-linter id: super-linter - uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.2.1 + uses: super-linter/super-linter@47984f49b4e87383eed97890fe2dca6063bbd9c3 # v8.3.1 env: CREATE_LOG_FILE: "true" DEFAULT_BRANCH: main diff --git a/.golangci.yml b/.golangci.yml index bc93761e5a..b8491947da 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,6 +5,11 @@ linters: enable: - misspell - revive + - modernize # Modern Go patterns (NEW in v2.6.0) + - gocritic # Comprehensive opinionated linter + - gosec # Security-focused + # godot linter disabled - too pedantic about comment punctuation + - unconvert # Remove unnecessary conversions settings: errcheck: exclude-functions: @@ -17,6 +22,24 @@ linters: - os.Remove - os.RemoveAll - os.WriteFile + gocritic: + disabled-checks: + - ifElseChain # else-if chains are often clearer than switches + - singleCaseSwitch # Single case switches can be intentional for consistency + - appendAssign # Appending to different variable is often intentional + - unlambda # Explicit lambdas can be clearer than direct function refs + - elseif # else-if pattern is acceptable + - assignOp # Long form assignment can be clearer + - argOrder # False positives on string contains + - dupBranchBody # Duplicate branches can be intentional for clarity + gosec: + excludes: + - G101 # Ignore "Potential hardcoded credentials" - often false positives + - G602 # Ignore "slice bounds check" - handled by runtime + - G115 # Ignore "integer overflow conversion" - acceptable in most cases + config: + G204: "0644" # Allow common file permissions in tests + G306: "0644" # Allow common file permissions exclusions: generated: lax presets: @@ -46,6 +69,130 @@ linters: - linters: - revive text: exported + - linters: + - gosec + text: "G204" # Allow exec.Command in controlled contexts + path: pkg/awmg/gateway\.go + - linters: + - gosec + text: "G204" # Allow docker commands in actionlint + path: pkg/cli/actionlint\.go + - linters: + - gosec + text: "G204" # Allow git commands in remote_fetch + path: pkg/parser/remote_fetch\.go + - linters: + - gosec + text: "G404" # Allow math/rand for non-crypto purposes + path: pkg/cli/(add_command|update_git)\.go + - linters: + - gosec + text: "G306" # Allow 0644 permissions in test files + path: _test\.go + - linters: + - gosec + text: "G305" # Allow file path operations in logs_download + path: pkg/cli/logs_download\.go + - linters: + - gosec + text: "G110" # Allow decompression in logs_download + path: pkg/cli/logs_download\.go + - linters: + - gocritic + text: "deprecatedComment" # Allow existing deprecated comment format + - linters: + - gocritic + text: "commentFormatting" # Allow commented out code + - linters: + - gocritic + text: "badCall" # filepath.Join with 1 arg is acceptable + - linters: + - godot + path: _test\.go # Don't require periods in test comments + - linters: + - modernize + text: "omitzero" # omitzero is acceptable for struct tags + - linters: + - modernize + text: "mapsloop" # maps.Copy requires Go 1.21+, keep compatible + - linters: + - modernize + text: "bloop" # b.Loop() is new, keep compatible with older Go + - linters: + - modernize + text: "minmax" # min/max builtins are Go 1.21+, keep compatible + - linters: + - modernize + text: "forvar" # Copying loop variable is sometimes clearer + - linters: + - modernize + text: "plusbuild" # Keep build constraint for compatibility + path: shell_backslash_integration_test\.go + - linters: + - modernize + text: "any" # Keep interface{} for clarity in schema tests + path: schema_strict_documentation_test\.go + - linters: + - modernize + text: "any" # Keep interface{} for clarity in tests + path: logs_awinfo_backward_compat_test\.go + - linters: + - modernize + text: "rangeint" # Keep traditional loops for compatibility + - linters: + - modernize + text: "stringsseq" # SplitSeq requires Go 1.23+, keep compatible + - linters: + - modernize + text: "slicescontains" # slices.Contains requires Go 1.21+ + - linters: + - modernize + text: "stringscutprefix" # strings.Cut* requires Go 1.20+ + - linters: + - modernize + text: "stringsbuilder" # Minor optimization, acceptable pattern + - linters: + - modernize + text: "reflecttypefor" # TypeFor requires Go 1.22+ + - linters: + - unconvert + path: _test\.go # Allow explicit conversions in tests for clarity + - linters: + - gosec + text: "G204" # Allow git commands in download_workflow + path: pkg/cli/download_workflow\.go + - linters: + - gosec + text: "G204" # Allow exec.Command with config in mcp_inspect + path: pkg/cli/mcp_inspect\.go + - linters: + - gosec + text: "G204" # Allow exec.Command with config in mcp_inspect_mcp + path: pkg/cli/mcp_inspect_mcp\.go + - linters: + - gosec + text: "G306" # 0755 is correct permission for executable script + path: pkg/cli/mcp_inspect\.go + - linters: + - gosec + text: "G204" # Allow docker commands in poutine + path: pkg/cli/poutine\.go + - linters: + - gosec + text: "G204" # Allow node command in tests + path: pkg/workflow/js_comments_test\.go + - linters: + - gosec + text: "G204" # Allow npx command in integration tests + path: pkg/workflow/playwright_mcp_integration_test\.go + - linters: + - gosec + text: "G204" # Allow exec of binary in status tests + path: pkg/cli/status_command_test\.go + - linters: + - gosec + text: "G204" # Allow docker commands in zizmor + path: pkg/cli/zizmor\.go paths: - third_party$ - builtin$ diff --git a/cmd/awmg/main.go b/cmd/awmg/main.go index d05ca54fc7..17dd54741c 100644 --- a/cmd/awmg/main.go +++ b/cmd/awmg/main.go @@ -8,7 +8,7 @@ import ( "github.com/githubnext/gh-aw/pkg/console" ) -// Build-time variables +// Build-time variables. var ( version = "dev" ) diff --git a/pkg/awmg/gateway.go b/pkg/awmg/gateway.go index 7a7528ba78..567ccfca4f 100644 --- a/pkg/awmg/gateway.go +++ b/pkg/awmg/gateway.go @@ -20,26 +20,26 @@ import ( var gatewayLog = logger.New("awmg:gateway") -// version is set by the main package +// version is set by the main package. var version = "dev" -// SetVersionInfo sets the version information for the awmg package +// SetVersionInfo sets the version information for the awmg package. func SetVersionInfo(v string) { version = v } -// GetVersion returns the current version +// GetVersion returns the current version. func GetVersion() string { return version } -// MCPGatewayConfig represents the configuration for the MCP gateway +// MCPGatewayConfig represents the configuration for the MCP gateway. type MCPGatewayConfig struct { MCPServers map[string]MCPServerConfig `json:"mcpServers"` Gateway GatewaySettings `json:"gateway,omitempty"` } -// MCPServerConfig represents configuration for a single MCP server +// MCPServerConfig represents configuration for a single MCP server. type MCPServerConfig struct { Command string `json:"command,omitempty"` Args []string `json:"args,omitempty"` @@ -48,7 +48,7 @@ type MCPServerConfig struct { Container string `json:"container,omitempty"` } -// GatewaySettings represents gateway-specific settings +// GatewaySettings represents gateway-specific settings. type GatewaySettings struct { Port int `json:"port,omitempty"` APIKey string `json:"apiKey,omitempty"` diff --git a/pkg/campaign/template.go b/pkg/campaign/template.go index cbf38bb8d4..f9695e04e1 100644 --- a/pkg/campaign/template.go +++ b/pkg/campaign/template.go @@ -20,7 +20,7 @@ var projectUpdateInstructionsTemplate string //go:embed prompts/closing_instructions.md var closingInstructionsTemplate string -// CampaignPromptData holds data for rendering campaign orchestrator prompts +// CampaignPromptData holds data for rendering campaign orchestrator prompts. type CampaignPromptData struct { // ProjectURL is the GitHub Project URL ProjectURL string @@ -38,7 +38,7 @@ type CampaignPromptData struct { MaxDiscoveryPagesPerRun int } -// renderTemplate renders a template string with the given data +// renderTemplate renders a template string with the given data. func renderTemplate(tmplStr string, data CampaignPromptData) (string, error) { // Create custom template functions for Handlebars-style conditionals funcMap := template.FuncMap{ @@ -66,7 +66,7 @@ func renderTemplate(tmplStr string, data CampaignPromptData) (string, error) { return buf.String(), nil } -// RenderOrchestratorInstructions renders the orchestrator instructions with the given data +// RenderOrchestratorInstructions renders the orchestrator instructions with the given data. func RenderOrchestratorInstructions(data CampaignPromptData) string { result, err := renderTemplate(orchestratorInstructionsTemplate, data) if err != nil { diff --git a/pkg/cli/fileutil/fileutil.go b/pkg/cli/fileutil/fileutil.go index 2da7cebeb6..f66b145070 100644 --- a/pkg/cli/fileutil/fileutil.go +++ b/pkg/cli/fileutil/fileutil.go @@ -6,7 +6,7 @@ import ( "path/filepath" ) -// FileExists checks if a file exists and is not a directory +// FileExists checks if a file exists and is not a directory. func FileExists(path string) bool { info, err := os.Stat(path) if err != nil { @@ -15,7 +15,7 @@ func FileExists(path string) bool { return !info.IsDir() } -// DirExists checks if a directory exists +// DirExists checks if a directory exists. func DirExists(path string) bool { info, err := os.Stat(path) if os.IsNotExist(err) { @@ -24,7 +24,7 @@ func DirExists(path string) bool { return info.IsDir() } -// IsDirEmpty checks if a directory is empty +// IsDirEmpty checks if a directory is empty. func IsDirEmpty(path string) bool { files, err := os.ReadDir(path) if err != nil { @@ -33,7 +33,7 @@ func IsDirEmpty(path string) bool { return len(files) == 0 } -// CopyFile copies a file from src to dst using buffered IO +// CopyFile copies a file from src to dst using buffered IO. func CopyFile(src, dst string) error { in, err := os.Open(src) if err != nil { @@ -53,7 +53,7 @@ func CopyFile(src, dst string) error { return out.Sync() } -// CalculateDirectorySize recursively calculates the total size of files in a directory +// CalculateDirectorySize recursively calculates the total size of files in a directory. func CalculateDirectorySize(dirPath string) int64 { var totalSize int64 diff --git a/pkg/cli/templates/github-agentic-workflows.md b/pkg/cli/templates/github-agentic-workflows.md index f04794f4a9..30ddce78ae 100644 --- a/pkg/cli/templates/github-agentic-workflows.md +++ b/pkg/cli/templates/github-agentic-workflows.md @@ -454,6 +454,19 @@ The YAML frontmatter supports these fields: if-no-changes: "warn" # Optional: "warn" (default), "error", or "ignore" ``` Not supported for cross-repository operations. + - `update-discussion:` - Update discussion title, body, or labels + ```yaml + safe-outputs: + update-discussion: + title: true # Optional: enable title updates + body: true # Optional: enable body updates + labels: true # Optional: enable label updates + allowed-labels: [status, type] # Optional: restrict to specific labels + max: 1 # Optional: max updates (default: 1) + target: "*" # Optional: "triggering" (default), "*", or number + target-repo: "owner/repo" # Optional: cross-repository + ``` + When using `safe-outputs.update-discussion`, the main job does **not** need `discussions: write` permission since updates are handled by a separate job with appropriate permissions. - `update-release:` - Update GitHub release descriptions ```yaml safe-outputs: @@ -463,6 +476,17 @@ The YAML frontmatter supports these fields: github-token: ${{ secrets.CUSTOM_TOKEN }} # Optional: custom token ``` Operation types: `replace`, `append`, `prepend`. + - `upload-asset:` - Publish files to orphaned git branch + ```yaml + safe-outputs: + upload-asset: + branch: "assets/${{ github.workflow }}" # Optional: branch name + max-size: 10240 # Optional: max file size in KB (default: 10MB) + allowed-exts: [.png, .jpg, .pdf] # Optional: allowed file extensions + max: 10 # Optional: max assets (default: 10) + target-repo: "owner/repo" # Optional: cross-repository + ``` + Publishes workflow artifacts to an orphaned git branch for persistent storage. Default allowed extensions include common non-executable types. Maximum file size is 50MB (51200 KB). - `create-code-scanning-alert:` - Generate SARIF security advisories ```yaml safe-outputs: @@ -486,6 +510,28 @@ The YAML frontmatter supports these fields: target-repo: "owner/repo" # Optional: cross-repository ``` Requires PAT with elevated permissions as `GH_AW_AGENT_TOKEN`. + - `assign-to-user:` - Assign users to issues or pull requests + ```yaml + safe-outputs: + assign-to-user: + assignees: [user1, user2] # Optional: restrict to specific users + max: 3 # Optional: max assignments (default: 3) + target: "*" # Optional: "triggering" (default), "*", or number + target-repo: "owner/repo" # Optional: cross-repository + ``` + When using `safe-outputs.assign-to-user`, the main job does **not** need `issues: write` or `pull-requests: write` permission since user assignment is handled by a separate job with appropriate permissions. + - `hide-comment:` - Hide comments on issues, PRs, or discussions + ```yaml + safe-outputs: + hide-comment: + max: 5 # Optional: max comments to hide (default: 5) + allowed-reasons: # Optional: restrict hide reasons + - spam + - outdated + - resolved + target-repo: "owner/repo" # Optional: cross-repository + ``` + Allowed reasons: `spam`, `abuse`, `off_topic`, `outdated`, `resolved`. When using `safe-outputs.hide-comment`, the main job does **not** need write permissions since comment hiding is handled by a separate job. - `noop:` - Log completion message for transparency (auto-enabled) ```yaml safe-outputs: diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 1c688aa2be..63b4d194fb 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -5,7 +5,7 @@ import ( "time" ) -// CLIExtensionPrefix is the prefix used in user-facing output to refer to the CLI extension +// CLIExtensionPrefix is the prefix used in user-facing output to refer to the CLI extension. const CLIExtensionPrefix = "gh aw" // Semantic types for measurements and identifiers @@ -44,23 +44,24 @@ type LineLength int // func InstallTool(name string, version Version) error { ... } type Version string -// FeatureFlag represents a feature flag identifier +// FeatureFlag represents a feature flag identifier. type FeatureFlag string -// MaxExpressionLineLength is the maximum length for a single line expression before breaking into multiline +// MaxExpressionLineLength is the maximum length for a single line expression before breaking into multiline. const MaxExpressionLineLength LineLength = 120 -// ExpressionBreakThreshold is the threshold for breaking long lines at logical points +// ExpressionBreakThreshold is the threshold for breaking long lines at logical points. const ExpressionBreakThreshold LineLength = 100 -// DefaultMCPRegistryURL is the default MCP registry URL +// DefaultMCPRegistryURL is the default MCP registry URL. const DefaultMCPRegistryURL = "https://api.mcp.github.com/v0" -// DefaultClaudeCodeVersion is the default version of the Claude Code CLI +// DefaultClaudeCodeVersion is the default version of the Claude Code CLI. const DefaultClaudeCodeVersion Version = "2.0.75" -// DefaultCopilotVersion is the default version of the GitHub Copilot CLI -// WARNING: UPGRADING COPILOT CLI REQUIRES A FULL INTEGRATION TEST RUN TO ENSURE COMPATIBILITY +// DefaultCopilotVersion is the default version of the GitHub Copilot CLI. +// +// WARNING: UPGRADING COPILOT CLI REQUIRES A FULL INTEGRATION TEST RUN TO ENSURE COMPATIBILITY. const DefaultCopilotVersion Version = "0.0.372" // DefaultCopilotDetectionModel is the default model for the Copilot engine when used in the detection job diff --git a/pkg/gitutil/gitutil.go b/pkg/gitutil/gitutil.go index 64df98ef2c..1224f321cd 100644 --- a/pkg/gitutil/gitutil.go +++ b/pkg/gitutil/gitutil.go @@ -2,8 +2,8 @@ package gitutil import "strings" -// IsAuthError checks if an error message indicates an authentication issue -// This is used to detect when GitHub API calls fail due to missing or invalid credentials +// IsAuthError checks if an error message indicates an authentication issue. +// This is used to detect when GitHub API calls fail due to missing or invalid credentials. func IsAuthError(errMsg string) bool { lowerMsg := strings.ToLower(errMsg) return strings.Contains(lowerMsg, "gh_token") || @@ -15,8 +15,8 @@ func IsAuthError(errMsg string) bool { strings.Contains(lowerMsg, "permission denied") } -// IsHexString checks if a string contains only hexadecimal characters -// This is used to validate Git commit SHAs and other hexadecimal identifiers +// IsHexString checks if a string contains only hexadecimal characters. +// This is used to validate Git commit SHAs and other hexadecimal identifiers. func IsHexString(s string) bool { if len(s) == 0 { return false diff --git a/pkg/logger/error_formatting.go b/pkg/logger/error_formatting.go index 9d77f6c9f3..6ba2d55086 100644 --- a/pkg/logger/error_formatting.go +++ b/pkg/logger/error_formatting.go @@ -5,19 +5,19 @@ import ( "strings" ) -// Pre-compiled regexes for performance (avoid recompiling in hot paths) +// Pre-compiled regexes for performance (avoid recompiling in hot paths). var ( // Timestamp patterns for log cleanup - // Pattern 1: ISO 8601 with T or space separator (e.g., "2024-01-01T12:00:00.123Z " or "2024-01-01 12:00:00 ") + // Pattern 1: ISO 8601 with T or space separator (e.g., "2024-01-01T12:00:00.123Z " or "2024-01-01 12:00:00 "). timestampPattern1 = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:\d{2}|Z)?\s*`) - // Pattern 2: Bracketed date-time (e.g., "[2024-01-01 12:00:00] ") + // Pattern 2: Bracketed date-time (e.g., "[2024-01-01 12:00:00] "). timestampPattern2 = regexp.MustCompile(`^\[\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\]\s*`) - // Pattern 3: Bracketed time only (e.g., "[12:00:00] ") + // Pattern 3: Bracketed time only (e.g., "[12:00:00] "). timestampPattern3 = regexp.MustCompile(`^\[\d{2}:\d{2}:\d{2}\]\s+`) - // Pattern 4: Time only with optional milliseconds (e.g., "12:00:00.123 ") + // Pattern 4: Time only with optional milliseconds (e.g., "12:00:00.123 "). timestampPattern4 = regexp.MustCompile(`^\d{2}:\d{2}:\d{2}(\.\d+)?\s+`) - // Log level pattern for message cleanup (case-insensitive) + // Log level pattern for message cleanup (case-insensitive). logLevelPattern = regexp.MustCompile(`(?i)^\[?(ERROR|WARNING|WARN|INFO|DEBUG)\]?\s*[:-]?\s*`) ) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 5eaf7616cf..9d3dac7504 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -12,7 +12,7 @@ import ( "github.com/githubnext/gh-aw/pkg/tty" ) -// Logger represents a debug logger for a specific namespace +// Logger represents a debug logger for a specific namespace. type Logger struct { namespace string enabled bool @@ -22,17 +22,17 @@ type Logger struct { } var ( - // DEBUG environment variable value, read once at initialization + // DEBUG environment variable value, read once at initialization. debugEnv = os.Getenv("DEBUG") - // DEBUG_COLORS environment variable to control color output + // DEBUG_COLORS environment variable to control color output. debugColors = os.Getenv("DEBUG_COLORS") != "0" - // Check if stderr is a terminal (for color support) + // Check if stderr is a terminal (for color support). isTTY = tty.IsStderrTerminal() - // Color palette - chosen to be readable on both light and dark backgrounds - // Using ANSI 256-color codes for better compatibility + // Color palette - chosen to be readable on both light and dark backgrounds. + // Using ANSI 256-color codes for better compatibility. colorPalette = []string{ "\033[38;5;33m", // Blue "\033[38;5;35m", // Green @@ -72,7 +72,7 @@ func New(namespace string) *Logger { } } -// selectColor selects a color for the namespace based on its hash +// selectColor selects a color for the namespace based on its hash. func selectColor(namespace string) string { if !debugColors || !isTTY { return "" diff --git a/pkg/parser/ansi_strip.go b/pkg/parser/ansi_strip.go index 19906627c6..b697213be8 100644 --- a/pkg/parser/ansi_strip.go +++ b/pkg/parser/ansi_strip.go @@ -8,7 +8,7 @@ import ( var ansiStripLog = logger.New("parser:ansi_strip") -// StripANSI removes ANSI escape codes from a string +// StripANSI removes ANSI escape codes from a string. func StripANSI(s string) string { if ansiStripLog.Enabled() { ansiStripLog.Printf("Stripping ANSI codes from string: length=%d", len(s)) diff --git a/pkg/styles/theme.go b/pkg/styles/theme.go index 934e1d298f..fd29bdf546 100644 --- a/pkg/styles/theme.go +++ b/pkg/styles/theme.go @@ -9,19 +9,19 @@ import "github.com/charmbracelet/lipgloss" // Light variants use darker, more saturated colors for visibility on light backgrounds. // Dark variants use brighter colors (Dracula theme inspired) for dark backgrounds. var ( - // ColorError is used for error messages and critical issues + // ColorError is used for error messages and critical issues. ColorError = lipgloss.AdaptiveColor{ Light: "#D73737", // Darker red for light backgrounds Dark: "#FF5555", // Bright red for dark backgrounds (Dracula) } - // ColorWarning is used for warning messages and cautionary information + // ColorWarning is used for warning messages and cautionary information. ColorWarning = lipgloss.AdaptiveColor{ Light: "#E67E22", // Darker orange for light backgrounds Dark: "#FFB86C", // Bright orange for dark backgrounds (Dracula) } - // ColorSuccess is used for success messages and confirmations + // ColorSuccess is used for success messages and confirmations. ColorSuccess = lipgloss.AdaptiveColor{ Light: "#27AE60", // Darker green for light backgrounds Dark: "#50FA7B", // Bright green for dark backgrounds (Dracula) diff --git a/pkg/timeutil/format.go b/pkg/timeutil/format.go index ce4c40dc05..f8f1314f9e 100644 --- a/pkg/timeutil/format.go +++ b/pkg/timeutil/format.go @@ -5,8 +5,8 @@ import ( "time" ) -// FormatDuration formats a duration for display like the debug npm package -// It provides granular formatting from nanoseconds to hours +// FormatDuration formats a duration for display like the debug npm package. +// It provides granular formatting from nanoseconds to hours. func FormatDuration(d time.Duration) string { if d < time.Microsecond { return fmt.Sprintf("%dns", d.Nanoseconds()) diff --git a/pkg/tty/tty.go b/pkg/tty/tty.go index 2be043d87d..fd14fc4b05 100644 --- a/pkg/tty/tty.go +++ b/pkg/tty/tty.go @@ -9,12 +9,12 @@ import ( "golang.org/x/term" ) -// IsStdoutTerminal returns true if stdout is connected to a terminal +// IsStdoutTerminal returns true if stdout is connected to a terminal. func IsStdoutTerminal() bool { return term.IsTerminal(int(os.Stdout.Fd())) } -// IsStderrTerminal returns true if stderr is connected to a terminal +// IsStderrTerminal returns true if stderr is connected to a terminal. func IsStderrTerminal() bool { return term.IsTerminal(int(os.Stderr.Fd())) } diff --git a/pkg/workflow/action_cache.go b/pkg/workflow/action_cache.go index 42df57f22d..9cdfee7c8e 100644 --- a/pkg/workflow/action_cache.go +++ b/pkg/workflow/action_cache.go @@ -13,18 +13,18 @@ import ( var actionCacheLog = logger.New("workflow:action_cache") const ( - // CacheFileName is the name of the cache file in .github/aw/ + // CacheFileName is the name of the cache file in .github/aw/. CacheFileName = "actions-lock.json" ) -// ActionCacheEntry represents a cached action pin resolution +// ActionCacheEntry represents a cached action pin resolution. type ActionCacheEntry struct { Repo string `json:"repo"` Version string `json:"version"` SHA string `json:"sha"` } -// ActionCache manages cached action pin resolutions +// ActionCache manages cached action pin resolutions. type ActionCache struct { Entries map[string]ActionCacheEntry `json:"entries"` // key: "repo@version" path string diff --git a/scripts/lint_error_messages.go b/scripts/lint_error_messages.go index 8347929974..0a3f6a6e99 100644 --- a/scripts/lint_error_messages.go +++ b/scripts/lint_error_messages.go @@ -12,7 +12,7 @@ import ( "strings" ) -// QualityIssue represents a quality issue with an error message +// QualityIssue represents a quality issue with an error message. type QualityIssue struct { File string Line int @@ -20,7 +20,7 @@ type QualityIssue struct { Suggestion string } -// FileStats tracks statistics for a single file +// FileStats tracks statistics for a single file. type FileStats struct { Total int Compliant int @@ -28,17 +28,17 @@ type FileStats struct { } var ( - // Patterns to detect good error messages + // Patterns to detect good error messages. hasExample = regexp.MustCompile(`(?i)\bexample:\s`) hasExpected = regexp.MustCompile(`(?i)\b(expected|valid|must be|should be)\b`) - // Patterns for error types that MUST have examples + // Patterns for error types that MUST have examples. isValidationError = regexp.MustCompile(`(?i)\b(invalid|must|cannot|missing|required|unknown|duplicate|unsupported)\b`) isFormatError = regexp.MustCompile(`(?i)\bformat\b`) isTypeError = regexp.MustCompile(`(?i)\b(must be|got %T|expected type)\b`) isEnumError = regexp.MustCompile(`(?i)\b(valid (options|values|engines|modes|levels)|one of)\b`) - // Patterns for errors that can skip examples + // Patterns for errors that can skip examples. isWrappedError = regexp.MustCompile(`%w`) hasDocLink = regexp.MustCompile(`https?://`) )