[!TIP]

[!NOTE|label:headers]

  • -H "Accept: application/vnd.github.v3+json"
  • -H "Authorization: token <TOKEN>"
  • -H "Authorization: Bearer <TOKEN>"
  • -H "Content-Type: application/json"
  • -H "Time-Zone: Europe/Amsterdam"
  • -H "X-GitHub-Api-Version: 2022-11-28"

user

get username from token

$ curl -s -H "Authorization: token <TOKEN>" https://api.github.com/user | jq -r .login
# or
$ curl -s -H "Authorization: Bearer <TOKEN>" https://api.github.com/user | jq -r .login

metadata

$ curl -sL https://api.github.com/meta | jq -r '.ssh_keys | .[]'
$ curl -sL https://api.github.com/meta | jq -r '.ssh_keys | .[]'  | sed -e 's/^/github.com /' >> ~/.ssh/know_hosts

repo

  • list all repos and permissions

    [!TIP]

    • list all repos: GET /user/repos
    • list repos in special /: GET /orgs/<ORG>/repos
    $ curl -sS -g -H "Authorization: Bearer <TOKEN>" \
           -H "Accept: application/vnd.github+json"
           'https://api.github.com/user/repos?per_page=100&type=all' |
      jq -r '.[] | select(.permissions != null)
                 | (
                     if   p.admin     then "ADMIN"
                     elif p.maintain  then "MAINTAIN"
                     elif p.push      then "WRITE"
                     elif p.triage    then "TRIAGE"
                     elif p.pull      then "READ"
                     else "NONE" end
                   )
                   + "\t" + .html_url' |
      sort
    
  • get repo info

    [!TIP] GET /repos/{owner}/{repo}

    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook
    
  • get repo contributors

    [!TIP] GET /repos/{owner}/{repo}/contributors

    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook/contributors
    

pull request

  • get pull request info

    [!TIP] GET /repos/{owner}/{repo}/pulls/{pull_number}

    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook/pulls/1
    
  • get comments of a pull request

    [!TIP] GET /repos/{owner}/{repo}/issues/{issue_number}/comments

    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook/issues/1/comments
    

branches

get branches

[!TIP] GET /repos/{owner}/{repo}/branches

# i.e.:
$ curl -fsSL https://api.github.com/repos/marslo/ibook/branches

get details of a branch

[!TIP] GET /repos/{owner}/{repo}/branches/{branch}

# i.e.:
$ curl -fsSL https://api.github.com/repos/marslo/ibook/branches/main

revision and tags

get commits

[!TIP|label:API] GET /repos/{owner}/{repo}/commits

$ curl -fsSL https://api.github.com/repos/<OWNER>/<REPO>/commits

# i.e.:
$ curl -fsSL https://api.github.com/repos/marslo/ibook/commits

post commit status

[!TIP|label:API] POST repos/${OWNER}/${REPO}/statuses/${sha}

$ curl -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
       -H "Accept: application/vnd.github+json" \
       https://api.github.com/repos/${OWNER}/${REPO}/statuses/${SHA} \
       -d '{
         "state": "success",
         "target_url": "https://ci.example.com/build/status/123",
         "description": "All tests passed",
         "context": "ci/build"
       }'

get HEAD of branch

[!TIP|label:API] GET /repos/{owner}/{repo}/git/refs/heads/{branch}

$ curl -fsSL https://api.github.com/repos/<OWNER>/<REPO>/git/refs/heads/<BRANCH>
# i.e.:
$ curl -fsSL https://api.github.com/repos/marslo/ibook/git/refs/heads/marslo --jq .object.sha

$ gh api "repos/<OWNER>/<REPO>/refs/heads/<BRANCH>"
# i.e.:
$ gh api "repos/marslo/ibook/git/refs/heads/marslo" --jq .object.sha

get revision info

[!TIP|label:API] GET /repos/{owner}/{repo}/commits/{sha}

$ gh api repos/{owner}/{repo}/commits/{sha}

# i.e.:
$ gh api repos/${OWNER}/${REPO}/commits/{sha} \
     --jq '[
            "revision: \(.sha)",
            "author: \(.commit.author.name) <\(.commit.author.email)> - \(.commit.author.date)",
            "committer: \(.commit.committer.name) <\(.commit.committer.email)> - \(.commit.committer.date)",
            {message: (.commit.message | split("\n")) }
           ]'

