github-bot-sdk 0.2.1

A comprehensive Rust SDK for GitHub App integration with authentication, webhooks, and API client
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
51
52
53
54
55
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# GitHub Projects v2 Operations


**Architectural Layer**: Installation-Level Operations
**Module Path**: `src/client/project.rs`
**Dependencies**:

- Types: `InstallationClient` (installation-client.md)
- Shared: `ApiError`, `Result` (shared-types.md)

## Overview


GitHub Projects v2 is a completely redesigned project management system with a flexible data model. Unlike Projects Classic (v1), Projects v2:

- Uses GraphQL API for most operations
- Supports custom fields with various types
- Has organization-level and user-level projects
- Provides more flexible item management

**Important**: This SDK provides REST API operations where available. For advanced Projects v2 features (custom fields, views, workflows), users should use GitHub's GraphQL API directly.

## Type Definitions


### ProjectV2


Represents a GitHub Projects v2 project.

```rust
/// GitHub Projects v2 project.
///
/// Projects v2 provide flexible project management with custom fields,
/// multiple views, and automation capabilities.
#[derive(Debug, Clone, Serialize, Deserialize)]

pub struct ProjectV2 {
    /// Unique project identifier
    pub id: u64,

    /// Node ID for GraphQL API
    pub node_id: String,

    /// Project number (unique within owner)
    pub number: u64,

    /// Project title
    pub title: String,

    /// Project description
    pub description: Option<String>,

    /// Project owner (organization or user)
    pub owner: ProjectOwner,

    /// Project visibility
    pub public: bool,

    /// Creation timestamp
    pub created_at: DateTime<Utc>,

    /// Last update timestamp
    pub updated_at: DateTime<Utc>,

    /// Project URL
    pub url: String,
}
```

### ProjectOwner


Owner of a project (organization or user).

```rust
/// Project owner (organization or user).
#[derive(Debug, Clone, Serialize, Deserialize)]

pub struct ProjectOwner {
    /// Owner login name
    pub login: String,

    /// Owner type
    #[serde(rename = "type")]
    pub owner_type: String, // "Organization" or "User"

    /// Owner ID
    pub id: u64,

    /// Owner node ID
    pub node_id: String,
}
```

### ProjectV2Item


Represents an item (issue or pull request) added to a project.

```rust
/// Item in a GitHub Projects v2 project.
///
/// Items are issues or pull requests added to the project.
#[derive(Debug, Clone, Serialize, Deserialize)]

pub struct ProjectV2Item {
    /// Unique item identifier (project-specific)
    pub id: String,

    /// Node ID for GraphQL API
    pub node_id: String,

    /// Content type
    pub content_type: String, // "Issue" or "PullRequest"

    /// Content node ID (issue or PR node ID)
    pub content_node_id: String,

    /// Creation timestamp
    pub created_at: DateTime<Utc>,

    /// Last update timestamp
    pub updated_at: DateTime<Utc>,
}
```

### AddProjectV2ItemRequest


Request to add an item to a project.

```rust
/// Request to add an item to a GitHub Projects v2 project.
#[derive(Debug, Clone, Serialize)]

pub struct AddProjectV2ItemRequest {
    /// Node ID of the content to add (issue or pull request)
    pub content_node_id: String,
}
```

## Operations


### List Organization Projects


List all Projects v2 for an organization.

**Signature**:

```rust
pub async fn list_organization_projects(
    &self,
    org: &str,
) -> Result<Vec<ProjectV2>, ApiError>
```

**Arguments**:

- `org` - Organization login name

**Returns**:

- `Ok(Vec<ProjectV2>)` - List of projects
- `Err(ApiError::NotFound)` - Organization not found
- `Err(ApiError::AuthorizationFailed)` - Insufficient permissions
- `Err(ApiError)` - Other errors

**Behavior**:

1. Make GET request to `/orgs/{org}/projects`
2. Parse response into `Vec<ProjectV2>`
3. Return projects

**Example**:

```rust
let projects = client.list_organization_projects("my-org").await?;
for project in projects {
    println!("Project: {} ({})", project.title, project.number);
}
```

---

### List User Projects


List all Projects v2 for a user.

**Signature**:

```rust
pub async fn list_user_projects(
    &self,
    username: &str,
) -> Result<Vec<ProjectV2>, ApiError>
```

**Arguments**:

- `username` - User login name

**Returns**:

- `Ok(Vec<ProjectV2>)` - List of projects
- `Err(ApiError::NotFound)` - User not found
- `Err(ApiError::AuthorizationFailed)` - Insufficient permissions (private projects)
- `Err(ApiError)` - Other errors

**Behavior**:

1. Make GET request to `/users/{username}/projects`
2. Parse response into `Vec<ProjectV2>`
3. Return projects

**Example**:

```rust
let projects = client.list_user_projects("octocat").await?;
```

---

### Get Project


Get details about a specific project.

**Signature**:

```rust
pub async fn get_project(
    &self,
    owner: &str,
    project_number: u64,
) -> Result<ProjectV2, ApiError>
```

**Arguments**:

- `owner` - Organization or user login name
- `project_number` - Project number (unique within owner)

**Returns**:

- `Ok(ProjectV2)` - Project details
- `Err(ApiError::NotFound)` - Project not found
- `Err(ApiError::AuthorizationFailed)` - Insufficient permissions
- `Err(ApiError)` - Other errors

**Behavior**:

1. Make GET request to `/users/{owner}/projects/{project_number}` or `/orgs/{owner}/projects/{project_number}`
2. Parse response into `ProjectV2`
3. Return project

**Note**: The API endpoint varies based on whether owner is an organization or user. This implementation tries organization first, then falls back to user endpoint.

