Setup hermes sync with memories and github skill
This commit is contained in:
515
skills/github/github-repo-management/SKILL.md
Normal file
515
skills/github/github-repo-management/SKILL.md
Normal file
@@ -0,0 +1,515 @@
|
||||
---
|
||||
name: github-repo-management
|
||||
description: Clone, create, fork, configure, and manage GitHub repositories. Manage remotes, secrets, releases, and workflows. Works with gh CLI or falls back to git + GitHub REST API via curl.
|
||||
version: 1.1.0
|
||||
author: Hermes Agent
|
||||
license: MIT
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [GitHub, Repositories, Git, Releases, Secrets, Configuration]
|
||||
related_skills: [github-auth, github-pr-workflow, github-issues]
|
||||
---
|
||||
|
||||
# GitHub Repository Management
|
||||
|
||||
Create, clone, fork, configure, and manage GitHub repositories. Each section shows `gh` first, then the `git` + `curl` fallback.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Authenticated with GitHub (see `github-auth` skill)
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
if command -v gh &>/dev/null && gh auth status &>/dev/null; then
|
||||
AUTH="gh"
|
||||
else
|
||||
AUTH="git"
|
||||
if [ -z "$GITHUB_TOKEN" ]; then
|
||||
if [ -f ~/.hermes/.env ] && grep -q "^GITHUB_TOKEN=" ~/.hermes/.env; then
|
||||
GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" ~/.hermes/.env | head -1 | cut -d= -f2 | tr -d '\n\r')
|
||||
elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then
|
||||
GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get your GitHub username (needed for several operations)
|
||||
if [ "$AUTH" = "gh" ]; then
|
||||
GH_USER=$(gh api user --jq '.login')
|
||||
else
|
||||
GH_USER=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | python3 -c "import sys,json; print(json.load(sys.stdin)['login'])")
|
||||
fi
|
||||
```
|
||||
|
||||
If you're inside a repo already:
|
||||
|
||||
```bash
|
||||
REMOTE_URL=$(git remote get-url origin)
|
||||
OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github\.com[:/]||; s|\.git$||')
|
||||
OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1)
|
||||
REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Cloning Repositories
|
||||
|
||||
Cloning is pure `git` — works identically either way:
|
||||
|
||||
```bash
|
||||
# Clone via HTTPS (works with credential helper or token-embedded URL)
|
||||
git clone https://github.com/owner/repo-name.git
|
||||
|
||||
# Clone into a specific directory
|
||||
git clone https://github.com/owner/repo-name.git ./my-local-dir
|
||||
|
||||
# Shallow clone (faster for large repos)
|
||||
git clone --depth 1 https://github.com/owner/repo-name.git
|
||||
|
||||
# Clone a specific branch
|
||||
git clone --branch develop https://github.com/owner/repo-name.git
|
||||
|
||||
# Clone via SSH (if SSH is configured)
|
||||
git clone git@github.com:owner/repo-name.git
|
||||
```
|
||||
|
||||
**With gh (shorthand):**
|
||||
|
||||
```bash
|
||||
gh repo clone owner/repo-name
|
||||
gh repo clone owner/repo-name -- --depth 1
|
||||
```
|
||||
|
||||
## 2. Creating Repositories
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
# Create a public repo and clone it
|
||||
gh repo create my-new-project --public --clone
|
||||
|
||||
# Private, with description and license
|
||||
gh repo create my-new-project --private --description "A useful tool" --license MIT --clone
|
||||
|
||||
# Under an organization
|
||||
gh repo create my-org/my-new-project --public --clone
|
||||
|
||||
# From existing local directory
|
||||
cd /path/to/existing/project
|
||||
gh repo create my-project --source . --public --push
|
||||
```
|
||||
|
||||
**With git + curl:**
|
||||
|
||||
```bash
|
||||
# Create the remote repo via API
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/user/repos \
|
||||
-d '{
|
||||
"name": "my-new-project",
|
||||
"description": "A useful tool",
|
||||
"private": false,
|
||||
"auto_init": true,
|
||||
"license_template": "mit"
|
||||
}'
|
||||
|
||||
# Clone it
|
||||
git clone https://github.com/$GH_USER/my-new-project.git
|
||||
cd my-new-project
|
||||
|
||||
# -- OR -- push an existing local directory to the new repo
|
||||
cd /path/to/existing/project
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git remote add origin https://github.com/$GH_USER/my-new-project.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
To create under an organization:
|
||||
|
||||
```bash
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/orgs/my-org/repos \
|
||||
-d '{"name": "my-new-project", "private": false}'
|
||||
```
|
||||
|
||||
### From a Template
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh repo create my-new-app --template owner/template-repo --public --clone
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/owner/template-repo/generate \
|
||||
-d '{"owner": "'"$GH_USER"'", "name": "my-new-app", "private": false}'
|
||||
```
|
||||
|
||||
## 3. Forking Repositories
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh repo fork owner/repo-name --clone
|
||||
```
|
||||
|
||||
**With git + curl:**
|
||||
|
||||
```bash
|
||||
# Create the fork via API
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/owner/repo-name/forks
|
||||
|
||||
# Wait a moment for GitHub to create it, then clone
|
||||
sleep 3
|
||||
git clone https://github.com/$GH_USER/repo-name.git
|
||||
cd repo-name
|
||||
|
||||
# Add the original repo as "upstream" remote
|
||||
git remote add upstream https://github.com/owner/repo-name.git
|
||||
```
|
||||
|
||||
### Keeping a Fork in Sync
|
||||
|
||||
```bash
|
||||
# Pure git — works everywhere
|
||||
git fetch upstream
|
||||
git checkout main
|
||||
git merge upstream/main
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**With gh (shortcut):**
|
||||
|
||||
```bash
|
||||
gh repo sync $GH_USER/repo-name
|
||||
```
|
||||
|
||||
## 4. Repository Information
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh repo view owner/repo-name
|
||||
gh repo list --limit 20
|
||||
gh search repos "machine learning" --language python --sort stars
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
# View repo details
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
r = json.load(sys.stdin)
|
||||
print(f\"Name: {r['full_name']}\")
|
||||
print(f\"Description: {r['description']}\")
|
||||
print(f\"Stars: {r['stargazers_count']} Forks: {r['forks_count']}\")
|
||||
print(f\"Default branch: {r['default_branch']}\")
|
||||
print(f\"Language: {r['language']}\")"
|
||||
|
||||
# List your repos
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/user/repos?per_page=20&sort=updated" \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for r in json.load(sys.stdin):
|
||||
vis = 'private' if r['private'] else 'public'
|
||||
print(f\" {r['full_name']:40} {vis:8} {r.get('language', ''):10} ★{r['stargazers_count']}\")"
|
||||
|
||||
# Search repos
|
||||
curl -s \
|
||||
"https://api.github.com/search/repositories?q=machine+learning+language:python&sort=stars&per_page=10" \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for r in json.load(sys.stdin)['items']:
|
||||
print(f\" {r['full_name']:40} ★{r['stargazers_count']:6} {r['description'][:60] if r['description'] else ''}\")"
|
||||
```
|
||||
|
||||
## 5. Repository Settings
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh repo edit --description "Updated description" --visibility public
|
||||
gh repo edit --enable-wiki=false --enable-issues=true
|
||||
gh repo edit --default-branch main
|
||||
gh repo edit --add-topic "machine-learning,python"
|
||||
gh repo edit --enable-auto-merge
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
curl -s -X PATCH \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO \
|
||||
-d '{
|
||||
"description": "Updated description",
|
||||
"has_wiki": false,
|
||||
"has_issues": true,
|
||||
"allow_auto_merge": true
|
||||
}'
|
||||
|
||||
# Update topics
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.mercy-preview+json" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/topics \
|
||||
-d '{"names": ["machine-learning", "python", "automation"]}'
|
||||
```
|
||||
|
||||
## 6. Branch Protection
|
||||
|
||||
```bash
|
||||
# View current protection
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/branches/main/protection
|
||||
|
||||
# Set up branch protection
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/branches/main/protection \
|
||||
-d '{
|
||||
"required_status_checks": {
|
||||
"strict": true,
|
||||
"contexts": ["ci/test", "ci/lint"]
|
||||
},
|
||||
"enforce_admins": false,
|
||||
"required_pull_request_reviews": {
|
||||
"required_approving_review_count": 1
|
||||
},
|
||||
"restrictions": null
|
||||
}'
|
||||
```
|
||||
|
||||
## 7. Secrets Management (GitHub Actions)
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh secret set API_KEY --body "your-secret-value"
|
||||
gh secret set SSH_KEY < ~/.ssh/id_rsa
|
||||
gh secret list
|
||||
gh secret delete API_KEY
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
Secrets require encryption with the repo's public key — more involved via API:
|
||||
|
||||
```bash
|
||||
# Get the repo's public key for encrypting secrets
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/secrets/public-key
|
||||
|
||||
# Encrypt and set (requires Python with PyNaCl)
|
||||
python3 -c "
|
||||
from base64 import b64encode
|
||||
from nacl import encoding, public
|
||||
import json, sys
|
||||
|
||||
# Get the public key
|
||||
key_id = '<key_id_from_above>'
|
||||
public_key = '<base64_key_from_above>'
|
||||
|
||||
# Encrypt
|
||||
sealed = public.SealedBox(
|
||||
public.PublicKey(public_key.encode('utf-8'), encoding.Base64Encoder)
|
||||
).encrypt('your-secret-value'.encode('utf-8'))
|
||||
print(json.dumps({
|
||||
'encrypted_value': b64encode(sealed).decode('utf-8'),
|
||||
'key_id': key_id
|
||||
}))"
|
||||
|
||||
# Then PUT the encrypted secret
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/secrets/API_KEY \
|
||||
-d '<output from python script above>'
|
||||
|
||||
# List secrets (names only, values hidden)
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/secrets \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for s in json.load(sys.stdin)['secrets']:
|
||||
print(f\" {s['name']:30} updated: {s['updated_at']}\")"
|
||||
```
|
||||
|
||||
Note: For secrets, `gh secret set` is dramatically simpler. If setting secrets is needed and `gh` isn't available, recommend installing it for just that operation.
|
||||
|
||||
## 8. Releases
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh release create v1.0.0 --title "v1.0.0" --generate-notes
|
||||
gh release create v2.0.0-rc1 --draft --prerelease --generate-notes
|
||||
gh release create v1.0.0 ./dist/binary --title "v1.0.0" --notes "Release notes"
|
||||
gh release list
|
||||
gh release download v1.0.0 --dir ./downloads
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
# Create a release
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/releases \
|
||||
-d '{
|
||||
"tag_name": "v1.0.0",
|
||||
"name": "v1.0.0",
|
||||
"body": "## Changelog\n- Feature A\n- Bug fix B",
|
||||
"draft": false,
|
||||
"prerelease": false,
|
||||
"generate_release_notes": true
|
||||
}'
|
||||
|
||||
# List releases
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/releases \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for r in json.load(sys.stdin):
|
||||
tag = r.get('tag_name', 'no tag')
|
||||
print(f\" {tag:15} {r['name']:30} {'draft' if r['draft'] else 'published'}\")"
|
||||
|
||||
# Upload a release asset (binary file)
|
||||
RELEASE_ID=<id_from_create_response>
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
"https://uploads.github.com/repos/$OWNER/$REPO/releases/$RELEASE_ID/assets?name=binary-amd64" \
|
||||
--data-binary @./dist/binary-amd64
|
||||
```
|
||||
|
||||
## 9. GitHub Actions Workflows
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh workflow list
|
||||
gh run list --limit 10
|
||||
gh run view <RUN_ID>
|
||||
gh run view <RUN_ID> --log-failed
|
||||
gh run rerun <RUN_ID>
|
||||
gh run rerun <RUN_ID> --failed
|
||||
gh workflow run ci.yml --ref main
|
||||
gh workflow run deploy.yml -f environment=staging
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
# List workflows
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/workflows \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for w in json.load(sys.stdin)['workflows']:
|
||||
print(f\" {w['id']:10} {w['name']:30} {w['state']}\")"
|
||||
|
||||
# List recent runs
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?per_page=10" \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for r in json.load(sys.stdin)['workflow_runs']:
|
||||
print(f\" Run {r['id']} {r['name']:30} {r['conclusion'] or r['status']}\")"
|
||||
|
||||
# Download failed run logs
|
||||
RUN_ID=<run_id>
|
||||
curl -s -L \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/logs \
|
||||
-o /tmp/ci-logs.zip
|
||||
cd /tmp && unzip -o ci-logs.zip -d ci-logs
|
||||
|
||||
# Re-run a failed workflow
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/rerun
|
||||
|
||||
# Re-run only failed jobs
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/runs/$RUN_ID/rerun-failed-jobs
|
||||
|
||||
# Trigger a workflow manually (workflow_dispatch)
|
||||
WORKFLOW_ID=<workflow_id_or_filename>
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$OWNER/$REPO/actions/workflows/$WORKFLOW_ID/dispatches \
|
||||
-d '{"ref": "main", "inputs": {"environment": "staging"}}'
|
||||
```
|
||||
|
||||
## 10. Gists
|
||||
|
||||
**With gh:**
|
||||
|
||||
```bash
|
||||
gh gist create script.py --public --desc "Useful script"
|
||||
gh gist list
|
||||
```
|
||||
|
||||
**With curl:**
|
||||
|
||||
```bash
|
||||
# Create a gist
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/gists \
|
||||
-d '{
|
||||
"description": "Useful script",
|
||||
"public": true,
|
||||
"files": {
|
||||
"script.py": {"content": "print(\"hello\")"}
|
||||
}
|
||||
}'
|
||||
|
||||
# List your gists
|
||||
curl -s \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/gists \
|
||||
| python3 -c "
|
||||
import sys, json
|
||||
for g in json.load(sys.stdin):
|
||||
files = ', '.join(g['files'].keys())
|
||||
print(f\" {g['id']} {g['description'] or '(no desc)':40} {files}\")"
|
||||
```
|
||||
|
||||
## Quick Reference Table
|
||||
|
||||
| Action | gh | git + curl |
|
||||
|--------|-----|-----------|
|
||||
| Clone | `gh repo clone o/r` | `git clone https://github.com/o/r.git` |
|
||||
| Create repo | `gh repo create name --public` | `curl POST /user/repos` |
|
||||
| Fork | `gh repo fork o/r --clone` | `curl POST /repos/o/r/forks` + `git clone` |
|
||||
| Repo info | `gh repo view o/r` | `curl GET /repos/o/r` |
|
||||
| Edit settings | `gh repo edit --...` | `curl PATCH /repos/o/r` |
|
||||
| Create release | `gh release create v1.0` | `curl POST /repos/o/r/releases` |
|
||||
| List workflows | `gh workflow list` | `curl GET /repos/o/r/actions/workflows` |
|
||||
| Rerun CI | `gh run rerun ID` | `curl POST /repos/o/r/actions/runs/ID/rerun` |
|
||||
| Set secret | `gh secret set KEY` | `curl PUT /repos/o/r/actions/secrets/KEY` (+ encryption) |
|
||||
@@ -0,0 +1,161 @@
|
||||
# GitHub REST API Cheatsheet
|
||||
|
||||
Base URL: `https://api.github.com`
|
||||
|
||||
All requests need: `-H "Authorization: token $GITHUB_TOKEN"`
|
||||
|
||||
Use the `gh-env.sh` helper to set `$GITHUB_TOKEN`, `$GH_OWNER`, `$GH_REPO` automatically:
|
||||
```bash
|
||||
source ~/.hermes/skills/github/github-auth/scripts/gh-env.sh
|
||||
```
|
||||
|
||||
## Repositories
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| Get repo info | GET | `/repos/{owner}/{repo}` |
|
||||
| Create repo (user) | POST | `/user/repos` |
|
||||
| Create repo (org) | POST | `/orgs/{org}/repos` |
|
||||
| Update repo | PATCH | `/repos/{owner}/{repo}` |
|
||||
| Delete repo | DELETE | `/repos/{owner}/{repo}` |
|
||||
| List your repos | GET | `/user/repos?per_page=30&sort=updated` |
|
||||
| List org repos | GET | `/orgs/{org}/repos` |
|
||||
| Fork repo | POST | `/repos/{owner}/{repo}/forks` |
|
||||
| Create from template | POST | `/repos/{owner}/{template}/generate` |
|
||||
| Get topics | GET | `/repos/{owner}/{repo}/topics` |
|
||||
| Set topics | PUT | `/repos/{owner}/{repo}/topics` |
|
||||
|
||||
## Pull Requests
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| List PRs | GET | `/repos/{owner}/{repo}/pulls?state=open` |
|
||||
| Create PR | POST | `/repos/{owner}/{repo}/pulls` |
|
||||
| Get PR | GET | `/repos/{owner}/{repo}/pulls/{number}` |
|
||||
| Update PR | PATCH | `/repos/{owner}/{repo}/pulls/{number}` |
|
||||
| List PR files | GET | `/repos/{owner}/{repo}/pulls/{number}/files` |
|
||||
| Merge PR | PUT | `/repos/{owner}/{repo}/pulls/{number}/merge` |
|
||||
| Request reviewers | POST | `/repos/{owner}/{repo}/pulls/{number}/requested_reviewers` |
|
||||
| Create review | POST | `/repos/{owner}/{repo}/pulls/{number}/reviews` |
|
||||
| Inline comment | POST | `/repos/{owner}/{repo}/pulls/{number}/comments` |
|
||||
|
||||
### PR Merge Body
|
||||
|
||||
```json
|
||||
{"merge_method": "squash", "commit_title": "feat: description (#N)"}
|
||||
```
|
||||
|
||||
Merge methods: `"merge"`, `"squash"`, `"rebase"`
|
||||
|
||||
### PR Review Events
|
||||
|
||||
`"APPROVE"`, `"REQUEST_CHANGES"`, `"COMMENT"`
|
||||
|
||||
## Issues
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| List issues | GET | `/repos/{owner}/{repo}/issues?state=open` |
|
||||
| Create issue | POST | `/repos/{owner}/{repo}/issues` |
|
||||
| Get issue | GET | `/repos/{owner}/{repo}/issues/{number}` |
|
||||
| Update issue | PATCH | `/repos/{owner}/{repo}/issues/{number}` |
|
||||
| Add comment | POST | `/repos/{owner}/{repo}/issues/{number}/comments` |
|
||||
| Add labels | POST | `/repos/{owner}/{repo}/issues/{number}/labels` |
|
||||
| Remove label | DELETE | `/repos/{owner}/{repo}/issues/{number}/labels/{name}` |
|
||||
| Add assignees | POST | `/repos/{owner}/{repo}/issues/{number}/assignees` |
|
||||
| List labels | GET | `/repos/{owner}/{repo}/labels` |
|
||||
| Search issues | GET | `/search/issues?q={query}+repo:{owner}/{repo}` |
|
||||
|
||||
Note: The Issues API also returns PRs. Filter with `"pull_request" not in item` when parsing.
|
||||
|
||||
## CI / GitHub Actions
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| List workflows | GET | `/repos/{owner}/{repo}/actions/workflows` |
|
||||
| List runs | GET | `/repos/{owner}/{repo}/actions/runs?per_page=10` |
|
||||
| List runs (branch) | GET | `/repos/{owner}/{repo}/actions/runs?branch={branch}` |
|
||||
| Get run | GET | `/repos/{owner}/{repo}/actions/runs/{run_id}` |
|
||||
| Download logs | GET | `/repos/{owner}/{repo}/actions/runs/{run_id}/logs` |
|
||||
| Re-run | POST | `/repos/{owner}/{repo}/actions/runs/{run_id}/rerun` |
|
||||
| Re-run failed | POST | `/repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs` |
|
||||
| Trigger dispatch | POST | `/repos/{owner}/{repo}/actions/workflows/{id}/dispatches` |
|
||||
| Commit status | GET | `/repos/{owner}/{repo}/commits/{sha}/status` |
|
||||
| Check runs | GET | `/repos/{owner}/{repo}/commits/{sha}/check-runs` |
|
||||
|
||||
## Releases
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| List releases | GET | `/repos/{owner}/{repo}/releases` |
|
||||
| Create release | POST | `/repos/{owner}/{repo}/releases` |
|
||||
| Get release | GET | `/repos/{owner}/{repo}/releases/{id}` |
|
||||
| Delete release | DELETE | `/repos/{owner}/{repo}/releases/{id}` |
|
||||
| Upload asset | POST | `https://uploads.github.com/repos/{owner}/{repo}/releases/{id}/assets?name={filename}` |
|
||||
|
||||
## Secrets
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| List secrets | GET | `/repos/{owner}/{repo}/actions/secrets` |
|
||||
| Get public key | GET | `/repos/{owner}/{repo}/actions/secrets/public-key` |
|
||||
| Set secret | PUT | `/repos/{owner}/{repo}/actions/secrets/{name}` |
|
||||
| Delete secret | DELETE | `/repos/{owner}/{repo}/actions/secrets/{name}` |
|
||||
|
||||
## Branch Protection
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| Get protection | GET | `/repos/{owner}/{repo}/branches/{branch}/protection` |
|
||||
| Set protection | PUT | `/repos/{owner}/{repo}/branches/{branch}/protection` |
|
||||
| Delete protection | DELETE | `/repos/{owner}/{repo}/branches/{branch}/protection` |
|
||||
|
||||
## User / Auth
|
||||
|
||||
| Action | Method | Endpoint |
|
||||
|--------|--------|----------|
|
||||
| Get current user | GET | `/user` |
|
||||
| List user repos | GET | `/user/repos` |
|
||||
| List user gists | GET | `/gists` |
|
||||
| Create gist | POST | `/gists` |
|
||||
| Search repos | GET | `/search/repositories?q={query}` |
|
||||
|
||||
## Pagination
|
||||
|
||||
Most list endpoints support:
|
||||
- `?per_page=100` (max 100)
|
||||
- `?page=2` for next page
|
||||
- Check `Link` header for `rel="next"` URL
|
||||
|
||||
## Rate Limits
|
||||
|
||||
- Authenticated: 5,000 requests/hour
|
||||
- Check remaining: `curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/rate_limit`
|
||||
|
||||
## Common curl Patterns
|
||||
|
||||
```bash
|
||||
# GET
|
||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$GH_OWNER/$GH_REPO
|
||||
|
||||
# POST with JSON body
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$GH_OWNER/$GH_REPO/issues \
|
||||
-d '{"title": "...", "body": "..."}'
|
||||
|
||||
# PATCH (update)
|
||||
curl -s -X PATCH \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$GH_OWNER/$GH_REPO/issues/42 \
|
||||
-d '{"state": "closed"}'
|
||||
|
||||
# DELETE
|
||||
curl -s -X DELETE \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
https://api.github.com/repos/$GH_OWNER/$GH_REPO/issues/42/labels/bug
|
||||
|
||||
# Parse JSON response with python3
|
||||
curl -s ... | python3 -c "import sys,json; data=json.load(sys.stdin); print(data['field'])"
|
||||
```
|
||||
Reference in New Issue
Block a user