Skip to content

Instantly share code, notes, and snippets.

@richkuz
Created August 7, 2022 13:56
Show Gist options
  • Save richkuz/e8842fce354edbd4e12dcbfa9ca40ff6 to your computer and use it in GitHub Desktop.
Save richkuz/e8842fce354edbd4e12dcbfa9ca40ff6 to your computer and use it in GitHub Desktop.
Notes about using the new GitHub ProjectV2 API

Notes on GitHub ProjectV2 API

GitHub Projects Beta aka GitHub Projects Next aka GitHub ProjectNext is now known as GitHub ProjectV2 in the API.

It's not immediately obvious how to use the new API, especially if you're coming from the old beta API.

You no longer need to set the HTTP header: GraphQL-Features: projects_next_graphql.

You still need to add your GitHub personal access token to the Authorization header, e.g. Authorization: Basic ghp_...

Here's a query to help you get started. It queries information about the items in the project https://github.com/orgs/richkuz-org/projects/2/views/1

query richkuzProjectItems
{
  viewer {
    id
    login
    organization(login: "richkuz-org") {
      
      #projectNext(number: 2) {
      projectV2(number:2) {
        
        id
        title # Project title
        
        items(first: 20) {
          nodes {
            databaseId
						id
            content {
              __typename
              ... on Issue {
                # Find associated issue with Project item:
                url
                #... all fields associated with an Issue are available
              }
            }
            
            # Query custom fields associated with the Project Item:
            fieldValueByName(name:"foo") {
              __typename
              ... on ProjectV2ItemFieldTextValue {
                id
                text
              }
              ... on ProjectV2ItemFieldDateValue {
                id
                date
              }
              ... on ProjectV2ItemFieldSingleSelectValue {
                name
                optionId
              }
            }
            
            # # List all field types
            # fieldValues(first:20) {
            #   nodes { 
            #     __typename
            #   }
            # }
            
            fieldValues(first:20) {
              nodes {
                ... on ProjectV2ItemFieldSingleSelectValue {
                  name
                  id
                }
                ... on ProjectV2ItemFieldLabelValue {
                  labels(first:20) {
                    nodes {
                      id
                      name # e.g. "my-custom-label", "label1", ...
                      
                      # Query a list of PRs that have this label:
                      pullRequests(first:20) {
                        nodes {
                          url
                        }
                      }
                      # Query a list of Issues that have this label:
                      issues(first:20) {
                        nodes {
                          url
                        }
                      }
                    }
                  }
                }
                ... on ProjectV2ItemFieldTextValue {
                  text
                  id
                  updatedAt
                  creator {
                    url
                  }
                }
                ... on ProjectV2ItemFieldMilestoneValue {
                  milestone {
                    id
                  }
                }
                ... on ProjectV2ItemFieldRepositoryValue {
                  repository {
                    id
                    url
                  }
                }
            	}
            }
          }
        }
      }
    }
  }
}

Example response:

{
  "data": {
    "viewer": {
      "id": "MDQ6VXNlcjYyNTIyMjQ4",
      "login": "richkuz",
      "organization": {
        "projectV2": {
          "id": "PVT_kwDOBQfyVc0FoQ",
          "title": "My Project",
          "items": {
            "nodes": [
              {
                "databaseId": 79558,
                "id": "PVTI_lADOBQfyVc0Foc4AATbG",
                "content": {
                  "__typename": "Issue",
                  "url": "https://github.com/richkuz-org/repo1/issues/2"
                },
                "fieldValueByName": {
                  "__typename": "ProjectV2ItemFieldTextValue",
                  "id": "PVTFTV_lQDOBQfyVc0Foc4AATbGzgFbUdY",
                  "text": "issue2's foo value"
                },
                "fieldValues": {
                  "nodes": [
                    {
                      "repository": {
                        "id": "MDEwOlJlcG9zaXRvcnkzNjg2MTc3NzU=",
                        "url": "https://github.com/richkuz-org/repo1"
                      }
                    },
                    {
                      "labels": {
                        "nodes": [
                          {
                            "id": "MDU6TGFiZWwzMTU2OTk1NzM2",
                            "name": "label1",
                            "pullRequests": {
                              "nodes": []
                            },
                            "issues": {
                              "nodes": [
                                {
                                  "url": "https://github.com/richkuz-org/repo1/issues/1"
                                },
                                {
                                  "url": "https://github.com/richkuz-org/repo1/issues/2"
                                }
                              ]
                            }
                          }
                        ]
                      }
                    },
                    {
                      "text": "issue2",
                      "id": "PVTFTV_lQDOBQfyVc0Foc4AATbGzgAEkIQ",
                      "updatedAt": "2021-08-20T19:44:57Z",
                      "creator": {
                        "url": "https://github.com/richkuz"
                      }
                    },
                    {
                      "name": "3",
                      "id": "PVTFSV_lQDOBQfyVc0Foc4AATbGzgFbUIU"
                    },
                    {
                      "text": "issue2's foo value",
                      "id": "PVTFTV_lQDOBQfyVc0Foc4AATbGzgFbUdY",
                      "updatedAt": "2022-08-07T13:45:32Z",
                      "creator": {
                        "url": "https://github.com/richkuz"
                      }
                    }
                  ]
                }
              },
              {
                "databaseId": 155869,
                "id": "PVTI_lADOBQfyVc0Foc4AAmDd",
                "content": {
                  "__typename": "Issue",
                  "url": "https://github.com/richkuz-org/repo1/issues/1"
                },
                "fieldValueByName": {
                  "__typename": "ProjectV2ItemFieldTextValue",
                  "id": "PVTFTV_lQDOBQfyVc0Foc4AAmDdzgFbUdc",
                  "text": "issue1's foo value"
                },
                "fieldValues": {
                  "nodes": [
                    {
                      "repository": {
                        "id": "MDEwOlJlcG9zaXRvcnkzNjg2MTc3NzU=",
                        "url": "https://github.com/richkuz-org/repo1"
                      }
                    },
                    {
                      "labels": {
                        "nodes": [
                          {
                            "id": "MDU6TGFiZWwzMTU2OTk1NzM2",
                            "name": "label1",
                            "pullRequests": {
                              "nodes": []
                            },
                            "issues": {
                              "nodes": [
                                {
                                  "url": "https://github.com/richkuz-org/repo1/issues/1"
                                },
                                {
                                  "url": "https://github.com/richkuz-org/repo1/issues/2"
                                }
                              ]
                            }
                          }
                        ]
                      }
                    },
                    {
                      "text": "Issue1",
                      "id": "PVTFTV_lQDOBQfyVc0Foc4AAmDdzgAICrM",
                      "updatedAt": "2021-10-01T20:30:23Z",
                      "creator": {
                        "url": "https://github.com/richkuz"
                      }
                    },
                    {
                      "name": "1",
                      "id": "PVTFSV_lQDOBQfyVc0Foc4AAmDdzgFbUIQ"
                    },
                    {
                      "text": "issue1's foo value",
                      "id": "PVTFTV_lQDOBQfyVc0Foc4AAmDdzgFbUdc",
                      "updatedAt": "2022-08-07T13:45:36Z",
                      "creator": {
                        "url": "https://github.com/richkuz"
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      }
    }
  }
}
@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

The new ProjectV2 API lets you access the issue URL or PR URL associated with a project Item 🥳

query richkuzProjectItems2
{
  viewer {
    organization(login: "richkuz-org") {
      projectV2(number:2) {
        items(first: 20) {
          nodes {
            id
            content {
              __typename
              ... on Issue {
                # Find associated issue with Project item:
                url
              }
            }
          }
        }
      }
    }
  }
}

Response:

{
  "data": {
    "viewer": {
      "organization": {
        "projectV2": {
          "items": {
            "nodes": [
              {
                "id": "PVTI_lADOBQfyVc0Foc4AATbG",
                "content": {
                  "__typename": "Issue",
                  "url": "https://github.com/richkuz-org/repo1/issues/2"
                }
              },
              {
                "id": "PVTI_lADOBQfyVc0Foc4AAmDd",
                "content": {
                  "__typename": "Issue",
                  "url": "https://github.com/richkuz-org/repo1/issues/1"
                }
              }
            ]
          }
        }
      }
    }
  }
}

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

In the new API, it's now possible to find all associated Project Item(s) for a given Issue.

query findProjectItemsForIssueNumber($owner: String!, $repoName: String!, $issueNumber:Int!) {
  viewer {
    organization(login:$owner) {
      repository(name:$repoName) {
        issue(number:$issueNumber) {
          url
          projectItems(first:20) {
            nodes {
              id
            }
          }
        }
      }
    }
  }
}
# Response:
# {
#   "data": {
#     "viewer": {
#       "organization": {
#         "repository": {
#           "issue": {
#             "url": "https://github.com/richkuz-org/repo1/issues/3",
#             "projectItems": {
#               "nodes": [
#                 {
#                   "id": "PVTI_lADOBQfyVc0Foc4Afl9P"
#                 }
#               ]
#             }
#           }
#         }
#       }
#     }
#   }
# }

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

A ProjectV2 projectId is different from the same project's ProjectNext projectId value, i.e. these return different values for the same project number:

query findProjectId($owner: String!, $projectNumber: Int!) {
    organization(login: $owner) {
        projectNext(number: $projectNumber) {
            id
        }
    }
}

query NEWfindProjectId($owner: String!, $projectNumber: Int!) {
    organization(login: $owner) {
        projectV2(number: $projectNumber) {
            id
        }
    }
}

So when you roll out ProjectV2 API changes, make sure to fix all APIs at once, not incrementally.

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

Some of the new ProjectV2 APIs require new API token scope: ['read:project'] . In the past, we could get away with only ['admin:org', 'repo', 'workflow'] scopes. Re-generate API tokens with the necessary scopes at: https://github.com/settings/tokens.

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

@richkuz
Copy link
Author

richkuz commented Aug 7, 2022

Merged PR updating GitHub ProjectsNext label assigner action to use GitHub ProjectV2 APs: richkuz/projectnext-label-assigner#1

@dlozanor
Copy link

dlozanor commented Oct 1, 2023

Dear @richkuz, is there a way to get all archived items for a projectV2 using graphql, I'm able to retreive all information associated to a ProjectV2 but not archived ones. Version 3.9

Thanks for your replay

@matebenyovszky
Copy link

@dlozanor I use a parameter "closed" on project level. This is how I list all projects and all items with custom field values:

{
  organization(login: "integrityauthority") {
    projectsV2(first: 100) {
      nodes {
        id
        title
        public
        closed
        url
        fields(first: 20) {
          nodes {
            ... on ProjectV2FieldCommon {
              id
              name
            }
            ... on ProjectV2SingleSelectField {
              id
              name
              options {
                id
                name
              }
            }
            ... on ProjectV2IterationField {
              id
              name
              configuration {
                iterations {
                  startDate
                  id
                }
              }
            }
          }
        }
        items(first: 100) {
          nodes {
            id
            fieldValues(first: 20) {
              nodes {
                ... on ProjectV2ItemFieldTextValue {
                  text
                  field {
                    ... on ProjectV2FieldCommon {
                      name
                    }
                  }
                }
                ... on ProjectV2ItemFieldDateValue {
                  date
                  field {
                    ... on ProjectV2FieldCommon {
                      name
                    }
                  }
                }
                ... on ProjectV2ItemFieldSingleSelectValue {
                  name
                  field {
                    ... on ProjectV2FieldCommon {
                      name
                    }
                  }
                }
                ... on ProjectV2ItemFieldNumberValue {
                  number
                  field {
                    ... on ProjectV2FieldCommon {
                      name
                    }
                  }
                }
                ... on ProjectV2ItemFieldIterationValue {
                  title
                  startDate
                  duration
                  field {
                    ... on ProjectV2FieldCommon {
                      name
                    }
                  }
                }
              }
            }
            content {
              ... on Issue {
                title
                url
                repository {
                  name
                }
                assignees(first: 5) {
                  nodes {
                    login
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

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