actions runners

  • list workflow runs

    [!TIP|label:API] GET /repos/{owner}/{repo}/actions/runs

    $ curl -fsSL https://api.github.com/repos/<OWNER>/<REPO>/actions/runs
    
    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook/actions/runs
    
  • get workflow run logs

    [!TIP|label:API] GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs

    $ curl -fsSL https://api.github.com/repos/<OWNER>/<REPO>/actions/runs/<RUN_ID>/logs
    
    # i.e.:
    $ curl -fsSL https://api.github.com/repos/marslo/ibook/actions/runs/1234567890/logs
    
  • trigger workflow run

    [!TIP|label:API] POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches

    # i.e.:
    $ curl -X POST -H "Accept: application/vnd.github.v3+json" \
      -H "Authorization: token ghp_v**********************************n" \
      https://api.github.com/repos/marslo/ibook/actions/workflows/ci.yml/dispatches \
      -d '{"ref":"main"}'
    

releases

release version

$ curl --silent 'https://api.github.com/repos/<owner>/<repo>/releases/latest' | jq -r .tag_name

# i.e.:
$ curl --silent 'https://api.github.com/repos/sharkdp/bat/releases/latest' | jq -r .tag_name

branch protection

[!NOTE|label:references:]

get branch protection

[!TIP|label:API] GET /repos/{owner}/{repo}/branches/{branch}/protection

$ gh api "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection"

init branch protection

$ lock=true
$ jq -n --argjson lock "${lock}" '{
    required_status_checks: null,
    required_pull_request_reviews: null,
    restrictions: null,
    enforce_admins: $lock,
    lock_branch: $lock
  }' |
  gh api -X PUT -H "Accept: application/vnd.github+json" \
     "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection" --input -

update lock_branch status

[!TIP|label:jq tricy]

$ jq -n '.var1=true | .var2=false'
{
  "var1": true,
  "var2": false
}
$ lock=true  # or false

# read current settings
$ base=$(gh api -H "Accept: application/vnd.github+json" "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection")

