X Tutup
package shared import ( "encoding/base64" "errors" "fmt" "net/url" "path" "strings" "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/prompt" ) const ( Active WorkflowState = "active" DisabledManually WorkflowState = "disabled_manually" ) type WorkflowState string type Workflow struct { Name string ID int64 Path string State WorkflowState } type WorkflowsPayload struct { Workflows []Workflow } func (w *Workflow) Disabled() bool { return w.State != Active } func (w *Workflow) Base() string { return path.Base(w.Path) } func GetWorkflows(client *api.Client, repo ghrepo.Interface, limit int) ([]Workflow, error) { perPage := limit page := 1 if limit > 100 || limit == 0 { perPage = 100 } workflows := []Workflow{} for { if limit > 0 && len(workflows) == limit { break } var result WorkflowsPayload path := fmt.Sprintf("repos/%s/actions/workflows?per_page=%d&page=%d", ghrepo.FullName(repo), perPage, page) err := client.REST(repo.RepoHost(), "GET", path, nil, &result) if err != nil { return nil, err } for _, workflow := range result.Workflows { workflows = append(workflows, workflow) if limit > 0 && len(workflows) == limit { break } } if len(result.Workflows) < perPage { break } page++ } return workflows, nil } type FilteredAllError struct { error } func SelectWorkflow(workflows []Workflow, promptMsg string, states []WorkflowState) (*Workflow, error) { filtered := []Workflow{} candidates := []string{} for _, workflow := range workflows { for _, state := range states { if workflow.State == state { filtered = append(filtered, workflow) candidates = append(candidates, fmt.Sprintf("%s (%s)", workflow.Name, workflow.Base())) break } } } if len(candidates) == 0 { return nil, FilteredAllError{errors.New("")} } var selected int err := prompt.SurveyAskOne(&survey.Select{ Message: promptMsg, Options: candidates, PageSize: 15, }, &selected) if err != nil { return nil, err } return &filtered[selected], nil } func FindWorkflow(client *api.Client, repo ghrepo.Interface, workflowSelector string, states []WorkflowState) ([]Workflow, error) { if workflowSelector == "" { return nil, errors.New("empty workflow selector") } workflow, err := getWorkflowByID(client, repo, workflowSelector) if err == nil { return []Workflow{*workflow}, nil } else { var httpErr api.HTTPError if !errors.As(err, &httpErr) || httpErr.StatusCode != 404 { return nil, err } } return getWorkflowsByName(client, repo, workflowSelector, states) } func getWorkflowByID(client *api.Client, repo ghrepo.Interface, ID string) (*Workflow, error) { var workflow Workflow err := client.REST(repo.RepoHost(), "GET", fmt.Sprintf("repos/%s/actions/workflows/%s", ghrepo.FullName(repo), ID), nil, &workflow) if err != nil { return nil, err } return &workflow, nil } func getWorkflowsByName(client *api.Client, repo ghrepo.Interface, name string, states []WorkflowState) ([]Workflow, error) { workflows, err := GetWorkflows(client, repo, 0) if err != nil { return nil, fmt.Errorf("couldn't fetch workflows for %s: %w", ghrepo.FullName(repo), err) } filtered := []Workflow{} for _, workflow := range workflows { desiredState := false for _, state := range states { if workflow.State == state { desiredState = true break } } if !desiredState { continue } // TODO consider fuzzy or prefix match if strings.EqualFold(workflow.Name, name) { filtered = append(filtered, workflow) } } return filtered, nil } func ResolveWorkflow(io *iostreams.IOStreams, client *api.Client, repo ghrepo.Interface, prompt bool, workflowSelector string, states []WorkflowState) (*Workflow, error) { if prompt { workflows, err := GetWorkflows(client, repo, 0) if len(workflows) == 0 { err = errors.New("no workflows are enabled") } if err != nil { var httpErr api.HTTPError if errors.As(err, &httpErr) && httpErr.StatusCode == 404 { err = errors.New("no workflows are enabled") } return nil, fmt.Errorf("could not fetch workflows for %s: %w", ghrepo.FullName(repo), err) } return SelectWorkflow(workflows, "Select a workflow", states) } workflows, err := FindWorkflow(client, repo, workflowSelector, states) if err != nil { return nil, err } if len(workflows) == 0 { return nil, fmt.Errorf("could not find any workflows named %s", workflowSelector) } if len(workflows) == 1 { return &workflows[0], nil } if !io.CanPrompt() { errMsg := "could not resolve to a unique workflow; found:" for _, workflow := range workflows { errMsg += fmt.Sprintf(" %s", workflow.Base()) } return nil, errors.New(errMsg) } return SelectWorkflow(workflows, "Which workflow do you mean?", states) } func GetWorkflowContent(client *api.Client, repo ghrepo.Interface, workflow Workflow, ref string) ([]byte, error) { path := fmt.Sprintf("repos/%s/contents/%s", ghrepo.FullName(repo), workflow.Path) if ref != "" { q := fmt.Sprintf("?ref=%s", url.QueryEscape(ref)) path = path + q } type Result struct { Content string } var result Result err := client.REST(repo.RepoHost(), "GET", path, nil, &result) if err != nil { return nil, err } decoded, err := base64.StdEncoding.DecodeString(result.Content) if err != nil { return nil, fmt.Errorf("failed to decode workflow file: %w", err) } return decoded, nil }
X Tutup