← back to drape-io__drape-cli

Function bodies 75 total

All specs Real LLM only Function bodies
resolveFlag function · go · L9-L14 (6 LOC)
cmd/flags.go
func resolveFlag(flagVal, envKey string) string {
	if flagVal != "" {
		return flagVal
	}
	return os.Getenv(envKey)
}
errMissing function · go · L16-L18 (3 LOC)
cmd/flags.go
func errMissing(name string) error {
	return fmt.Errorf("required: %s", name)
}
init function · go · L36-L103 (68 LOC)
cmd/root.go
func init() {
	rootCmd.PersistentFlags().StringVar(&flagOrg, "org", "", "Organization slug (env: DRAPE_ORG)")
	rootCmd.PersistentFlags().StringVar(&flagRepo, "repo", "", "Repository name (env: DRAPE_REPO)")
	rootCmd.PersistentFlags().StringVar(&flagToken, "token", "", "API token (env: DRAPE_TOKEN)")
	rootCmd.PersistentFlags().StringVar(&flagAPIURL, "api-url", "", "API base URL (env: DRAPE_API_URL, default: https://app.drape.io)")
	rootCmd.PersistentFlags().BoolVar(&flagVerbose, "verbose", false, "Verbose logging")
	rootCmd.PersistentFlags().BoolVar(&flagDryRun, "dry-run", false, "Parse and validate locally, don't upload")
}

