Skip to content

Undocumented behaviour of the -w flag for gh run list  #9038

Description

@joshuajtward

Describe the bug

The -w flag for gh run list behaves differently depending on whether a workflow name or a workflow filename is passed to it. Specifically, if a workflow has been manually disabled then the gh run list -w will only return values with the filename as input, and nothing is returned for the workflow name (assuming no duplicate workflow names...).

Versions checked: 2.44.1, 2.48.0

Steps to reproduce the behavior

  1. In a repository with a workflow which has been manually disabled
  2. Run gh run list -w my-workflow-name and observe that no runs are found
  3. Run gh run list -w my-workflow-name.yml and observe that previous runs are listed (potentially as expected?)

Expected vs actual behavior

Given the nature of workflow naming I can see reasonable grounds for this being a desirable feature of the CLI, so the scope of this issue is just to get the behaviour included in the documentation. If it turns out to be undesirable behaviour then I am happy to raise that as another issue!

Logs

screenshot showing gh run list output

Activity

  1. andyfeller commented on May 10, 2024

    @andyfeller
    Contributor

    Thanks for reporting this issue! ❤ Let's dig into this a little bit and figure out what all can be done. 🙇

    How does this code work?

    Let's dig into how gh run list works with filenames or workflow names:

    func listRun(opts *ListOptions) error {
    baseRepo, err := opts.BaseRepo()
    if err != nil {
    return fmt.Errorf("failed to determine base repo: %w", err)
    }
    c, err := opts.HttpClient()
    if err != nil {
    return fmt.Errorf("failed to create http client: %w", err)
    }
    client := api.NewClientFromHTTP(c)
    filters := &shared.FilterOptions{
    Branch: opts.Branch,
    Actor: opts.Actor,
    Status: opts.Status,
    Event: opts.Event,
    Created: opts.Created,
    Commit: opts.Commit,
    }
    opts.IO.StartProgressIndicator()
    if opts.WorkflowSelector != "" {
    states := []workflowShared.WorkflowState{workflowShared.Active}
    if workflow, err := workflowShared.ResolveWorkflow(
    opts.Prompter, opts.IO, client, baseRepo, false, opts.WorkflowSelector,
    states); err == nil {
    filters.WorkflowID = workflow.ID
    filters.WorkflowName = workflow.Name
    } else {
    return err
    }
    }

    I think the salient point in the block above is that gh run list is hardcoded for active state workflows like you said:

    states := []workflowShared.WorkflowState{workflowShared.Active}

    Switching gears to how gh workflow list -a:

    if opts.All {
    filteredWorkflows = workflows
    } else {
    for _, workflow := range workflows {
    if !workflow.Disabled() {
    filteredWorkflows = append(filteredWorkflows, workflow)
    }
    }
    }

    What to do?

    Specifically, if a workflow has been manually disabled then the gh run list -w will only return values with the filename as input, and nothing is returned for the workflow name (assuming no duplicate workflow names...).

    Absolutely makes sense, which I think is an easy Option 1. Thinking about how gh workflow list works, I wonder if it also makes sense to add a flag that would allow users to pull inactive workflows as an Option 2.

    • Option 1: Update documentation that gh run list -w only works on active workflows
    • Option 2: Add flag to gh run list similar to gh workflow list -a

    @joshuajtward : what do you think? could you share your use case for retrieving and working with inactive workflows?

  2. added
    priority-3Affects a small number of users or is largely cosmetic
    gh-runrelating to the gh run command
    and removed on May 10, 2024
  3. joshuajtward commented on May 13, 2024

    @joshuajtward
    ContributorAuthor

    Hi @andyfeller! Thanks for the reply, that all makes sense. One thing to add to your Option 1 - gh run list does fetch the disabled workflows, but only if the input is the filename, i.e. you need to add .yml to get the disabled workflows back too. Would it be sufficient to have:

    • Option 1: Update documentation to call out the different behaviour when calling gh run list -w with a workflow name vs a filename

    This would mean this nuance of the CLI is documented without the need for code changes. Obviously if you prefer adding the -a bring it into line with how gh workflow list works then I'm happy with that approach too for consistency. I'm also happy to raise a PR for either of those options, let me know your thoughts.

    In terms of our use cases, we have some pipeline observability tooling which fetches data using gh run list -w. Adding .yml to this solved it for us, but I wanted to document it so fewer people run into this!

  4. andyfeller commented on May 14, 2024

    @andyfeller
    Contributor

    Just to be clear, I would like to do both: improve documentation and provide the same level of data for those who want it. 👍

    Marking this as help wanted for any of our community looking for an low effort issue to pick up.

  5. joshuajtward commented on May 22, 2024

    @joshuajtward
    ContributorAuthor

    @andyfeller while digging into this I think I have stumbled upon the root issue.

    In FindWorkflow if the selector is the workflow ID or the workflow filename then getWorkflowByID is used, which doesn't accept a statesprop, but if the Name field is used then FindWorkflow uses getWorkflowsByName which does accept the states prop:

    // FindWorkflow looks up a workflow either by numeric database ID, file name, or its Name field
    func FindWorkflow(client *api.Client, repo ghrepo.Interface, workflowSelector string, states []WorkflowState) ([]Workflow, error) {
    	if workflowSelector == "" {
    		return nil, errors.New("empty workflow selector")
    	}
    
    	if _, err := strconv.Atoi(workflowSelector); err == nil || isWorkflowFile(workflowSelector) {
    		workflow, err := getWorkflowByID(client, repo, workflowSelector)
    		if err != nil {
    			return nil, err
    		}
    		return []Workflow{*workflow}, nil
    	}
    
    	return getWorkflowsByName(client, repo, workflowSelector, states)
    }

    This would explain why I was only seeing the disabled workflows excluded when using the Name field of the workflow. Given that it would potentially have a wider impact across the CLI, do you think we could explore adding a states prop to getWorkflowByID so that the output of FindWorkflow is consistent for all input types?

  6. andyfeller commented on May 22, 2024

    @andyfeller
    Contributor

    do you think we could explore adding a states prop to getWorkflowByID so that the output of FindWorkflow is consistent for all input types?

    My knee jerk is to say "Yeah, totally!" though I have hesitation because of how GitHub Actions handles versioning of workflows on the server side. Basically, GitHub will create a new version of the workflow on the server side with different ID if you rename a workflow file, causing all of the previous workflow runs to "disappear" from the newly renamed workflow in the UI. This is where looking up workflows by ID needs to ignore state.

  7. joshuajtward commented on Jun 3, 2024

    @joshuajtward
    ContributorAuthor

    @andyfeller will this do the job? #9162

  8. added a commit that references this issue on Jun 13, 2024
  9. 301166 commented on Jul 15, 2024

    @301166

    JSON Fields

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggh-runrelating to the gh run commandhelp wantedContributions welcomepriority-3Affects a small number of users or is largely cosmetic

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions