Module: ActiveProject::Adapters::GithubProject::Issues
- Includes:
- Helpers
- Included in:
- ActiveProject::Adapters::GithubProjectAdapter
- Defined in:
- lib/active_project/adapters/github_project/issues.rb
Overview
Project-item CRUD operations for GitHub Projects v2.
This module exists because GitHub decided that “issues,” “drafts,” and “project items” are three different species, and we have to *unify the galaxy.*
Constant Summary collapse
- DEFAULT_ITEM_PAGE_SIZE =
Like everything on GitHub: decent default, weird edge cases. Why not 25 like a normal person?
50
Instance Method Summary collapse
-
#create_issue(project_id, attrs) ⇒ Object
Create a new issue in the project.
-
#delete_issue_original(project_id, item_id) ⇒ Object
Delete a ProjectV2Item from a project.
-
#find_issue(item_id, _ctx = {}) ⇒ Object
Fetch a single issue or draft item by its mysterious GraphQL node ID.
-
#list_issues(project_id, options = {}) ⇒ Object
Lists every issue or draft in a GitHub Project.
-
#status_known?(project_id, sym) ⇒ Boolean
Check if a status symbol like :in_progress is known for a project.
-
#update_issue_original(project_id, item_id, attrs = {}) ⇒ Object
Update fields on an existing ProjectV2Item.
Methods included from Helpers
#fetch_all_pages, #map_user, #owner_node_id, #project_field_ids
Instance Method Details
#create_issue(project_id, attrs) ⇒ Object
Create a new issue in the project.
Choose your destiny:
- Pass :content_id → links an existing GitHub Issue or PR into the project.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 98 def create_issue(project_id, attrs) content_id = attrs[:content_id] or raise ArgumentError, "DraftIssues not supported—pass :content_id of a real Issue or PR" mutation = <<~GQL mutation($project:ID!, $content:ID!) { addProjectV2ItemById(input:{projectId:$project, contentId:$content}) { item { id } } } GQL data = request_gql( query: mutation, variables: { project: project_id, content: content_id } ).dig("addProjectV2ItemById", "item") find_issue(data["id"]) end |
#delete_issue_original(project_id, item_id) ⇒ Object
Delete a ProjectV2Item from a project. No soft delete, no grace period — just *execute Order 66*.
174 175 176 177 178 179 180 181 182 183 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 174 def delete_issue_original(project_id, item_id) mutation = <<~GQL mutation($proj:ID!, $item:ID!){ deleteProjectV2Item(input:{projectId:$proj, itemId:$item}){deletedItemId} } GQL request_gql(query: mutation, variables: { proj: project_id, item: item_id }) true end |
#find_issue(item_id, _ctx = {}) ⇒ Object
Fetch a single issue or draft item by its mysterious GraphQL node ID. If it’s missing, you get a 404 so you can take a day off.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 56 def find_issue(item_id, _ctx = {}) query = <<~GQL query($id:ID!){ node(id:$id){ ... on ProjectV2Item{ id type fieldValues(first:20){ nodes{ ... on ProjectV2ItemFieldTextValue{ text field { ... on ProjectV2FieldCommon { name } } } } } content{ __typename ... on Issue{ id number title body state assignees(first:10){nodes{login id}} reporter:author{login} } } createdAt updatedAt project { id } } } } GQL node = request_gql(query: query, variables: { id: item_id })["node"] raise NotFoundError, "Project item #{item_id} not found" unless node map_item_to_issue(node, node.dig("project", "id")) end |
#list_issues(project_id, options = {}) ⇒ Object
Lists every issue or draft in a GitHub Project. Handles pagination the GitHub way: manually, painfully, endlessly.
options → control how much data you want per jump into hyperspace.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 23 def list_issues(project_id, = {}) page_size = .fetch(:page_size, DEFAULT_ITEM_PAGE_SIZE) query = <<~GQL query($id:ID!, $first:Int!, $after:String){ node(id:$id){ ... on ProjectV2{ items(first:$first, after:$after){ nodes{ id type content{__typename ... on Issue{ id number title body state assignees(first:10){nodes{login id}} reporter:author{login} } } createdAt updatedAt } pageInfo{hasNextPage endCursor} } } } } GQL nodes = fetch_all_pages( query, variables: { id: project_id, first: page_size }, connection_path: %w[node items] ) { |vars| request_gql(query: query, variables: vars) } nodes.map { |n| map_item_to_issue(n, project_id) } end |
#status_known?(project_id, sym) ⇒ Boolean
Check if a status symbol like :in_progress is known for a project. Avoids exploding like fukushima reactor if you try to set a status that doesn’t exist.
189 190 191 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 189 def status_known?(project_id, sym) (@status_cache && @status_cache[project_id] || {}).key?(sym) end |
#update_issue_original(project_id, item_id, attrs = {}) ⇒ Object
Update fields on an existing ProjectV2Item.
You can adjust:
- Title (text field)
- Status (single-select nightmare field)
NOTE: Requires you to preload field mappings, because GitHub’s GraphQL API refuses to help unless you memorize all their withcrafts.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/active_project/adapters/github_project/issues.rb', line 128 def update_issue_original(project_id, item_id, attrs = {}) field_ids = project_field_ids(project_id) # -- Update Title (basic) -- if attrs[:title] mutation = <<~GQL mutation($proj:ID!, $item:ID!, $field:ID!, $title:String!) { updateProjectV2ItemFieldValue(input:{ projectId:$proj, itemId:$item, fieldId:$field, value:{text:$title} }) { projectV2Item { id } } } GQL request_gql(query: mutation, variables: { proj: project_id, item: item_id, field: field_ids.fetch("Title"), title: attrs[:title] }) end # -- Update Status (dark side difficulty) -- if attrs[:status] status_field_id = field_ids.fetch("Status") option_id = status_option_id(project_id, attrs[:status]) mutation = <<~GQL mutation($proj:ID!, $item:ID!, $field:ID!, $opt:String!) { updateProjectV2ItemFieldValue(input:{ projectId:$proj, itemId:$item, fieldId:$field, value:{singleSelectOptionId:$opt} }) { projectV2Item { id } } } GQL request_gql(query: mutation, variables: { proj: project_id, item: item_id, field: status_field_id, opt: option_id }) end find_issue(item_id) end |