# wait-for-release ## Purpose Poll a Gitea repository's releases endpoint until a release whose `tag_name` matches a shell-style glob pattern is published, or a timeout elapses. Designed to run in the background of a Claude Code session while a CI pipeline produces the release. ## Usage ``` wait-for-release [OPTIONS] REPO PATTERN ``` ### Arguments | Argument | Description | |----------|-------------| | `REPO` | Gitea repo in `owner/name` form (e.g. `skynet/myapp`). | | `PATTERN` | Shell-style glob matched against each release's `tag_name` (e.g. `v1.2.3.*`). **Quote it** to prevent the caller's shell from expanding it. | ### Flags | Flag | Description | |------|-------------| | `-t`, `--token TOKEN` | Gitea access token. Fallback order: `$GITEA_TOKEN`, `$GITHUB_TOKEN`. Omitted → unauthenticated request. | | `--timeout SECONDS` | Max total wait time (default: 600). `0` means poll once then give up. | | `--interval SECONDS` | Polling interval (default: 5; min: 1). | | `--server URL` | Gitea base URL. Fallback order: `$GITHUB_SERVER_URL`, `https://gitea.oreillyit.nz`. | | `-v`, `--verbose` | Emit polling progress to stderr. | | `-n`, `--dryrun` | Print resolved configuration and exit; make no API calls. | | `-h`, `--help` | Show usage. | ## Behaviour 1. Validate inputs: REPO must be `owner/name`; `--timeout` is a non-negative integer; `--interval` is an integer ≥ 1. 2. Compute `API_URL = /api/v1/repos///releases?limit=50`. 3. Compute `DEADLINE = now + timeout`. 4. Loop: 1. `GET API_URL` with a 30-second per-request timeout. Add `Authorization: token ` when a token is available. 2. On HTTP 200: extract `tag_name` values from the JSON body (via `jq` when installed, otherwise a simple regex). For each tag, test `[[ "$tag" == $PATTERN ]]` (bash glob). On the first match, print the tag to stdout and exit 0. 3. On HTTP 401 or 403: print auth error to stderr, exit 3. 4. On HTTP 404: print not-found error to stderr, exit 3. 5. On any other HTTP code or network failure: keep retrying (log to stderr when `--verbose`). 5. Between polls, sleep for `--interval` seconds, capped so the sleep never overshoots the deadline. 6. When the deadline has passed without a match, print a timeout error to stderr and exit 1. ## Dryrun Behaviour When `--dryrun` is passed, no HTTP requests are made. Output (to stdout): ``` [dryrun] Server: https://gitea.oreillyit.nz [dryrun] Repo: skynet/myapp [dryrun] Pattern: v1.2.3.* [dryrun] Timeout: 600s [dryrun] Interval: 5s [dryrun] Auth: yes [dryrun] API URL: https://gitea.oreillyit.nz/api/v1/repos/skynet/myapp/releases?limit=50 ``` `Auth: yes` when a token was supplied or present in the environment; otherwise `Auth: no`. ## Exit Codes | Code | Meaning | |------|---------| | 0 | A release matching PATTERN was found; its `tag_name` is on stdout. | | 1 | Timeout elapsed with no match. | | 2 | Usage error (missing / invalid arguments). | | 3 | Terminal API error (401, 403, 404). | ## Edge Cases | Case | Handling | |------|----------| | REPO missing the slash | Error, exit 2. | | PATTERN unquoted by caller and expanded by their shell | Caller's responsibility; the spec requires quoting. | | No token for a private repo | API returns 401/403 → exit 3. | | Invalid token | HTTP 401 → exit 3. | | Repo doesn't exist / hidden | HTTP 404 → exit 3. | | Transient 5xx or network error | Retry each `--interval` seconds until timeout. | | Multiple releases match PATTERN | The first match in API response order (most recent first) wins. | | PATTERN matches an already-published release | Returns on the first poll. | | `--timeout 0` | Exactly one poll, then timeout if no match. | | `--interval 0` | Error, exit 2. | ## Examples ```bash # Wait for any build of a specific semver wait-for-release skynet/myapp 'v1.2.3.*' # Exact build wait-for-release skynet/myapp 'v1.2.3.45' # Any v1.x release, 20-minute window wait-for-release --timeout 1200 skynet/myapp 'v1.*' # With explicit token for a private repo wait-for-release -t "$MY_TOKEN" skynet/private 'v1.2.*' # Dryrun preview wait-for-release --dryrun skynet/myapp 'v1.*' ``` ### In a Claude Code session Invoke via the Bash tool with `run_in_background=true`. The session is notified when the script exits. On success stdout holds the matched tag; the exit code signals the outcome. ```bash wait-for-release skynet/myapp "v${VERSION}.*" ```