# update lock_branch and enforce_admins only, and keep other settings unchanged ( dyanamically get keys and values )
$ jq -n \
     --argjson base "$base" \
     --argjson lock "$lock" '
     (
       $base
       | del( .url )
       | with_entries(
           if ( .value | type=="object" and has("enabled") )
           then { key: .key, value: (.value.enabled // false) }
           else .
           end
         )
     )
     | .lock_branch                   = $lock
     | .enforce_admins                = $lock
     | .required_status_checks        = $base.required_status_checks
     | .required_pull_request_reviews = $base.required_pull_request_reviews
     | .restrictions                  = $base.restrictions
  ' |
  gh api -X PUT -H "Accept: application/vnd.github+json" \
     "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection" --input -

[!TIP|label:jq tricy] $ jq -n '{var1:true, var2:false}' { "var1": true, "var2": false }

$ lock=true  # or false

# read current settings
$ base=$(gh api -H "Accept: application/vnd.github+json" "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection")

# update lock_branch and enforce_admins only
$ jq -n \
     --argjson base "${base}" \
     --argjson lock "${lock}" \
  '{
    required_status_checks:           $base.required_status_checks,
    required_pull_request_reviews:    $base.required_pull_request_reviews,
    restrictions:                     $base.restrictions,

    enforce_admins:                   $lock,
    lock_branch:                      $lock,

    required_linear_history:          ( $base.required_linear_history.enabled // false ),
    allow_force_pushes:               ( $base.allow_force_pushes.enabled // false ),
    allow_deletions:                  ( $base.allow_deletions.enabled // false ),
    block_creations:                  ( $base.block_creations.enabled // false ),
    required_conversation_resolution: ( $base.required_conversation_resolution.enabled // false ),
    allow_fork_syncing:               ( $base.allow_fork_syncing.enabled // false )
  }' |
  gh api -X PUT \
     -H "Accept: application/vnd.github+json" \
     "repos/${OWNER}/${REPO}/branches/${BRANCH}/protection" --input -

rulesets

[!NOTE|label:references:]

list all rulesets

$ gh api "repos/{owner}/{repo}/rulesets"

# or: list id and name
$ gh api "repos/{owner}/{repo}/rulesets" | jq -r '.[] | (.id|tostring) + ": " + .name'
7288536: BranchDeleteRule
7288533: BranchNamingRule
7288566: PRRuleSet

update ruleset

[!NOTE|label:references:]

  • get current rulesets

    [!TIP|label:API] GET /repos/{owner}/{repo}/rulesets/{ruleset_id}

    $ gh api \
        -H 'Accept: application/vnd.github+json' \
        -H 'X-GitHub-Api-Version: 2022-11-28' \
        "/repos/${OWNER}/${REPO}/rulesets/${RULESET_ID}" > ruleset.org.json
    
  • create new ruleset json

    $ branch='refs/heads/devel'
    $ jq --arg ref "${BRANCH}" '{
        name, target, enforcement, bypass_actors, rules,
        conditions: {
          ref_name: {
            include: ( .conditions.ref_name.include // ["~ALL"] ),
            exclude: ( (.conditions.ref_name.exclude // []) + [$ref] | unique )
          }
        }
      }' "ruleset" > "ruleset.new.json"
    
  • update ruleset

    [!TIP|label:API] PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}

    $ gh api -X PUT \
        -H 'Accept: application/vnd.github+json' \
        -H 'X-GitHub-Api-Version: 2022-11-28' \
        "/repos/${OWNER}/${REPO}/rulesets/${RULSET_ID}" \
        --input "ruleset.new.json"
    

rulsets update history

[!NOTE|label:references:]

rule suites

[!NOTE|label:references:]

list failure rule suites

$ gh api -H 'X-GitHub-Api-Version: 2022-11-28' \
  "/repos/${OWNER}/${REPO}/rulesets/rule-suites?ref=refs/heads/${BRANCH}&time_period=week"

# or
$ gh api -H 'X-GitHub-Api-Version: 2022-11-28' \
  "/repos/${OWNER}/${REPO}/rulesets/rule-suites?ref=refs/heads/${BRANCH}&time_period=week" \
  --jq '.[] | {id, ref, pushed_at, actor_name, result}'
sample result
{
  "actor_name": "username",
  "id": 1445681219,
  "pushed_at": "2025-09-17T16:23:14-07:00",
  "ref": "refs/heads/devel",
  "result": "pass"
}
{
  "actor_name": "username",
  "id": 1445649205,
  "pushed_at": "2025-09-17T16:10:30-07:00",
  "ref": "refs/heads/devel",
  "result": "fail"
}
{
  "actor_name": "username",
  "id": 1445570037,
  "pushed_at": "2025-09-17T15:44:01-07:00",
  "ref": "refs/heads/devel",
  "result": "fail"
}

check failure evaluations

$ gh api -H 'X-GitHub-Api-Version: 2022-11-28' "/repos/${OWNER}/${REPO}/rulesets/rule-suites/${RULE_SUITE_ID}"

# or list only failure evaluations
$ gh api -H 'X-GitHub-Api-Version: 2022-11-28' \
  "/repos/${OWNER}/${REPO}/rulesets/rule-suites/${RULE_SUITE_ID}" \
  --jq '.rule_evaluations[] | select(.result=="fail")'

# or
$ gh api -H 'X-GitHub-Api-Version: 2022-11-28' \
  "/repos/${OWNER}/${REPO}/rulesets/rule-suites/${RULE_SUITE_ID}" \
  --jq '{ref, result, failed_rules: (.rule_evaluations | map(select(.result=="fail")))}'
failure evaluations result
{
  "details": "Cannot create ref due to creations being restricted.",
  "enforcement": "active",
  "result": "fail",
  "rule_source": {
    "id": 7288533,
    "name": "BranchNamingRule",
    "type": "ruleset"
  },
  "rule_type": "creation"
}
{
  "details": "2 of 2 required status checks are expected.",
  "enforcement": "active",
  "result": "fail",
  "rule_source": {
    "id": 7288566,
    "name": "PRRuleSet",
    "type": "ruleset"
  },
  "rule_type": "required_status_checks"
}

have fun

emoji

$ curl -fsSL -XGET https://api.github.com/emojis

zen

$ curl -fsSL -XGET https://api.github.com/zen

octocat

$ curl -fsSL -XGET https://api.github.com/octocat

rate limit

$ curl -fsSL -XGET https://api.github.com/rate_limit
Copyright © marslo 2020-2025 all right reserved,powered by GitbookLast Modified: 2025-09-17 23:43:49

results matching ""

    No results matching ""