mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-13 12:45:13 +00:00
New skill: issue-fields-migration (#990)
* Add issue-fields-migration skill Standalone skill to bulk-copy field values from Project V2 fields to org-level issue fields. Includes 5-phase workflow (discovery, option mapping, data scan, preview/dry-run, execution) with API references for issue fields REST API and Projects V2 API. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Expand issue-fields-migration skill to support label migration Add support for migrating repo-based labels to org-level issue fields, in addition to the existing project field migration flow. Changes: - Add Step 0 routing: ask user if migrating labels or project fields - Add Label Migration Flow (Phases L1-L5) with conflict detection, bulk mapping, and optional label removal - Add labels API to Available Tools table - Create references/labels-api.md - Add 3 label migration examples (single, bulk, cross-repo) - Expand Important Notes with label-specific guidance - Rename existing phases to P1-P6 under Project Field Migration Flow - Include P1 fixes from prior work (proxy field filtering, batch option mapping, preflight permission checks, pagination fixes) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: payload format, field_id type + 10 UX/scale improvements Bug fixes: - Wrap write endpoint payload in {"issue_field_values": [...]} (was bare array) - Use integer field_id, not string (both Phase L5 and P6) UX improvements: - Label filtering guidance for repos with 50+ labels - Smarter auto-suggest with 4 pattern tiers (exact, prefix-number, strip-separators, substring) - Handle zero-issue labels gracefully (stop and suggest alternatives) - Add time estimates to migration previews - Document read response shape (.single_select_option.name vs .value) Scale & reliability: - Script generation guidance for 100+ issue migrations - Idempotent/resumable migration note - Warn about --limit 1000 silent truncation - Warn about macOS bash 3.x (no declare -A) - PR filtering guidance (type field) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update README.skills.md with build Regenerated skills index to reflect label migration support and updated references for issue-fields-migration skill. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments: fix MCP conventions, step numbering, pagination, phase refs - Align MCP tool calls with repo conventions (method: instead of action:, owner: instead of project_owner:) in SKILL.md and projects-api.md - Fix step numbering in Phase P2 (duplicate step 5 → renumber to 6) - Update example phase references to use P1-P6/P1-P5 labels - Add pageInfo pagination to GraphQL fields and fieldValues queries - Fix MCP tool name in labels-api.md to mcp__github__list_issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
129
skills/issue-fields-migration/references/issue-fields-api.md
Normal file
129
skills/issue-fields-migration/references/issue-fields-api.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Issue Fields REST API Reference
|
||||
|
||||
Issue fields are org-level custom metadata for issues. All endpoints require the API version header:
|
||||
|
||||
```
|
||||
-H "X-GitHub-Api-Version: 2026-03-10"
|
||||
```
|
||||
|
||||
## List Org Issue Fields
|
||||
|
||||
```bash
|
||||
gh api /orgs/{org}/issue-fields \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10"
|
||||
```
|
||||
|
||||
Returns an array of field objects:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "IF_abc123",
|
||||
"name": "Priority",
|
||||
"content_type": "single_select",
|
||||
"options": [
|
||||
{ "id": "OPT_1", "name": "Critical" },
|
||||
{ "id": "OPT_2", "name": "High" },
|
||||
{ "id": "OPT_3", "name": "Medium" },
|
||||
{ "id": "OPT_4", "name": "Low" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "IF_def456",
|
||||
"name": "Due Date",
|
||||
"content_type": "date",
|
||||
"options": null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Field types**: `text`, `single_select`, `number`, `date`
|
||||
|
||||
**Useful jq filter**:
|
||||
|
||||
```bash
|
||||
gh api /orgs/{org}/issue-fields \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
--jq '.[] | {id, name, content_type, options: [.options[]?.name]}'
|
||||
```
|
||||
|
||||
## Read Issue Field Values
|
||||
|
||||
```bash
|
||||
gh api /repos/{owner}/{repo}/issues/{number}/issue-field-values \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10"
|
||||
```
|
||||
|
||||
Returns the current field values for the issue. Use this to check whether a value already exists before writing.
|
||||
|
||||
## Write Issue Field Values (POST, additive)
|
||||
|
||||
Adds values to an issue without removing existing values for other fields.
|
||||
|
||||
**Important**: uses `repository_id` (integer), not `owner/repo`.
|
||||
|
||||
```bash
|
||||
# First, get the repository ID:
|
||||
REPO_ID=$(gh api /repos/{owner}/{repo} --jq .id)
|
||||
|
||||
# Then write the value:
|
||||
echo '[
|
||||
{
|
||||
"field_id": "IF_abc123",
|
||||
"value": "High"
|
||||
}
|
||||
]' | gh api /repositories/$REPO_ID/issues/{number}/issue-field-values \
|
||||
-X POST \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
--input -
|
||||
```
|
||||
|
||||
### Value format by field type
|
||||
|
||||
| Field Type | value format | Example |
|
||||
|-----------|-------------|---------|
|
||||
| text | String | `"value": "Some text"` |
|
||||
| single_select | Option name (string) | `"value": "High"` |
|
||||
| number | Number | `"value": 42` |
|
||||
| date | ISO 8601 date string | `"value": "2025-03-15"` |
|
||||
|
||||
**Key**: for `single_select`, the REST API accepts the option **name** as a string. You do not need to look up option IDs.
|
||||
|
||||
### Writing multiple fields at once
|
||||
|
||||
Pass multiple objects in the array to set several fields in a single call:
|
||||
|
||||
```bash
|
||||
echo '[
|
||||
{"field_id": "IF_abc123", "value": "High"},
|
||||
{"field_id": "IF_def456", "value": "2025-06-01"}
|
||||
]' | gh api /repositories/$REPO_ID/issues/{number}/issue-field-values \
|
||||
-X POST \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
--input -
|
||||
```
|
||||
|
||||
## Write Issue Field Values (PUT, replace all)
|
||||
|
||||
Replaces all field values on the issue. Use with caution.
|
||||
|
||||
```bash
|
||||
echo '[{"field_id": "IF_abc123", "value": "Low"}]' | \
|
||||
gh api /repositories/$REPO_ID/issues/{number}/issue-field-values \
|
||||
-X PUT \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
--input -
|
||||
```
|
||||
|
||||
**Warning**: PUT removes any field values not included in the request body. Always use POST for migrations to preserve other field values.
|
||||
|
||||
## Permissions
|
||||
|
||||
- **Repository**: "Issues" read/write
|
||||
- **Organization**: "Issue Fields" read/write
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
- Standard rate limits apply (5,000 requests/hour for authenticated users)
|
||||
- Secondary rate limits may trigger for rapid sequential writes
|
||||
- Recommended: 100ms delay between calls, exponential backoff on 429
|
||||
74
skills/issue-fields-migration/references/labels-api.md
Normal file
74
skills/issue-fields-migration/references/labels-api.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Labels API Reference
|
||||
|
||||
Reference for GitHub Labels REST API endpoints used in the label migration flow.
|
||||
|
||||
## List Labels in a Repository
|
||||
|
||||
```
|
||||
GET /repos/{owner}/{repo}/labels
|
||||
```
|
||||
|
||||
Returns all labels defined on a repository. Paginated (max 100 per page).
|
||||
|
||||
**CLI shortcut:**
|
||||
|
||||
```bash
|
||||
gh label list -R {owner}/{repo} --limit 1000 --json name,color,description
|
||||
```
|
||||
|
||||
**Response fields:** `id`, `node_id`, `url`, `name`, `description`, `color`, `default`.
|
||||
|
||||
## List Issues by Label
|
||||
|
||||
```
|
||||
GET /repos/{owner}/{repo}/issues?labels={label_name}&state=all&per_page=100
|
||||
```
|
||||
|
||||
Returns issues (and pull requests) matching the label. Filter out PRs by checking `pull_request` field is absent.
|
||||
|
||||
**CLI shortcut:**
|
||||
|
||||
```bash
|
||||
gh issue list -R {owner}/{repo} --label "{label_name}" --state all \
|
||||
--json number,title,labels --limit 1000
|
||||
```
|
||||
|
||||
The `gh issue list` command automatically excludes PRs.
|
||||
|
||||
**Pagination:** use `--limit` in CLI or `page` query param in REST. For repos with >1000 matching issues, use cursor-based pagination via Link headers.
|
||||
|
||||
## Remove a Label from an Issue
|
||||
|
||||
```
|
||||
DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{label_name}
|
||||
```
|
||||
|
||||
Removes a single label from an issue. Returns `200 OK` with the remaining labels on the issue.
|
||||
|
||||
**Important:** URL-encode label names with spaces or special characters:
|
||||
- `good first issue` → `good%20first%20issue`
|
||||
- `bug/critical` → `bug%2Fcritical`
|
||||
|
||||
**CLI shortcut:**
|
||||
|
||||
```bash
|
||||
gh api /repos/{owner}/{repo}/issues/{number}/labels/{label_name} -X DELETE
|
||||
```
|
||||
|
||||
## Add a Label to an Issue
|
||||
|
||||
```
|
||||
POST /repos/{owner}/{repo}/issues/{issue_number}/labels
|
||||
```
|
||||
|
||||
Body: `{"labels": ["label1", "label2"]}`
|
||||
|
||||
Not typically needed for migration, but useful for rollback scenarios.
|
||||
|
||||
## Notes
|
||||
|
||||
- Labels are repo-scoped. The same label name can exist independently in different repos.
|
||||
- There is no MCP tool for listing repo labels. Use `gh label list` or the REST API.
|
||||
- The MCP tool `mcp__github__list_issues` supports a `labels` filter for fetching issues by label.
|
||||
- Label names are case-insensitive for matching purposes, but the API preserves the original casing.
|
||||
- Maximum labels per issue: no hard limit, but practically dozens.
|
||||
116
skills/issue-fields-migration/references/projects-api.md
Normal file
116
skills/issue-fields-migration/references/projects-api.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Projects V2 API Reference (for Migration)
|
||||
|
||||
This reference covers the subset of the Projects V2 API needed for field migration: discovering project fields and reading item values.
|
||||
|
||||
## List Project Fields
|
||||
|
||||
### Via MCP Tool
|
||||
|
||||
```
|
||||
mcp__github__projects_list(
|
||||
owner: "{org}",
|
||||
project_number: {n},
|
||||
method: "list_project_fields"
|
||||
)
|
||||
```
|
||||
|
||||
### Via GraphQL
|
||||
|
||||
```bash
|
||||
gh api graphql -f query='
|
||||
query {
|
||||
organization(login: "ORG") {
|
||||
projectV2(number: N) {
|
||||
fields(first: 30) {
|
||||
pageInfo { hasNextPage endCursor }
|
||||
nodes {
|
||||
... on ProjectV2Field {
|
||||
id
|
||||
name
|
||||
dataType
|
||||
}
|
||||
... on ProjectV2SingleSelectField {
|
||||
id
|
||||
name
|
||||
dataType
|
||||
options { id name }
|
||||
}
|
||||
... on ProjectV2IterationField {
|
||||
id
|
||||
name
|
||||
dataType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Field Data Types
|
||||
|
||||
| dataType | Description | Migrates to |
|
||||
|----------|-------------|-------------|
|
||||
| TEXT | Free-form text | `text` issue field |
|
||||
| SINGLE_SELECT | Dropdown with options | `single_select` issue field |
|
||||
| NUMBER | Numeric value | `number` issue field |
|
||||
| DATE | Date value | `date` issue field |
|
||||
| ITERATION | Sprint/iteration cycles | No equivalent (skip) |
|
||||
|
||||
## List Project Items (with field values)
|
||||
|
||||
### Via MCP Tool
|
||||
|
||||
```
|
||||
mcp__github__projects_list(
|
||||
owner: "{org}",
|
||||
project_number: {n},
|
||||
method: "list_project_items"
|
||||
)
|
||||
```
|
||||
|
||||
Returns paginated results. Each item includes:
|
||||
- Item type (ISSUE, DRAFT_ISSUE, PULL_REQUEST)
|
||||
- Content reference (repo owner, repo name, issue number)
|
||||
- Field values for all project fields
|
||||
|
||||
### Via GraphQL
|
||||
|
||||
```bash
|
||||
gh api graphql -f query='
|
||||
query($cursor: String) {
|
||||
organization(login: "ORG") {
|
||||
projectV2(number: N) {
|
||||
items(first: 100, after: $cursor) {
|
||||
pageInfo { hasNextPage endCursor }
|
||||
nodes {
|
||||
type
|
||||
content {
|
||||
... on Issue {
|
||||
number
|
||||
repository { nameWithOwner }
|
||||
}
|
||||
}
|
||||
fieldValues(first: 20) {
|
||||
pageInfo { hasNextPage endCursor }
|
||||
nodes {
|
||||
... on ProjectV2ItemFieldTextValue { text field { ... on ProjectV2Field { name } } }
|
||||
... on ProjectV2ItemFieldSingleSelectValue { name field { ... on ProjectV2SingleSelectField { name } } }
|
||||
... on ProjectV2ItemFieldNumberValue { number field { ... on ProjectV2Field { name } } }
|
||||
... on ProjectV2ItemFieldDateValue { date field { ... on ProjectV2Field { name } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -f cursor="$CURSOR"
|
||||
```
|
||||
|
||||
### Important Notes for Migration
|
||||
|
||||
- **Pagination**: projects can have up to 10,000 items. Always paginate using `pageInfo.hasNextPage` and `pageInfo.endCursor`.
|
||||
- **Draft items**: items with `type: DRAFT_ISSUE` have no real issue attached. Skip these during migration.
|
||||
- **Pull requests**: items with `type: PULL_REQUEST` are PRs, not issues. Issue fields apply to issues only. Skip these.
|
||||
- **Cross-repo**: a single project can contain issues from many repositories. Group items by repo to batch repo ID lookups.
|
||||
- **Field value access**: each field value node type is different (`ProjectV2ItemFieldTextValue`, `ProjectV2ItemFieldSingleSelectValue`, etc.). Handle each type.
|
||||
Reference in New Issue
Block a user