Metadata-Version: 2.5
Name: render-lab-tasks-github
Version: 0.1.1
Summary: GitHub issue tasks for Render Workflows
Project-URL: Repository, https://github.com/render-lab/render-tasks-python
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: httpx<0.29,>=0.28
Requires-Dist: render-lab-tasks-core<0.2,>=0.1.1
Requires-Dist: render-lab-triggers<0.2,>=0.1.0
Requires-Dist: render==1.0.1
Description-Content-Type: text/markdown

# render-lab-tasks-github

GitHub tasks for Render Workflows. Version 0.1.1 implements all 26 registered
tasks and the registration-free webhook adapter. Version 0.1.0 contained only
the original issue-list/label subset.

Install from [PyPI](https://pypi.org/project/render-lab-tasks-github/) with Python 3.12+:

```sh
pip install render-lab-tasks-github==0.1.1
```

```python
from render import TaskContext, Workflows
from render_lab_tasks_github.tasks import app as github_app, list_new_issues

app = Workflows.from_workflows(github_app)


@app.task(name="example.readIssues")
async def read_issues(ctx: TaskContext):
    return await ctx.run(list_new_issues, {"repo": "render-oss/sdk", "limit": 5})
```

Call `app.start()` from the workflow entry point. Raw `list_new_issues_impl` and
`apply_labels_impl` are also exported from `.tasks`; inject `GitHubDeps` with a
`GitHubPort` fake to test or wrap under your own task name. Do not call a wrapped
task directly. Use `await ctx.run(task, input)`.

## Contract

`list_new_issues` takes `repo` (`owner/name`), optional `sinceISO`, and optional
nonnegative integer `limit` (default 50; explicit null also selects 50, matching
TypeScript). Returns plain issue dictionaries with
`number`, `title`, `body`, `url`, `labels`, `createdAt`, and nullable `author`.
Lists open issues newest-created first, skips pull requests, and follows pages
until the requested issue count or the end. `sinceISO` filters by GitHub's
updated-since behavior, matching the TS adapter. Zero limit performs no request.

`apply_labels` takes `repo`, `issueNumber`, and `labels`. Returns `issueNumber`
and the requested `labels`. An empty label list makes no HTTP request. This task
writes when called; dry-run decisions belong to the workflow caller.

## Environment

| Variable | Required | Purpose |
| --- | --- | --- |
| GITHUB_TOKEN | For writes/private repos; optional for public reads | GitHub token with permissions for the requested repository/operation |

Credentials are read during calls, never at import. GitHub responses determine
permission failures. HTTPX uses a 30-second timeout and no automatic retries.
Render retries failed tasks up to three times with a 1000 ms base delay and 2x
backoff. Pagination may make multiple requests within an attempt; writes may be
retried and callers must account for vendor idempotency.

## Render SDK 1.0.1 result limitation

The raw implementation always returns a list. The pinned SDK unwraps a singleton
list after a durable child run, so consumers should normalize the result:

```python
issues = await ctx.run(list_new_issues, {"repo": "owner/repo", "limit": 5})
if isinstance(issues, dict):
    issues = [issues]
```

Both examples include this workaround. See [ADR-0005](../../docs/adr/0005-sdk-singleton-list-results.md).

## Repository and PR operations

The expanded pack covers repositories, organization inventory, branches, file
reads/writes, atomic multi-file commits, PRs/reviews/merges, workflow dispatch,
search, and issue comments/updates. Raw implementations accept `GitHubDeps`.
`GITHUB_TOKEN` remains lazy; public reads can run unauthenticated. Search and
writes require the appropriate token permissions.

`commit_files` rejects empty/duplicate/traversing paths, limits decoded content
to 3,500,000 bytes, and optionally checks the expected branch head. It creates
blobs/tree/commit before updating the branch without forcing it. Branch creation
and deletion handle already-existing/missing resources. `merge_when_green`
performs one checks/status read per attempt before merging. No live repository
writes or merges were used for this port.

## Webhook adapter

`render_lab_tasks_github.webhooks.github_adapter(on_event, ...)` returns a
registration-free adapter for `render_lab_triggers`. The callback receives the
verified event and returns `{"task": "namespace.task", "args": [event]}` or `None`.
The signing credential `GITHUB_WEBHOOK_SECRET` is read inside verification unless
provided explicitly. Importing this module does not register tasks. Signature
checks use the raw body; live delivery remains in the testing backlog.