**Example**:

```rust
let project = client.get_project("my-org", 1).await?;
println!("Project: {}", project.title);
```

---

### Add Item to Project


Add an issue or pull request to a project.

**Signature**:

```rust
pub async fn add_item_to_project(
    &self,
    owner: &str,
    project_number: u64,
    content_node_id: &str,
) -> Result<ProjectV2Item, ApiError>
```

**Arguments**:

- `owner` - Organization or user login name
- `project_number` - Project number
- `content_node_id` - Node ID of the issue or pull request to add

**Returns**:

- `Ok(ProjectV2Item)` - Created project item
- `Err(ApiError::NotFound)` - Project not found for this owner
- `Err(ApiError::AuthorizationFailed)` - No write access to the project
- `Err(ApiError::GraphQlError { .. })` - Mutation error (e.g., content already in project)
- `Err(ApiError)` - Other transport errors

**Behavior**:

1. Resolve the project's GraphQL node ID (`PVT_...`) from `owner` + `project_number`:
   - Query `organization(login: $owner) { projectV2(number: $number) { id } }` first
   - If the organisation is not found (`NOT_FOUND` error), fall back to `user(login: $owner) { projectV2(number: $number) { id } }`
   - If both lookups fail, return `Err(ApiError::NotFound)`
2. Call the `addProjectV2ItemById` GraphQL mutation with the resolved `projectId` and `content_node_id`
3. Parse the `item` from the mutation response into `ProjectV2Item`
4. Return item

**Example**:

```rust
// Get issue node ID from issue object
let issue = client.get_issue("owner", "repo", 123).await?;
let item = client.add_item_to_project("my-org", 1, &issue.node_id).await?;
println!("Added item: {}", item.id);
```

---

### Get Issue Linked Projects


Get all Projects v2 linked to a specific issue.

**Signature**:

```rust
pub async fn get_issue_linked_projects(
    &self,
    owner: &str,
    repo: &str,
    issue_number: u64,
) -> Result<Vec<ProjectV2>, ApiError>
```

**Arguments**:

- `owner` - Repository owner (organisation or user login)
- `repo` - Repository name
- `issue_number` - Issue number

**Returns**:

- `Ok(Vec<ProjectV2>)` - Projects linked to the issue (may be empty)
- `Err(ApiError::NotFound)` - Repository or issue does not exist
- `Err(ApiError::AuthenticationFailed)` - Token is invalid
- `Err(ApiError)` - Other errors

**Behavior**:

1. Send a paginated GraphQL `repository(owner, name) { issue(number) { projectsV2(first: 20, after: $cursor) { pageInfo { hasNextPage endCursor } nodes { ... } } } }` query
2. If the repository or issue does not exist, GitHub GraphQL returns `type: "NOT_FOUND"` in `.errors[]` — surface this as `ApiError::NotFound`
3. Loop through pages: after each response, if `pageInfo.hasNextPage` is true, issue a follow-up query with `after: endCursor`; stop when `hasNextPage` is false
4. Map each node across all pages to a `ProjectV2` struct (populating all fields including owner)
5. Return an empty `Vec` when the issue exists but is not linked to any projects

**Example**:

```rust
let projects = client.get_issue_linked_projects("my-org", "my-repo", 42).await?;
for project in &projects {
    println!("Issue is in project: {} ({})", project.title, project.number);
}
// Returns Ok(vec![]) if the issue has no linked projects
```

---

### Remove Item from Project


Remove an item from a project.

**Signature**:

```rust
pub async fn remove_item_from_project(
    &self,
    owner: &str,
    project_number: u64,
    item_id: &str,
) -> Result<(), ApiError>
```

**Arguments**:

- `owner` - Organization or user login name
- `project_number` - Project number
- `item_id` - Project item ID (not the issue/PR ID)

**Returns**:

- `Ok(())` - Item removed successfully
- `Err(ApiError::NotFound)` - Project or item not found
- `Err(ApiError::AuthorizationFailed)` - Insufficient permissions
- `Err(ApiError)` - Other errors

**Behavior**:

1. Make DELETE request to `/projects/{project_id}/items/{item_id}`
2. Verify successful response
3. Return success

**Example**:

```rust
client.remove_item_from_project("my-org", 1, "item-id").await?;
```

---

## GraphQL API Note


For advanced Projects v2 operations not available via REST API, users should use GitHub's GraphQL API:

- **Custom Fields**: Set, update, and read custom field values
- **Views**: Create and manage project views
- **Workflows**: Configure project automation
- **Field Definitions**: List and create custom fields

The REST API provides basic project and item management. For full Projects v2 functionality, GraphQL is required.

## Error Handling


All operations return `Result<T, ApiError>` with these common errors:

- `ApiError::NotFound` - Project, organization, or content not found
- `ApiError::AuthorizationFailed` - Insufficient permissions to access or modify project
- `ApiError::GraphQlError` - GraphQL-level error (e.g., content already in project, malformed response)
- `ApiError::RateLimitExceeded` - API rate limit exceeded
- `ApiError::HttpClientError` - HTTP transport error

## Permissions


Projects v2 operations require:

- **Read**: Read access to the organization/user and project
- **Write**: Write access to project (for add/remove items)
- **Admin**: Admin access (for create/update/delete project)

Installation must have the `organization_projects: read` or `organization_projects: write` permission.

## Implementation Notes


1. Projects v2 REST API is limited compared to GraphQL API
2. Node IDs are required for adding items (use GraphQL or get from issue/PR objects)
3. Custom field management requires GraphQL API
4. Project creation/update/deletion may require GraphQL API (check GitHub API docs)
5. Some endpoints may still be in beta (check API documentation)