The convenience modules are thin wrappers over GhEx.REST that fill in the
endpoint path. Each function returns the same {:ok, body, meta} /
{:error, reason} shape as the core and passes opts through to Req (so
:params, headers, and a Req.Test plug all work). They cover the common paths;
for anything else, call GhEx.REST directly or follow the
Extending gh_ex guide to build an application-owned resource
module.
On the write wrappers (create, update, merge, and the like), the attrs
argument is the sole request body: each sets :json to attrs, so a :json
passed in opts is ignored.
The list_* functions return a single page. Each has a stream_* companion
that auto-paginates into a lazy Stream of individual items, following
Link: rel="next" (see the Pagination guide). The wrapped
endpoints (Search, Actions runs/workflows/jobs, Checks) unwrap their array key
for you.
# every open issue, not just the first page
client
|> GhEx.Issues.stream("elixir-lang", "elixir", params: [state: "open", per_page: 100])
|> Stream.map(& &1["number"])
|> Enum.to_list()For a path without a stream_* wrapper, call GhEx.REST.stream/3 directly with
the path and, for an object-wrapped response, the items: key.
Issues
GhEx.Issues — list, get, create, update, create or edit comments, mutate
assignees, manage the repository label vocabulary, and add, remove, or replace
labels on issues.
GhEx.Issues.list(client, "elixir-lang", "elixir", params: [state: "open"])
GhEx.Issues.create(client, "o", "r", %{title: "Bug", body: "..."})
GhEx.Issues.create_comment(client, "o", "r", 7, "thanks for the report")
GhEx.Issues.update_comment(client, "o", "r", comment_id, "build is green")
GhEx.Issues.add_assignees(client, "o", "r", 7, ["octocat"])
GhEx.Issues.remove_assignees(client, "o", "r", 7, ["hubot"])
GhEx.Issues.stream_labels(client, "o", "r") |> Enum.take(100)
GhEx.Issues.create_label(client, "o", "r", %{name: "priority:high", color: "d93f0b"})
GhEx.Issues.update_label(client, "o", "r", "priority:high", %{description: "Address next"})
GhEx.Issues.add_labels(client, "o", "r", 7, ["bug", "p1"])
GhEx.Issues.remove_label(client, "o", "r", 7, "needs triage")
GhEx.Issues.replace_all_labels(client, "o", "r", 7, ["confirmed", "p1"])Pull requests
GhEx.PullRequests — list, get, create, update, synchronous and asynchronous
merge, merge status, commits, raw diff/patch, files, review requests, reviews,
and line-anchored review comments.
GhEx.Stacks — list, get, create, add, and unstack pull request stacks. See the
Stacked pull requests guide for the asynchronous merge flow and
GraphQL/webhook fields.
GhEx.PullRequests.create(client, "o", "r", %{title: "Fix", head: "fix", base: "main"})
{:ok, merged?, _meta} = GhEx.PullRequests.is_merged(client, "o", "r", 42)
GhEx.PullRequests.list_commits(client, "o", "r", 42)
GhEx.PullRequests.list_files(client, "o", "r", 42)
GhEx.PullRequests.get_diff(client, "o", "r", 42)
GhEx.PullRequests.merge(client, "o", "r", 42, %{merge_method: "squash"})
GhEx.PullRequests.request_reviewers(client, "o", "r", 42, %{reviewers: ["octocat"]})
GhEx.PullRequests.create_review(client, "o", "r", 42, %{event: "APPROVE"})
GhEx.Stacks.create(client, "o", "r", %{pull_requests: [41, 42]})
GhEx.PullRequests.merge_async(client, "o", "r", 42, %{merge_action: "default"})
GhEx.PullRequests.create_comment(client, "o", "r", 42, %{
body: "Please handle nil.", commit_id: sha, path: "lib/a.ex", line: 12, side: "RIGHT"
})Repositories and contents
GhEx.Repositories — get, list (org/user), create, update, delete, collaborator
authorization, commits, branches, and ETag-conditional event polling.
GhEx.Contents — read and write files.
GhEx.Repositories.get(client, "elixir-lang", "elixir")
GhEx.Repositories.list_for_org(client, "elixir-lang", params: [type: "public"])
{:ok, is_collaborator, _meta} = GhEx.Repositories.is_collaborator(client, "o", "r", actor)
{:ok, permission, _meta} = GhEx.Repositories.get_collaborator_permission(client, "o", "r", actor)
{:ok, events, meta} = GhEx.Repositories.events(client, "o", "r")
case GhEx.Repositories.events(client, "o", "r", headers: [{"if-none-match", meta.etag}]) do
{:ok, :not_modified, poll_meta} -> poll_meta.headers["x-poll-interval"]
{:ok, new_events, poll_meta} -> {new_events, poll_meta.etag}
end
{:ok, file, _meta} = GhEx.Contents.get(client, "o", "r", "mix.exs", params: [ref: "main"])
GhEx.Contents.create_or_update_file(client, "o", "r", "NOTES.md", %{
message: "add notes",
content: Base.encode64("hello"),
sha: file["sha"]
})content is Base64-encoded, and updating an existing file needs its blob sha.
Commits
GhEx.Commits — get a commit, compare refs, find associated pull requests, and
list or create commit comments. Repository-wide listing remains in
GhEx.Repositories.list_commits/4 and GhEx.Repositories.stream_commits/4.
GhEx.Commits.get(client, "o", "r", sha)
GhEx.Commits.compare(client, "o", "r", "main", "feature/agent")
GhEx.Commits.list_pulls(client, "o", "r", sha)
GhEx.Commits.create_comment(client, "o", "r", sha, %{body: "Looks good"})Git references
GhEx.Git — get, create, and delete branch or tag references. Read and delete
helpers accept both heads/name and fully qualified refs/heads/name forms;
create always sends GitHub the required fully qualified form.
GhEx.Git.get_ref(client, "o", "r", "heads/main")
GhEx.Git.create_ref(client, "o", "r", %{ref: "heads/release", sha: sha})
GhEx.Git.delete_ref(client, "o", "r", "refs/heads/release")Releases
GhEx.Releases — list, get, create, update, delete, generate notes, and upload
raw release assets to GitHub's dedicated upload endpoint.
GhEx.Releases.get_latest(client, "o", "r")
GhEx.Releases.create(client, "o", "r", %{
tag_name: "v1.0.0",
name: "v1.0.0",
generate_release_notes: true
})
asset = %{
name: "gh_ex.tar.gz",
content_type: "application/gzip",
data: File.read!("gh_ex.tar.gz"),
label: "Linux archive"
}
GhEx.Releases.upload_asset(client, "o", "r", release_id, asset)Actions
GhEx.Actions — workflows, runs, jobs, artifacts, logs, dispatch, deployment
approvals, cancel, and rerun. A workflow is its numeric id or its file name
("ci.yml"). Artifact and run-log downloads return ZIP bytes; job-log downloads
return plain-text bytes.
GhEx.Actions.list_workflows(client, "o", "r")
GhEx.Actions.dispatch_workflow(client, "o", "r", "ci.yml", %{ref: "main", inputs: %{env: "prod"}})
GhEx.Actions.list_runs(client, "o", "r", params: [branch: "main", status: "failure"])
GhEx.Actions.rerun(client, "o", "r", run_id)
GhEx.Actions.list_pending_deployments(client, "o", "r", run_id)
GhEx.Actions.review_pending_deployments(client, "o", "r", run_id, %{
environment_ids: [environment_id],
state: "approved",
comment: "Ship it"
})
{:ok, zip_bytes, _meta} = GhEx.Actions.download_artifact(client, "o", "r", artifact_id, "zip")
{:ok, logs, _meta} = GhEx.Actions.download_job_logs(client, "o", "r", job_id)
GhEx.Actions.rerun_failed_jobs(client, "o", "r", run_id)Deployments
GhEx.Deployments — deployment requests and their append-only status history.
The deployment object identifies the ref and environment; automation waiting for
completion should inspect the latest deployment status rather than polling the
deployment object for a state change.
{:ok, deployment, _meta} =
GhEx.Deployments.create(client, "o", "r", %{
ref: "main",
environment: "production",
required_contexts: []
})
GhEx.Deployments.create_status(client, "o", "r", deployment["id"], %{
state: "in_progress",
log_url: "https://deploys.example.test/42"
})
{:ok, statuses, _meta} = GhEx.Deployments.list_statuses(client, "o", "r", deployment["id"])
latest_status = List.first(statuses)Activity
GhEx.Activity — repository, organization, user, and public event feeds plus
repository starring. Each feed/list has a lazy stream companion. Watching stays
separate from starring and is not part of this module.
GhEx.Activity.stream_repo_events(client, "o", "r") |> Enum.take(100)
GhEx.Activity.list_starred(client, "octocat")
{:ok, starred?, _meta} = GhEx.Activity.starred?(client, "o", "r")
GhEx.Activity.star(client, "o", "r")Checks and statuses
GhEx.Checks — check runs, annotations, and run rerequests. GhEx.Statuses —
commit statuses.
GhEx.Checks.create_run(client, "o", "r", %{name: "lint", head_sha: sha, status: "in_progress"})
GhEx.Checks.list_for_ref(client, "o", "r", sha)
{:ok, run_or_nil, _meta} = GhEx.Checks.find_run_for_ref(client, "o", "r", sha, "lint", app_id)
GhEx.Checks.stream_annotations(client, "o", "r", check_run_id) |> Enum.take(100)
GhEx.Checks.rerequest_run(client, "o", "r", check_run_id)
GhEx.Statuses.create(client, "o", "r", sha, %{state: "success", context: "ci/lint"})
GhEx.Statuses.get_combined(client, "o", "r", "main")Security alerts
GhEx.CodeSecurity covers repository code-scanning, Dependabot, and
secret-scanning alerts. The corresponding security feature must be available
and enabled, and the token needs the matching repository alert permission.
Updates require write permission.
GhEx.CodeSecurity.list_alerts(client, "o", "r", params: [state: "open"])
GhEx.CodeSecurity.stream_dependabot_alerts(client, "o", "r") |> Enum.take(100)
GhEx.CodeSecurity.get_secret_alert(client, "o", "r", alert_number, params: [hide_secret: true])
GhEx.CodeSecurity.update_alert(client, "o", "r", alert_number, %{
state: "dismissed",
dismissed_reason: "false positive"
})Search
GhEx.Search — repositories, code, issues_and_pull_requests, users, commits. The
first argument is the q query; pass params: for sort and order.
GhEx.Search.repositories(client, "tetris language:elixir", params: [sort: "stars"])
GhEx.Search.issues_and_pull_requests(client, "repo:o/r is:open label:bug")Users, organizations, and teams
GhEx.Users, GhEx.Organizations, GhEx.Teams.
GhEx.Users.get_authenticated(client)
GhEx.Users.get(client, "joshrotenberg")
GhEx.Organizations.list_members(client, "elixir-lang")
GhEx.Teams.list(client, "elixir-lang")Gists
GhEx.Gists — list, get, create, update, delete.
GhEx.Gists.create(client, %{
description: "example",
public: false,
files: %{"hello.txt" => %{content: "hi"}}
})Webhooks
GhEx.Hooks manages repository webhook configurations. GhEx.Webhooks is the
receiving side: verify a delivery signature and parse the payload. See the
Webhooks guide for the full receiver pattern.
GhEx.Hooks.create(client, "o", "r", %{
active: true,
events: ["push", "pull_request"],
config: %{url: "https://example.test/github", content_type: "json", secret: secret}
})
with :ok <- GhEx.Webhooks.verify(body, signature, secret),
{:ok, payload} <- GhEx.Webhooks.parse(body) do
handle(event_name, payload)
end