Fixes https://gitea.com/gitea/tea/issues/1053
## What
tea hangs forever on Windows when it is started by something that owns a console but redirects
tea's stdio: a Windows service, a CI runner, an automation harness. Every command is affected,
`tea --version` included.
## Root cause
`modules/theme` imported `charm.land/lipgloss/v2/compat` for one struct type,
`compat.AdaptiveColor`. But compat detects the terminal background from package-level vars:
```go
var (
HasDarkBackground = lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
Profile = colorprofile.Detect(os.Stdout, os.Environ())
)
```
Go initialises every package in the import graph before `main()` runs, and every file in package
`cmd` imports `modules/context`, which imports `modules/theme`. So tea queried the terminal on
every invocation, before urfave/cli had even looked at the arguments — which is why `--version`
hung.
On Windows that query opens `CONIN$`/`CONOUT$` and asks the console directly instead of giving up
when stdio is redirected, then waits for a reply that never comes. The read has a 2 second timeout,
but it does not fire, because the cancel it relies on is a no-op for that handle. Full trace in the
issue.
## Changes
- `modules/theme/theme.go` — drop the `compat` import and use `lipgloss.LightDark`, a plain
function that touches no terminal. `TeaTheme.Theme` is already handed the `isDark` it needs.
This also fixes a bug hiding in plain sight: `compat.AdaptiveColor` resolves against a
process-wide value detected at init, so the title color ignored the `isDark` argument huh passed
in. `Theme(true)` and `Theme(false)` returned the same color.
- `modules/theme/background.go` — new `HasDarkBackground()` helper that only asks the terminal when
stdin and stdout are both terminals, and otherwise assumes dark, which is the default lipgloss
itself falls back to. This is the same rule lipgloss already applies on Unix.
- `modules/interact/print.go` — `printTitleAndContent` called
`lipgloss.HasDarkBackground(os.Stdin, os.Stdout)` directly, so it hit the same wait on the
interactive paths, `tea login add` among them. It now goes through the helper.
## Why fix this in tea
The underlying bug is upstream and I have opened PRs for both halves of it: https://github.com/charmbracelet/ultraviolet/pull/138 and
https://github.com/charmbracelet/lipgloss/pull/713. But it is not fixed in any released version — lipgloss v2.0.5 is byte-identical to
v2.0.4 in the relevant files — so upgrading dependencies does not help, and tea would stay broken on
Windows until Charm cuts a release and tea bumps `go.mod`.
Separately, these changes stand on their own. tea should not query the terminal in order to print a
version string, whatever upstream does.
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Willem Kokke <mail@willem.net>
When --redirect-url is omitted, the local callback listener binds to a
free port and opts.RedirectURL is rewritten with it. oauth2Config.RedirectURL
was never updated, so Exchange() sent the stale http://127.0.0.1:0 while
the authorize step had sent the real port. RFC-6749-compliant servers
(Gitea >= #37704, current Forgejo) reject the mismatch.
Propagate the resolved URL back into oauth2Config before Exchange. Add a
regression test using httptest that drives the flow end-to-end and asserts
the redirect_uri values match.
---------
Co-authored-by: dbankmann <204984+dbankmann@users.noreply.gitea.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1019
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Daniel Bankmann <204984+dbankmann@noreply.gitea.com>
Co-committed-by: Daniel Bankmann <204984+dbankmann@noreply.gitea.com>
## Why
Today `tea comment` can only *add* a comment. Editing or deleting requires falling back to `tea api`. This came up while I was iterating on PRs in this same repo earlier today and had to correct a couple of comments by hand. Every comparable forge CLI (gh, glab, etc.) exposes these operations as first-class commands.
## What
Restructures `tea comment` from a single-action command into a parent with four subcommands. The parent's default action remains the existing "add" behavior, so the historical shorthand keeps working.
| Command | Purpose |
|---|---|
| `tea comment add <idx> [<body>]` | Add a comment (explicit subcommand) |
| `tea comment list <idx>` | Tabular listing including comment IDs |
| `tea comment edit <id> [<body>]` | Replace the body of one comment |
| `tea comment delete <id> [<id>...]` | Delete one or more comments |
| `tea comment <idx> [<body>]` | Unchanged — still routes to `add` |
The `list` command exists specifically so users can discover the IDs that `edit` and `delete` accept.
## Backward compatibility
The whole point of routing the parent's default `Action` through `add` is to preserve every existing invocation. `tea comment 1 "body"` still does what it did before. No flag or arg names change.
## Input forms (for add and edit)
Same pattern as the original `tea comment`:
1. Positional body (`tea comment edit <id> "new body"`) — wins if present.
2. Piped stdin if no positional body is given.
3. External `$EDITOR` (pre-populated with the current body, on `edit`) if neither.
This matches the stdin-handling fix in #1011 — positional body wins over a non-TTY stdin so the command doesn't hang in CI/subshells.
## Verification
All four subcommands were exercised live against `https://gitea.com/dinsmoor/tea-testing` issue #1. The test artifacts and a summary log are visible on that issue right now. Specifically:
- The annotated summary comment lists every operation tested and the comment IDs each one acted on.
- Comments 1197162 (legacy add), 1197163 (subcommand add, later edited), 1197164 (stdin add) are still there to be inspected.
- Comment 1197166 was created and then deleted; its absence from `tea comment list` output is evidence that delete works.
## New files
- `cmd/comments/add.go` — extracted from the old `cmd/comment.go`
- `cmd/comments/list.go`
- `cmd/comments/edit.go`
- `cmd/comments/delete.go`
- `modules/print/comment.go` — adds `CommentsList` helper for the tabular output
`cmd/comment.go` is rewritten as a thin parent that wires these together.
## Open questions for the reviewer
- **Naming**: should the top-level command be `comments` (plural) or stay `comment` (singular)? I kept it singular with `comments` as an alias to match the existing user-visible name.
- **Delete confirmation**: I did not add a confirmation prompt — `delete` just deletes. Some projects gate this behind `--yes` / interactive `[y/N]`. I'd rather follow whatever convention the maintainers prefer.
- **Output format on list**: currently uses the existing `print.tableWithHeader` helper, matching `tea organizations list` etc. Other tea listings support `--output json` / `--output csv` via the shared `--output` flag, which works here automatically through the same helper.
---
This patch was authored interactively with an AI assistant, driven and reviewed by a human (Tyler / @dinsmoor) every step.
*pull request created by Tyler's lovingly wrangled demon machine <3*
Reviewed-on: https://gitea.com/gitea/tea/pulls/1015
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: dinsmoor <204368+dinsmoor@noreply.gitea.com>
Co-committed-by: dinsmoor <204368+dinsmoor@noreply.gitea.com>
Closes#979. An alternative to the approach in #980 — this one is purely client-side title-mangling, no SDK changes needed.
Gitea already treats any PR with a `WIP:` or `[WIP]` title prefix (case-insensitive) as a draft. This patch wires three flags around that behavior:
- `tea pulls create --draft` — prepend `WIP: ` to the title at creation time
- `tea pulls edit --draft <idx>` — add `WIP: ` to an existing PR's title
- `tea pulls edit --ready <idx>` — strip any recognized draft prefix
All three are idempotent. `--draft` and `--ready` on edit are mutually exclusive. If the user also passes `--title` on edit, the toggle applies to the supplied title; otherwise the current title is fetched from the server first.
Why this approach over a server-payload-based one: Gitea's draft state is *defined* as the title-prefix convention (see the Gitea source for `HasWIPPrefix`). Modeling it server-side would either duplicate or fight that. A small string helper covers it without needing the SDK to add a `Draft` field.
Verified against `gitea.com` (1.26.0+dev) with a throwaway repo:
- create with `--draft` → server reports `draft: true` ✓
- `edit --ready` strips → `draft: false` ✓
- `edit --draft` adds back → `draft: true` ✓
- second `edit --draft` is idempotent ✓
- `edit --draft --ready` errors ✓
Unit tests for the prefix detection live in `modules/utils/draft_test.go`.
---
This patch was authored interactively with an AI assistant, driven and reviewed by a human (Tyler / @dinsmoor) every step. Reproduction, design decisions, and the choice not to follow #980's payload approach were mine — happy to discuss any of it.
*pull request created by Tyler's lovingly wrangled demon machine <3*
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1008
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Tyler <tyler@dinsmoor.us>
Co-committed-by: Tyler <tyler@dinsmoor.us>
Closes#1013.
## Background
While trying to use `tea` from a non-interactive context I hit a friction point: after `tea login add` succeeded, plain `git push` over HTTPS still prompted for credentials. I filed #1013 as a feature request to add credential helper integration — then found, on reading the source, that the integration **already exists**:
- `tea login add` accepts `--helper` (alias `-j`), which calls `task.SetupHelper` to register a credential helper in `~/.gitconfig`.
- `tea login helper get` correctly implements git's credential protocol, reading the request from stdin and returning `protocol`/`host`/`username`/`password` lines.
- `tea login helper setup` does the same for every configured login.
I verified end-to-end that this works as advertised: after `tea login helper setup`, an HTTPS `git push` against a configured Gitea host authenticates silently using the stored token, no prompts, with `GIT_TERMINAL_PROMPT=0` set as a safety check.
So the feature is fine. The problem is that nobody can find it:
| Surface | Before | Issue |
|---|---|---|
| Flag name on `tea login add` | `--helper` (alias `-j`) | Generic; nothing tying it to git or credentials |
| Flag usage text | `"Add helper"` | Says nothing |
| `tea login helper` command | `Hidden: true` | Not in `tea login --help` |
| `tea login helper` usage | `"Git helper"` | Says nothing |
| `tea login helper` description | `"Git helper"` | Same string again |
| `store/erase` subcommand description | `"Command drops"` | Sentence fragment, no meaning |
| `setup` subcommand description | `"Setup helper to tea authenticate"` | Awkward, doesn't explain what it touches |
| `get` subcommand description | `"Get token to auth"` | Doesn't mention git, stdin, or the credential protocol |
| Mention in `tea login add --help` | None | Feature is invisible |
## What this patch does
Purely cosmetic / documentation changes — **no behavior changes**:
1. Renames `--helper` to `--git-credentials`, keeping `--helper` and `-j` as aliases so existing scripts and muscle memory keep working.
2. Removes `Hidden: true` from `tea login helper` so it appears in `tea login --help`.
3. Rewrites every placeholder `Usage` and `Description` string in the helper command tree to describe what the thing actually does.
4. Expands the top-level `Description` of `tea login add` to mention the option and explain what it does.
5. Prints a one-line hint after a successful non-helper login: `Tip: pass --git-credentials (or run 'tea login helper setup') to authenticate 'git push' and 'git clone' over HTTPS with this token.`
The credential helper protocol implementation, `SetupHelper`'s gitconfig writes, and the `get`/`store`/`setup` action functions are all unchanged.
## Help output after the patch
```
$ tea login --help
COMMANDS:
...
helper, git-credential Act as a git credential helper for stored Gitea logins
...
$ tea login helper --help
NAME:
tea logins helper - Act as a git credential helper for stored Gitea logins
DESCRIPTION:
Speaks git's credential helper protocol so that HTTPS push and clone
operations against your configured Gitea instances authenticate silently
using the tokens tea already stores.
Typical use is automatic: 'tea login add --git-credentials' (or 'tea login
helper setup' for existing logins) registers '!tea login helper' as a
credential helper in ~/.gitconfig. Git then invokes the 'get' subcommand
when it needs credentials for a configured host.
COMMANDS:
store, erase No-op (git credential protocol store/erase)
setup Register tea as a git credential helper for every configured login
get Return the stored token for a URL (git credential protocol)
```
## Open questions for the reviewer
A few choices in here that are subjective — happy to change any of them:
- **Flag name**: `--git-credentials` was the first clear name I tried. `--credential-helper` and `--git-helper` are also reasonable. Or keep `--helper` as canonical and just fix its usage text.
- **Canonical subcommand name**: I kept `helper` as canonical with `git-credential` as alias, matching what was already there. Could flip this — `gh` uses `gh auth git-credential` as canonical with no `helper` form.
- **Should `--git-credentials` default to true?** Most users probably want it on; the current opt-in design surprises them. But flipping the default is a behavior change so I left it alone here.
- **Should the hint be silenced by an env var or a config flag?** I left it always-on for the people who need to see it; can gate it if it bothers automation users.
- **Teardown on `tea login delete`** would parallel the setup behavior, but is genuinely a separate change. Not in this PR.
---
This patch was authored interactively with an AI assistant, driven and reviewed by a human (Tyler / @dinsmoor) every step.
*pull request created by Tyler's lovingly wrangled demon machine <3*
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1014
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Tyler <tyler@dinsmoor.us>
Co-committed-by: Tyler <tyler@dinsmoor.us>
## The bug
`tea pulls create` and `tea pulls edit` print `• **Conflicting files**` for any open PR that the server reports as `mergeable: false`. But Gitea's API returns `mergeable: false` for **draft PRs by design** — drafts cannot be merged regardless of conflict state. The current code conflates "not mergeable for any reason" with "has file conflicts."
### Reproduction (gitea.com 1.26.0+dev)
```
$ tea pulls create --base main --head my-branch --title "WIP: clean diff" --description "..."
# #N WIP: clean diff (open)
...
• **Conflicting files** ← misleading
• Maintainers are allowed to edit
```
The PR has no actual conflicts. The web UI shows it as draft + cleanly diffable. `tea pulls edit --title "WIP: ..."` shows the same misleading line.
API confirms the root signal:
```
$ curl /api/v1/repos/owner/repo/pulls/N
{ "draft": true, "mergeable": false, ... }
```
Strip the WIP prefix, and `mergeable` flips back to `true`. So `mergeable=false` here means "blocked because draft," not "conflicts."
## Fix
Distinguish the two reasons in `modules/print/pull.go`:
```go
switch {
case pr.Mergeable:
out += "- No Conflicts\n"
case pr.Draft:
out += "- Draft (not mergeable until marked ready)\n"
default:
out += "- **Conflicting files**\n"
}
```
Real conflicts still fall through to the existing "Conflicting files" message.
## Behavior matrix
| PR state | API `mergeable` | Before | After |
|---|---|---|---|
| Open, clean, ready | true | No Conflicts | No Conflicts |
| Open, draft, clean | false | **Conflicting files** (wrong) | **Draft (not mergeable until marked ready)** |
| Open, conflicting | false | Conflicting files | Conflicting files |
| Closed/merged | — | (no line shown) | (no line shown) |
## Verification
Against `dinsmoor/tea-testing` PR #6 on gitea.com:
- Set title to `WIP: ...` → API `mergeable=false`, `draft=true` → tea prints `Draft (not mergeable until marked ready)` ✓
- Strip WIP → API `mergeable=true`, `draft=false` → tea prints `No Conflicts` ✓
---
This patch was authored interactively with an AI assistant, driven and reviewed by a human (Tyler / @dinsmoor) every step.
*pull request created by Tyler's lovingly wrangled demon machine <3*
Reviewed-on: https://gitea.com/gitea/tea/pulls/1012
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Tyler <tyler@dinsmoor.us>
Co-committed-by: Tyler <tyler@dinsmoor.us>
## Summary
Add first-class `tea wiki` commands backed by the existing Gitea wiki API and SDK support.
## What this adds
- `tea wiki list`
- `tea wiki view <page>`
- `tea wiki revisions <page>`
- `tea wiki create`
- `tea wiki edit <page>`
- `tea wiki delete <page>`
## Implementation details
- registers a new top-level `wiki` entity command
- keeps command logic under `cmd/wiki/`
- adds wiki-specific renderers in `modules/print/wiki.go`
- adds wiki task helpers in `modules/task/wiki.go`
- reuses existing repo/login/output/pagination patterns used elsewhere in `tea`
- base64-encodes wiki content for create/edit API calls
- requires explicit `--confirm` for delete
- preserves the current page title during edit when `--title` is omitted
## Test coverage
The PR is intentionally split into two commits:
1. `feat: add wiki CLI commands`
2. `test: add wiki integration coverage`
Validation performed:
- focused command, task, and print tests for the new wiki functionality
- integration coverage for the wiki command lifecycle
- `make lint`
- `make fmt-check`
- `make docs-check`
- `make build`
- upstream PR CI passed:
- `check-and-test / Integration Test`
- `check-and-test / Lint Build And Unit Coverage`
## Motivation
This makes `tea` a better interface for both human and agent-driven workflows by exposing wiki operations as stable first-class CLI commands instead of requiring ad-hoc API calls or custom wrappers.
---
Generated by Hermes Agent with GPT-5.4
---------
Co-authored-by: nitro <nitro@nitroui-Macmini.local>
Reviewed-on: https://gitea.com/gitea/tea/pulls/998
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: kuil09 <202447+kuil09@noreply.gitea.com>
Co-committed-by: kuil09 <202447+kuil09@noreply.gitea.com>
## Summary
\`Page: -1\` in the Gitea SDK calls \`setDefaults()\` which sets both \`Page=0\` and \`PageSize=0\`, resulting in \`?page=0&limit=0\` being sent to the server. The server interprets \`limit=0\` as "use server default" (typically 30 items via \`DEFAULT_PAGING_NUM\`), not "return everything". Any resource beyond the first page of results was silently invisible.
This affected 8 call sites, with the most user-visible impact being \`tea issues edit --add-labels\` and \`tea pulls edit --add-labels\` silently failing to apply labels on repositories with more than ~30 labels.
## Affected call sites
| File | API call | User-visible impact |
|---|---|---|
| \`modules/task/labels.go\` | \`ListRepoLabels\` | \`issues/pulls edit --add-labels\` fails silently |
| \`modules/interact/issue_create.go\` | \`ListRepoLabels\` | interactive label picker missing labels |
| \`modules/task/pull_review_comment.go\` | \`ListPullReviews\` | review comments truncated |
| \`modules/task/login_ssh.go\` | \`ListMyPublicKeys\` | SSH key auto-detection fails |
| \`modules/task/login_create.go\` | \`ListAccessTokens\` | token name deduplication misses existing tokens |
| \`cmd/pulls.go\` | \`ListPullReviews\` | PR detail view missing reviews |
| \`cmd/releases/utils.go\` | \`ListReleases\` | tag lookup fails on repos with many releases |
| \`cmd/attachments/delete.go\` | \`ListReleaseAttachments\` | attachment deletion fails when many attachments exist |
## Fix
Each call site is replaced with an explicit pagination loop that follows \`resp.NextPage\` until all pages are exhausted.
Reviewed-on: https://gitea.com/gitea/tea/pulls/967
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Alain Thiffault <athiffau@effectivemomentum.com>
Co-committed-by: Alain Thiffault <athiffau@effectivemomentum.com>
Treat explicit --repo slugs as remote targets so commands do not probe
the current worktree. This avoids SHA256 repository failures when local
git autodetection is unnecessary.
---------
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/960
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Matěj Cepl <mcepl@cepl.eu>
Co-committed-by: Matěj Cepl <mcepl@cepl.eu>
## Summary
- Add `"ci"` as a new selectable field for `tea pr list --fields`, allowing users to see CI status across multiple PRs at a glance
- Fetch CI status via `GetCombinedStatus` API **only when the `ci` field is explicitly requested** via `--fields`, avoiding unnecessary API calls in default usage
- Improve CI status display in both detail and list views:
- **Detail view** (`tea pr <index>`): show each CI check with symbol, context name, description, and clickable link to CI run
- **List view** (`tea pr list --fields ci`): show symbol + context name per CI check (e.g., `✓ lint, ⏳ build, ❌ test`)
- **Machine-readable output**: return raw state string (e.g., `success`, `pending`)
- Replace pending CI symbol from `⭮` to `⏳` for better readability
- Extract `formatCIStatus` helper and reuse it in `PullDetails` to reduce code duplication
- Add comprehensive tests for CI status formatting and PR list integration
## Detail View Example
```
- CI:
- ✓ [**lint**](https://ci.example.com/lint): Lint passed
- ⏳ [**build**](https://ci.example.com/build): Build is running
- ❌ [**test**](https://ci.example.com/test): 3 tests failed
```
## List View Example
```
INDEX TITLE STATE CI
123 Fix bug open ✓ lint, ⏳ build, ❌ test
```
## Usage
```bash
# Show CI status column in list
tea pr list --fields index,title,state,ci
# Default output is unchanged (no CI column, no extra API calls)
tea pr list
```
## Files Changed
- `cmd/pulls/list.go` — conditionally fetch CI status per PR when `ci` field is selected
- `modules/print/pull.go` — add `ci` field, `formatCIStatus` helper, improve detail/list CI display
- `modules/print/pull_test.go` — comprehensive tests for CI status formatting
## Test plan
- [x] `go build ./...` passes
- [x] `go test ./...` passes (11 new tests)
- [x] `tea pr list` — default output unchanged, no extra API calls
- [x] `tea pr list --fields index,title,state,ci` — CI column with context names
- [x] `tea pr <index>` — CI section shows each check with name, description, and link
- [x] `tea pr list --fields ci -o csv` — machine-readable output shows raw state strings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: https://gitea.com/gitea/tea/pulls/956
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
## Summary
- Extract duplicate \`getReleaseByTag\` into shared \`cmd/releases/utils.go\`
- Replace \`log.Fatal\` calls with proper error returns in config and login commands; \`GetLoginByToken\`/\`GetLoginsByHost\`/\`GetLoginByHost\` now return errors
- Remove dead \`portChan\` channel in \`modules/auth/oauth.go\`
- Fix YAML integer detection to use \`strconv.ParseInt\` (correctly handles negatives and large ints)
- Fix \`path.go\` error handling to use \`errors.As\` + \`syscall.ENOTDIR\` instead of string comparison
- Extract repeated credential helper key into local variable in \`SetupHelper\`
- Use existing \`isRemoteDeleted()\` in \`pull_clean.go\` instead of duplicating the logic
- Fix ~30 error message casing violations to follow Go conventions
- Use \`fmt.Errorf\` consistently instead of string concatenation in \`generic.go\`
Reviewed-on: https://gitea.com/gitea/tea/pulls/947
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Bo-Yi Wu (吳柏毅) <appleboy.tw@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-committed-by: Nicolas <bircni@icloud.com>
## Summary
- Introduce `github.com/go-authgate/sdk-go/credstore` to store OAuth tokens securely in the OS keyring (macOS Keychain / Linux Secret Service / Windows Credential Manager), with automatic fallback to an encrypted JSON file
- Add `AuthMethod` field to `Login` struct; new OAuth logins are marked `auth_method: oauth` and no longer write `token`/`refresh_token`/`token_expiry` to `config.yml`
- Add `GetAccessToken()` / `GetRefreshToken()` / `GetTokenExpiry()` accessors that transparently read from credstore for OAuth logins, with fallback to YAML fields for legacy logins
- Update all token reference sites across the codebase to use the new accessors
- Non-OAuth logins (token, SSH) are completely unaffected; no migration of existing tokens
## Key files
| File | Role |
|------|------|
| `modules/config/credstore.go` | **New** — credstore wrapper (Load/Save/Delete) |
| `modules/config/login.go` | Login struct, token accessors, refresh logic |
| `modules/auth/oauth.go` | OAuth flow, token creation / re-authentication |
| `modules/api/client.go`, `cmd/login/helper.go`, `cmd/login/oauth_refresh.go` | Token reference updates |
| `modules/task/pull_*.go`, `modules/task/repo_clone.go` | Git operation token reference updates |
## Test plan
- [x] `go build ./...` compiles successfully
- [x] `go test ./...` all tests pass
- [x] `tea login add --oauth` completes OAuth flow; verify config.yml has `auth_method: oauth` but no token/refresh_token/token_expiry
- [x] `tea repos ls` API calls work (token read from credstore)
- [x] `tea login delete <name>` credstore token is also removed
- [x] Existing non-OAuth logins continue to work unchanged
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: https://gitea.com/gitea/tea/pulls/926
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
- switch to golangci-lint for linting
- switch to gofmpt for formatting
- fix lint and fmt issues that came up from switch to new tools
- upgrade go-sdk to 0.23.2
- support pagination for listing tracked times
- remove `FixPullHeadSha` workaround (upstream fix has been merged for 5+ years at this point)
- standardize on US spelling (previously a mix of US&UK spelling)
- remove some unused code
- reduce some duplication in parsing state and issue type
- reduce some duplication in reading input for secrets and variables
- reduce some duplication with PR Review code
- report error for when yaml parsing fails
- various other misc cleanup
Reviewed-on: https://gitea.com/gitea/tea/pulls/869
Co-authored-by: techknowlogick <techknowlogick@gitea.com>
Co-committed-by: techknowlogick <techknowlogick@gitea.com>
## Problem
Tea commands fail when run from git worktrees with the error:
Remote repository required: Specify ID via --repo or execute from a
local git repo.
Even though the worktree is in a valid git repository with remotes
configured.
Additionally, `tea pr create` was missing context validation, showing
cryptic errors like `"path segment [0]
is empty"` instead of helpful messages.
## Root Cause
1. **Worktree issue**: go-git's `PlainOpenWithOptions` was not
configured to read the `commondir` file that
git worktrees use. This file points to the main repository's `.git`
directory where remotes are actually
stored (worktrees don't have their own remotes).
2. **PR create issue**: Missing `ctx.Ensure()` validation meant errors
weren't caught early with clear
messages.
## Solution
### 1. Enable worktree support (`modules/git/repo.go`)
```go
EnableDotGitCommonDir: true, // Enable commondir support for worktrees
This tells go-git to:
- Read the commondir file in .git/worktrees/<name>/commondir
- Follow the reference (typically ../..) to the main repository
- Load remotes from the main repo's config
2. Add context validation (cmd/pulls/create.go)
ctx.Ensure(context.CtxRequirement{
LocalRepo: true,
RemoteRepo: true,
})
Provides clear error messages and matches the pattern used in pr
checkout (fixed in commit 0970b945 from
2020).
3. Add test coverage (modules/git/repo_test.go)
- Creates a real git repository with a worktree
- Verifies that RepoFromPath() can open the worktree
- Confirms that Config() correctly reads remotes from main repo
Test Results
Without fix:
❌ FAIL: Should NOT be empty, but was map[]
With fix:
✅ PASS: TestRepoFromPath_Worktree (0.12s)
Manual test in worktree:
cd /path/to/worktree
tea pr create --title "test"
# Now works! ✅
Checklist
- Tested manually in a git worktree
- Added test case that fails without the fix
- All existing tests pass
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/850
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: Brandon Martin <brandon@codedmart.com>
Co-committed-by: Brandon Martin <brandon@codedmart.com>
Since one of the last updates (I cannot tell you exactly which one, but likely 0.10 or 0.11), tea always asks me for my ssh passphrase without actually needing it. I do not have anything configured regarding SSH keys.
The passphrase is not even verified, you can enter anything there. But as this is quite annoying, I fixed this by moving the prompt to only be used when a ssh key/cert is configured.
Would be nice to get this in. Thanks!
Reviewed-on: https://gitea.com/gitea/tea/pulls/844
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: qwerty287 <qwerty287@posteo.de>
Co-committed-by: qwerty287 <qwerty287@posteo.de>