280 lines
10 KiB
Go
280 lines
10 KiB
Go
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gitea
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
// ActionTask represents a workflow run task (from /actions/tasks endpoint)
|
|
// This is the format returned by older Gitea versions
|
|
type ActionTask struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"` // Workflow name
|
|
HeadBranch string `json:"head_branch"`
|
|
HeadSHA string `json:"head_sha"`
|
|
RunNumber int64 `json:"run_number"`
|
|
Event string `json:"event"`
|
|
DisplayTitle string `json:"display_title"` // PR title or commit message
|
|
Status string `json:"status"`
|
|
WorkflowID string `json:"workflow_id"` // e.g. "ci.yml"
|
|
URL string `json:"url"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
RunStartedAt time.Time `json:"run_started_at"`
|
|
}
|
|
|
|
// ActionTaskResponse holds the response for listing action tasks
|
|
type ActionTaskResponse struct {
|
|
TotalCount int64 `json:"total_count"`
|
|
WorkflowRuns []*ActionTask `json:"workflow_runs"`
|
|
}
|
|
|
|
// ActionWorkflowRun represents a workflow run (from /actions/runs endpoint)
|
|
// This is the format returned by newer Gitea versions
|
|
type ActionWorkflowRun struct {
|
|
ID int64 `json:"id"`
|
|
DisplayTitle string `json:"display_title"`
|
|
Event string `json:"event"`
|
|
HeadBranch string `json:"head_branch"`
|
|
HeadSha string `json:"head_sha"`
|
|
Path string `json:"path"`
|
|
RunAttempt int64 `json:"run_attempt"`
|
|
RunNumber int64 `json:"run_number"`
|
|
Status string `json:"status"`
|
|
Conclusion string `json:"conclusion"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
CompletedAt time.Time `json:"completed_at"`
|
|
Actor *User `json:"actor"`
|
|
TriggerActor *User `json:"trigger_actor"`
|
|
Repository *Repository `json:"repository"`
|
|
HeadRepository *Repository `json:"head_repository"`
|
|
RepositoryID int64 `json:"repository_id"`
|
|
}
|
|
|
|
// ActionWorkflowRunsResponse holds the response for listing workflow runs
|
|
type ActionWorkflowRunsResponse struct {
|
|
TotalCount int64 `json:"total_count"`
|
|
WorkflowRuns []*ActionWorkflowRun `json:"workflow_runs"`
|
|
}
|
|
|
|
// ActionWorkflowJob represents a job within a workflow run
|
|
type ActionWorkflowJob struct {
|
|
ID int64 `json:"id"`
|
|
RunID int64 `json:"run_id"`
|
|
RunURL string `json:"run_url"`
|
|
RunAttempt int64 `json:"run_attempt"`
|
|
Name string `json:"name"`
|
|
HeadBranch string `json:"head_branch"`
|
|
HeadSha string `json:"head_sha"`
|
|
Status string `json:"status"`
|
|
Conclusion string `json:"conclusion"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
CompletedAt time.Time `json:"completed_at"`
|
|
RunnerID int64 `json:"runner_id"`
|
|
RunnerName string `json:"runner_name"`
|
|
Labels []string `json:"labels"`
|
|
Steps []*ActionWorkflowStep `json:"steps"`
|
|
}
|
|
|
|
// ActionWorkflowJobsResponse holds the response for listing workflow jobs
|
|
type ActionWorkflowJobsResponse struct {
|
|
TotalCount int64 `json:"total_count"`
|
|
Jobs []*ActionWorkflowJob `json:"jobs"`
|
|
}
|
|
|
|
// ActionWorkflowStep represents a step within a job
|
|
type ActionWorkflowStep struct {
|
|
Name string `json:"name"`
|
|
Number int64 `json:"number"`
|
|
Status string `json:"status"`
|
|
Conclusion string `json:"conclusion"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
CompletedAt time.Time `json:"completed_at"`
|
|
}
|
|
|
|
// ListRepoActionRunsOptions options for listing repository action runs
|
|
type ListRepoActionRunsOptions struct {
|
|
ListOptions
|
|
Branch string // Filter by branch
|
|
Event string // Filter by triggering event
|
|
Status string // Filter by status (pending, queued, in_progress, failure, success, skipped)
|
|
Actor string // Filter by actor (user who triggered the run)
|
|
HeadSHA string // Filter by the SHA of the head commit
|
|
}
|
|
|
|
// QueryEncode encodes the options to URL query parameters
|
|
func (opt *ListRepoActionRunsOptions) QueryEncode() string {
|
|
query := opt.getURLQuery()
|
|
if opt.Branch != "" {
|
|
query.Add("branch", opt.Branch)
|
|
}
|
|
if opt.Event != "" {
|
|
query.Add("event", opt.Event)
|
|
}
|
|
if opt.Status != "" {
|
|
query.Add("status", opt.Status)
|
|
}
|
|
if opt.Actor != "" {
|
|
query.Add("actor", opt.Actor)
|
|
}
|
|
if opt.HeadSHA != "" {
|
|
query.Add("head_sha", opt.HeadSHA)
|
|
}
|
|
return query.Encode()
|
|
}
|
|
|
|
// ListRepoActionJobsOptions options for listing repository action jobs
|
|
type ListRepoActionJobsOptions struct {
|
|
ListOptions
|
|
Status string // Filter by status (pending, queued, in_progress, failure, success, skipped)
|
|
}
|
|
|
|
// QueryEncode encodes the options to URL query parameters
|
|
func (opt *ListRepoActionJobsOptions) QueryEncode() string {
|
|
query := opt.getURLQuery()
|
|
if opt.Status != "" {
|
|
query.Add("status", opt.Status)
|
|
}
|
|
return query.Encode()
|
|
}
|
|
|
|
// ListRepoActionRuns lists workflow runs for a repository.
|
|
// Requires Gitea 1.25.0 or later. For older versions, use ListRepoActionTasks.
|
|
func (c *Client) ListRepoActionRuns(owner, repo string, opt ListRepoActionRunsOptions) (*ActionWorkflowRunsResponse, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
opt.setDefaults()
|
|
|
|
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/runs", owner, repo))
|
|
link.RawQuery = opt.QueryEncode()
|
|
|
|
resp := new(ActionWorkflowRunsResponse)
|
|
response, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, resp)
|
|
return resp, response, err
|
|
}
|
|
|
|
// GetRepoActionRun gets a single workflow run.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) GetRepoActionRun(owner, repo string, runID int64) (*ActionWorkflowRun, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
run := new(ActionWorkflowRun)
|
|
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/actions/runs/%d", owner, repo, runID), jsonHeader, nil, run)
|
|
return run, resp, err
|
|
}
|
|
|
|
// ListRepoActionRunJobs lists jobs for a workflow run.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) ListRepoActionRunJobs(owner, repo string, runID int64, opt ListRepoActionJobsOptions) (*ActionWorkflowJobsResponse, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
opt.setDefaults()
|
|
|
|
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/runs/%d/jobs", owner, repo, runID))
|
|
link.RawQuery = opt.QueryEncode()
|
|
|
|
resp := new(ActionWorkflowJobsResponse)
|
|
response, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, resp)
|
|
return resp, response, err
|
|
}
|
|
|
|
// ListRepoActionJobs lists all jobs for a repository.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) ListRepoActionJobs(owner, repo string, opt ListRepoActionJobsOptions) (*ActionWorkflowJobsResponse, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
opt.setDefaults()
|
|
|
|
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/jobs", owner, repo))
|
|
link.RawQuery = opt.QueryEncode()
|
|
|
|
resp := new(ActionWorkflowJobsResponse)
|
|
response, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, resp)
|
|
return resp, response, err
|
|
}
|
|
|
|
// GetRepoActionJob gets a single job.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) GetRepoActionJob(owner, repo string, jobID int64) (*ActionWorkflowJob, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
job := new(ActionWorkflowJob)
|
|
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/actions/jobs/%d", owner, repo, jobID), jsonHeader, nil, job)
|
|
return job, resp, err
|
|
}
|
|
|
|
// GetRepoActionJobLogs gets the logs for a specific job.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) GetRepoActionJobLogs(owner, repo string, jobID int64) ([]byte, *Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/actions/jobs/%d/logs", owner, repo, jobID), nil, nil)
|
|
}
|
|
|
|
// ListRepoActionTasks lists workflow tasks for a repository (Gitea 1.24.x and earlier)
|
|
// Use this for older Gitea versions that don't have /actions/runs endpoint
|
|
func (c *Client) ListRepoActionTasks(owner, repo string, opt ListOptions) (*ActionTaskResponse, *Response, error) {
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
opt.setDefaults()
|
|
|
|
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/tasks", owner, repo))
|
|
link.RawQuery = opt.getURLQuery().Encode()
|
|
|
|
resp := new(ActionTaskResponse)
|
|
response, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, resp)
|
|
return resp, response, err
|
|
}
|
|
|
|
// DeleteRepoActionRun deletes a workflow run.
|
|
// Requires Gitea 1.25.0 or later.
|
|
func (c *Client) DeleteRepoActionRun(owner, repo string, runID int64) (*Response, error) {
|
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_25_0); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/actions/runs/%d", owner, repo, runID), jsonHeader, nil)
|
|
return resp, err
|
|
}
|