Skip to content

gh project item-list Should Include Draft Issue ID #8005

Description

@dsanders11

Describe the feature or problem you’d like to solve

To use gh project item-edit on a draft issue to edit the title or body, you need the draft issue content ID, but the output of gh project item-list does not include that ID, so it's difficult to edit draft issues from the CLI.

Proposed solution

There should be an id field under content when outputting JSON for gh project item-list so that users can get the ID they need to edit the draft issue.

Alternatively gh project item-edit could be updated to do an additional query to try to convert an ID with prefix PVTI_ to DI_ and failing if it's not a draft issue.

Additional context

Relevant code section about requiring the draft issue ID to edit title or body:

// update draft issue
if config.opts.title != "" || config.opts.body != "" {
if !strings.HasPrefix(config.opts.itemID, "DI_") {
return cmdutil.FlagErrorf("ID must be the ID of the draft issue content which is prefixed with `DI_`")
}
query, variables := buildEditDraftIssue(config)
err := config.client.Mutate("EditDraftIssueItem", query, variables)
if err != nil {
return err
}
if config.opts.format == "json" {
return printDraftIssueJSON(config, query.UpdateProjectV2DraftIssue.DraftIssue)
}
return printDraftIssueResults(config, query.UpdateProjectV2DraftIssue.DraftIssue)
}