// Execute runs the root command and returns an exit code.
func Execute() int {
	if err := rootCmd.Execute(); err != nil {
		// Check if the error wraps an exit code
		if coded, ok := err.(*ExitError); ok {
			output.Error("%v", coded.Err)
			return coded.Code
		}
		output.Error("%v", err)
		if hint := enhanceCobraError(err); hint != "" {
			output.Error("%s", hint
Execute function · go · L46-L60 (15 LOC)
cmd/root.go
func Execute() int {
	if err := rootCmd.Execute(); err != nil {
		// Check if the error wraps an exit code
		if coded, ok := err.(*ExitError); ok {
			output.Error("%v", coded.Err)
			return coded.Code
		}
		output.Error("%v", err)
		if hint := enhanceCobraError(err); hint != "" {
			output.Error("%s", hint)
		}
		return exitcode.UsageError
	}
	return exitcode.Success
}
enhanceCobraError function · go · L66-L81 (16 LOC)
cmd/root.go
func enhanceCobraError(err error) string {
	msg := err.Error()

	if argsErrorRe.MatchString(msg) {
		return "hint: this often happens when a flag is passed twice (e.g. --branch used twice),\n" +
			"      causing the second occurrence to consume the next flag's value as its argument.\n" +
			"      Check your command for duplicate flags."
	}

	if strings.Contains(msg, "unknown flag") || strings.Contains(msg, "unknown shorthand flag") {
		// Extract the flag name for a better message
		return "hint: run the command with --help to see available flags."
	}

	return ""
}
Error method · go · L89-L91 (3 LOC)
cmd/root.go
func (e *ExitError) Error() string {
	return e.Err.Error()
}
resolveRepoID function · go · L113-L126 (14 LOC)
cmd/root.go
func resolveRepoID(client *api.Client, orgSlug string) (int, error) {
	repoName := resolveFlag(flagRepo, "DRAPE_REPO")
	if repoName == "" {
		return 0, &ExitError{Code: exitcode.UsageError, Err: errMissing("--repo or DRAPE_REPO")}
	}

	output.Verbose("Looking up repository %q in org %q...", repoName, orgSlug)
	repo, err := client.LookupRepo(orgSlug, repoName)
	if err != nil {
		return 0, &ExitError{Code: exitcode.UploadError, Err: err}
	}
	output.Verbose("Resolved repo %q to ID %d", repoName, repo.ID)
	return repo.ID, nil
}
Repobility — same analyzer, your code, free for public repos · /scan/
resolveOrg function · go · L128-L134 (7 LOC)
cmd/root.go
func resolveOrg() (string, error) {
	org := resolveFlag(flagOrg, "DRAPE_ORG")
	if org == "" {
		return "", &ExitError{Code: exitcode.UsageError, Err: errMissing("--org or DRAPE_ORG")}
	}
	return org, nil
}
init function · go · L39-L53 (15 LOC)
cmd/upload_coverage.go
func init() {
	uploadCoverageCmd.Flags().StringVar(&flagCovFormat, "format", "", "Coverage format: cobertura, lcov, go (required)")
	uploadCoverageCmd.Flags().StringVar(&flagCovPathPrefix, "path-prefix", "", "Path prefix mapping for repo structure")
	uploadCoverageCmd.Flags().StringVar(&flagCovBranch, "branch", "", "Git branch (auto-detected from CI)")
	uploadCoverageCmd.Flags().StringVar(&flagCovSHA, "sha", "", "Git commit SHA (auto-detected from CI)")
	uploadCoverageCmd.Flags().BoolVar(&flagCovWait, "wait", true, "Wait for server-side processing")
	uploadCoverageCmd.Flags().IntVar(&flagCovTimeout, "timeout", 120, "Max wait time in seconds")
	uploadCoverageCmd.Flags().StringVar(&flagCovTargetBranch, "target-branch", "", "Target branch for PR diff (auto-detected from CI)")
	uploadCoverageCmd.Flags().StringVar(&flagCovRunDate, "run-date", "", "ISO 8601 date for historical uploads (e.g. 2026-03-15)")
	uploadCoverageCmd.Flags().StringSliceVar(&flagCovGroups, "group", nil, "Group label(s) 
runUploadCoverage function · go · L55-L170 (116 LOC)
cmd/upload_coverage.go
func runUploadCoverage(cmd *cobra.Command, args []string) error {
	filePath := filepath.Clean(args[0])

	// Read file
	data, err := os.ReadFile(filePath) //nolint:gosec // G304: path is from CLI args, cleaned above
	if err != nil {
		return &ExitError{Code: exitcode.ParseError, Err: fmt.Errorf("reading file %s: %w", filePath, err)}
	}
	output.Info("Read %s (%d bytes)", filepath.Base(filePath), len(data))

	// Detect CI
	ci := cidetect.Detect(os.Getenv)
	if ci == nil {
		ci = cidetect.DetectFromGit()
	}

	branch := resolveGitContext(flagCovBranch, ci, func(info *cidetect.CIInfo) string { return info.Branch })
	sha := resolveGitContext(flagCovSHA, ci, func(info *cidetect.CIInfo) string { return info.CommitSHA })

	if branch == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--branch (could not auto-detect)")}
	}
	if sha == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--sha (could not auto-detect)")}
	}

	if flagDryRun {
		output.Info("[dry-run
printCoverageDiff function · go · L172-L228 (57 LOC)
cmd/upload_coverage.go
func printCoverageDiff(diff *api.CoverageDiffInfo, prNumber int) error {
	output.Info("")
	if prNumber > 0 {
		output.Info("Coverage Diff (PR #%d)", prNumber)
	} else {
		output.Info("Coverage Diff")
	}

	if diff.BaseCoverageRate != nil {
		output.Info("  Base:      %s%%", *diff.BaseCoverageRate)
	} else {
		output.Info("  Base:      (no baseline)")
	}

	if diff.CoverageDelta != nil {
		output.Info("  Head:      %s%%  (%s%%)", diff.HeadCoverageRate, formatDelta(*diff.CoverageDelta))
	} else {
		output.Info("  Head:      %s%%", diff.HeadCoverageRate)
	}

	if diff.NewCodeCoverageRate != nil {
		output.Info("  New code:  %s%%  (%d/%d lines)", *diff.NewCodeCoverageRate, diff.NewLinesCovered, diff.NewLinesTotal)
	} else if diff.NewLinesTotal > 0 {
		output.Info("  New code:  %d/%d lines", diff.NewLinesCovered, diff.NewLinesTotal)
	}

	output.Info("  Regressed: %d lines", diff.RegressedLinesCount)

	if len(diff.RegressedFiles) > 0 {
		output.Info("")
		output.Info("  Regressed files:")
		for
formatDelta function · go · L230-L238 (9 LOC)
cmd/upload_coverage.go
func formatDelta(delta string) string {
	if len(delta) == 0 {
		return delta
	}
	if delta[0] != '-' {
		return "+" + delta
	}
	return delta
}
formatLineRanges function · go · L240-L253 (14 LOC)
cmd/upload_coverage.go
func formatLineRanges(ranges [][]int) string {
	parts := make([]string, 0, len(ranges))
	for _, r := range ranges {
		if len(r) != 2 {
			continue
		}
		if r[0] == r[1] {
			parts = append(parts, strconv.Itoa(r[0]))
		} else {
			parts = append(parts, fmt.Sprintf("%d-%d", r[0], r[1]))
		}
	}
	return strings.Join(parts, ", ")
}
init function · go · L10-L12 (3 LOC)
cmd/upload.go
func init() {
	rootCmd.AddCommand(uploadCmd)
}
init function · go · L34-L42 (9 LOC)
cmd/upload_lint.go
func init() {
	uploadLintCmd.Flags().StringVar(&flagLintBranch, "branch", "", "Git branch (auto-detected from CI)")
	uploadLintCmd.Flags().StringVar(&flagLintSHA, "sha", "", "Git commit SHA (auto-detected from CI)")
	uploadLintCmd.Flags().StringVar(&flagLintFormat, "format", "sarif", "Lint report format (default: sarif)")
	uploadLintCmd.Flags().BoolVar(&flagLintWait, "wait", true, "Wait for server-side processing")
	uploadLintCmd.Flags().IntVar(&flagLintTimeout, "timeout", 120, "Max wait time in seconds")

	uploadCmd.AddCommand(uploadLintCmd)
}
Open data scored by Repobility · https://repobility.com
runUploadLint function · go · L44-L153 (110 LOC)
cmd/upload_lint.go
func runUploadLint(cmd *cobra.Command, args []string) error {
	filePath := filepath.Clean(args[0])

	data, err := os.ReadFile(filePath) //nolint:gosec // G304: path is from CLI args, cleaned above
	if err != nil {
		return &ExitError{Code: exitcode.ParseError, Err: fmt.Errorf("reading file %s: %w", filePath, err)}
	}
	output.Info("Read %s (%d bytes)", filepath.Base(filePath), len(data))

	ci := cidetect.Detect(os.Getenv)
	if ci == nil {
		ci = cidetect.DetectFromGit()
	}

	branch := resolveGitContext(flagLintBranch, ci, func(info *cidetect.CIInfo) string { return info.Branch })
	sha := resolveGitContext(flagLintSHA, ci, func(info *cidetect.CIInfo) string { return info.CommitSHA })

	if branch == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--branch (could not auto-detect)")}
	}
	if sha == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--sha (could not auto-detect)")}
	}

	if flagDryRun {
		output.Info("[dry-run] Would upload %s (format: %s,
printLintDiff function · go · L155-L199 (45 LOC)
cmd/upload_lint.go
func printLintDiff(diff *api.LintDiffInfo, prNumber int) error {
	output.Info("")
	if prNumber > 0 {
		output.Info("Lint Diff (PR #%d)", prNumber)
	} else {
		output.Info("Lint Diff")
	}

	output.Info("  Base violations: %d", diff.BaseViolationCount)
	output.Info("  Head violations: %d", diff.HeadViolationCount)
	output.Info("  New:             %d", diff.NewViolationCount)
	output.Info("  Resolved:        %d", diff.ResolvedViolationCount)
	if diff.SuppressedViolationCount > 0 {
		output.Info("  Suppressed:      %d", diff.SuppressedViolationCount)
	}

	if len(diff.NewViolations) > 0 {
		output.Info("")
		output.Info("  New violations:")
		for _, v := range diff.NewViolations {
			output.Info("    %s:%d [%s] %s: %s", v.FilePath, v.Line, v.Severity, v.RuleID, v.Message)
		}
	}

	if diff.Passed {
		output.Info("  Result:    PASSED")
		if diff.SuppressedViolationCount > 0 && diff.NewViolationCount == 0 {
			output.Info("")
			output.Info("All %d new violation(s) are suppressed — passing CI"
severityMeetsThreshold function · go · L44-L49 (6 LOC)
cmd/upload_scan.go
func severityMeetsThreshold(severity, threshold string) bool {
	if threshold == "any" {
		return true
	}
	return severityRank[severity] >= severityRank[threshold]
}
init function · go · L59-L72 (14 LOC)
cmd/upload_scan.go
func init() {
	uploadScanCmd.Flags().StringVar(&flagScanBranch, "branch", "", "Git branch (auto-detected from CI)")
	uploadScanCmd.Flags().StringVar(&flagScanSHA, "sha", "", "Git commit SHA (auto-detected from CI)")
	uploadScanCmd.Flags().StringVar(&flagScanFormat, "format", "sarif", "Scan report format: sarif, cyclonedx (default: sarif)")
	uploadScanCmd.Flags().StringVar(&flagScanName, "scan-name", "", "Scan name (e.g. docker image name, tool name)")
	uploadScanCmd.Flags().StringVar(&flagScanTag, "scan-tag", "", "Scan tag (e.g. image tag, version)")
	uploadScanCmd.Flags().StringVar(&flagScanType, "scan-type", "", "Scan type: image, dependency (default: auto-detect from format)")
	uploadScanCmd.Flags().BoolVar(&flagScanWait, "wait", true, "Wait for server-side processing")
	uploadScanCmd.Flags().IntVar(&flagScanTimeout, "timeout", 120, "Max wait time in seconds")
	uploadScanCmd.Flags().BoolVar(&flagScanFailOnVulns, "fail-on-vulnerabilities", false, "Exit non-zero if unsuppressed vulner
runUploadScan function · go · L74-L312 (239 LOC)
cmd/upload_scan.go
func runUploadScan(cmd *cobra.Command, args []string) error {
	// Validate --fail-on-severity value
	validSev := false
	for _, s := range validSeverities {
		if flagScanFailOnSeverity == s {
			validSev = true
			break
		}
	}
	if !validSev {
		return &ExitError{Code: exitcode.UsageError, Err: fmt.Errorf("invalid --fail-on-severity value %q, must be one of: critical, high, medium, low, any", flagScanFailOnSeverity)}
	}

	files, err := expandGlobs(args)
	if err != nil {
		return &ExitError{Code: exitcode.UsageError, Err: err}
	}
	if len(files) == 0 {
		return &ExitError{Code: exitcode.ParseError, Err: fmt.Errorf("no files matched the given pattern(s)")}
	}

	output.Info("Found %d file(s) to upload", len(files))

	ci := cidetect.Detect(os.Getenv)
	if ci == nil {
		ci = cidetect.DetectFromGit()
	}

	branch := resolveGitContext(flagScanBranch, ci, func(info *cidetect.CIInfo) string { return info.Branch })
	sha := resolveGitContext(flagScanSHA, ci, func(info *cidetect.CIInfo) string { return
printScanDiff function · go · L314-L374 (61 LOC)
cmd/upload_scan.go
func printScanDiff(diff *api.ScanDiffInfo, prNumber int) error {
	output.Info("")
	if prNumber > 0 {
		output.Info("Scan Diff (PR #%d)", prNumber)
	} else {
		output.Info("Scan Diff")
	}

	totalNew := diff.NewCriticalCount + diff.NewHighCount + diff.NewMediumCount + diff.NewLowCount
	output.Info("  New CVEs:    %d (critical: %d, high: %d, medium: %d, low: %d)",
		totalNew, diff.NewCriticalCount, diff.NewHighCount, diff.NewMediumCount, diff.NewLowCount)
	if diff.SuppressedCVECount > 0 {
		output.Info("  Suppressed:  %d", diff.SuppressedCVECount)
	}
	if len(diff.ResolvedCVEs) > 0 {
		output.Info("  Resolved:    %d", len(diff.ResolvedCVEs))
	}
	output.Info("  Unchanged:   %d", diff.UnchangedCVECount)

	if len(diff.NewCVEs) > 0 {
		output.Info("")
		output.Info("  New CVEs:")
		for _, cve := range diff.NewCVEs {
			suppressed := ""
			if cve.Suppression != nil {
				suppressed = fmt.Sprintf(" [suppressed: %s]", cve.Suppression.Type)
			}
			output.Info("    %s [%s] %s@%s (%s)%s",
				cve.C
init function · go · L40-L52 (13 LOC)
cmd/upload_tests.go
func init() {
	uploadTestsCmd.Flags().StringVar(&flagBranch, "branch", "", "Git branch (auto-detected from CI)")
	uploadTestsCmd.Flags().StringVar(&flagSHA, "sha", "", "Git commit SHA (auto-detected from CI)")
	uploadTestsCmd.Flags().StringVar(&flagFormat, "format", "", "Force format (junit, ctrf). Default: auto-detect")
	uploadTestsCmd.Flags().StringVar(&flagJobName, "job-name", "", "CI job name (auto-detected from CI)")
	uploadTestsCmd.Flags().IntVar(&flagPRNumber, "pr-number", 0, "PR number (auto-detected from CI)")
	uploadTestsCmd.Flags().BoolVar(&flagWait, "wait", true, "Wait for server-side processing before exiting")
	uploadTestsCmd.Flags().IntVar(&flagTimeout, "timeout", 120, "Max wait time in seconds for processing")
	uploadTestsCmd.Flags().StringVar(&flagRunDate, "run-date", "", "ISO 8601 date for historical uploads (e.g. 2026-03-15)")
	uploadTestsCmd.Flags().StringSliceVar(&flagGroups, "group", nil, "Group label(s) for this upload (can be specified multiple times)")

	upload
runUploadTests function · go · L54-L265 (212 LOC)
cmd/upload_tests.go
func runUploadTests(cmd *cobra.Command, args []string) error {
	// Expand glob patterns
	files, err := expandGlobs(args)
	if err != nil {
		return &ExitError{Code: exitcode.UsageError, Err: err}
	}
	if len(files) == 0 {
		return &ExitError{Code: exitcode.ParseError, Err: fmt.Errorf("no files matched the given pattern(s)")}
	}

	output.Info("Found %d file(s) to upload", len(files))

	// Detect CI environment
	ci := cidetect.Detect(os.Getenv)
	if ci == nil {
		ci = cidetect.DetectFromGit()
	}

	branch := resolveGitContext(flagBranch, ci, func(info *cidetect.CIInfo) string { return info.Branch })
	sha := resolveGitContext(flagSHA, ci, func(info *cidetect.CIInfo) string { return info.CommitSHA })

	if branch == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--branch (could not auto-detect)")}
	}
	if sha == "" {
		return &ExitError{Code: exitcode.UsageError, Err: errMissing("--sha (could not auto-detect)")}
	}

	if ci != nil {
		output.Verbose("Detected CI: %s", ci.Pro
About: code-quality intelligence by Repobility · https://repobility.com
resolveGitContext function · go · L268-L276 (9 LOC)
cmd/upload_tests.go
func resolveGitContext(flagVal string, ci *cidetect.CIInfo, getter func(*cidetect.CIInfo) string) string {
	if flagVal != "" {
		return flagVal
	}
	if ci != nil {
		return getter(ci)
	}
	return ""
}
dryRunValidate function · go · L278-L314 (37 LOC)
cmd/upload_tests.go
func dryRunValidate(files []string) error {
	output.Info("[dry-run] Validating files locally, no upload will be performed")

	var allCases []junit.TestCase
	var parseErrors int

	for _, f := range files {
		data, err := os.ReadFile(filepath.Clean(f)) //nolint:gosec // G304: path is from CLI args + glob expansion
		if err != nil {
			output.Error("Failed to read %s: %v", f, err)
			parseErrors++
			continue
		}

		cases, err := junit.Parse(data)
		if err != nil {
			output.Error("Failed to parse %s: %v", f, err)
			parseErrors++
			continue
		}

		summary := junit.Summarize(cases)
		output.Info("  %s: %d tests (%d passed, %d failed, %d skipped, %d errors)",
			filepath.Base(f), summary.Total, summary.Passed, summary.Failed, summary.Skipped, summary.Errored)
		allCases = append(allCases, cases...)
	}

	summary := junit.Summarize(allCases)
	output.Info("")
	output.Info("[dry-run] Total: %d tests (%d passed, %d failed, %d skipped, %d errors)",
		summary.Total, summary.Passed, summary.Faile
init function · go · L10-L12 (3 LOC)
cmd/validate.go
func init() {
	rootCmd.AddCommand(validateCmd)
}
init function · go · L24-L26 (3 LOC)
cmd/validate_tests.go
func init() {
	validateCmd.AddCommand(validateTestsCmd)
}
runValidateTests function · go · L28-L83 (56 LOC)
cmd/validate_tests.go
func runValidateTests(cmd *cobra.Command, args []string) error {
	files, err := expandGlobs(args)
	if err != nil {
		return &ExitError{Code: exitcode.UsageError, Err: err}
	}

	if len(files) == 0 {
		return &ExitError{Code: exitcode.ParseError, Err: fmt.Errorf("no files matched the given pattern(s)")}
	}

	output.Info("Found %d file(s) to validate", len(files))

	var allCases []junit.TestCase
	var parseErrors int

	for _, f := range files {
		data, err := os.ReadFile(filepath.Clean(f)) //nolint:gosec // G304: path is from CLI args + glob expansion
		if err != nil {
			output.Error("Failed to read %s: %v", f, err)
			parseErrors++
			continue
		}

		cases, err := junit.Parse(data)
		if err != nil {
			output.Error("Failed to parse %s: %v", f, err)
			parseErrors++
			continue
		}

		summary := junit.Summarize(cases)
		output.Verbose("  %s: %d tests (%d passed, %d failed, %d skipped, %d errors)",
			filepath.Base(f), summary.Total, summary.Passed, summary.Failed, summary.Skipped, summary
expandGlobs function · go · L86-L109 (24 LOC)
cmd/validate_tests.go
func expandGlobs(patterns []string) ([]string, error) {
	seen := make(map[string]bool)
	var files []string

	for _, pattern := range patterns {
		matches, err := doublestar.FilepathGlob(pattern)
		if err != nil {
			return nil, fmt.Errorf("invalid glob pattern %q: %w", pattern, err)
		}
		for _, m := range matches {
			abs, err := filepath.Abs(m)
			if err != nil {
				abs = m
			}
			if seen[abs] {
				continue
			}
			seen[abs] = true
			files = append(files, m)
		}
	}

	return files, nil
}
SetVersionInfo function · go · L16-L20 (5 LOC)
cmd/version.go
func SetVersionInfo(version, commit, date string) {
	cliVersion = version
	cliCommit = commit
	cliDate = date
}
init function · go · L30-L32 (3 LOC)
cmd/version.go
func init() {
	rootCmd.AddCommand(versionCmd)
}
Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
NewClient function · go · L24-L40 (17 LOC)
internal/api/client.go
func NewClient(baseURL, token string) (*Client, error) {
	u, err := url.Parse(baseURL)
	if err != nil {
		return nil, fmt.Errorf("invalid base URL %q: %w", baseURL, err)
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return nil, fmt.Errorf("invalid base URL scheme %q: must be http or https", u.Scheme)
	}
	return &Client{
		BaseURL: baseURL,
		Token:   token,
		HTTPClient: &http.Client{
			Timeout: 30 * time.Second,
		},
		UserAgent: "drape-cli/dev",
	}, nil
}
LookupRepo method · go · L49-L78 (30 LOC)
internal/api/client.go
func (c *Client) LookupRepo(orgSlug, repoName string) (*RepoInfo, error) {
	url := fmt.Sprintf("%s/api/v1/orgs/%s/repos/?name=%s", c.BaseURL, orgSlug, repoName)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("creating request: %w", err)
	}
	c.setHeaders(req)

	resp, err := c.doWithRetries(req)
	if err != nil {
		return nil, fmt.Errorf("looking up repo: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	if resp.StatusCode == http.StatusNotFound {
		return nil, fmt.Errorf("repository %q not found in org %q", repoName, orgSlug)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, parseErrorResponse(resp)
	}

	var repos []RepoInfo
	if err := json.NewDecoder(resp.Body).Decode(&repos); err != nil {
		return nil, fmt.Errorf("decoding response: %w", err)
	}
	if len(repos) == 0 {
		return nil, fmt.Errorf("repository %q not found in org %q", repoName, orgSlug)
	}
	return &repos[0], nil
}
setHeaders method · go · L80-L83 (4 LOC)
internal/api/client.go
func (c *Client) setHeaders(req *http.Request) {
	req.Header.Set("Authorization", "Bearer "+c.Token)
	req.Header.Set("User-Agent", c.UserAgent)
}
doWithRetries method · go · L85-L113 (29 LOC)
internal/api/client.go
func (c *Client) doWithRetries(req *http.Request) (*http.Response, error) {
	const maxRetries = 3
	var lastErr error
	for attempt := range maxRetries {
		if attempt > 0 {
			// Exponential backoff: 1s, 2s for retries 1 and 2
			delay := time.Second << (attempt - 1)
			output.Verbose("Retrying request after %v (attempt %d/%d)", delay, attempt+1, maxRetries)
			time.Sleep(delay)
		}

		resp, err := c.HTTPClient.Do(req) //nolint:gosec // G704: BaseURL is validated in NewClient
		if err != nil {
			lastErr = err
			continue
		}

		// Only retry on 5xx errors
		if resp.StatusCode >= 500 {
			body, _ := io.ReadAll(resp.Body)
			_ = resp.Body.Close()
			lastErr = fmt.Errorf("server error %d: %s", resp.StatusCode, string(body))
			continue
		}

		return resp, nil
	}
	return nil, fmt.Errorf("request failed after %d attempts: %w", maxRetries, lastErr)
}
parseErrorResponse function · go · L122-L138 (17 LOC)
internal/api/client.go
func parseErrorResponse(resp *http.Response) error {
	body, _ := io.ReadAll(resp.Body)
	var errResp ErrorResponse
	if json.Unmarshal(body, &errResp) == nil {
		msg := errResp.Error
		if msg == "" {
			msg = errResp.Message
		}
		if msg == "" {
			msg = errResp.Detail
		}
		if msg != "" {
			return fmt.Errorf("API error %d: %s", resp.StatusCode, msg)
		}
	}
	return fmt.Errorf("API error %d: %s", resp.StatusCode, string(body))
}
InitiateCoverageUpload method · go · L61-L97 (37 LOC)
internal/api/coverage.go
func (c *Client) InitiateCoverageUpload(orgSlug string, repoID int, req CoverageUploadRequest) (*CoverageInitiateResponse, error) {
	metadata := map[string]any{
		"format": req.Format,
	}
	if req.PathPrefix != "" {
		metadata["path_prefix"] = req.PathPrefix
	}
	if req.PRNumber != 0 {
		metadata["pr_number"] = req.PRNumber
	}
	if req.PRTitle != "" {
		metadata["pr_title"] = req.PRTitle
	}
	if req.PRURL != "" {
		metadata["pr_url"] = req.PRURL
	}
	if req.PRAuthor != "" {
		metadata["pr_author"] = req.PRAuthor
	}
	if req.TargetBranch != "" {
		metadata["target_branch"] = req.TargetBranch
	}
	if req.RunDate != "" {
		metadata["run_date"] = req.RunDate
	}
	if req.Group != "" {
		metadata["group"] = req.Group
	}

	return c.InitiateUpload(orgSlug, repoID, UploadInitiateRequest{
		UploadType: "coverage",
		Branch:     req.Branch,
		SHA:        req.SHA,
		Filename:   req.Filename,
		Metadata:   metadata,
	})
}
CompleteCoverageUpload method · go · L100-L102 (3 LOC)
internal/api/coverage.go
func (c *Client) CompleteCoverageUpload(orgSlug string, repoID, uploadID int) error {
	return c.CompleteUpload(orgSlug, repoID, uploadID)
}
PollCoverageStatus method · go · L105-L120 (16 LOC)
internal/api/coverage.go
func (c *Client) PollCoverageStatus(orgSlug string, repoID, uploadID int, timeout time.Duration) (*CoverageStatusResponse, error) {
	raw, err := c.PollUploadStatus(orgSlug, repoID, uploadID, timeout, "Coverage")
	if err != nil {
		// Map to CoverageStatusResponse even on failure
		if raw != nil {
			return &CoverageStatusResponse{
				UploadID:     raw.UploadID,
				Status:       raw.Status,
				ErrorMessage: raw.ErrorMessage,
			}, err
		}
		return nil, err
	}

	return mapCoverageStatus(raw), nil
}
Repobility — same analyzer, your code, free for public repos · /scan/
mapCoverageStatus function · go · L122-L155 (34 LOC)
internal/api/coverage.go
func mapCoverageStatus(raw *UploadStatusResponse) *CoverageStatusResponse {
	result := &CoverageStatusResponse{
		UploadID:     raw.UploadID,
		Status:       raw.Status,
		ErrorMessage: raw.ErrorMessage,
	}

	if raw.Result != nil {
		if v, ok := raw.Result["snapshot_id"]; ok {
			if f, ok := v.(float64); ok {
				id := int(f)
				result.CoverageSnapshotID = &id
			}
		}
		if v, ok := raw.Result["coverage_rate"]; ok {
			if s, ok := v.(string); ok {
				result.CoverageRate = &s
			}
		}
		if v, ok := raw.Result["file_count"]; ok {
			if f, ok := v.(float64); ok {
				count := int(f)
				result.FileCount = &count
			}
		}
		if v, ok := raw.Result["coverage_diff"]; ok {
			if diffMap, ok := v.(map[string]any); ok {
				result.CoverageDiff = mapCoverageDiff(diffMap)
			}
		}
	}

	return result
}
mapCoverageDiff function · go · L157-L218 (62 LOC)
internal/api/coverage.go
func mapCoverageDiff(m map[string]any) *CoverageDiffInfo {
	diff := &CoverageDiffInfo{}

	if v, ok := m["passed"].(bool); ok {
		diff.Passed = v
	}
	if v, ok := m["base_coverage_rate"].(string); ok {
		diff.BaseCoverageRate = &v
	}
	if v, ok := m["head_coverage_rate"].(string); ok {
		diff.HeadCoverageRate = v
	}
	if v, ok := m["coverage_delta"].(string); ok {
		diff.CoverageDelta = &v
	}
	if v, ok := m["new_lines_total"].(float64); ok {
		diff.NewLinesTotal = int(v)
	}
	if v, ok := m["new_lines_covered"].(float64); ok {
		diff.NewLinesCovered = int(v)
	}
	if v, ok := m["new_code_coverage_rate"].(string); ok {
		diff.NewCodeCoverageRate = &v
	}
	if v, ok := m["regressed_lines_count"].(float64); ok {
		diff.RegressedLinesCount = int(v)
	}
	if files, ok := m["regressed_files"].([]any); ok {
		for _, f := range files {
			if fm, ok := f.(map[string]any); ok {
				rf := RegressedFileInfo{}
				if v, ok := fm["file_path"].(string); ok {
					rf.FilePath = v
				}
				if v, ok := fm["regress
PollLintStatus method · go · L39-L53 (15 LOC)
internal/api/lint.go
func (c *Client) PollLintStatus(orgSlug string, repoID, uploadID int, timeout time.Duration) (*LintStatusResponse, error) {
	raw, err := c.PollUploadStatus(orgSlug, repoID, uploadID, timeout, "Lint")
	if err != nil {
		if raw != nil {
			return &LintStatusResponse{
				UploadID:     raw.UploadID,
				Status:       raw.Status,
				ErrorMessage: raw.ErrorMessage,
			}, err
		}
		return nil, err
	}

	return mapLintStatus(raw), nil
}
mapLintStatus function · go · L55-L87 (33 LOC)
internal/api/lint.go
func mapLintStatus(raw *UploadStatusResponse) *LintStatusResponse {
	result := &LintStatusResponse{
		UploadID:     raw.UploadID,
		Status:       raw.Status,
		ErrorMessage: raw.ErrorMessage,
	}

	if raw.Result == nil {
		return result
	}

	if v, ok := raw.Result["snapshot_id"].(float64); ok {
		id := int(v)
		result.SnapshotID = &id
	}
	if v, ok := raw.Result["total_violations"].(float64); ok {
		count := int(v)
		result.TotalViolations = &count
	}
	if v, ok := raw.Result["error_count"].(float64); ok {
		count := int(v)
		result.ErrorCount = &count
	}
	if v, ok := raw.Result["warning_count"].(float64); ok {
		count := int(v)
		result.WarningCount = &count
	}
	if diffMap, ok := raw.Result["lint_diff"].(map[string]any); ok {
		result.LintDiff = mapLintDiff(diffMap)
	}

	return result
}
mapLintDiff function · go · L89-L142 (54 LOC)
internal/api/lint.go
func mapLintDiff(m map[string]any) *LintDiffInfo {
	diff := &LintDiffInfo{}

	if v, ok := m["passed"].(bool); ok {
		diff.Passed = v
	}
	if v, ok := m["base_violation_count"].(float64); ok {
		diff.BaseViolationCount = int(v)
	}
	if v, ok := m["head_violation_count"].(float64); ok {
		diff.HeadViolationCount = int(v)
	}
	if v, ok := m["new_violation_count"].(float64); ok {
		diff.NewViolationCount = int(v)
	}
	if v, ok := m["resolved_violation_count"].(float64); ok {
		diff.ResolvedViolationCount = int(v)
	}
	if v, ok := m["suppressed_violation_count"].(float64); ok {
		diff.SuppressedViolationCount = int(v)
	}
	if violations, ok := m["new_violations"].([]any); ok {
		for _, v := range violations {
			if vm, ok := v.(map[string]any); ok {
				lv := LintViolation{}
				if s, ok := vm["rule_id"].(string); ok {
					lv.RuleID = s
				}
				if s, ok := vm["file_path"].(string); ok {
					lv.FilePath = s
				}
				if f, ok := vm["line"].(float64); ok {
					lv.Line = int(f)
				}
				if s, 
PollScanStatus method · go · L59-L73 (15 LOC)
internal/api/scan.go
func (c *Client) PollScanStatus(orgSlug string, repoID, uploadID int, timeout time.Duration) (*ScanStatusResponse, error) {
	raw, err := c.PollUploadStatus(orgSlug, repoID, uploadID, timeout, "Scan")
	if err != nil {
		if raw != nil {
			return &ScanStatusResponse{
				UploadID:     raw.UploadID,
				Status:       raw.Status,
				ErrorMessage: raw.ErrorMessage,
			}, err
		}
		return nil, err
	}

	return mapScanStatus(raw), nil
}
mapScanStatus function · go · L75-L112 (38 LOC)
internal/api/scan.go
func mapScanStatus(raw *UploadStatusResponse) *ScanStatusResponse {
	result := &ScanStatusResponse{
		UploadID:     raw.UploadID,
		Status:       raw.Status,
		ErrorMessage: raw.ErrorMessage,
	}

	if raw.Result == nil {
		return result
	}

	if v, ok := raw.Result["scan_id"].(float64); ok {
		id := int(v)
		result.ScanID = &id
	}
	if v, ok := raw.Result["scan_name"].(string); ok {
		result.ScanName = &v
	}
	if v, ok := raw.Result["total_vulnerabilities"].(float64); ok {
		count := int(v)
		result.TotalVulnerabilities = &count
	}
	if v, ok := raw.Result["highest_severity"].(string); ok {
		result.HighestSeverity = &v
	}
	if v, ok := raw.Result["unsuppressed_vulnerabilities"].(float64); ok {
		count := int(v)
		result.UnsuppressedVulnerabilities = &count
	}
	if v, ok := raw.Result["unsuppressed_highest_severity"].(string); ok {
		result.UnsuppressedHighestSeverity = &v
	}
	if diffMap, ok := raw.Result["scan_diff"].(map[string]any); ok {
		result.ScanDiff = mapScanDiff(diffMap)
	}

	return
mapScanDiff function · go · L114-L182 (69 LOC)
internal/api/scan.go
func mapScanDiff(m map[string]any) *ScanDiffInfo {
	diff := &ScanDiffInfo{}

	if v, ok := m["passed"].(bool); ok {
		diff.Passed = v
	}
	if v, ok := m["new_critical_count"].(float64); ok {
		diff.NewCriticalCount = int(v)
	}
	if v, ok := m["new_high_count"].(float64); ok {
		diff.NewHighCount = int(v)
	}
	if v, ok := m["new_medium_count"].(float64); ok {
		diff.NewMediumCount = int(v)
	}
	if v, ok := m["new_low_count"].(float64); ok {
		diff.NewLowCount = int(v)
	}
	if v, ok := m["suppressed_cves_count"].(float64); ok {
		diff.SuppressedCVECount = int(v)
	}
	if v, ok := m["unchanged_cves_count"].(float64); ok {
		diff.UnchangedCVECount = int(v)
	}

	if cves, ok := m["new_cves"].([]any); ok {
		for _, c := range cves {
			if cm, ok := c.(map[string]any); ok {
				diff.NewCVEs = append(diff.NewCVEs, mapScanCVE(cm))
			}
		}
	}
	if cves, ok := m["resolved_cves"].([]any); ok {
		for _, c := range cves {
			if cm, ok := c.(map[string]any); ok {
				diff.ResolvedCVEs = append(diff.ResolvedCV
Open data scored by Repobility · https://repobility.com
mapScanCVE function · go · L184-L212 (29 LOC)
internal/api/scan.go
func mapScanCVE(m map[string]any) ScanCVE {
	cve := ScanCVE{}
	if s, ok := m["cve_id"].(string); ok {
		cve.CVEID = s
	}
	if s, ok := m["severity"].(string); ok {
		cve.Severity = s
	}
	if s, ok := m["package_name"].(string); ok {
		cve.PackageName = s
	}
	if s, ok := m["package_version"].(string); ok {
		cve.PackageVersion = s
	}
	if s, ok := m["fix_state"].(string); ok {
		cve.FixState = s
	}
	if sup, ok := m["suppression"].(map[string]any); ok {
		s := &Suppression{}
		if v, ok := sup["suppression_type"].(string); ok {
			s.Type = v
		}
		if v, ok := sup["justification"].(string); ok {
			s.Justification = v
		}
		cve.Suppression = s
	}
	return cve
}
InitiateTestUpload method · go · L40-L80 (41 LOC)
internal/api/tests.go
func (c *Client) InitiateTestUpload(orgSlug string, repoID int, metadata TestUploadMetadata) (*TestInitiateResponse, error) {
	meta := map[string]any{}
	if metadata.Format != "" {
		meta["format"] = metadata.Format
	}
	if metadata.ProviderType != "" {
		meta["provider_type"] = metadata.ProviderType
	}
	if metadata.ProviderRunID != "" {
		meta["provider_run_id"] = metadata.ProviderRunID
	}
	if metadata.JobName != "" {
		meta["job_name"] = metadata.JobName
	}
	if metadata.PRNumber != 0 {
		meta["pr_number"] = metadata.PRNumber
	}
	if metadata.PRTitle != "" {
		meta["pr_title"] = metadata.PRTitle
	}
	if metadata.PRURL != "" {
		meta["pr_url"] = metadata.PRURL
	}
	if metadata.PRAuthor != "" {
		meta["pr_author"] = metadata.PRAuthor
	}
	if metadata.RunDate != "" {
		meta["run_date"] = metadata.RunDate
	}
	if metadata.Group != "" {
		meta["group"] = metadata.Group
	}

	return c.InitiateUpload(orgSlug, repoID, UploadInitiateRequest{
		UploadType: "test_results",
		Branch:     metadata.Branch,
CompleteTestUpload method · go · L83-L85 (3 LOC)
internal/api/tests.go
func (c *Client) CompleteTestUpload(orgSlug string, repoID, uploadID int) error {
	return c.CompleteUpload(orgSlug, repoID, uploadID)
}
page 1 / 2next ›