feat(deploy): commit-status reporting to Git providers
Report deploy status back to the Git provider as a commit status (pending/success/failure) for git-sourced workloads (static + dockerfile). - GitProvider.SetCommitStatus on gitea/github/gitlab over the existing SSRF-safe client; fixed "tinyforge" context so redeploys update one row. postJSON returns status-code-only errors (never echoes the upstream body, which a hostile provider could use to reflect the auth token into the best-effort log line). - Best-effort deploy hook: pending on deploy start, success/failure on outcome, gated on a per-workload report_commit_status flag. Never fails or blocks a deploy; emits nothing on the unchanged-SHA short-circuit. - UI ToggleSwitch (create + edit) + reportCommitStatus in sourceForms.ts + en/ru i18n. - Tests: per-provider state mapping + request shape; reporter gating (enabled/disabled/empty-SHA/nil/error-swallow). Reviewed via go-reviewer + security-reviewer (0 CRITICAL/HIGH; one MEDIUM body-echo log-leak fixed).
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -115,6 +116,43 @@ func (g *GitHubProvider) TestConnection(ctx context.Context, owner, repo string)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetCommitStatus reports a deploy status on a commit via GitHub's commit-
|
||||
// status API (works for github.com and GitHub Enterprise — apiBase already
|
||||
// carries the /api/v3 suffix for GHE). The "context" field is fixed to
|
||||
// "tinyforge" so repeated deploys update one status row.
|
||||
func (g *GitHubProvider) SetCommitStatus(ctx context.Context, owner, repo, sha string, status CommitStatus, targetURL, description string) error {
|
||||
body, err := json.Marshal(map[string]string{
|
||||
"state": githubState(status),
|
||||
"target_url": targetURL,
|
||||
"description": truncateDescription(description),
|
||||
"context": commitStatusContext,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal status: %w", err)
|
||||
}
|
||||
apiURL := fmt.Sprintf("%s/repos/%s/%s/statuses/%s",
|
||||
g.apiBase, url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(sha))
|
||||
if err := postJSON(ctx, g.httpClient, apiURL, body, g.setAuth); err != nil {
|
||||
return fmt.Errorf("set commit status: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// githubState maps a provider-agnostic CommitStatus onto GitHub's API
|
||||
// vocabulary. GitHub accepts the same four words Tinyforge uses.
|
||||
func githubState(status CommitStatus) string {
|
||||
switch status {
|
||||
case CommitStatusSuccess:
|
||||
return "success"
|
||||
case CommitStatusFailure:
|
||||
return "failure"
|
||||
case CommitStatusError:
|
||||
return "error"
|
||||
default:
|
||||
return "pending"
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GitHubProvider) ListBranches(ctx context.Context, owner, repo string) ([]string, error) {
|
||||
var allBranches []string
|
||||
page := 1
|
||||
|
||||
Reference in New Issue
Block a user