Activity

  1. arunsathiya commented on Sep 16, 2023

    @arunsathiya
    Contributor

    Alternatively gh project item-edit could be updated to do an additional query to try to convert an ID with prefix PVTI_ to DI_ and failing if it's not a draft issue.

    It seems that it's not just a matter of changing the prefix, because the ID itself is different for draft issues, issues and pull requests. These three are valid item types for project v2, based on this:

    type ProjectItemContent struct {
    TypeName string `graphql:"__typename"`
    DraftIssue DraftIssue `graphql:"... on DraftIssue"`
    PullRequest PullRequest `graphql:"... on PullRequest"`
    Issue Issue `graphql:"... on Issue"`
    }

    Having said that, I feel that we should take the same approach as below:

    func (p ProjectItem) Repo() string {
    switch p.Content.TypeName {
    case "Issue":
    return p.Content.Issue.Repository.NameWithOwner
    case "PullRequest":
    return p.Content.PullRequest.Repository.NameWithOwner
    }
    return ""
    }

    This is the relevant block that'll need to be updated:

    func (p ProjectItem) ID() string {
    return p.Id
    }

    Also on JSON output type:

    I am happy to submit a PR for this once there's some confirmation that this is the direction we'd like to take.

    There should be an id field under content when outputting JSON for gh project item-list so that users can get the ID they need to edit the draft issue.

    Also, I feel that this is not entirely necessary because ID as a property must be separate, as it is now.

  2. arunsathiya commented on Sep 16, 2023

    @arunsathiya
    Contributor

    There should be an id field under content when outputting JSON for gh project item-list so that users can get the ID they need to edit the draft issue.

    It also seems that there's a number within content section, which represents a published issue's or a pull request's number. Since draft issues don't have such a number, that's not included within content.

    The actual project item's ID (prefixed either with DI_ or PVTI_) can continue to appear as a separate ID field outside of content, is my opinion.

  3. williammartin commented on Sep 18, 2023

    @williammartin
    Member

    Thanks for your investigations @arunsathiya, I'd like @mntlty to chime in on this. I don't have a good sense of the graphql schema here and why there is an Id within the content block on GQL responses and how it relates to the Id outside the content block e.g.:

    {
       "content":{
          "__typename":"DraftIssue",
          "id":"DI_lADOB-vozM4AVk16zgD-F-g",
          "body":"What what what",
          "title":"draft for reals"
       },
       "id":"PVTI_lADOB-vozM4AVk16zgJRWFo",
       "fieldValues":{
          "nodes":[
             {
                "__typename":"ProjectV2ItemFieldTextValue",
                "text":"draft for reals",
                "field":{
                   "__typename":"ProjectV2Field",
                   "id":"PVTF_lADOB-vozM4AVk16zgNyZIc",
                   "name":"Title",
                   "dataType":"TITLE"
                }
             }
          ]
       }
    }
    
  4. mntlty commented on Sep 19, 2023

    @mntlty
    Contributor

    Thanks for your investigations @arunsathiya, I'd like @mntlty to chime in on this. I don't have a good sense of the graphql schema here and why there is an Id within the content block on GQL responses and how it relates to the Id outside the content block e.g.:

    {
       "content":{
          "__typename":"DraftIssue",
          "id":"DI_lADOB-vozM4AVk16zgD-F-g",
          "body":"What what what",
          "title":"draft for reals"
       },
       "id":"PVTI_lADOB-vozM4AVk16zgJRWFo",
       "fieldValues":{
          "nodes":[
             {
                "__typename":"ProjectV2ItemFieldTextValue",
                "text":"draft for reals",
                "field":{
                   "__typename":"ProjectV2Field",
                   "id":"PVTF_lADOB-vozM4AVk16zgNyZIc",
                   "name":"Title",
                   "dataType":"TITLE"
                }
             }
          ]
       }
    }
    

    @williammartin there are two IDs, as they represent two different item types - the prefix gives a clue as to what each is.

    the top level ID (in this example prefixed with PVTI which stands for Project V Two Item), and it is the item that exists on the project which references the linked item (in this example prefixed with PVTF which stands for Project V Two Field). A more concrete example is if you have a Pull Request or an Issue, these have their own IDs as GraphQL objects, and a new one is created when they are added to a project (they can be added to multiple projects, after all!) which effectively acts as a join table.

    Returning to the OP, here's a GraphQL example from one of my projects:

    "items": {
    	"nodes": [
    		{
    			"id": "PVTI_lAHOABGJPs4AItjezgEZ6g8",
    			"type": "DRAFT_ISSUE",
    			"__typename": "ProjectV2Item",
    			"content": {
    				"body": "",
    				"title": "a title",
    				"id": "DI_lAHOABGJPs4AItjezgB6jYI",
    				"__typename": "DraftIssue"
    			}
    		},

    As you can see, the outer item ID is a PVTI, while the inner one is of type DraftIssue, and is therefore prefixed with DI_.

    For this operation https://docs.github.com/en/graphql/reference/input-objects#updateprojectv2draftissueinput the only supported ID is for the Draft Issue itself, and not for the Project Item which represents the Draft Issue. To ensure the right ID is passed, the check exists.

  5. arunsathiya commented on Sep 19, 2023

    @arunsathiya
    Contributor

    As you can see, the outer item ID is a PVTI, while the inner one is of type DraftIssue, and is therefore prefixed with DI_.

    Thank you for sharing all of that information, @mntlty! Particularly helpful to have the above example.

    I see that the json format output for item-list does not currently show the draft issue ID (starting with DI_ under the content section), rather just the project item ID (starting with PVTI_) outside of content.

    {
      "items": [
        {
          "content": {
            "type": "DraftIssue",
            "body": "test",
            "title": "test"
          },
          "id": "PVTI_lAHOARuJY84AVcnszgJPkl4",
          "status": "In Progress",
          "title": "test"
        }
      ],
      "totalCount": 1
    }

    @williammartin Would it make sense to retain this format as is, but include the draft issue ID (starting with DI_) in the content section, but also, on the prettified view (without --format json), show the DI_ ID instead of PVTI_ ID? Here's the proposed JSON update:

    {
      "items": [
        {
          "content": {
            "type": "DraftIssue",
            "body": "test",
            "title": "test",
    +       "id": "DI_lAHOARuJY84AVcnszgD9Rf4"
          },
          "id": "PVTI_lAHOARuJY84AVcnszgJPkl4",
          "status": "In Progress",
          "title": "test"
        }
      ],
      "totalCount": 3
    }

    And the proposed huamn-readable output:

    ? Which project would you like to use? Open source (#1)
    TYPE         TITLE                            NUMBER  REPOSITORY                       ID
    DraftIssue   hey                                                                       DI_lAHOARuJY84AVcnszgD9Rf4
    PullRequest  update(run): Use attempt inp...  7831    cli/cli                          PVTI_lAHOARuJY84AVcnszgJPwgI
    DraftIssue   new item here                                                             DI_lAHOARuJY84AVcnszgD-oSU
    

    For those scripting, they wouldn't face any breakage, but those depending on human-readable output will now see the correct ID that can be used for further processing with item-edit

    Please let me know what you think of the above approach, and I am happy to take this forward after confirmation.

  6. williammartin commented on Sep 19, 2023

    @williammartin
    Member

    Thanks @arunsathiya and @mntlty. After playing around with the project command I think I understand the distinction between projects, fields, and items a bit better.

    @arunsathiya I think including the id in the content field in the json output makes sense, as this is a fairly straight forward mapping as an API concept. However, I don't think that changing the human readable output in the way you've proposed makes sense and in fact could be a breaking change for anyone scripting via it.

    Imagine a text field titled Extra Notes as a field in a project. To update this field across all items I would run:

    gh project item-edit --id <ITEM_ID> --field-id <FIELD_ID> --project-id <PROJECT_ID> --text "changing this field via CLI"
    

    Where the ITEM_ID is currently listed in the ID column, it would now point to the DraftIssue which doesn't afford modifying the wrapping item's fields.

    Proposal

    My proposal would be that we only modify the json format as you have described above and don't output this new column in the human readable format. This is consistent with the existing approach of not displaying all the data.

    In this way, anyone writing scripts can use jq to parse out the necessary Id for draft issues.

    I would like confirmation from @mntlty here before proceeding though, and thank you for your continued involvement @arunsathiya.

    Extra Thoughts

    I must admit, I found the CLI experience a bit confusing in the distinction between draft issues and the rest. I wonder whether we could provide a few more examples in the CLI help for how you would work with a draft issue and why it is different than every other type.

  7. mntlty commented on Sep 19, 2023

    @mntlty
    Contributor

    Thanks @arunsathiya and @mntlty. After playing around with the project command I think I understand the distinction between projects, fields, and items a bit better.

    @arunsathiya I think including the id in the content field in the json output makes sense, as this is a fairly straight forward mapping as an API concept. However, I don't think that changing the human readable output in the way you've proposed makes sense and in fact could be a breaking change for anyone scripting via it.

    Imagine a text field titled Extra Notes as a field in a project. To update this field across all items I would run:

    gh project item-edit --id <ITEM_ID> --field-id <FIELD_ID> --project-id <PROJECT_ID> --text "changing this field via CLI"
    

    Where the ITEM_ID is currently listed in the ID column, it would now point to the DraftIssue which doesn't afford modifying the wrapping item's fields.

    Proposal

    My proposal would be that we only modify the json format as you have described above and don't output this new column in the human readable format. This is consistent with the existing approach of not displaying all the data.

    In this way, anyone writing scripts can use jq to parse out the necessary Id for draft issues.

    I would like confirmation from @mntlty here before proceeding though, and thank you for your continued involvement @arunsathiya.

    Extra Thoughts

    I must admit, I found the CLI experience a bit confusing in the distinction between draft issues and the rest. I wonder whether we could provide a few more examples in the CLI help for how you would work with a draft issue and why it is different than every other type.

    If I recall correctly, I had originally had the text output show the DI_ value but it was changed based on feedback that it was not consistent with the output of other items, which was confusing.

    Adding the ID to the content object makes sense, and agree that more documentation here would be helpful, otherwise you're likely to get more issues that are really asking about our GraphQL apis than the CLI 😄

  8. arunsathiya commented on Sep 19, 2023

    @arunsathiya
    Contributor

    Where the ITEM_ID is currently listed in the ID column, it would now point to the DraftIssue which doesn't afford modifying the wrapping item's fields.

    Good point! You're right that it seems to be only the title and body fields that'll need the draft issue ID (DI_) while to modify everything else one will need PVTI_.

    I agree with the proposal above. I'm happy to work on:

    • Adding DI_ to the content object.
    • More examples in the documentation.
  9. dsanders11 commented on Sep 21, 2023

    @dsanders11
    Author

    It seems that it's not just a matter of changing the prefix, because the ID itself is different for draft issues, issues and pull requests.

    To clarify, I meant gh project item-edit could automatically look up the DI_ ID from the PVTI_ ID for the user if they specify --body or --title, and throw an error if the provided PVTI_ ID is not associated with a DraftIssue. This would be a nicer UX - since, as @williammartin pointed out, it's a bit confusing at the moment, and requires users of the CLI to have this understanding of how things work on the GraphQL API.

    Adding DI_ to the content object.

    Also, just to clarify, I think id should be added to the content object for all types, for consistency, and since the ID of the associated pull request or issue might be useful if you then wanted to do some GraphQL queries.

  10. williammartin commented on Sep 27, 2023

    @williammartin
    Member

    I'm just adding a help wanted label to this so that it doesn't appear untriaged, but we know @arunsathiya is looking at it.

  11. yasunori0418 commented on Feb 25, 2024

    @yasunori0418
    Contributor

    I would like the draft issue id to be included in the content that can be obtained with gh project item-list --format json, but what is the response to this issue?
    Hasn't PR etc. been created yet for this response?
    I'd like to help if possible, but I'm not familiar with Go, so it's a bit difficult.
    However, I'm currently looking at the source code to see if I can fix it somehow!

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

    enhancementa request to improve CLIgh-projectrelating to the gh project commandhelp wantedContributions welcome

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions