Compare commits

..

36 Commits

Author SHA1 Message Date
Renovate Bot 989651408e fix(deps): update go dependencies 2026-07-16 00:16:20 +00:00
Renovate Bot 7f0213940d fix(deps): update go dependencies (#1051)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [charm.land/lipgloss/v2](https://github.com/charmbracelet/lipgloss) | `v2.0.4` → `v2.0.5` | ![age](https://developer.mend.io/api/mc/badges/age/go/charm.land%2flipgloss%2fv2/v2.0.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/charm.land%2flipgloss%2fv2/v2.0.4/v2.0.5?slim=true) |
| [github.com/urfave/cli/v3](https://github.com/urfave/cli) | `v3.10.0` → `v3.10.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2furfave%2fcli%2fv3/v3.10.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2furfave%2fcli%2fv3/v3.10.0/v3.10.1?slim=true) |
| [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) | [`v0.46.0` → `v0.47.0`](https://cs.opensource.google/go/x/sys/+/refs/tags/v0.46.0...refs/tags/v0.47.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fsys/v0.47.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fsys/v0.46.0/v0.47.0?slim=true) |

---

### Release Notes

<details>
<summary>charmbracelet/lipgloss (charm.land/lipgloss/v2)</summary>

### [`v2.0.5`](https://github.com/charmbracelet/lipgloss/releases/tag/v2.0.5)

[Compare Source](https://github.com/charmbracelet/lipgloss/compare/v2.0.4...v2.0.5)

### Graphemes, Schmraphemes

If you’re using emojis in the terminal you're in for a rough ride. That said, we do what we can. This release brings some in some very specific edge case rendering improvements. Enjoy.

Enjoy!

#### Changelog

- [`10f9584`](https://github.com/charmbracelet/lipgloss/commit/10f9584edb197ddbbfc789081d33b6fadaea5742): chore(deps): bump ultraviolet for emoji-related improvements

***

<a href="https://charm.land/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-banner-next.jpg" width="400"></a>

Thoughts? Questions? We love hearing from you. Feel free to reach out on [X](https://x.com/charmcli), [Discord](https://charm.land/discord), [Slack](https://charm.land/slack), [The Fediverse](https://mastodon.social/@&#8203;charmcli), [Bluesky](https://bsky.app/profile/charm.land).

</details>

<details>
<summary>urfave/cli (github.com/urfave/cli/v3)</summary>

### [`v3.10.1`](https://github.com/urfave/cli/releases/tag/v3.10.1)

[Compare Source](https://github.com/urfave/cli/compare/v3.10.0...v3.10.1)

#### What's Changed

- chore(deps): bump actions/checkout from 6 to 7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2371](https://github.com/urfave/cli/pull/2371)
- fix: align gfmrun example counter with actual runnable count by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2369](https://github.com/urfave/cli/pull/2369)
- v3: yield the version flag's -v alias to a user-defined flag by [@&#8203;c-tonneslan](https://github.com/c-tonneslan) in [#&#8203;2330](https://github.com/urfave/cli/pull/2330)
- fix: keep completion subcommand order deterministic in help output by [@&#8203;suzuki-shunsuke](https://github.com/suzuki-shunsuke) in [#&#8203;2374](https://github.com/urfave/cli/pull/2374)
- fix: allow DefaultCommand to handle its own flags by [@&#8203;lihan3238](https://github.com/lihan3238) in [#&#8203;2322](https://github.com/urfave/cli/pull/2322)

#### New Contributors

- [@&#8203;lihan3238](https://github.com/lihan3238) made their first contribution in [#&#8203;2322](https://github.com/urfave/cli/pull/2322)

**Full Changelog**: <https://github.com/urfave/cli/compare/v3.10.0...v3.10.1>

</details>

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1051
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
2026-07-15 01:41:25 +00:00
Willem Kokke 3b5703177d fix(theme): don't query the terminal at start-up (#1054)
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>
2026-07-13 04:31:26 +00:00
Lunny Xiao 2a9c8ff6fd upgrade go sdk and add test (#1048)
Fix #1046Reviewed-on: https://gitea.com/gitea/tea/pulls/1048
2026-07-01 18:06:19 +00:00
Brien Coffield 12947f068a feat(comments): accept -d/--description for comment body (#1043)
Closes #1042.

### What

`tea issue create`, `tea issue edit` and `tea pr create` all take the body via
`-d` / `--description`, but `tea comments add` and `tea comments edit` only
accepted it positionally — passing `-d` errored with
`flag provided but not defined: -d`.

This adds `-d` / `--description` to both `comments` subcommands so every
body-bearing command shares one flag.

### Behaviour / precedence

Unchanged for existing usage. Body resolution is now:

1. positional argument (kept first for back-compat),
2. `-d` / `--description`,
3. piped stdin,
4. `$EDITOR` (interactive only).

### Testing

- `go build`, `go vet ./...`, `go test -short ./cmd/... ./modules/...` all pass.
- Manually verified `tea comments add --help` / `edit --help` list the flag,
  and that `-d` resolves the body (reaches the API, no parse error, no editor
  prompt, no stdin block).

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1043
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Brien Coffield <coffbr01@gmail.com>
Co-committed-by: Brien Coffield <coffbr01@gmail.com>
2026-06-29 00:52:24 +00:00
Lunny Xiao d4545d8ed7 Add reply to code review (#978)
Follow https://gitea.com/gitea/go-sdk/pulls/784

Reviewed-on: https://gitea.com/gitea/tea/pulls/978
2026-06-26 21:40:31 +00:00
dinsmoor 885381e3e4 fix(http): add transport timeouts so tea fails fast on stalled servers (#1020)
Fixes #1018

Co-authored-by: dinsmoor <204368+dinsmoor@noreply.gitea.com>
Co-committed-by: dinsmoor <204368+dinsmoor@noreply.gitea.com>
2026-06-26 19:59:05 +00:00
techknowlogick 6a57af24ad fix(config): write to keychain before config (#1044)
Reviewed-on: https://gitea.com/gitea/tea/pulls/1044
Co-authored-by: techknowlogick <techknowlogick@gitea.com>
Co-committed-by: techknowlogick <techknowlogick@gitea.com>
2026-06-26 19:53:59 +00:00
Minjie Fang 88f5cdcafa fix(labels): add org label for ls and pr (#1017)
Fix https://gitea.com/gitea/tea/issues/634, https://gitea.com/gitea/tea/issues/669

Reviewed-on: https://gitea.com/gitea/tea/pulls/1017
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Minjie Fang <wingsallen@gmail.com>
Co-committed-by: Minjie Fang <wingsallen@gmail.com>
2026-06-24 17:46:12 +00:00
Renovate Bot 5cfee362c8 chore(deps): update actions/checkout action to v7 (#1041)
Reviewed-on: https://gitea.com/gitea/tea/pulls/1041
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-23 00:18:41 +00:00
Renovate Bot fff82ac723 fix(deps): update module github.com/urfave/cli/v3 to v3.10.0 (#1040)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/urfave/cli/v3](https://github.com/urfave/cli) | `v3.9.1` → `v3.10.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2furfave%2fcli%2fv3/v3.10.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2furfave%2fcli%2fv3/v3.9.1/v3.10.0?slim=true) |

---

### Release Notes

<details>
<summary>urfave/cli (github.com/urfave/cli/v3)</summary>

### [`v3.10.0`](https://github.com/urfave/cli/releases/tag/v3.10.0)

[Compare Source](https://github.com/urfave/cli/compare/v3.9.1...v3.10.0)

#### What's Changed

- feat: add Flag.SchemaType() and Flag.SchemaItemsType() for JSON Schema introspection by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2368](https://github.com/urfave/cli/pull/2368)
- feat: add Command.Walk() and Command.Path() convenience methods by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2353](https://github.com/urfave/cli/pull/2353)
- fix: let --help flag take precedence over parse errors by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2360](https://github.com/urfave/cli/pull/2360)
- fix: resolve remaining help invocation inconsistencies by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2361](https://github.com/urfave/cli/pull/2361)
- fix: skip After hook when help is displayed on subcommand by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2363](https://github.com/urfave/cli/pull/2363)
- fix: show GLOBAL OPTIONS in SubcommandHelpTemplate by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2359](https://github.com/urfave/cli/pull/2359)
- fix: resolve broken links in CHANGELOG.md by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2357](https://github.com/urfave/cli/pull/2357)
- docs: document what happened to build tags in v3 migration guide by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2358](https://github.com/urfave/cli/pull/2358)
- Various docs updates and dependency bumps

**Full Changelog**: <https://github.com/urfave/cli/compare/v3.9.1...v3.10.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1040
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-20 20:04:37 +00:00
Daniel Bankmann b11d991d1e fix(oauth): pass resolved redirect_uri to token exchange (#1019)
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>
2026-06-20 20:03:34 +00:00
Renovate Bot 4b209d68de fix(deps): update go dependencies (#1039)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [charm.land/glamour/v2](https://github.com/charmbracelet/glamour) | `v2.0.0` → `v2.0.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/charm.land%2fglamour%2fv2/v2.0.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/charm.land%2fglamour%2fv2/v2.0.0/v2.0.1?slim=true) |
| [charm.land/lipgloss/v2](https://github.com/charmbracelet/lipgloss) | `v2.0.3` → `v2.0.4` | ![age](https://developer.mend.io/api/mc/badges/age/go/charm.land%2flipgloss%2fv2/v2.0.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/charm.land%2flipgloss%2fv2/v2.0.3/v2.0.4?slim=true) |

---

### Release Notes

<details>
<summary>charmbracelet/glamour (charm.land/glamour/v2)</summary>

### [`v2.0.1`](https://github.com/charmbracelet/glamour/releases/tag/v2.0.1)

[Compare Source](https://github.com/charmbracelet/glamour/compare/v2.0.0...v2.0.1)

#### Changelog

##### Bug fixes

- [`975a0f3`](https://github.com/charmbracelet/glamour/commit/975a0f30cc6519fde4481ab084987222c8f06c34): fix: close wrap writer before its downstream chain ([#&#8203;575](https://github.com/charmbracelet/glamour/issues/575)) ([@&#8203;taciturnaxolotl](https://github.com/taciturnaxolotl))

##### Other work

- [`c293649`](https://github.com/charmbracelet/glamour/commit/c29364924407add0616fc067e4c70ddf9a5da0dd): chore: fix pre-existing lint failures ([#&#8203;575](https://github.com/charmbracelet/glamour/issues/575)) ([@&#8203;taciturnaxolotl](https://github.com/taciturnaxolotl))
- [`95c93db`](https://github.com/charmbracelet/glamour/commit/95c93db04489cebf252ec856584445c7e85ee276): chore: bump lipgloss to v2.0.4 ([@&#8203;taciturnaxolotl](https://github.com/taciturnaxolotl))
- [`600b93a`](https://github.com/charmbracelet/glamour/commit/600b93a40bb9754522c7e3496b8b41989cf1dec7): chore: remove CODEOWNERS ([@&#8203;aymanbagabas](https://github.com/aymanbagabas))
- [`253da61`](https://github.com/charmbracelet/glamour/commit/253da61fcb275fcd28296956ffae5f7d98ff618d): fix(ci): use local golangci config ([@&#8203;aymanbagabas](https://github.com/aymanbagabas))

***

<a href="https://charm.sh/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-badge.jpg"
width="400"></a>

Thoughts? Questions? We love hearing from you. Feel free to reach out on [Twitter](https://twitter.com/charmcli), [The Fediverse](https://mastodon.social/@&#8203;charm), or on [Discord](https://charm.sh/chat).

</details>

<details>
<summary>charmbracelet/lipgloss (charm.land/lipgloss/v2)</summary>

### [`v2.0.4`](https://github.com/charmbracelet/lipgloss/releases/tag/v2.0.4)

[Compare Source](https://github.com/charmbracelet/lipgloss/compare/v2.0.3...v2.0.4)

### Mini Crash Patch

Hi! This is a small patch to fix a writer-related panic. Thanks for using Lip Gloss!

#### Changelog

##### Fixed

- [`fefa41d`](https://github.com/charmbracelet/lipgloss/commit/fefa41d): fix: prevent crash when writing to a closed wrap writer ([#&#8203;699](https://github.com/charmbracelet/lipgloss/issues/699)) ([@&#8203;taciturnaxolotl](https://github.com/taciturnaxolotl))

##### Docs

- [`40ec0e6`](https://github.com/charmbracelet/lipgloss/commit/40ec0e6): docs: fix typo in table comment ([#&#8203;641](https://github.com/charmbracelet/lipgloss/issues/641)) ([@&#8203;aymanbagabas](https://github.com/aymanbagabas))
- [`a4d0b40`](https://github.com/charmbracelet/lipgloss/commit/a4d0b40): docs: restore missing diaereses ([#&#8203;664](https://github.com/charmbracelet/lipgloss/issues/664)) ([@&#8203;meowgorithm](https://github.com/meowgorithm))

##### Chore

- [`aa91b99`](https://github.com/charmbracelet/lipgloss/commit/aa91b99): chore: remove CODEOWNERS ([@&#8203;aymanbagabas](https://github.com/aymanbagabas))
- [`9cbfe8b`](https://github.com/charmbracelet/lipgloss/commit/9cbfe8b): chore(lint): exclude revive naming linter ([@&#8203;aymanbagabas](https://github.com/aymanbagabas))

***

<a href="https://charm.land/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-banner-next.jpg" width="400"></a>

Thoughts? Questions? We love hearing from you. Feel free to reach out on [X](https://x.com/charmcli), [Discord](https://charm.land/discord), [Slack](https://charm.land/slack), [The Fediverse](https://mastodon.social/@&#8203;charmcli), [Bluesky](https://bsky.app/profile/charm.land).

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1039
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-18 02:32:16 +00:00
Renovate Bot 2b844786f0 fix(deps): update go dependencies (#1037)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/go-authgate/sdk-go](https://github.com/go-authgate/sdk-go) | `v0.12.0` → `v0.14.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgo-authgate%2fsdk-go/v0.14.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgo-authgate%2fsdk-go/v0.12.0/v0.14.0?slim=true) |
| [github.com/urfave/cli/v3](https://github.com/urfave/cli) | `v3.9.0` → `v3.9.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2furfave%2fcli%2fv3/v3.9.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2furfave%2fcli%2fv3/v3.9.0/v3.9.1?slim=true) |

---

### Release Notes

<details>
<summary>go-authgate/sdk-go (github.com/go-authgate/sdk-go)</summary>

### [`v0.14.0`](https://github.com/go-authgate/sdk-go/releases/tag/v0.14.0)

[Compare Source](https://github.com/go-authgate/sdk-go/compare/v0.13.0...v0.14.0)

#### Changelog

##### Features

- [`1e9404e`](https://github.com/go-authgate/sdk-go/commit/1e9404eea69d8f6de17177a98a8ca33a915dee01): feat(credstore): add DefaultStorePath path helper ([@&#8203;appleboy](https://github.com/appleboy))
- [`3498105`](https://github.com/go-authgate/sdk-go/commit/34981059ec8287317d5160a292d05a749d17f888): feat(credstore): add DefaultTokenStorePath shorthand ([@&#8203;appleboy](https://github.com/appleboy))

### [`v0.13.0`](https://github.com/go-authgate/sdk-go/releases/tag/v0.13.0)

[Compare Source](https://github.com/go-authgate/sdk-go/compare/v0.12.0...v0.13.0)

#### Changelog

##### Others

- [`fc432e3`](https://github.com/go-authgate/sdk-go/commit/fc432e3da28dbca06767d1be5ace784092974527): feat(credstore)!: add encrypted file store with keyring master key ([#&#8203;35](https://github.com/go-authgate/sdk-go/issues/35)) ([@&#8203;appleboy](https://github.com/appleboy))

</details>

<details>
<summary>urfave/cli (github.com/urfave/cli/v3)</summary>

### [`v3.9.1`](https://github.com/urfave/cli/releases/tag/v3.9.1)

[Compare Source](https://github.com/urfave/cli/compare/v3.9.0...v3.9.1)

#### What's Changed

- fix: inherit Reader/Writer/ErrWriter from parent on subcommand setup by [@&#8203;c-tonneslan](https://github.com/c-tonneslan) in [#&#8203;2329](https://github.com/urfave/cli/pull/2329)
- fix: correct greedy colon parsing in bash completion script by [@&#8203;TimSoethout](https://github.com/TimSoethout) in [#&#8203;2336](https://github.com/urfave/cli/pull/2336)
- fix: Honor env sources on duplicated flags by [@&#8203;ibobgunardi](https://github.com/ibobgunardi) in [#&#8203;2355](https://github.com/urfave/cli/pull/2355)
- fix: Remove incorrect flag check by [@&#8203;MohitPanchariya](https://github.com/MohitPanchariya) in [#&#8203;2280](https://github.com/urfave/cli/pull/2280)
- fix: let completion command use normal flag parsing pipeline by [@&#8203;suzuki-shunsuke](https://github.com/suzuki-shunsuke) in [#&#8203;2279](https://github.com/urfave/cli/pull/2279)
- fix: bash completion spacing by [@&#8203;cyphercodes](https://github.com/cyphercodes) in [#&#8203;2337](https://github.com/urfave/cli/pull/2337)
- fix: fish custom completion arguments by [@&#8203;puneetdixit200](https://github.com/puneetdixit200) in [#&#8203;2338](https://github.com/urfave/cli/pull/2338)
- fix: empty positional arg after a flag regression test by [@&#8203;c-tonneslan](https://github.com/c-tonneslan) in [#&#8203;2328](https://github.com/urfave/cli/pull/2328)
- docs: document build tags in v3 migration guide by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2358](https://github.com/urfave/cli/pull/2358)
- chore(deps): bump mkdocs-git-revision-date-localized-plugin by [@&#8203;dependabot](https://github.com/dependabot) in [#&#8203;2347](https://github.com/urfave/cli/pull/2347)
- Fix typos by [@&#8203;myfloss](https://github.com/myfloss) in [#&#8203;2339](https://github.com/urfave/cli/pull/2339)

**Full Changelog**: <https://github.com/urfave/cli/compare/v3.9.0...v3.9.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1037
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-16 21:09:11 +00:00
LeonM 67bb0e7789 feat(pulls): show PR URL in detail view (#1036)
Fixes #1035.

## Summary
- include the pull request URL in `tea pr <number>` detail output
- keep `tea pr create` output to one URL by relying on the shared detail renderer
- add a focused regression test

## Tests
- `go test ./modules/print`
- `go test ./...`

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Leon Müller <mueller4leon@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1036
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: LeonM <206012+leonm@noreply.gitea.com>
Co-committed-by: LeonM <206012+leonm@noreply.gitea.com>
2026-06-15 20:35:21 +00:00
Renovate Bot 6de58b2223 fix(deps): update go dependencies (#1034)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) | [`v0.52.0` → `v0.53.0`](https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.52.0...refs/tags/v0.53.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fcrypto/v0.53.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fcrypto/v0.52.0/v0.53.0?slim=true) |
| [golang.org/x/term](https://pkg.go.dev/golang.org/x/term) | [`v0.43.0` → `v0.44.0`](https://cs.opensource.google/go/x/term/+/refs/tags/v0.43.0...refs/tags/v0.44.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fterm/v0.44.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fterm/v0.43.0/v0.44.0?slim=true) |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1034
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-15 20:30:27 +00:00
Renovate Bot 27bcbf80ae fix(deps): update module golang.org/x/sys to v0.46.0 (#1028)
Reviewed-on: https://gitea.com/gitea/tea/pulls/1028
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-09 16:02:18 +00:00
Renovate Bot dfbbda83f3 fix(deps): update module gitea.dev/sdk to v1.1.0 (#1027)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| gitea.dev/sdk | `v1.0.1` → `v1.1.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/gitea.dev%2fsdk/v1.1.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/gitea.dev%2fsdk/v1.0.1/v1.1.0?slim=true) |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1027
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-08 22:42:38 +00:00
Renovate Bot df320c74ca fix(deps): update module github.com/go-authgate/sdk-go to v0.12.0 (#1024)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/go-authgate/sdk-go](https://github.com/go-authgate/sdk-go) | `v0.11.0` → `v0.12.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgo-authgate%2fsdk-go/v0.12.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgo-authgate%2fsdk-go/v0.11.0/v0.12.0?slim=true) |

---

### Release Notes

<details>
<summary>go-authgate/sdk-go (github.com/go-authgate/sdk-go)</summary>

### [`v0.12.0`](https://github.com/go-authgate/sdk-go/releases/tag/v0.12.0)

[Compare Source](https://github.com/go-authgate/sdk-go/compare/v0.11.0...v0.12.0)

#### Changelog

##### Bug fixes

- [`506ff28`](https://github.com/go-authgate/sdk-go/commit/506ff28e68b10f348fb937c9d734b20ea72245a6): fix: authenticate confidential clients and harden token handling ([#&#8203;33](https://github.com/go-authgate/sdk-go/issues/33)) ([@&#8203;appleboy](https://github.com/appleboy))

##### Refactor

- [`81b51e2`](https://github.com/go-authgate/sdk-go/commit/81b51e244f1ce5f069d6e2a0ac18a1ffb6d25706): refactor: simplify control flow across sdk packages ([#&#8203;30](https://github.com/go-authgate/sdk-go/issues/30)) ([@&#8203;appleboy](https://github.com/appleboy))
- [`7fcdb3c`](https://github.com/go-authgate/sdk-go/commit/7fcdb3cde0b80754262e81bd2e2d86baf8f00f64): refactor(oauth): use error-code constants at all sites ([#&#8203;31](https://github.com/go-authgate/sdk-go/issues/31)) ([@&#8203;appleboy](https://github.com/appleboy))
- [`4407ea6`](https://github.com/go-authgate/sdk-go/commit/4407ea621e8f2f14cb8629dfb80cb4d1e536099e): refactor(middleware): split token scope once for required-scope checks ([#&#8203;32](https://github.com/go-authgate/sdk-go/issues/32)) ([@&#8203;appleboy](https://github.com/appleboy))

##### Documentation updates

- [`f8b8b28`](https://github.com/go-authgate/sdk-go/commit/f8b8b28fd70f30799933e0592878f7e1146a71ea): docs(jwksauth): document UID across remaining godoc and test comments ([@&#8203;appleboy](https://github.com/appleboy))

##### Others

- [`a90443e`](https://github.com/go-authgate/sdk-go/commit/a90443e6226c4f401f40ed9917af2b19cd2f1747): fix(discovery,middleware): coalesce concurrent discovery fetches via singleflight with per-caller cancellation; route scope errors through the error handler ([#&#8203;16](https://github.com/go-authgate/sdk-go/issues/16)) ([@&#8203;appleboy](https://github.com/appleboy))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1024
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-06-05 03:55:19 +00:00
dinsmoor 09fc09c2f7 feat(comments): add list/edit/delete subcommands to tea comment (#1015)
## 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>
2026-05-31 22:20:48 +00:00
Tyler 5fa24b9a65 feat(pulls): add --draft to create and --draft/--ready to edit (#1008)
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>
2026-05-31 02:50:32 +00:00
Tyler 18274f1ebc fix(pulls): restore standard fork-flow PR creation (#1010)
Closes #1009.

## The standard fork-flow

The textbook workflow for opening a PR with any git CLI (gh, glab, hub, tea, etc.) is:

1. Fork `upstream/repo` on the server.
2. Clone the fork locally; add `upstream` as a second remote.
3. Branch off, commit, push the branch to your fork.
4. Tell the tool: "open a PR on `upstream/repo`, source is `fork:branch`".

In tea that's:

```
tea pulls create --repo upstream/repo --head fork:branch --base main
```

This is the flow tea supported before #850 and the flow this repo's own contribution model assumes.

## What broke

#850 ("Enable git worktree support and improve pr create error handling", Nov 2025) correctly addressed worktree detection by adding `LocalRepo: true` to `runPullsCreate`'s `CtxRequirement`. But that requirement is checked before `--repo` is interpreted, and a slug-style `--repo gitea/tea` doesn't satisfy `LocalRepo` — only a path does.

Result: the standard fork-flow invocation above started failing with:

```
Error: local repository required: execute from a repo dir, or specify a path with --repo
```

— which is misleading, because the user IS in a repo dir and `--repo` IS set.

## The fix

Only require `LocalRepo` when the command genuinely needs the working tree:

- **Interactive mode** (no flags) — uses tree info for prompts.
- **`--head` omitted** — defaults head from the current branch.

Otherwise the command runs with just `RemoteRepo`, and `task.CreatePull` takes the explicit `--repo` and `--head` as given. The #850 worktree fix is preserved for the in-tree path.

## Behavior table

| Invocation | Before | After |
|---|---|---|
| `tea pulls create` (interactive) | works | works (unchanged) |
| `tea pulls create --head my-branch --base main` (in-tree, same repo) | works | works (unchanged) |
| `tea pulls create --repo upstream/repo --head fork:branch --base main` (fork-flow) | **fails with misleading error** | **works** |
| `tea pulls create --repo upstream/repo --base main` (no `--head`, no working tree) | fails | still fails with the same error (correctly — head can't be defaulted without a working tree or explicit flag) |

## Verification

Smoke-tested by opening a PR from `/tmp` (deliberately not a git repo):

```
cd /tmp
tea-dev pulls create --login gitea.com --repo dinsmoor/tea-testing \
                     --head dinsmoor:xfork-smoke --base main \
                     --title "xfork smoke test" --description "..."
→ https://gitea.com/dinsmoor/tea-testing/pulls/4
```

And in fact, **this very PR was opened using the patched binary** invoked from `/tmp`, since the released `tea` still has the bug.

---

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/1010
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Tyler <tyler@dinsmoor.us>
Co-committed-by: Tyler <tyler@dinsmoor.us>
2026-05-28 18:29:11 +00:00
Tyler d1b9b7735e fix(comment): don't block on stdin when body is given positionally (#1011)
## The bug

`tea comment <idx> "body"` hangs forever in any non-TTY context — CI pipelines, subshells, agent harnesses, scripts — unless the user explicitly redirects stdin with `< /dev/null`.

### Reproduction (released `tea` 0.14.1)

```
# Plain positional body — hangs forever
$ tea comment --repo owner/repo 1 "body text"

# Heredoc body — hangs forever
$ tea comment --repo owner/repo 1 "$(cat <<'EOM'
body text
EOM
)"

# Workaround that works (but shouldn't be necessary)
$ tea comment --repo owner/repo 1 "body text" < /dev/null
```

Verified on `gitea.com` (server 1.26.0+dev) with `tea 0.14.1`. Both hanging cases hit a 30s timeout in testing; in normal shell use they hang indefinitely.

## Root cause

`cmd/comment.go:58-65`:

```go
body := strings.Join(ctx.Args().Tail(), " ")
if interact.IsStdinPiped() {
    if bodyStdin, err := io.ReadAll(ctx.Reader); err != nil {
        return err
    } else if len(bodyStdin) != 0 {
        body = strings.Join([]string{body, string(bodyStdin)}, "\n\n")
    }
}
```

`interact.IsStdinPiped()` is implemented as `!term.IsTerminal(os.Stdin)` — true for *any* non-TTY stdin, not just for piped data. When tea enters this branch in a subshell where stdin is open but no producer ever writes to it (the typical case for shell scripts and automation), `io.ReadAll` blocks waiting for an EOF that never arrives.

## Fix

Only consume stdin when the user did **not** supply a positional body. If they passed a body via args, that's their content — ignore stdin entirely.

```go
if len(body) == 0 && interact.IsStdinPiped() {
    // ... read stdin ...
    body = string(bodyStdin)
}
```

## Behavior matrix

| Invocation | Before | After |
|---|---|---|
| `tea comment <idx> "body"` (TTY) | works | works |
| `tea comment <idx> "body"` (non-TTY, no redirect) | **hangs forever** | **works** |
| `tea comment <idx> "body" < /dev/null` | works | works |
| `echo body \| tea comment <idx>` | works | works |
| `tea comment <idx> "prefix"` + piped stdin | "prefix" + stdin concatenated | positional body wins, stdin ignored |
| `tea comment <idx>` (TTY, no body, no pipe) | opens editor | opens editor |

The one behavior change is the prefix-plus-stdin case (5th row). I couldn't find anyone relying on that pattern and it wasn't documented; defaulting to "positional body wins" matches the principle of least surprise.

## Verification

Confirmed each row against `dinsmoor/tea-testing` issue #1 on `gitea.com` with the patched binary. Previously-hanging invocations now post in <0.5s. Piped-stdin path unchanged.

---

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/1011
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Tyler <tyler@dinsmoor.us>
Co-committed-by: Tyler <tyler@dinsmoor.us>
2026-05-28 17:45:44 +00:00
Tyler 6dd33b5f4f docs(login): make the git credential helper discoverable (#1014)
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>
2026-05-28 17:38:58 +00:00
Tyler 23a3967e15 fix(print): distinguish draft PRs from conflicting PRs (#1012)
## 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>
2026-05-28 17:29:00 +00:00
kuil09 06e4d16bf3 feat: add wiki CLI commands (#998)
## 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>
2026-05-26 21:14:47 +00:00
Lunny Xiao 28ba9b915b Move sdk from code.gitea.io/sdk/gitea to gitea.dev/sdk (#1006)
Reviewed-on: https://gitea.com/gitea/tea/pulls/1006
Reviewed-by: Zettat123 <39446+zettat123@noreply.gitea.com>
2026-05-26 04:51:09 +00:00
Minjie Fang 579099f9d9 fix(context): improve local repo detection logic and test (#999)
Fix https://gitea.com/gitea/tea/issues/995

Reviewed-on: https://gitea.com/gitea/tea/pulls/999
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Minjie Fang <wingsallen@gmail.com>
Co-committed-by: Minjie Fang <wingsallen@gmail.com>
2026-05-25 22:12:19 +00:00
Lunny Xiao a664449282 Use git command instead of go git (#1005)
Remove go git library because it doesn't support sha256 repository but have an interface so that we could have other backend for the future.

Reviewed-on: https://gitea.com/gitea/tea/pulls/1005
Reviewed-by: Zettat123 <39446+zettat123@noreply.gitea.com>
2026-05-23 20:24:47 +00:00
techknowlogick 8e0666ab85 update import path to use gitea.dev (#1003)
Reviewed-on: https://gitea.com/gitea/tea/pulls/1003
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.com>
Co-committed-by: techknowlogick <techknowlogick@gitea.com>
2026-05-23 17:26:43 +00:00
Renovate Bot bbe97a5e23 fix(deps): update module golang.org/x/crypto to v0.52.0 [security] (#1002)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) | [`v0.51.0` → `v0.52.0`](https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.51.0...refs/tags/v0.52.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fcrypto/v0.52.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fcrypto/v0.51.0/v0.52.0?slim=true) |

---

### Invoking key constraints not enforced in golang.org/x/crypto/ssh/agent
[CVE-2026-39833](https://nvd.nist.gov/vuln/detail/CVE-2026-39833) / [GO-2026-5005](https://pkg.go.dev/vuln/GO-2026-5005)

<details>
<summary>More information</summary>

#### Details
The in-memory keyring returned by NewKeyring() silently accepted keys with the ConfirmBeforeUse constraint but never enforced it. The key would sign without any confirmation prompt, with no indication to the caller that the constraint was not in effect. NewKeyring() now returns an error when unsupported constraints are requested.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79436](https://go.dev/issue/79436)
- [https://go.dev/cl/778640](https://go.dev/cl/778640)
- [https://go.dev/cl/778641](https://go.dev/cl/778641)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5005) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking agent constraints dropped when forwarding keys in golang.org/x/crypto/ssh/agent
[CVE-2026-39832](https://nvd.nist.gov/vuln/detail/CVE-2026-39832) / [GO-2026-5006](https://pkg.go.dev/vuln/GO-2026-5006)

<details>
<summary>More information</summary>

#### Details
When adding a key to a remote agent constraint extensions such as restrict-destination-v00@&#8203;openssh.com were not serialized in the request. Destination restrictions were silently stripped when forwarding keys, allowing unrestricted use of the key on the remote host. The client now serializes all constraint extensions. Additionally, the in-memory keyring returned by NewKeyring() now rejects keys with unsupported constraint extensions instead of silently ignoring them.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79435](https://go.dev/issue/79435)
- [https://go.dev/cl/778642](https://go.dev/cl/778642)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5006) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking byte arithmetic causes underflow and panic in golang.org/x/crypto/ssh
[CVE-2026-46597](https://nvd.nist.gov/vuln/detail/CVE-2026-46597) / [GO-2026-5013](https://pkg.go.dev/vuln/GO-2026-5013)

<details>
<summary>More information</summary>

#### Details
An incorrectly placed cast from bytes to int allowed for server-side panic in the AES-GCM packet decoder for well-crafted inputs.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79561](https://go.dev/issue/79561)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781620](https://go.dev/cl/781620)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5013) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking bypass of certificate restrictions in golang.org/x/crypto/ssh
[CVE-2026-39828](https://nvd.nist.gov/vuln/detail/CVE-2026-39828) / [GO-2026-5014](https://pkg.go.dev/vuln/GO-2026-5014)

<details>
<summary>More information</summary>

#### Details
When an SSH server authentication callback returned PartialSuccessError with non-nil Permissions, those permissions were silently discarded, potentially dropping certificate restrictions such as force-command after a second factor succeeded. Returning non-nil Permissions with PartialSuccessError now results in a connection error.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79562](https://go.dev/issue/79562)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781621](https://go.dev/cl/781621)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5014) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking server panic during CheckHostKey/Authenticate in golang.org/x/crypto/ssh
[CVE-2026-39835](https://nvd.nist.gov/vuln/detail/CVE-2026-39835) / [GO-2026-5015](https://pkg.go.dev/vuln/GO-2026-5015)

<details>
<summary>More information</summary>

#### Details
SSH servers which use CertChecker as a public key callback without setting IsUserAuthority or IsHostAuthority could be caused to panic by a client presenting a certificate. CertChecker now returns an error instead of panicking when these callbacks are nil.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79563](https://go.dev/issue/79563)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781660](https://go.dev/cl/781660)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5015) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking memory leak when rejecting channels can lead to DoS in golang.org/x/crypto/ssh
[CVE-2026-39827](https://nvd.nist.gov/vuln/detail/CVE-2026-39827) / [GO-2026-5016](https://pkg.go.dev/vuln/GO-2026-5016)

<details>
<summary>More information</summary>

#### Details
An authenticated SSH client that repeatedly opened channels which were rejected by the server caused unbounded memory growth, eventually crashing the server process and affecting all connected users. Rejected channels are now properly removed from the connection's internal state and released for garbage collection.

#### Severity
Unknown

#### References
- [https://go.dev/issue/35127](https://go.dev/issue/35127)
- [https://go.dev/cl/781320](https://go.dev/cl/781320)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5016) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking client can cause server deadlock on unexpected responses in golang.org/x/crypto/ssh
[CVE-2026-39830](https://nvd.nist.gov/vuln/detail/CVE-2026-39830) / [GO-2026-5017](https://pkg.go.dev/vuln/GO-2026-5017)

<details>
<summary>More information</summary>

#### Details
A malicious SSH peer could send unsolicited global request responses to fill an internal buffer, blocking the connection's read loop. The blocked goroutine could not be released by calling Close(), resulting in a resource leak per connection. Unsolicited global responses are now discarded.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79564](https://go.dev/issue/79564)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781640](https://go.dev/cl/781640)
- [https://go.dev/cl/781664](https://go.dev/cl/781664)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5017) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking pathological RSA/DSA parameters may cause DoS in golang.org/x/crypto/ssh
[CVE-2026-39829](https://nvd.nist.gov/vuln/detail/CVE-2026-39829) / [GO-2026-5018](https://pkg.go.dev/vuln/GO-2026-5018)

<details>
<summary>More information</summary>

#### Details
The RSA and DSA public key parsers did not enforce size limits on key parameters. A crafted public key with an excessively large modulus or DSA parameter could cause several minutes of CPU consumption during signature verification. This could be triggered by unauthenticated clients during public key authentication. RSA moduli are now limited to 8192 bits, and DSA parameters are validated per FIPS 186-2.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79565](https://go.dev/issue/79565)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781641](https://go.dev/cl/781641)
- [https://go.dev/cl/781661](https://go.dev/cl/781661)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5018) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking bypass of FIDO/U2F security keys physical interaction in golang.org/x/crypto/ssh
[CVE-2026-39831](https://nvd.nist.gov/vuln/detail/CVE-2026-39831) / [GO-2026-5019](https://pkg.go.dev/vuln/GO-2026-5019)

<details>
<summary>More information</summary>

#### Details
The Verify() method for FIDO/U2F security key types (sk-ecdsa-sha2-nistp256@&#8203;openssh.com, sk-ssh-ed25519@&#8203;openssh.com) did not check the User Presence flag. Signatures generated without physical touch were accepted, allowing unattended use of a hardware security key. To restore the previous behavior, return a "no-touch-required" extension in Permissions.Extensions from PublicKeyCallback.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79566](https://go.dev/issue/79566)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781662](https://go.dev/cl/781662)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5019) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking infinite loop on large channel writes in golang.org/x/crypto/ssh
[CVE-2026-39834](https://nvd.nist.gov/vuln/detail/CVE-2026-39834) / [GO-2026-5020](https://pkg.go.dev/vuln/GO-2026-5020)

<details>
<summary>More information</summary>

#### Details
When writing data larger than 4GB in a single Write call on an SSH channel, an integer overflow in the internal payload size calculation caused the write loop to spin indefinitely, sending empty packets without making progress. The size comparison now uses int64 to prevent truncation.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79567](https://go.dev/issue/79567)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781663](https://go.dev/cl/781663)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5020) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking auth bypass via unenforced @&#8203;revoked status in golang.org/x/crypto/ssh/knownhosts
[CVE-2026-42508](https://nvd.nist.gov/vuln/detail/CVE-2026-42508) / [GO-2026-5021](https://pkg.go.dev/vuln/GO-2026-5021)

<details>
<summary>More information</summary>

#### Details
Previously, a revoked 'SignatureKey' belonging to a CA was not correctly checked for revocation. Now, both the 'key' and 'key.SignatureKey' are checked for @&#8203;revoked.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79568](https://go.dev/issue/79568)
- [https://go.dev/cl/781220](https://go.dev/cl/781220)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5021) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking VerifiedPublicKeyCallback permissions skip enforcement in golang.org/x/crypto/ssh
[CVE-2026-46595](https://nvd.nist.gov/vuln/detail/CVE-2026-46595) / [GO-2026-5023](https://pkg.go.dev/vuln/GO-2026-5023)

<details>
<summary>More information</summary>

#### Details
Previously, CVE-2024-45337 fixed an authorization bypass for misused ssh server configurations; if any other type of callback is passed other than public key, then the source-address validation would be skipped.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79570](https://go.dev/issue/79570)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)
- [https://go.dev/cl/781642](https://go.dev/cl/781642)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5023) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking pathological inputs can lead to client panic in golang.org/x/crypto/ssh/agent
[CVE-2026-46598](https://nvd.nist.gov/vuln/detail/CVE-2026-46598) / [GO-2026-5033](https://pkg.go.dev/vuln/GO-2026-5033)

<details>
<summary>More information</summary>

#### Details
For certain crafted inputs, a 'ed25519.PrivateKey' was created by casting malformed wire bytes, leading to a panic when used.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79596](https://go.dev/issue/79596)
- [https://go.dev/cl/781360](https://go.dev/cl/781360)
- [https://groups.google.com/g/golang-announce/c/a082jnz-LvI](https://groups.google.com/g/golang-announce/c/a082jnz-LvI)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5033) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - ""
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

---------

Co-authored-by: silverwind <2021+silverwind@noreply.gitea.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/1002
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-05-22 21:21:18 +00:00
Renovate Bot 82323c7270 chore(deps): update module golang.org/x/net to v0.55.0 [security] (#1001)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) | [`v0.54.0` → `v0.55.0`](https://cs.opensource.google/go/x/net/+/refs/tags/v0.54.0...refs/tags/v0.55.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fnet/v0.55.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fnet/v0.54.0/v0.55.0?slim=true) |

---

### Invoking incorrect handling of namespaced elements in foreign content in golang.org/x/net/html
[CVE-2026-42506](https://nvd.nist.gov/vuln/detail/CVE-2026-42506) / [GO-2026-5025](https://pkg.go.dev/vuln/GO-2026-5025)

<details>
<summary>More information</summary>

#### Details
Parsing arbitrary HTML which is then rendered using Render can result in an unexpected HTML tree. This can be leveraged to execute XSS attacks in applications that attempt to sanitize input HTML before rendering.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79571](https://go.dev/issue/79571)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)
- [https://go.dev/cl/781700](https://go.dev/cl/781700)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5025) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking failure to reject ASCII-only Punycode-encoded labels in golang.org/x/net/idna
[CVE-2026-39821](https://nvd.nist.gov/vuln/detail/CVE-2026-39821) / [GO-2026-5026](https://pkg.go.dev/vuln/GO-2026-5026)

<details>
<summary>More information</summary>

#### Details
The ToASCII and ToUnicode functions incorrectly accept Punycode-encoded labels that decode to an ASCII-only label. For example, ToUnicode("xn--example-.com") incorrectly returns the name "example.com" rather than an error.

This behavior can lead to privilege escalation in programs using the idna package. For example, a program which performs privilege checks on the ASCII hostname may reject "example.com" but permit "xn--example-.com". If that program subsequently converts the ASCII hostname to Unicode, it will inadvertently permits access to the Unicode name "example.com".

#### Severity
Unknown

#### References
- [https://go.dev/cl/767220](https://go.dev/cl/767220)
- [https://go.dev/issue/78760](https://go.dev/issue/78760)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5026) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking incorrect handling of HTML elements in foreign content in golang.org/x/net/html
[CVE-2026-42502](https://nvd.nist.gov/vuln/detail/CVE-2026-42502) / [GO-2026-5027](https://pkg.go.dev/vuln/GO-2026-5027)

<details>
<summary>More information</summary>

#### Details
Parsing arbitrary HTML which is then rendered using Render can result in an unexpected HTML tree. This can be leveraged to execute XSS attacks in applications that attempt to sanitize input HTML before rendering.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79572](https://go.dev/issue/79572)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)
- [https://go.dev/cl/781701](https://go.dev/cl/781701)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5027) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking denial of service when parsing arbitrary HTML in golang.org/x/net/html
[CVE-2026-25680](https://nvd.nist.gov/vuln/detail/CVE-2026-25680) / [GO-2026-5028](https://pkg.go.dev/vuln/GO-2026-5028)

<details>
<summary>More information</summary>

#### Details
Parsing arbitrary HTML can consume excessive CPU time, possibly leading to denial of service.

#### Severity
Unknown

#### References
- [https://go.dev/cl/781702](https://go.dev/cl/781702)
- [https://go.dev/issue/79573](https://go.dev/issue/79573)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5028) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking incorrect handling of character references in DOCTYPE nodes in golang.org/x/net/html
[CVE-2026-25681](https://nvd.nist.gov/vuln/detail/CVE-2026-25681) / [GO-2026-5029](https://pkg.go.dev/vuln/GO-2026-5029)

<details>
<summary>More information</summary>

#### Details
Parsing arbitrary HTML which is then rendered using Render can result in an unexpected HTML tree. This can be leveraged to execute XSS attacks in applications that attempt to sanitize input HTML before rendering.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79574](https://go.dev/issue/79574)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)
- [https://go.dev/cl/781703](https://go.dev/cl/781703)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5029) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Invoking duplicate attributes can cause XSS in golang.org/x/net/html
[CVE-2026-27136](https://nvd.nist.gov/vuln/detail/CVE-2026-27136) / [GO-2026-5030](https://pkg.go.dev/vuln/GO-2026-5030)

<details>
<summary>More information</summary>

#### Details
Parsing arbitrary HTML which is then rendered using Render can result in an unexpected HTML tree. This can be leveraged to execute XSS attacks in applications that attempt to sanitize input HTML before rendering.

#### Severity
Unknown

#### References
- [https://go.dev/issue/79575](https://go.dev/issue/79575)
- [https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8](https://groups.google.com/g/golang-announce/c/iI-mYSI0lu8)
- [https://go.dev/cl/781685](https://go.dev/cl/781685)

This data is provided by [OSV](https://osv.dev/vulnerability/GO-2026-5030) and the [Go Vulnerability Database](https://github.com/golang/vulndb) ([CC-BY 4.0](https://github.com/golang/vulndb#license)).
</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - ""
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1001
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-05-22 20:51:54 +00:00
Renovate Bot 861201541d fix(deps): update module golang.org/x/sys to v0.45.0 (#1000)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) | [`v0.44.0` → `v0.45.0`](https://cs.opensource.google/go/x/sys/+/refs/tags/v0.44.0...refs/tags/v0.45.0) | ![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fsys/v0.45.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fsys/v0.44.0/v0.45.0?slim=true) |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTAuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE5MC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/1000
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-05-22 07:35:59 +00:00
Renovate Bot 3d667c1594 chore(deps): update docker.gitea.com/gitea docker tag to v1.26.2 (#997)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [docker.gitea.com/gitea](https://github.com/go-gitea/gitea) | service | patch | `1.26.1` → `1.26.2` |

---

### Release Notes

<details>
<summary>go-gitea/gitea (docker.gitea.com/gitea)</summary>

### [`v1.26.2`](https://github.com/go-gitea/gitea/blob/HEAD/CHANGELOG.md#1262---2026-05-20)

[Compare Source](https://github.com/go-gitea/gitea/compare/v1.26.1...v1.26.2)

- SECURITY
  - fix(permissions): Fix reading permission ([#&#8203;37769](https://github.com/go-gitea/gitea/issues/37769))
  - fix(actions): make artifact signature payloads unambiguous ([#&#8203;37707](https://github.com/go-gitea/gitea/issues/37707))
  - fix: Unify public-only token filtering in API queries and repo access checks ([#&#8203;37118](https://github.com/go-gitea/gitea/issues/37118))
  - fix: Add missed token scope checking ([#&#8203;37735](https://github.com/go-gitea/gitea/issues/37735))
  - fix(oauth): bind token exchanges to the original client request ([#&#8203;37704](https://github.com/go-gitea/gitea/issues/37704))
  - fix(oauth): strengthen PKCE validation and refresh token replay protection ([#&#8203;37706](https://github.com/go-gitea/gitea/issues/37706))
  - fix(web): enforce token scopes on raw, media, and attachment downloads ([#&#8203;37698](https://github.com/go-gitea/gitea/issues/37698))
  - fix(security): enforce wiki git writes and LFS token access at request time ([#&#8203;37695](https://github.com/go-gitea/gitea/issues/37695))
  - feat(api): encrypt AWS creds ([#&#8203;37679](https://github.com/go-gitea/gitea/issues/37679))
  - fix(deps): update dependency mermaid to v11.15.0 \[security], add e2e test
  - fix(packages): Add label for private and internal package and fix composor package source permission check ([#&#8203;37610](https://github.com/go-gitea/gitea/issues/37610))
  - fix(git): Fix smart http request scope bug ([#&#8203;37583](https://github.com/go-gitea/gitea/issues/37583))
  - Fix basic auth bug ([#&#8203;37503](https://github.com/go-gitea/gitea/issues/37503))
  - Fix allow maintainer edit permission check ([#&#8203;37479](https://github.com/go-gitea/gitea/issues/37479)) ([#&#8203;37484](https://github.com/go-gitea/gitea/issues/37484))
  - Fix URL sanitization to handle schemeless credentials ([#&#8203;37440](https://github.com/go-gitea/gitea/issues/37440)) ([#&#8203;37471](https://github.com/go-gitea/gitea/issues/37471))
  - Fix attachment Content-Security-Policy ([#&#8203;37455](https://github.com/go-gitea/gitea/issues/37455)) ([#&#8203;37464](https://github.com/go-gitea/gitea/issues/37464))
  - chore(deps): bump go-git/go-git/v5 to 5.19.0 ([#&#8203;37608](https://github.com/go-gitea/gitea/issues/37608))

- BUGFIXES
  - fix(pull): handle empty pull request files view to allow reviews ([#&#8203;37783](https://github.com/go-gitea/gitea/issues/37783))
  - fix(markup): make RenderString never fail ([#&#8203;37779](https://github.com/go-gitea/gitea/issues/37779))
  - fix: add natural sort to sortTreeViewNodes ([#&#8203;37772](https://github.com/go-gitea/gitea/issues/37772))
  - fix: package creation unique conflict ([#&#8203;37774](https://github.com/go-gitea/gitea/issues/37774))
  - fix!: add DEFAULT\_TITLE\_SOURCE setting for pull request title default behavior ([#&#8203;37465](https://github.com/go-gitea/gitea/issues/37465))
  - fix: Allow direct commits for unprotected files with push restrictions ([#&#8203;37657](https://github.com/go-gitea/gitea/issues/37657))
  - fix(actions): wrong assumption that run id always >= job id ([#&#8203;37737](https://github.com/go-gitea/gitea/issues/37737))
  - fix(auth): set User-Agent on avatar fetch and sync avatar on link-account register ([#&#8203;37564](https://github.com/go-gitea/gitea/issues/37564)) ([#&#8203;37588](https://github.com/go-gitea/gitea/issues/37588))
  - fix(actions): deadlock between PrepareRunAndInsert and UpdateTaskByState ([#&#8203;37692](https://github.com/go-gitea/gitea/issues/37692))
  - fix(repo): /generate must sync the branch table for the new repo ([#&#8203;37693](https://github.com/go-gitea/gitea/issues/37693))
  - build: Fix snap build (1.26)
  - fix(actions): run TransferLogs on UpdateLog{Rows:\[], NoMore:true} ([#&#8203;37631](https://github.com/go-gitea/gitea/issues/37631))
  - fix show correct mergebase
  - fix: make clone URL respect public URL detection setting ([#&#8203;37615](https://github.com/go-gitea/gitea/issues/37615))
  - fix: "run as root" check ([#&#8203;37622](https://github.com/go-gitea/gitea/issues/37622))
  - chore(deps): update dependency go to v1.26.3 ([#&#8203;37601](https://github.com/go-gitea/gitea/issues/37601))
  - Compare dropdown fails when selecting branch with no common merge-base ([#&#8203;37470](https://github.com/go-gitea/gitea/issues/37470))
  - fix: treat email addresses case-insensitively ([#&#8203;37600](https://github.com/go-gitea/gitea/issues/37600))
  - fix(actions): fix blank lines after ::endgroup:: ([#&#8203;37597](https://github.com/go-gitea/gitea/issues/37597))
  - fix(actions): report individual step status in workflow job API response ([#&#8203;37592](https://github.com/go-gitea/gitea/issues/37592))
  - fix: Invalid UTF-8 commit messages in JSON API responses ([#&#8203;37542](https://github.com/go-gitea/gitea/issues/37542))
  - fix: use consistent GetUser family functions ([#&#8203;37553](https://github.com/go-gitea/gitea/issues/37553))
  - fix(api): return 409 message instead of empty JSON for wrong commit id ([#&#8203;37572](https://github.com/go-gitea/gitea/issues/37572))
  - fix(actions): prevent panic when workflow contains null jobs ([#&#8203;37570](https://github.com/go-gitea/gitea/issues/37570))
  - Make ServeSetHeaders default to download attachment if filename exists ([#&#8203;37552](https://github.com/go-gitea/gitea/issues/37552)) ([#&#8203;37555](https://github.com/go-gitea/gitea/issues/37555))
  - Fix(actions): validate workflow param to prevent 500 error ([#&#8203;37546](https://github.com/go-gitea/gitea/issues/37546)) ([#&#8203;37554](https://github.com/go-gitea/gitea/issues/37554))
  - Don't unblock run-level-concurrency-blocked runs in the resolver ([#&#8203;37461](https://github.com/go-gitea/gitea/issues/37461)) ([#&#8203;37538](https://github.com/go-gitea/gitea/issues/37538))
  - Fix(packages): use file names for generic web downloads ([#&#8203;37514](https://github.com/go-gitea/gitea/issues/37514)) ([#&#8203;37520](https://github.com/go-gitea/gitea/issues/37520))
  - Fix merge autodetect can't close other PRs but only the last one when multiple PRs are pushed at once ([#&#8203;37512](https://github.com/go-gitea/gitea/issues/37512)) ([#&#8203;37516](https://github.com/go-gitea/gitea/issues/37516))
  - Fix update branch protection order ([#&#8203;37508](https://github.com/go-gitea/gitea/issues/37508)) ([#&#8203;37513](https://github.com/go-gitea/gitea/issues/37513))
  - Fix mCaptcha broken after Vite migration ([#&#8203;37492](https://github.com/go-gitea/gitea/issues/37492)) ([#&#8203;37509](https://github.com/go-gitea/gitea/issues/37509))
  - Fix review submission from single-commit PR view ([#&#8203;37475](https://github.com/go-gitea/gitea/issues/37475)) ([#&#8203;37485](https://github.com/go-gitea/gitea/issues/37485))
  - Fix scheduled action panic with null event payload ([#&#8203;37459](https://github.com/go-gitea/gitea/issues/37459)) ([#&#8203;37466](https://github.com/go-gitea/gitea/issues/37466))
  - Make GetPossibleUserByID can handle deleted user ([#&#8203;37430](https://github.com/go-gitea/gitea/issues/37430)) ([#&#8203;37431](https://github.com/go-gitea/gitea/issues/37431))
  - Remove excessive quote from terraform instructions ([#&#8203;37424](https://github.com/go-gitea/gitea/issues/37424)) ([#&#8203;37426](https://github.com/go-gitea/gitea/issues/37426))
  - Fix color regressions, add `priority` color ([#&#8203;37417](https://github.com/go-gitea/gitea/issues/37417)) ([#&#8203;37421](https://github.com/go-gitea/gitea/issues/37421))

- MISC
  - Add CurrentURL template variable back ([#&#8203;37444](https://github.com/go-gitea/gitea/issues/37444)) ([#&#8203;37449](https://github.com/go-gitea/gitea/issues/37449))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xODYuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE4Ni4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/997
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-05-21 01:27:33 +00:00
Renovate Bot ef0dc62dd6 fix(deps): update module github.com/go-git/go-git/v5 to v5.19.1 (#996)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | `v5.19.0` → `v5.19.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgo-git%2fgo-git%2fv5/v5.19.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgo-git%2fgo-git%2fv5/v5.19.0/v5.19.1?slim=true) |

---

### Release Notes

<details>
<summary>go-git/go-git (github.com/go-git/go-git/v5)</summary>

### [`v5.19.1`](https://github.com/go-git/go-git/releases/tag/v5.19.1)

[Compare Source](https://github.com/go-git/go-git/compare/v5.19.0...v5.19.1)

#### What's Changed

- v5: plumbing: transport/ssh, Shell-quote path by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2068](https://github.com/go-git/go-git/pull/2068)
- v5: git: submodule, Fix relative URL resolution by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2070](https://github.com/go-git/go-git/pull/2070)
- v5: git: submodule, canonical remote for relative URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2074](https://github.com/go-git/go-git/pull/2074)
- v5: git: submodule, error on remote without URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2078](https://github.com/go-git/go-git/pull/2078)
- v5: plumbing: format/idxfile, Validate offset64 indices by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2084](https://github.com/go-git/go-git/pull/2084)
- v5: \*: Reject malformed variable-length integers by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2092](https://github.com/go-git/go-git/pull/2092)
- v5: plumbing: format/packfile, Tighten delta validation by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2091](https://github.com/go-git/go-git/pull/2091)
- v5: Add `worktreeFilesystem` wrapper for worktree and hardening by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2100](https://github.com/go-git/go-git/pull/2100)
- v5: config: validate submodule names by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2082](https://github.com/go-git/go-git/pull/2082)
- build: Update module github.com/go-git/go-git/v5 to v5.19.0 \[SECURITY] (releases/v5.x) by [@&#8203;go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#&#8203;2111](https://github.com/go-git/go-git/pull/2111)
- v5: git: Allow MkdirAll on worktree-root paths by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2117](https://github.com/go-git/go-git/pull/2117)
- v5: git: Stop validating symlink target paths by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2116](https://github.com/go-git/go-git/pull/2116)
- v5: plumbing: format decoder input bounds and contracts by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2125](https://github.com/go-git/go-git/pull/2125)
- plumbing: format/packfile, cap delta chain depth in parser by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2137](https://github.com/go-git/go-git/pull/2137)

**Full Changelog**: <https://github.com/go-git/go-git/compare/v5.19.0...v5.19.1>

</details>
---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xODIuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE4Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/tea/pulls/996
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-05-19 04:53:00 +00:00
techknowlogick 70c7ee11f2 update renovate config 2026-05-14 16:24:31 +00:00
265 changed files with 6016 additions and 1648 deletions
+3 -3
View File
@@ -8,7 +8,7 @@ jobs:
goreleaser: goreleaser:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- run: git fetch --force --tags - run: git fetch --force --tags
@@ -23,7 +23,7 @@ jobs:
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
- name: get SDK version - name: get SDK version
id: sdk_version id: sdk_version
run: echo "version=$(go list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)" >> "$GITHUB_OUTPUT" run: echo "version=$(go list -f '{{.Version}}' -m gitea.dev/sdk)" >> "$GITHUB_OUTPUT"
- name: goreleaser - name: goreleaser
uses: goreleaser/goreleaser-action@v7 uses: goreleaser/goreleaser-action@v7
with: with:
@@ -49,7 +49,7 @@ jobs:
DOCKER_LATEST: nightly DOCKER_LATEST: nightly
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 # all history for all branches and tags fetch-depth: 0 # all history for all branches and tags
+3 -3
View File
@@ -9,7 +9,7 @@ jobs:
goreleaser: goreleaser:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- run: git fetch --force --tags - run: git fetch --force --tags
@@ -24,7 +24,7 @@ jobs:
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
- name: get SDK version - name: get SDK version
id: sdk_version id: sdk_version
run: echo "version=$(go list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)" >> "$GITHUB_OUTPUT" run: echo "version=$(go list -f '{{.Version}}' -m gitea.dev/sdk)" >> "$GITHUB_OUTPUT"
- name: goreleaser - name: goreleaser
uses: goreleaser/goreleaser-action@v7 uses: goreleaser/goreleaser-action@v7
with: with:
@@ -50,7 +50,7 @@ jobs:
DOCKER_LATEST: nightly DOCKER_LATEST: nightly
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 # all history for all branches and tags fetch-depth: 0 # all history for all branches and tags
+3 -3
View File
@@ -16,7 +16,7 @@ jobs:
name: Lint Build And Unit Coverage name: Lint Build And Unit Coverage
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
@@ -41,7 +41,7 @@ jobs:
GITEA_TEA_TEST_USERNAME: "test01" GITEA_TEA_TEST_USERNAME: "test01"
GITEA_TEA_TEST_PASSWORD: "test01" GITEA_TEA_TEST_PASSWORD: "test01"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
@@ -51,7 +51,7 @@ jobs:
make integration-test make integration-test
services: services:
gitea: gitea:
image: docker.gitea.com/gitea:1.26.1 image: docker.gitea.com/gitea:1.26.2
cmd: cmd:
- bash - bash
- -c - -c
+1 -1
View File
@@ -56,7 +56,7 @@ builds:
flags: flags:
- -trimpath - -trimpath
ldflags: ldflags:
- -s -w -X "code.gitea.io/tea/modules/version.Version={{ trimprefix .Summary "v" }}" -X "code.gitea.io/tea/modules/version.Tags=" -X "code.gitea.io/tea/modules/version.SDK={{ .Env.SDK_VERSION }}" - -s -w -X "gitea.dev/tea/modules/version.Version={{ trimprefix .Summary "v" }}" -X "gitea.dev/tea/modules/version.Tags=" -X "gitea.dev/tea/modules/version.SDK={{ .Env.SDK_VERSION }}"
binary: >- binary: >-
{{ .ProjectName }}- {{ .ProjectName }}-
{{- .Version }}- {{- .Version }}-
+1 -1
View File
@@ -124,7 +124,7 @@ import (
// local packages // local packages
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/sdk/gitea" "gitea.dev/sdk"
// external packages // external packages
"github.com/foo/bar" "github.com/foo/bar"
+5 -4
View File
@@ -24,16 +24,17 @@ endif
TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION)) TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION))
TAGS ?= TAGS ?=
SDK ?= $(shell $(GO) list -f '{{.Version}}' -m code.gitea.io/sdk/gitea) SDK ?= $(shell $(GO) list -f '{{.Version}}' -m gitea.dev/sdk)
LDFLAGS := -X "code.gitea.io/tea/modules/version.Version=$(TEA_VERSION)" -X "code.gitea.io/tea/modules/version.Tags=$(TAGS)" -X "code.gitea.io/tea/modules/version.SDK=$(SDK)" -s -w LDFLAGS := -X "gitea.dev/tea/modules/version.Version=$(TEA_VERSION)" -X "gitea.dev/tea/modules/version.Tags=$(TAGS)" -X "gitea.dev/tea/modules/version.SDK=$(SDK)" -s -w
# override to allow passing additional goflags via make CLI # override to allow passing additional goflags via make CLI
override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
PACKAGES ?= $(shell $(GO) list ./... | grep -v '^code.gitea.io/tea/tests') PACKAGES ?= $(shell $(GO) list ./... | grep -v '^gitea.dev/tea/tests')
UNIT_PACKAGES ?= $(PACKAGES) UNIT_PACKAGES ?= $(PACKAGES)
INTEGRATION_PACKAGES ?= $(shell $(GO) list ./tests/... 2>/dev/null) INTEGRATION_PACKAGES ?= $(shell $(GO) list ./tests/... 2>/dev/null)
INTEGRATION_TEST_TAGS ?= testtools INTEGRATION_TEST_TAGS ?= testtools
INTEGRATION_TEST_GOFLAGS ?= -v
SOURCES ?= $(shell find . -name "*.go" -type f) SOURCES ?= $(shell find . -name "*.go" -type f)
# OS specific vars. # OS specific vars.
@@ -103,7 +104,7 @@ unit-test:
.PHONY: integration-test .PHONY: integration-test
integration-test: integration-test:
@if [ -n "$(INTEGRATION_PACKAGES)" ]; then \ @if [ -n "$(INTEGRATION_PACKAGES)" ]; then \
$(GO) test -tags='$(INTEGRATION_TEST_TAGS)' $(INTEGRATION_PACKAGES); \ $(GO) test $(INTEGRATION_TEST_GOFLAGS) -tags='$(INTEGRATION_TEST_TAGS)' $(INTEGRATION_PACKAGES); \
else \ else \
echo "No integration test packages found"; \ echo "No integration test packages found"; \
fi fi
+3 -3
View File
@@ -3,7 +3,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Release](https://raster.shields.io/badge/dynamic/json.svg?label=release&url=https://gitea.com/api/v1/repos/gitea/tea/releases&query=$[0].tag_name)](https://gitea.com/gitea/tea/releases) [![Release](https://raster.shields.io/badge/dynamic/json.svg?label=release&url=https://gitea.com/api/v1/repos/gitea/tea/releases&query=$[0].tag_name)](https://gitea.com/gitea/tea/releases)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea) [![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/tea)](https://goreportcard.com/report/code.gitea.io/tea) [![GoDoc](https://pkg.go.dev/badge/code.gitea.io/tea?status.svg)](https://godoc.org/code.gitea.io/tea) [![Go Report Card](https://goreportcard.com/badge/gitea.dev/tea)](https://goreportcard.com/report/gitea.dev/tea) [![GoDoc](https://pkg.go.dev/badge/gitea.dev/tea?status.svg)](https://godoc.org/gitea.dev/tea)
![Tea Release Status](https://gitea.com/gitea/tea/actions/workflows/release-nightly.yml/badge.svg) ![Tea Release Status](https://gitea.com/gitea/tea/actions/workflows/release-nightly.yml/badge.svg)
## The official CLI for Gitea ## The official CLI for Gitea
@@ -97,7 +97,7 @@ ABOUT
More info about Gitea itself on https://about.gitea.com. More info about Gitea itself on https://about.gitea.com.
``` ```
- tea uses [code.gitea.io/sdk](https://code.gitea.io/sdk) and interacts with the Gitea API. - tea uses [gitea.dev/sdk](https://gitea.dev/sdk) and interacts with the Gitea API.
## Installation ## Installation
@@ -186,7 +186,7 @@ Make sure you have a current Go version installed (1.26 or newer).
- For a quick installation without `git` & `make`, set $version and exec: - For a quick installation without `git` & `make`, set $version and exec:
```sh ```sh
go install code.gitea.io/tea@${version} go install gitea.dev/tea@${version}
``` ```
## Contributing ## Contributing
+1 -1
View File
@@ -6,7 +6,7 @@ package cmd
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/actions" "gitea.dev/tea/cmd/actions"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/actions/runs" "gitea.dev/tea/cmd/actions/runs"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -8,8 +8,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -61,7 +61,7 @@ func runRunsDelete(ctx stdctx.Context, cmd *cli.Command) error {
} }
} }
_, err = client.DeleteRepoActionRun(c.Owner, c.Repo, runID) _, err = client.Actions.DeleteRepoRun(ctx, c.Owner, c.Repo, runID)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete run: %w", err) return fmt.Errorf("failed to delete run: %w", err)
} }
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"fmt" "fmt"
"time" "time"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -106,7 +106,7 @@ func RunRunsList(ctx stdctx.Context, cmd *cli.Command) error {
// Build list options // Build list options
listOpts := flags.GetListOptions(cmd) listOpts := flags.GetListOptions(cmd)
runs, _, err := client.ListRepoActionRuns(c.Owner, c.Repo, gitea.ListRepoActionRunsOptions{ runs, _, err := client.Actions.ListRepoRuns(ctx, c.Owner, c.Repo, gitea.ListRepoActionRunsOptions{
ListOptions: listOpts, ListOptions: listOpts,
Status: cmd.String("status"), Status: cmd.String("status"),
Branch: cmd.String("branch"), Branch: cmd.String("branch"),
+4 -4
View File
@@ -4,15 +4,15 @@
package runs package runs
import ( import (
stdctx "context"
"os" "os"
"testing" "testing"
"time" "time"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/config"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/config"
) )
func TestFilterRunsByTime(t *testing.T) { func TestFilterRunsByTime(t *testing.T) {
@@ -106,6 +106,6 @@ func TestRunRunsListRequiresRepoContext(t *testing.T) {
} }
require.NoError(t, cmd.Set("login", "test")) require.NoError(t, cmd.Set("login", "test"))
err = RunRunsList(stdctx.Background(), cmd) err = RunRunsList(t.Context(), cmd)
require.ErrorContains(t, err, "remote repository required") require.ErrorContains(t, err, "remote repository required")
} }
+11 -11
View File
@@ -9,10 +9,10 @@ import (
"strconv" "strconv"
"time" "time"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -69,10 +69,10 @@ func runRunsLogs(ctx stdctx.Context, cmd *cli.Command) error {
} }
if follow { if follow {
return followJobLogs(client, c, jobID, "") return followJobLogs(ctx, client, c, jobID, "")
} }
logs, _, err := client.GetRepoActionJobLogs(c.Owner, c.Repo, jobID) logs, _, err := client.Actions.GetRepoRunJobLogs(ctx, c.Owner, c.Repo, jobID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get logs for job %d: %w", jobID, err) return fmt.Errorf("failed to get logs for job %d: %w", jobID, err)
} }
@@ -83,7 +83,7 @@ func runRunsLogs(ctx stdctx.Context, cmd *cli.Command) error {
} }
// Otherwise, fetch all jobs and their logs // Otherwise, fetch all jobs and their logs
jobs, _, err := client.ListRepoActionRunJobs(c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{ jobs, _, err := client.Actions.ListRepoJobsByRun(ctx, c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
@@ -102,7 +102,7 @@ func runRunsLogs(ctx stdctx.Context, cmd *cli.Command) error {
// If following with single job, follow it // If following with single job, follow it
if follow && len(jobs.Jobs) == 1 { if follow && len(jobs.Jobs) == 1 {
return followJobLogs(client, c, jobs.Jobs[0].ID, jobs.Jobs[0].Name) return followJobLogs(ctx, client, c, jobs.Jobs[0].ID, jobs.Jobs[0].Name)
} }
// Fetch logs for each job // Fetch logs for each job
@@ -115,7 +115,7 @@ func runRunsLogs(ctx stdctx.Context, cmd *cli.Command) error {
fmt.Printf("Status: %s\n", job.Status) fmt.Printf("Status: %s\n", job.Status)
fmt.Println("---") fmt.Println("---")
logs, _, err := client.GetRepoActionJobLogs(c.Owner, c.Repo, job.ID) logs, _, err := client.Actions.GetRepoRunJobLogs(ctx, c.Owner, c.Repo, job.ID)
if err != nil { if err != nil {
fmt.Printf("Error fetching logs: %v\n", err) fmt.Printf("Error fetching logs: %v\n", err)
continue continue
@@ -128,7 +128,7 @@ func runRunsLogs(ctx stdctx.Context, cmd *cli.Command) error {
} }
// followJobLogs continuously fetches and displays logs for a running job // followJobLogs continuously fetches and displays logs for a running job
func followJobLogs(client *gitea.Client, c *context.TeaContext, jobID int64, jobName string) error { func followJobLogs(requestCtx stdctx.Context, client *gitea.Client, c *context.TeaContext, jobID int64, jobName string) error {
var lastLogLength int var lastLogLength int
if jobName != "" { if jobName != "" {
@@ -140,7 +140,7 @@ func followJobLogs(client *gitea.Client, c *context.TeaContext, jobID int64, job
for { for {
// Fetch job status // Fetch job status
job, _, err := client.GetRepoActionJob(c.Owner, c.Repo, jobID) job, _, err := client.Actions.GetRepoRunJob(requestCtx, c.Owner, c.Repo, jobID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get job: %w", err) return fmt.Errorf("failed to get job: %w", err)
} }
@@ -149,7 +149,7 @@ func followJobLogs(client *gitea.Client, c *context.TeaContext, jobID int64, job
isRunning := job.Status == "in_progress" || job.Status == "queued" || job.Status == "pending" isRunning := job.Status == "in_progress" || job.Status == "queued" || job.Status == "pending"
// Fetch logs // Fetch logs
logs, _, err := client.GetRepoActionJobLogs(c.Owner, c.Repo, jobID) logs, _, err := client.Actions.GetRepoRunJobLogs(requestCtx, c.Owner, c.Repo, jobID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get logs: %w", err) return fmt.Errorf("failed to get logs: %w", err)
} }
+6 -7
View File
@@ -8,11 +8,10 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -54,7 +53,7 @@ func runRunsView(ctx stdctx.Context, cmd *cli.Command) error {
} }
// Fetch run details // Fetch run details
run, _, err := client.GetRepoActionRun(c.Owner, c.Repo, runID) run, _, err := client.Actions.GetRepoRun(ctx, c.Owner, c.Repo, runID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get run: %w", err) return fmt.Errorf("failed to get run: %w", err)
} }
@@ -64,7 +63,7 @@ func runRunsView(ctx stdctx.Context, cmd *cli.Command) error {
// Fetch and print jobs if requested // Fetch and print jobs if requested
if cmd.Bool("jobs") { if cmd.Bool("jobs") {
jobs, _, err := client.ListRepoActionRunJobs(c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{ jobs, _, err := client.Actions.ListRepoJobsByRun(ctx, c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/actions/secrets" "gitea.dev/tea/cmd/actions/secrets"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+5 -5
View File
@@ -7,11 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/utils"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -62,7 +62,7 @@ func runSecretsCreate(ctx stdctx.Context, cmd *cli.Command) error {
return err return err
} }
_, err = client.CreateRepoActionSecret(c.Owner, c.Repo, secretName, gitea.CreateOrUpdateSecretOption{ _, err = client.Actions.CreateRepoSecret(ctx, c.Owner, c.Repo, secretName, gitea.CreateOrUpdateSecretOption{
Data: secretValue, Data: secretValue,
}) })
if err != nil { if err != nil {
+3 -3
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -56,7 +56,7 @@ func runSecretsDelete(ctx stdctx.Context, cmd *cli.Command) error {
} }
} }
_, err = client.DeleteRepoActionSecret(c.Owner, c.Repo, secretName) _, err = client.Actions.DeleteRepoSecret(ctx, c.Owner, c.Repo, secretName)
if err != nil { if err != nil {
return err return err
} }
+5 -5
View File
@@ -6,11 +6,11 @@ package secrets
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -38,7 +38,7 @@ func RunSecretsList(ctx stdctx.Context, cmd *cli.Command) error {
} }
client := c.Login.Client() client := c.Login.Client()
secrets, _, err := client.ListRepoActionSecret(c.Owner, c.Repo, gitea.ListRepoActionSecretOption{ secrets, _, err := client.Actions.ListRepoSecrets(ctx, c.Owner, c.Repo, gitea.ListRepoActionSecretOption{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+3 -3
View File
@@ -4,13 +4,13 @@
package secrets package secrets
import ( import (
stdctx "context"
"os" "os"
"testing" "testing"
"code.gitea.io/tea/modules/config"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/config"
) )
func TestSecretsListFlags(t *testing.T) { func TestSecretsListFlags(t *testing.T) {
@@ -93,6 +93,6 @@ func TestRunSecretsListRequiresRepoContext(t *testing.T) {
} }
require.NoError(t, cmd.Set("login", "test")) require.NoError(t, cmd.Set("login", "test"))
err = RunSecretsList(stdctx.Background(), cmd) err = RunSecretsList(t.Context(), cmd)
require.ErrorContains(t, err, "remote repository required") require.ErrorContains(t, err, "remote repository required")
} }
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/actions/variables" "gitea.dev/tea/cmd/actions/variables"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -56,7 +56,7 @@ func runVariablesDelete(ctx stdctx.Context, cmd *cli.Command) error {
} }
} }
_, err = client.DeleteRepoActionVariable(c.Owner, c.Repo, variableName) _, err = client.Actions.DeleteRepoVariable(ctx, c.Owner, c.Repo, variableName)
if err != nil { if err != nil {
return err return err
} }
+4 -4
View File
@@ -7,9 +7,9 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -42,7 +42,7 @@ func RunVariablesList(ctx stdctx.Context, cmd *cli.Command) error {
if name := cmd.String("name"); name != "" { if name := cmd.String("name"); name != "" {
// Get specific variable // Get specific variable
variable, _, err := client.GetRepoActionVariable(c.Owner, c.Repo, name) variable, _, err := client.Actions.GetRepoVariable(ctx, c.Owner, c.Repo, name)
if err != nil { if err != nil {
return err return err
} }
+3 -3
View File
@@ -4,13 +4,13 @@
package variables package variables
import ( import (
stdctx "context"
"os" "os"
"testing" "testing"
"code.gitea.io/tea/modules/config"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/config"
) )
func TestVariablesListFlags(t *testing.T) { func TestVariablesListFlags(t *testing.T) {
@@ -93,6 +93,6 @@ func TestRunVariablesListRequiresRepoContext(t *testing.T) {
} }
require.NoError(t, cmd.Set("login", "test")) require.NoError(t, cmd.Set("login", "test"))
err = RunVariablesList(stdctx.Background(), cmd) err = RunVariablesList(t.Context(), cmd)
require.ErrorContains(t, err, "remote repository required") require.ErrorContains(t, err, "remote repository required")
} }
+4 -4
View File
@@ -8,9 +8,9 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -69,7 +69,7 @@ func runVariablesSet(ctx stdctx.Context, cmd *cli.Command) error {
return err return err
} }
_, err = client.CreateRepoActionVariable(c.Owner, c.Repo, variableName, variableValue) _, err = client.Actions.CreateRepoVariable(ctx, c.Owner, c.Repo, variableName, variableValue)
if err != nil { if err != nil {
return err return err
} }
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/actions/workflows" "gitea.dev/tea/cmd/actions/workflows"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -55,7 +55,7 @@ func runWorkflowsDisable(ctx stdctx.Context, cmd *cli.Command) error {
} }
} }
_, err = client.DisableRepoActionWorkflow(c.Owner, c.Repo, workflowID) _, err = client.Actions.DisableRepoWorkflow(ctx, c.Owner, c.Repo, workflowID)
if err != nil { if err != nil {
return fmt.Errorf("failed to disable workflow: %w", err) return fmt.Errorf("failed to disable workflow: %w", err)
} }
+10 -10
View File
@@ -9,11 +9,11 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -87,7 +87,7 @@ func runWorkflowsDispatch(ctx stdctx.Context, cmd *cli.Command) error {
Inputs: inputs, Inputs: inputs,
} }
details, _, err := client.DispatchRepoActionWorkflow(c.Owner, c.Repo, workflowID, opt, true) details, _, err := client.Actions.DispatchRepoWorkflow(ctx, c.Owner, c.Repo, workflowID, opt, true)
if err != nil { if err != nil {
return fmt.Errorf("failed to dispatch workflow: %w", err) return fmt.Errorf("failed to dispatch workflow: %w", err)
} }
@@ -95,7 +95,7 @@ func runWorkflowsDispatch(ctx stdctx.Context, cmd *cli.Command) error {
print.ActionWorkflowDispatchResult(details) print.ActionWorkflowDispatchResult(details)
if cmd.Bool("follow") && details != nil && details.WorkflowRunID > 0 { if cmd.Bool("follow") && details != nil && details.WorkflowRunID > 0 {
return followDispatchedRun(client, c, details.WorkflowRunID) return followDispatchedRun(ctx, client, c, details.WorkflowRunID)
} }
return nil return nil
@@ -107,7 +107,7 @@ const (
) )
// followDispatchedRun waits for the dispatched run to start, then follows its logs // followDispatchedRun waits for the dispatched run to start, then follows its logs
func followDispatchedRun(client *gitea.Client, c *context.TeaContext, runID int64) error { func followDispatchedRun(ctx stdctx.Context, client *gitea.Client, c *context.TeaContext, runID int64) error {
fmt.Printf("\nWaiting for run %d to start...\n", runID) fmt.Printf("\nWaiting for run %d to start...\n", runID)
var jobs *gitea.ActionWorkflowJobsResponse var jobs *gitea.ActionWorkflowJobsResponse
@@ -115,7 +115,7 @@ func followDispatchedRun(client *gitea.Client, c *context.TeaContext, runID int6
time.Sleep(followPollInterval) time.Sleep(followPollInterval)
var err error var err error
jobs, _, err = client.ListRepoActionRunJobs(c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{}) jobs, _, err = client.Actions.ListRepoJobsByRun(ctx, c.Owner, c.Repo, runID, gitea.ListRepoActionJobsOptions{})
if err != nil { if err != nil {
return fmt.Errorf("failed to get jobs: %w", err) return fmt.Errorf("failed to get jobs: %w", err)
} }
@@ -136,14 +136,14 @@ func followDispatchedRun(client *gitea.Client, c *context.TeaContext, runID int6
deadline := time.Now().Add(followMaxDuration) deadline := time.Now().Add(followMaxDuration)
var lastLogLength int var lastLogLength int
for time.Now().Before(deadline) { for time.Now().Before(deadline) {
job, _, err := client.GetRepoActionJob(c.Owner, c.Repo, jobID) job, _, err := client.Actions.GetRepoRunJob(ctx, c.Owner, c.Repo, jobID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get job: %w", err) return fmt.Errorf("failed to get job: %w", err)
} }
isRunning := job.Status == "in_progress" || job.Status == "queued" || job.Status == "pending" isRunning := job.Status == "in_progress" || job.Status == "queued" || job.Status == "pending"
logs, _, logErr := client.GetRepoActionJobLogs(c.Owner, c.Repo, jobID) logs, _, logErr := client.Actions.GetRepoRunJobLogs(ctx, c.Owner, c.Repo, jobID)
if logErr != nil && isRunning { if logErr != nil && isRunning {
time.Sleep(followPollInterval) time.Sleep(followPollInterval)
continue continue
+3 -3
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -38,7 +38,7 @@ func runWorkflowsEnable(ctx stdctx.Context, cmd *cli.Command) error {
client := c.Login.Client() client := c.Login.Client()
workflowID := cmd.Args().First() workflowID := cmd.Args().First()
_, err = client.EnableRepoActionWorkflow(c.Owner, c.Repo, workflowID) _, err = client.Actions.EnableRepoWorkflow(ctx, c.Owner, c.Repo, workflowID)
if err != nil { if err != nil {
return fmt.Errorf("failed to enable workflow: %w", err) return fmt.Errorf("failed to enable workflow: %w", err)
} }
+5 -5
View File
@@ -7,11 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -36,7 +36,7 @@ func RunWorkflowsList(ctx stdctx.Context, cmd *cli.Command) error {
} }
client := c.Login.Client() client := c.Login.Client()
resp, _, err := client.ListRepoActionWorkflows(c.Owner, c.Repo) resp, _, err := client.Actions.ListRepoWorkflows(ctx, c.Owner, c.Repo)
if err != nil { if err != nil {
return fmt.Errorf("failed to list workflows: %w", err) return fmt.Errorf("failed to list workflows: %w", err)
} }
+4 -4
View File
@@ -7,9 +7,9 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -40,7 +40,7 @@ func runWorkflowsView(ctx stdctx.Context, cmd *cli.Command) error {
client := c.Login.Client() client := c.Login.Client()
workflowID := cmd.Args().First() workflowID := cmd.Args().First()
wf, _, err := client.GetRepoActionWorkflow(c.Owner, c.Repo, workflowID) wf, _, err := client.Actions.GetRepoWorkflow(ctx, c.Owner, c.Repo, workflowID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get workflow: %w", err) return fmt.Errorf("failed to get workflow: %w", err)
} }
+7 -6
View File
@@ -6,10 +6,11 @@ package cmd
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/admin/users"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/admin/users"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
) )
// CmdAdmin represents the namespace of admin commands. // CmdAdmin represents the namespace of admin commands.
@@ -19,7 +20,7 @@ var CmdAdmin = cli.Command{
Usage: "Operations requiring admin access on the Gitea instance", Usage: "Operations requiring admin access on the Gitea instance",
Aliases: []string{"a"}, Aliases: []string{"a"},
Category: catMisc, Category: catMisc,
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
return cli.ShowSubcommandHelp(cmd) return cli.ShowSubcommandHelp(cmd)
}, },
Commands: []*cli.Command{ Commands: []*cli.Command{
@@ -46,13 +47,13 @@ var cmdAdminUsers = cli.Command{
Flags: users.CmdUserList.Flags, Flags: users.CmdUserList.Flags,
} }
func runAdminUserDetail(_ stdctx.Context, cmd *cli.Command, u string) error { func runAdminUserDetail(requestCtx stdctx.Context, cmd *cli.Command, u string) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
client := ctx.Login.Client() client := ctx.Login.Client()
user, _, err := client.GetUserInfo(u) user, _, err := client.Users.GetUserInfo(requestCtx, u)
if err != nil { if err != nil {
return err return err
} }
+8 -8
View File
@@ -11,11 +11,11 @@ import (
"strings" "strings"
"syscall" "syscall"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -83,7 +83,7 @@ var CmdUserCreate = cli.Command{
} }
// RunUserCreate creates a new user // RunUserCreate creates a new user
func RunUserCreate(_ stdctx.Context, cmd *cli.Command) error { func RunUserCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -177,7 +177,7 @@ func RunUserCreate(_ stdctx.Context, cmd *cli.Command) error {
createOpts.Visibility = vis createOpts.Visibility = vis
// Create the user // Create the user
user, _, err := client.AdminCreateUser(createOpts) user, _, err := client.Admin.CreateUser(requestCtx, createOpts)
if err != nil { if err != nil {
return err return err
} }
@@ -202,13 +202,13 @@ func RunUserCreate(_ stdctx.Context, cmd *cli.Command) error {
} }
// Update user with admin/restricted/prohibit-login settings // Update user with admin/restricted/prohibit-login settings
_, err = client.AdminEditUser(username, editOpts) _, err = client.Admin.EditUser(requestCtx, username, editOpts)
if err != nil { if err != nil {
return fmt.Errorf("user created but failed to update admin/restricted/prohibit-login status: %w", err) return fmt.Errorf("user created but failed to update admin/restricted/prohibit-login status: %w", err)
} }
// Refresh user info to reflect the changes // Refresh user info to reflect the changes
user, _, err = client.GetUserInfo(username) user, _, err = client.Users.GetUserInfo(requestCtx, username)
if err != nil { if err != nil {
return fmt.Errorf("user updated but failed to retrieve updated user info: %w", err) return fmt.Errorf("user updated but failed to retrieve updated user info: %w", err)
} }
+5 -5
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -31,7 +31,7 @@ var CmdUserDelete = cli.Command{
} }
// RunUserDelete deletes a user // RunUserDelete deletes a user
func RunUserDelete(_ stdctx.Context, cmd *cli.Command) error { func RunUserDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -45,7 +45,7 @@ func RunUserDelete(_ stdctx.Context, cmd *cli.Command) error {
username := ctx.Args().First() username := ctx.Args().First()
// Get user details first to show what we're deleting // Get user details first to show what we're deleting
user, _, err := client.GetUserInfo(username) user, _, err := client.Users.GetUserInfo(requestCtx, username)
if err != nil { if err != nil {
return fmt.Errorf("failed to get user info: %w", err) return fmt.Errorf("failed to get user info: %w", err)
} }
@@ -67,7 +67,7 @@ func RunUserDelete(_ stdctx.Context, cmd *cli.Command) error {
} }
} }
_, err = client.AdminDeleteUser(username) _, err = client.Admin.DeleteUser(requestCtx, username)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete user: %w", err) return fmt.Errorf("failed to delete user: %w", err)
} }
+8 -9
View File
@@ -11,11 +11,10 @@ import (
"strings" "strings"
"syscall" "syscall"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -135,7 +134,7 @@ var CmdUserEdit = cli.Command{
} }
// RunUserEdit edits an existing user // RunUserEdit edits an existing user
func RunUserEdit(_ stdctx.Context, cmd *cli.Command) error { func RunUserEdit(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -149,7 +148,7 @@ func RunUserEdit(_ stdctx.Context, cmd *cli.Command) error {
username := ctx.Args().First() username := ctx.Args().First()
// Verify the user exists before attempting an update. // Verify the user exists before attempting an update.
_, _, err = client.GetUserInfo(username) _, _, err = client.Users.GetUserInfo(requestCtx, username)
if err != nil { if err != nil {
return fmt.Errorf("failed to get user info: %w", err) return fmt.Errorf("failed to get user info: %w", err)
} }
@@ -358,13 +357,13 @@ func RunUserEdit(_ stdctx.Context, cmd *cli.Command) error {
} }
// Update the user // Update the user
_, err = client.AdminEditUser(username, editOpts) _, err = client.Admin.EditUser(requestCtx, username, editOpts)
if err != nil { if err != nil {
return fmt.Errorf("failed to update user: %w", err) return fmt.Errorf("failed to update user: %w", err)
} }
// Refresh user info to reflect the changes // Refresh user info to reflect the changes
updatedUser, _, err := client.GetUserInfo(username) updatedUser, _, err := client.Users.GetUserInfo(requestCtx, username)
if err != nil { if err != nil {
return fmt.Errorf("user updated but failed to retrieve updated user info: %w", err) return fmt.Errorf("user updated but failed to retrieve updated user info: %w", err)
} }
+6 -6
View File
@@ -6,11 +6,11 @@ package users
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -33,7 +33,7 @@ var CmdUserList = cli.Command{
} }
// RunUserList list users // RunUserList list users
func RunUserList(_ stdctx.Context, cmd *cli.Command) error { func RunUserList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -45,7 +45,7 @@ func RunUserList(_ stdctx.Context, cmd *cli.Command) error {
} }
client := ctx.Login.Client() client := ctx.Login.Client()
users, _, err := client.AdminListUsers(gitea.AdminListUsersOptions{ users, _, err := client.Admin.ListUsers(requestCtx, gitea.AdminListUsersOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"code.gitea.io/sdk/gitea" "gitea.dev/sdk"
) )
func parseUserVisibility(visibility string) (*gitea.VisibleType, error) { func parseUserVisibility(visibility string) (*gitea.VisibleType, error) {
+4 -4
View File
@@ -13,9 +13,9 @@ import (
"strconv" "strconv"
"strings" "strings"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/api" "gitea.dev/tea/modules/api"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"golang.org/x/term" "golang.org/x/term"
@@ -104,7 +104,7 @@ type preparedAPIRequest struct {
Body []byte Body []byte
} }
func runApi(_ stdctx.Context, cmd *cli.Command) error { func runApi(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
+20 -23
View File
@@ -8,16 +8,14 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"testing" "testing"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
tea_git "code.gitea.io/tea/modules/git" tea_git "gitea.dev/tea/modules/git"
gogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -298,7 +296,7 @@ func runApiWithArgs(t *testing.T, args []string) (method string, body []byte, er
} }
fullArgs := append([]string{"api", "--login", "testLogin"}, args...) fullArgs := append([]string{"api", "--login", "testLogin"}, args...)
runErr := cmd.Run(stdctx.Background(), fullArgs) runErr := cmd.Run(t.Context(), fullArgs)
return capturedMethod, capturedBody, runErr return capturedMethod, capturedBody, runErr
} }
@@ -572,33 +570,32 @@ func TestExpandPlaceholders(t *testing.T) {
t.Run("replaces branch from local repo HEAD", func(t *testing.T) { t.Run("replaces branch from local repo HEAD", func(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
repo, err := gogit.PlainInit(tmpDir, false) runGit := func(args ...string) {
require.NoError(t, err) cmd := exec.Command("git", args...)
cmd.Dir = tmpDir
require.NoError(t, cmd.Run())
}
runGit("init")
runGit("config", "user.email", "test@test.com")
runGit("config", "user.name", "test")
// Create an initial commit so HEAD points to a branch. // Create an initial commit so HEAD points to a branch.
wt, err := repo.Worktree()
require.NoError(t, err)
tmpFile := filepath.Join(tmpDir, "init.txt") tmpFile := filepath.Join(tmpDir, "init.txt")
require.NoError(t, os.WriteFile(tmpFile, []byte("init"), 0o644)) require.NoError(t, os.WriteFile(tmpFile, []byte("init"), 0o644))
_, err = wt.Add("init.txt") runGit("add", "init.txt")
require.NoError(t, err) runGit("commit", "-m", "initial commit")
_, err = wt.Commit("initial commit", &gogit.CommitOptions{
Author: &object.Signature{Name: "test", Email: "test@test.com"},
})
require.NoError(t, err)
// Create and checkout a feature branch. // Create and checkout a feature branch.
headRef, err := repo.Head() runGit("checkout", "-b", "feature/my-branch")
repo, err := tea_git.RepoFromPath(tmpDir)
require.NoError(t, err) require.NoError(t, err)
branchRef := plumbing.NewBranchReferenceName("feature/my-branch")
ref := plumbing.NewHashReference(branchRef, headRef.Hash())
require.NoError(t, repo.Storer.SetReference(ref))
require.NoError(t, wt.Checkout(&gogit.CheckoutOptions{Branch: branchRef}))
ctx := &context.TeaContext{ ctx := &context.TeaContext{
Owner: "alice", Owner: "alice",
Repo: "proj", Repo: "proj",
LocalRepo: &tea_git.TeaRepo{Repository: repo}, LocalRepo: repo,
} }
result := expandPlaceholders("/repos/{owner}/{repo}/branches/{branch}", ctx) result := expandPlaceholders("/repos/{owner}/{repo}/branches/{branch}", ctx)
assert.Equal(t, "/repos/alice/proj/branches/feature/my-branch", result) assert.Equal(t, "/repos/alice/proj/branches/feature/my-branch", result)
+2 -2
View File
@@ -4,8 +4,8 @@
package cmd package cmd
import ( import (
"code.gitea.io/tea/cmd/attachments" "gitea.dev/tea/cmd/attachments"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+6 -6
View File
@@ -9,9 +9,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/cmd/releases" "gitea.dev/tea/cmd/releases"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -27,7 +27,7 @@ var CmdReleaseAttachmentCreate = cli.Command{
Flags: flags.AllDefaultFlags, Flags: flags.AllDefaultFlags,
} }
func runReleaseAttachmentCreate(_ stdctx.Context, cmd *cli.Command) error { func runReleaseAttachmentCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -46,7 +46,7 @@ func runReleaseAttachmentCreate(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("release tag needed to create attachment") return fmt.Errorf("release tag needed to create attachment")
} }
release, err := releases.GetReleaseByTag(ctx.Owner, ctx.Repo, tag, client) release, err := releases.GetReleaseByTag(requestCtx, ctx.Owner, ctx.Repo, tag, client)
if err != nil { if err != nil {
return err return err
} }
@@ -59,7 +59,7 @@ func runReleaseAttachmentCreate(_ stdctx.Context, cmd *cli.Command) error {
filePath := filepath.Base(asset) filePath := filepath.Base(asset)
if _, _, err = ctx.Login.Client().CreateReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, file, filePath); err != nil { if _, _, err = ctx.Login.Client().Releases.CreateReleaseAttachment(requestCtx, ctx.Owner, ctx.Repo, release.ID, file, filePath); err != nil {
file.Close() file.Close()
return err return err
} }
+8 -8
View File
@@ -7,11 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/releases"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/cmd/releases"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -32,7 +32,7 @@ var CmdReleaseAttachmentDelete = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runReleaseAttachmentDelete(_ stdctx.Context, cmd *cli.Command) error { func runReleaseAttachmentDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -56,14 +56,14 @@ func runReleaseAttachmentDelete(_ stdctx.Context, cmd *cli.Command) error {
return nil return nil
} }
release, err := releases.GetReleaseByTag(ctx.Owner, ctx.Repo, tag, client) release, err := releases.GetReleaseByTag(requestCtx, ctx.Owner, ctx.Repo, tag, client)
if err != nil { if err != nil {
return err return err
} }
var existing []*gitea.Attachment var existing []*gitea.Attachment
for page := 1; ; { for page := 1; ; {
page_attachments, resp, err := client.ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{ page_attachments, resp, err := client.Releases.ListReleaseAttachments(requestCtx, ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
ListOptions: gitea.ListOptions{Page: page, PageSize: 50}, ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
}) })
if err != nil { if err != nil {
@@ -87,7 +87,7 @@ func runReleaseAttachmentDelete(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("release does not have attachment named '%s'", name) return fmt.Errorf("release does not have attachment named '%s'", name)
} }
_, err = client.DeleteReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, attachment.ID) _, err = client.Releases.DeleteReleaseAttachment(requestCtx, ctx.Owner, ctx.Repo, release.ID, attachment.ID)
if err != nil { if err != nil {
return err return err
} }
+8 -9
View File
@@ -7,12 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/releases" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/releases"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -31,7 +30,7 @@ var CmdReleaseAttachmentList = cli.Command{
} }
// RunReleaseAttachmentList list release attachments // RunReleaseAttachmentList list release attachments
func RunReleaseAttachmentList(_ stdctx.Context, cmd *cli.Command) error { func RunReleaseAttachmentList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -46,12 +45,12 @@ func RunReleaseAttachmentList(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("release tag needed to list attachments") return fmt.Errorf("release tag needed to list attachments")
} }
release, err := releases.GetReleaseByTag(ctx.Owner, ctx.Repo, tag, client) release, err := releases.GetReleaseByTag(requestCtx, ctx.Owner, ctx.Repo, tag, client)
if err != nil { if err != nil {
return err return err
} }
attachments, _, err := ctx.Login.Client().ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{ attachments, _, err := ctx.Login.Client().Releases.ListReleaseAttachments(requestCtx, ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+1 -1
View File
@@ -6,7 +6,7 @@ package cmd
import ( import (
"context" "context"
"code.gitea.io/tea/cmd/branches" "gitea.dev/tea/cmd/branches"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+7 -7
View File
@@ -6,11 +6,11 @@ package branches
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -37,7 +37,7 @@ var CmdBranchesList = cli.Command{
} }
// RunBranchesList list branches // RunBranchesList list branches
func RunBranchesList(_ stdctx.Context, cmd *cli.Command) error { func RunBranchesList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -53,14 +53,14 @@ func RunBranchesList(_ stdctx.Context, cmd *cli.Command) error {
var branches []*gitea.Branch var branches []*gitea.Branch
var protections []*gitea.BranchProtection var protections []*gitea.BranchProtection
branches, _, err = ctx.Login.Client().ListRepoBranches(owner, ctx.Repo, gitea.ListRepoBranchesOptions{ branches, _, err = ctx.Login.Client().Repositories.ListRepoBranches(requestCtx, owner, ctx.Repo, gitea.ListRepoBranchesOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
return err return err
} }
protections, _, err = ctx.Login.Client().ListBranchProtections(owner, ctx.Repo, gitea.ListBranchProtectionsOptions{ protections, _, err = ctx.Login.Client().Repositories.ListBranchProtections(requestCtx, owner, ctx.Repo, gitea.ListBranchProtectionsOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+6 -6
View File
@@ -7,10 +7,10 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -44,7 +44,7 @@ var CmdBranchesUnprotect = cli.Command{
} }
// RunBranchesProtect function to protect/unprotect a list of branches // RunBranchesProtect function to protect/unprotect a list of branches
func RunBranchesProtect(_ stdctx.Context, cmd *cli.Command) error { func RunBranchesProtect(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -67,7 +67,7 @@ func RunBranchesProtect(_ stdctx.Context, cmd *cli.Command) error {
var err error var err error
command := ctx.Command.Name command := ctx.Command.Name
if command == "protect" { if command == "protect" {
_, _, err = ctx.Login.Client().CreateBranchProtection(owner, ctx.Repo, gitea.CreateBranchProtectionOption{ _, _, err = ctx.Login.Client().Repositories.CreateBranchProtection(requestCtx, owner, ctx.Repo, gitea.CreateBranchProtectionOption{
BranchName: branch, BranchName: branch,
RuleName: "", RuleName: "",
EnablePush: false, EnablePush: false,
@@ -93,7 +93,7 @@ func RunBranchesProtect(_ stdctx.Context, cmd *cli.Command) error {
UnprotectedFilePatterns: "", UnprotectedFilePatterns: "",
}) })
} else if command == "unprotect" { } else if command == "unprotect" {
_, err = ctx.Login.Client().DeleteBranchProtection(owner, ctx.Repo, branch) _, err = ctx.Login.Client().Repositories.DeleteBranchProtection(requestCtx, owner, ctx.Repo, branch)
} else { } else {
return fmt.Errorf("command %s is not supported", command) return fmt.Errorf("command %s is not supported", command)
} }
+5 -5
View File
@@ -7,10 +7,10 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -33,7 +33,7 @@ var CmdBranchesRename = cli.Command{
} }
// RunBranchesRename function to rename a branch // RunBranchesRename function to rename a branch
func RunBranchesRename(_ stdctx.Context, cmd *cli.Command) error { func RunBranchesRename(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -54,7 +54,7 @@ func RunBranchesRename(_ stdctx.Context, cmd *cli.Command) error {
owner = ctx.String("owner") owner = ctx.String("owner")
} }
successful, _, err := ctx.Login.Client().RenameRepoBranch(owner, ctx.Repo, oldBranchName, gitea.RenameRepoBranchOption{ successful, _, err := ctx.Login.Client().Repositories.RenameRepoBranch(requestCtx, owner, ctx.Repo, oldBranchName, gitea.RenameRepoBranchOption{
Name: newBranchName, Name: newBranchName,
}) })
if err != nil { if err != nil {
+9 -8
View File
@@ -7,14 +7,14 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/debug" "gitea.dev/tea/modules/debug"
"code.gitea.io/tea/modules/git" "gitea.dev/tea/modules/git"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/task" "gitea.dev/tea/modules/task"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -88,6 +88,7 @@ func runRepoClone(ctx stdctx.Context, cmd *cli.Command) error {
} }
_, err = task.RepoClone( _, err = task.RepoClone(
ctx,
dir, dir,
login, login,
owner, owner,
+5 -3
View File
@@ -2,13 +2,14 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// Tea is command line tool for Gitea. // Tea is command line tool for Gitea.
package cmd // import "code.gitea.io/tea" package cmd // import "gitea.dev/tea"
import ( import (
"fmt" "fmt"
"code.gitea.io/tea/modules/version"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/version"
) )
// App creates and returns a tea Command with all subcommands set // App creates and returns a tea Command with all subcommands set
@@ -38,8 +39,9 @@ func App() *cli.Command {
&CmdRepos, &CmdRepos,
&CmdBranches, &CmdBranches,
&CmdActions, &CmdActions,
&CmdWiki,
&CmdWebhooks, &CmdWebhooks,
&CmdAddComment, &CmdComments,
&CmdOpen, &CmdOpen,
&CmdNotifications, &CmdNotifications,
+18 -82
View File
@@ -4,92 +4,28 @@
package cmd package cmd
import ( import (
stdctx "context" "gitea.dev/tea/cmd/comments"
"errors"
"fmt"
"io"
"strings"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/interact"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/theme"
"code.gitea.io/tea/modules/utils"
"charm.land/huh/v2"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdAddComment is the main command to operate with notifications // CmdComments is the top-level command for managing comments on issues and pull requests.
var CmdAddComment = cli.Command{ var CmdComments = cli.Command{
Name: "comment", Name: "comments",
Aliases: []string{"c"}, Aliases: []string{"comment", "c"},
Category: catEntities, Category: catEntities,
Usage: "Add a comment to an issue / pr", Usage: "Manage comments on issues and pull requests",
Description: "Add a comment to an issue / pr", Description: `Manage comments on issues and pull requests.
When invoked with an issue/PR index and an optional body, behaves like 'tea comments add'
(this preserves the historical 'tea comment <idx> "<body>"' shorthand).`,
ArgsUsage: "<issue / pr index> [<comment body>]", ArgsUsage: "<issue / pr index> [<comment body>]",
Action: runAddComment, Action: comments.RunCommentsAdd,
Flags: flags.AllDefaultFlags, Flags: comments.CmdCommentsAdd.Flags,
} Commands: []*cli.Command{
&comments.CmdCommentsAdd,
func runAddComment(_ stdctx.Context, cmd *cli.Command) error { &comments.CmdCommentsList,
ctx, err := context.InitCommand(cmd) &comments.CmdCommentsEdit,
if err != nil { &comments.CmdCommentsDelete,
return err },
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
args := ctx.Args()
if args.Len() == 0 {
return fmt.Errorf("please specify issue / pr index")
}
idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return err
}
body := strings.Join(ctx.Args().Tail(), " ")
if interact.IsStdinPiped() {
// custom solution until https://github.com/AlecAivazis/survey/issues/328 is fixed
if bodyStdin, err := io.ReadAll(ctx.Reader); err != nil {
return err
} else if len(bodyStdin) != 0 {
body = strings.Join([]string{body, string(bodyStdin)}, "\n\n")
}
} else if len(body) == 0 {
if err := huh.NewForm(
huh.NewGroup(
huh.NewText().
Title("Comment(markdown):").
ExternalEditor(config.GetPreferences().Editor).
EditorExtension("md").
Value(&body),
),
).WithTheme(theme.GetTheme()).
Run(); err != nil {
return err
}
}
if len(body) == 0 {
return errors.New("no comment content provided")
}
client := ctx.Login.Client()
comment, _, err := client.CreateIssueComment(ctx.Owner, ctx.Repo, idx, gitea.CreateIssueCommentOption{
Body: body,
})
if err != nil {
return err
}
print.Comment(comment)
return nil
} }
+96
View File
@@ -0,0 +1,96 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import (
stdctx "context"
"errors"
"fmt"
"strings"
gitea "gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/config"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/interact"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/theme"
"gitea.dev/tea/modules/utils"
"charm.land/huh/v2"
"github.com/urfave/cli/v3"
)
// CmdCommentsAdd adds a comment to an issue or pull request.
var CmdCommentsAdd = cli.Command{
Name: "add",
Aliases: []string{"a"},
Usage: "Add a comment to an issue or pull request",
Description: "Add a comment to an issue or pull request.",
ArgsUsage: "<issue / pr index> [<comment body>]",
Action: RunCommentsAdd,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
Usage: "comment body (alternative to the positional argument)",
},
}, flags.AllDefaultFlags...),
}
// RunCommentsAdd creates a new comment.
func RunCommentsAdd(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
if ctx.Args().Len() == 0 {
return fmt.Errorf("please specify issue / pr index")
}
idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return err
}
stdinPiped := interact.IsStdinPiped()
body, err := resolveBody(strings.Join(ctx.Args().Tail(), " "), ctx.String("description"), stdinPiped, ctx.Reader)
if err != nil {
return err
}
if len(body) == 0 && !stdinPiped {
if err := huh.NewForm(
huh.NewGroup(
huh.NewText().
Title("Comment(markdown):").
ExternalEditor(config.GetPreferences().Editor).
EditorExtension("md").
Value(&body),
),
).WithTheme(theme.GetTheme()).
Run(); err != nil {
return err
}
}
if len(body) == 0 {
return errors.New("no comment content provided")
}
client := ctx.Login.Client()
comment, _, err := client.Issues.CreateIssueComment(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.CreateIssueCommentOption{
Body: body,
})
if err != nil {
return err
}
print.Comment(comment)
return nil
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import "io"
// resolveBody picks the comment body from the non-interactive sources, in
// precedence order:
//
// 1. the positional argument (kept first for back-compat with the historical
// 'tea comment <idx> "<body>"' shorthand),
// 2. the -d/--description flag (mirrors the body flag on 'issue create',
// 'issue edit' and 'pr create'),
// 3. piped stdin.
//
// stdin is only read when stdinPiped is true (a non-TTY stdin, e.g. CI,
// subshells or agent harnesses) and no body was supplied otherwise, so the
// command never blocks reading an interactive terminal when a body is already
// given. An empty result means the caller should fall back to the editor (when
// interactive) or error out.
func resolveBody(positional, description string, stdinPiped bool, stdin io.Reader) (string, error) {
if len(positional) != 0 {
return positional, nil
}
if len(description) != 0 {
return description, nil
}
if stdinPiped {
stdinBytes, err := io.ReadAll(stdin)
if err != nil {
return "", err
}
return string(stdinBytes), nil
}
return "", nil
}
+101
View File
@@ -0,0 +1,101 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import (
"io"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestResolveBody(t *testing.T) {
testCases := []struct {
name string
positional string
description string
stdinPiped bool
stdin string
expected string
}{
{
name: "positional only",
positional: "from positional",
expected: "from positional",
},
{
name: "description flag only",
description: "from -d",
expected: "from -d",
},
{
name: "positional wins over description for back-compat",
positional: "from positional",
description: "from -d",
expected: "from positional",
},
{
name: "description wins over piped stdin",
description: "from -d",
stdinPiped: true,
stdin: "from stdin",
expected: "from -d",
},
{
name: "piped stdin used when nothing else given",
stdinPiped: true,
stdin: "from stdin",
expected: "from stdin",
},
{
name: "stdin ignored when not piped (interactive terminal)",
stdinPiped: false,
stdin: "should never be read",
expected: "",
},
{
name: "empty when no source provided",
stdinPiped: false,
expected: "",
},
{
name: "piped but empty stdin yields empty body",
stdinPiped: true,
stdin: "",
expected: "",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
body, err := resolveBody(tc.positional, tc.description, tc.stdinPiped, strings.NewReader(tc.stdin))
require.NoError(t, err)
assert.Equal(t, tc.expected, body)
})
}
}
// TestResolveBodyDoesNotReadStdinWhenBodyGiven guards the original bug: when a
// body is supplied positionally (or via -d), stdin must not be consumed, so the
// command can never block on a non-TTY stdin under CI / agent harnesses.
func TestResolveBodyDoesNotReadStdinWhenBodyGiven(t *testing.T) {
reader := &trackingReader{}
body, err := resolveBody("positional body", "", true, reader)
require.NoError(t, err)
assert.Equal(t, "positional body", body)
assert.False(t, reader.read, "stdin must not be read when a body is supplied")
}
// trackingReader records whether Read was ever called.
type trackingReader struct {
read bool
}
func (r *trackingReader) Read(p []byte) (int, error) {
r.read = true
return 0, io.EOF
}
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import (
stdctx "context"
"fmt"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3"
)
// CmdCommentsDelete deletes one or more comments by ID.
var CmdCommentsDelete = cli.Command{
Name: "delete",
Aliases: []string{"rm"},
Usage: "Delete one or more comments by ID",
Description: "Delete one or more comments by their comment ID. Use 'tea comments list <issue>' to find IDs.",
ArgsUsage: "<comment id> [<comment id>...]",
Action: RunCommentsDelete,
Flags: flags.AllDefaultFlags,
}
// RunCommentsDelete removes one or more comments.
func RunCommentsDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
if ctx.Args().Len() == 0 {
return fmt.Errorf("please specify at least one comment id")
}
ids, err := utils.ArgsToIndices(ctx.Args().Slice())
if err != nil {
return fmt.Errorf("invalid comment id: %s", err)
}
client := ctx.Login.Client()
for _, id := range ids {
if _, err := client.Issues.DeleteIssueComment(requestCtx, ctx.Owner, ctx.Repo, id); err != nil {
return fmt.Errorf("could not delete comment %d: %s", id, err)
}
fmt.Printf("Deleted comment %d\n", id)
}
return nil
}
+105
View File
@@ -0,0 +1,105 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import (
stdctx "context"
"errors"
"fmt"
"strings"
gitea "gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/config"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/interact"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/theme"
"gitea.dev/tea/modules/utils"
"charm.land/huh/v2"
"github.com/urfave/cli/v3"
)
// CmdCommentsEdit edits an existing comment.
var CmdCommentsEdit = cli.Command{
Name: "edit",
Aliases: []string{"e"},
Usage: "Edit the body of an existing comment",
Description: `Edit the body of an existing comment by its comment ID. Use 'tea comments list <issue>' to find IDs.
The new body can be supplied as a positional argument, via -d/--description, piped on stdin, or (if none is given and stdin is a terminal) entered in your $EDITOR.`,
ArgsUsage: "<comment id> [<new body>]",
Action: RunCommentsEdit,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
Usage: "new comment body (alternative to the positional argument)",
},
}, flags.AllDefaultFlags...),
}
// RunCommentsEdit updates the body of an existing comment.
func RunCommentsEdit(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
if ctx.Args().Len() == 0 {
return fmt.Errorf("please specify comment id")
}
id, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return fmt.Errorf("invalid comment id %q: %s", ctx.Args().First(), err)
}
stdinPiped := interact.IsStdinPiped()
body, err := resolveBody(strings.Join(ctx.Args().Tail(), " "), ctx.String("description"), stdinPiped, ctx.Reader)
if err != nil {
return err
}
if len(body) == 0 && !stdinPiped {
// Fetch current body to pre-populate the editor.
client := ctx.Login.Client()
current, _, fetchErr := client.Issues.GetIssueComment(requestCtx, ctx.Owner, ctx.Repo, id)
if fetchErr != nil {
return fmt.Errorf("could not fetch comment %d: %s", id, fetchErr)
}
body = current.Body
if err := huh.NewForm(
huh.NewGroup(
huh.NewText().
Title("Comment(markdown):").
ExternalEditor(config.GetPreferences().Editor).
EditorExtension("md").
Value(&body),
),
).WithTheme(theme.GetTheme()).
Run(); err != nil {
return err
}
}
if len(body) == 0 {
return errors.New("no comment content provided")
}
client := ctx.Login.Client()
comment, _, err := client.Issues.EditIssueComment(requestCtx, ctx.Owner, ctx.Repo, id, gitea.EditIssueCommentOption{
Body: body,
})
if err != nil {
return err
}
print.Comment(comment)
return nil
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package comments
import (
stdctx "context"
"fmt"
gitea "gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3"
)
// CmdCommentsList lists comments on an issue or pull request.
var CmdCommentsList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List comments on an issue or pull request",
Description: "List comments on an issue or pull request. Comment IDs returned here are the IDs accepted by 'tea comments edit' and 'tea comments delete'.",
ArgsUsage: "<issue / pr index>",
Action: RunCommentsList,
Flags: append([]cli.Flag{
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...),
}
// RunCommentsList lists comments on the given issue/PR.
func RunCommentsList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
if ctx.Args().Len() == 0 {
return fmt.Errorf("please specify issue / pr index")
}
idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return err
}
client := ctx.Login.Client()
comments, _, err := client.Issues.ListIssueComments(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.ListIssueCommentOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err != nil {
return err
}
return print.CommentsList(comments, ctx.Output)
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"io" "io"
"time" "time"
"code.gitea.io/sdk/gitea" "gitea.dev/sdk"
) )
type detailLabelData struct { type detailLabelData struct {
+2 -1
View File
@@ -7,8 +7,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/utils"
) )
// CsvFlag is a wrapper around cli.StringFlag, with an added GetValues() method // CsvFlag is a wrapper around cli.StringFlag, with an added GetValues() method
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+4 -4
View File
@@ -8,7 +8,7 @@ import (
"io" "io"
"testing" "testing"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -75,7 +75,7 @@ func TestPaginationFlags(t *testing.T) {
}, },
Flags: PaginationFlags, Flags: PaginationFlags,
} }
err := cmd.Run(context.Background(), tc.args) err := cmd.Run(t.Context(), tc.args)
require.NoError(t, err) require.NoError(t, err)
}) })
} }
@@ -118,7 +118,7 @@ func TestPaginationFailures(t *testing.T) {
ErrWriter: io.Discard, ErrWriter: io.Discard,
} }
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
err := cmd.Run(context.Background(), tc.args) err := cmd.Run(t.Context(), tc.args)
require.ErrorContains(t, err, tc.expectedError.Error()) require.ErrorContains(t, err, tc.expectedError.Error())
// require.ErrorIs(t, err, tc.expectedError) // require.ErrorIs(t, err, tc.expectedError)
}) })
@@ -140,7 +140,7 @@ func TestGetListOptionsDoesNotLeakBetweenCommands(t *testing.T) {
Flags: PaginationFlags, Flags: PaginationFlags,
} }
require.NoError(t, cmd.Run(context.Background(), args)) require.NoError(t, cmd.Run(t.Context(), args))
} }
run([]string{"test", "--page", "5", "--limit", "10"}) run([]string{"test", "--page", "5", "--limit", "10"})
+8 -6
View File
@@ -4,13 +4,15 @@
package flags package flags
import ( import (
stdctx "context"
"fmt" "fmt"
"strings" "strings"
"time" "time"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/task" "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/task"
"github.com/araddon/dateparse" "github.com/araddon/dateparse"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -130,7 +132,7 @@ var IssuePRCreateFlags = append([]cli.Flag{
}, issuePRFlags...) }, issuePRFlags...)
// GetIssuePRCreateFlags parses all IssuePREditFlags // GetIssuePRCreateFlags parses all IssuePREditFlags
func GetIssuePRCreateFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, error) { func GetIssuePRCreateFlags(requestCtx stdctx.Context, ctx *context.TeaContext) (*gitea.CreateIssueOption, error) {
opts := gitea.CreateIssueOption{ opts := gitea.CreateIssueOption{
Title: ctx.String("title"), Title: ctx.String("title"),
Body: ctx.String("description"), Body: ctx.String("description"),
@@ -154,7 +156,7 @@ func GetIssuePRCreateFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, e
if client == nil { if client == nil {
client = ctx.Login.Client() client = ctx.Login.Client()
} }
if opts.Labels, err = task.ResolveLabelNames(client, ctx.Owner, ctx.Repo, labelNames); err != nil { if opts.Labels, err = task.ResolveLabelNames(requestCtx, client, ctx.Owner, ctx.Repo, labelNames); err != nil {
return nil, err return nil, err
} }
} }
@@ -163,7 +165,7 @@ func GetIssuePRCreateFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, e
if client == nil { if client == nil {
client = ctx.Login.Client() client = ctx.Login.Client()
} }
ms, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestoneName) ms, _, err := client.Repositories.GetMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, milestoneName)
if err != nil { if err != nil {
return nil, fmt.Errorf("milestone '%s' not found", milestoneName) return nil, fmt.Errorf("milestone '%s' not found", milestoneName)
} }
+22 -21
View File
@@ -8,13 +8,14 @@ import (
"fmt" "fmt"
"time" "time"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/cmd/issues" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/issues"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -37,12 +38,12 @@ type issueData struct {
} }
type issueDetailClient interface { type issueDetailClient interface {
GetIssue(owner, repo string, index int64) (*gitea.Issue, *gitea.Response, error) GetIssue(ctx stdctx.Context, owner, repo string, index int64) (*gitea.Issue, *gitea.Response, error)
GetIssueReactions(owner, repo string, index int64) ([]*gitea.Reaction, *gitea.Response, error) ListIssueReactions(ctx stdctx.Context, owner, repo string, index int64, opt gitea.ListIssueReactionsOptions) ([]*gitea.Reaction, *gitea.Response, error)
} }
type issueCommentClient interface { type issueCommentClient interface {
ListIssueComments(owner, repo string, index int64, opt gitea.ListIssueCommentOptions) ([]*gitea.Comment, *gitea.Response, error) ListIssueComments(ctx stdctx.Context, owner, repo string, index int64, opt gitea.ListIssueCommentOptions) ([]*gitea.Comment, *gitea.Response, error)
} }
type commentData = detailCommentData type commentData = detailCommentData
@@ -78,13 +79,13 @@ func runIssues(ctx stdctx.Context, cmd *cli.Command) error {
return issues.RunIssuesList(ctx, cmd) return issues.RunIssuesList(ctx, cmd)
} }
func runIssueDetail(_ stdctx.Context, cmd *cli.Command, index string) error { func runIssueDetail(requestCtx stdctx.Context, cmd *cli.Command, index string) error {
ctx, idx, err := resolveIssueDetailContext(cmd, index) ctx, idx, err := resolveIssueDetailContext(cmd, index)
if err != nil { if err != nil {
return err return err
} }
return runIssueDetailWithClient(ctx, idx, ctx.Login.Client()) return runIssueDetailWithClient(requestCtx, ctx, idx, ctx.Login.Client().Issues)
} }
func resolveIssueDetailContext(cmd *cli.Command, index string) (*context.TeaContext, int64, error) { func resolveIssueDetailContext(cmd *cli.Command, index string) (*context.TeaContext, int64, error) {
@@ -107,12 +108,12 @@ func resolveIssueDetailContext(cmd *cli.Command, index string) (*context.TeaCont
return ctx, idx, nil return ctx, idx, nil
} }
func runIssueDetailWithClient(ctx *context.TeaContext, idx int64, client issueDetailClient) error { func runIssueDetailWithClient(requestCtx stdctx.Context, ctx *context.TeaContext, idx int64, client issueDetailClient) error {
issue, _, err := client.GetIssue(ctx.Owner, ctx.Repo, idx) issue, _, err := client.GetIssue(requestCtx, ctx.Owner, ctx.Repo, idx)
if err != nil { if err != nil {
return err return err
} }
reactions, _, err := client.GetIssueReactions(ctx.Owner, ctx.Repo, idx) reactions, _, err := client.ListIssueReactions(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.ListIssueReactionsOptions{})
if err != nil { if err != nil {
return err return err
} }
@@ -120,14 +121,14 @@ func runIssueDetailWithClient(ctx *context.TeaContext, idx int64, client issueDe
if ctx.IsSet("output") { if ctx.IsSet("output") {
switch ctx.String("output") { switch ctx.String("output") {
case "json": case "json":
return runIssueDetailAsJSON(ctx, issue) return runIssueDetailAsJSON(requestCtx, ctx, issue)
} }
} }
print.IssueDetails(issue, reactions) print.IssueDetails(issue, reactions)
if issue.Comments > 0 { if issue.Comments > 0 {
err = interact.ShowCommentsMaybeInteractive(ctx, idx, issue.Comments) err = interact.ShowCommentsMaybeInteractive(requestCtx, ctx, idx, issue.Comments)
if err != nil { if err != nil {
return fmt.Errorf("error loading comments: %v", err) return fmt.Errorf("error loading comments: %v", err)
} }
@@ -136,17 +137,17 @@ func runIssueDetailWithClient(ctx *context.TeaContext, idx int64, client issueDe
return nil return nil
} }
func runIssueDetailAsJSON(ctx *context.TeaContext, issue *gitea.Issue) error { func runIssueDetailAsJSON(requestCtx stdctx.Context, ctx *context.TeaContext, issue *gitea.Issue) error {
return runIssueDetailAsJSONWithClient(ctx, issue, ctx.Login.Client()) return runIssueDetailAsJSONWithClient(requestCtx, ctx, issue, ctx.Login.Client().Issues)
} }
func runIssueDetailAsJSONWithClient(ctx *context.TeaContext, issue *gitea.Issue, c issueCommentClient) error { func runIssueDetailAsJSONWithClient(requestCtx stdctx.Context, ctx *context.TeaContext, issue *gitea.Issue, c issueCommentClient) error {
opts := gitea.ListIssueCommentOptions{ListOptions: flags.GetListOptions(ctx.Command)} opts := gitea.ListIssueCommentOptions{ListOptions: flags.GetListOptions(ctx.Command)}
comments := []*gitea.Comment{} comments := []*gitea.Comment{}
if ctx.Bool("comments") { if ctx.Bool("comments") {
var err error var err error
comments, _, err = c.ListIssueComments(ctx.Owner, ctx.Repo, issue.Index, opts) comments, _, err = c.ListIssueComments(requestCtx, ctx.Owner, ctx.Repo, issue.Index, opts)
if err != nil { if err != nil {
return err return err
} }
+7 -7
View File
@@ -7,12 +7,12 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/utils"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -30,7 +30,7 @@ var CmdIssuesClose = cli.Command{
} }
// editIssueState abstracts the arg parsing to edit the given issue // editIssueState abstracts the arg parsing to edit the given issue
func editIssueState(_ stdctx.Context, cmd *cli.Command, opts gitea.EditIssueOption) error { func editIssueState(requestCtx stdctx.Context, cmd *cli.Command, opts gitea.EditIssueOption) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -49,7 +49,7 @@ func editIssueState(_ stdctx.Context, cmd *cli.Command, opts gitea.EditIssueOpti
client := ctx.Login.Client() client := ctx.Login.Client()
for _, index := range indices { for _, index := range indices {
issue, _, err := client.EditIssue(ctx.Owner, ctx.Repo, index, opts) issue, _, err := client.Issues.EditIssue(requestCtx, ctx.Owner, ctx.Repo, index, opts)
if err != nil { if err != nil {
return err return err
} }
+8 -9
View File
@@ -6,10 +6,10 @@ package issues
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/task" "gitea.dev/tea/modules/task"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -25,7 +25,7 @@ var CmdIssuesCreate = cli.Command{
Flags: flags.IssuePRCreateFlags, Flags: flags.IssuePRCreateFlags,
} }
func runIssuesCreate(_ stdctx.Context, cmd *cli.Command) error { func runIssuesCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -35,20 +35,19 @@ func runIssuesCreate(_ stdctx.Context, cmd *cli.Command) error {
} }
if ctx.IsInteractiveMode() { if ctx.IsInteractiveMode() {
err := interact.CreateIssue(ctx.Login, ctx.Owner, ctx.Repo) err := interact.CreateIssue(requestCtx, ctx.Login, ctx.Owner, ctx.Repo)
if err != nil && !interact.IsQuitting(err) { if err != nil && !interact.IsQuitting(err) {
return err return err
} }
return nil return nil
} }
opts, err := flags.GetIssuePRCreateFlags(ctx) opts, err := flags.GetIssuePRCreateFlags(requestCtx, ctx)
if err != nil { if err != nil {
return err return err
} }
return task.CreateIssue( return task.CreateIssue(requestCtx, ctx.Login,
ctx.Login,
ctx.Owner, ctx.Owner,
ctx.Repo, ctx.Repo,
*opts, *opts,
+10 -9
View File
@@ -8,13 +8,14 @@ import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/interact"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/task"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/interact"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/task"
"gitea.dev/tea/modules/utils"
) )
// CmdIssuesEdit is the subcommand of issues to edit issues // CmdIssuesEdit is the subcommand of issues to edit issues
@@ -29,7 +30,7 @@ use an empty string (eg. --milestone "").`,
Flags: flags.IssuePREditFlags, Flags: flags.IssuePREditFlags,
} }
func runIssuesEdit(_ stdctx.Context, cmd *cli.Command) error { func runIssuesEdit(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -56,7 +57,7 @@ func runIssuesEdit(_ stdctx.Context, cmd *cli.Command) error {
for _, opts.Index = range indices { for _, opts.Index = range indices {
if ctx.IsInteractiveMode() { if ctx.IsInteractiveMode() {
var err error var err error
opts, err = interact.EditIssue(*ctx, opts.Index) opts, err = interact.EditIssue(requestCtx, *ctx, opts.Index)
if err != nil { if err != nil {
if interact.IsQuitting(err) { if interact.IsQuitting(err) {
return nil // user quit return nil // user quit
@@ -65,7 +66,7 @@ func runIssuesEdit(_ stdctx.Context, cmd *cli.Command) error {
} }
} }
issue, err := task.EditIssue(ctx, client, *opts) issue, err := task.EditIssue(requestCtx, ctx, client, *opts)
if err != nil { if err != nil {
return err return err
} }
+7 -7
View File
@@ -8,11 +8,11 @@ import (
"errors" "errors"
"time" "time"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/araddon/dateparse" "github.com/araddon/dateparse"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -33,7 +33,7 @@ var CmdIssuesList = cli.Command{
} }
// RunIssuesList list issues // RunIssuesList list issues
func RunIssuesList(_ stdctx.Context, cmd *cli.Command) error { func RunIssuesList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -72,7 +72,7 @@ func RunIssuesList(_ stdctx.Context, cmd *cli.Command) error {
milestones, _ := flags.MilestoneFilterFlag.GetValues(cmd) milestones, _ := flags.MilestoneFilterFlag.GetValues(cmd)
var issues []*gitea.Issue var issues []*gitea.Issue
if ctx.Repo != "" { if ctx.Repo != "" {
issues, _, err = ctx.Login.Client().ListRepoIssues(owner, ctx.Repo, gitea.ListIssueOption{ issues, _, err = ctx.Login.Client().Issues.ListRepoIssues(requestCtx, owner, ctx.Repo, gitea.ListIssueOption{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
State: state, State: state,
Type: kind, Type: kind,
@@ -92,7 +92,7 @@ func RunIssuesList(_ stdctx.Context, cmd *cli.Command) error {
if ctx.IsSet("assignee") { if ctx.IsSet("assignee") {
return errors.New("--assignee requires --repo (global issue search does not support assignee filter)") return errors.New("--assignee requires --repo (global issue search does not support assignee filter)")
} }
issues, _, err = ctx.Login.Client().ListIssues(gitea.ListIssueOption{ issues, _, err = ctx.Login.Client().Issues.ListIssues(requestCtx, gitea.ListIssueOption{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
State: state, State: state,
Type: kind, Type: kind,
+115
View File
@@ -0,0 +1,115 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package issues
import (
stdctx "context"
"crypto/ed25519"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"sync/atomic"
"testing"
"time"
"gitea.dev/tea/modules/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v3"
"golang.org/x/crypto/ssh"
)
func TestRunIssuesListWithSSHPubkeyLoginDoesNotDeadlock(t *testing.T) {
t.Parallel()
sshKeyPath, fingerprint := writeTestSSHKey(t)
var versionRequests atomic.Int32
var issueRequests atomic.Int32
var signedVersionRequests atomic.Int32
var signedIssueRequests atomic.Int32
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v1/version":
versionRequests.Add(1)
if r.Header.Get("Signature") != "" {
signedVersionRequests.Add(1)
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"version":"1.26.4"}`))
case "/api/v1/repos/gitea/tea/issues":
issueRequests.Add(1)
if r.Header.Get("Signature") != "" {
signedIssueRequests.Add(1)
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[]`))
default:
t.Errorf("unexpected path %s", r.URL.Path)
w.WriteHeader(http.StatusNotFound)
}
}))
defer server.Close()
config.SetConfigForTesting(config.LocalConfig{
Logins: []config.Login{{
Name: "ssh-login",
URL: server.URL,
SSHKey: sshKeyPath,
SSHKeyFingerprint: fingerprint,
VersionCheck: true,
Default: true,
}},
})
cmd := cli.Command{
Name: CmdIssuesList.Name,
Flags: CmdIssuesList.Flags,
}
require.NoError(t, cmd.Set("login", "ssh-login"))
require.NoError(t, cmd.Set("repo", "gitea/tea"))
require.NoError(t, cmd.Set("output", "json"))
done := make(chan error, 1)
go func() {
done <- RunIssuesList(stdctx.Background(), &cmd)
}()
select {
case err := <-done:
require.NoError(t, err)
case <-time.After(2 * time.Second):
t.Fatal("RunIssuesList deadlocked while bootstrapping the server version for HTTPSign authentication")
}
assert.EqualValues(t, 1, versionRequests.Load())
assert.EqualValues(t, 0, signedVersionRequests.Load())
assert.EqualValues(t, 1, issueRequests.Load())
assert.EqualValues(t, 1, signedIssueRequests.Load())
}
func writeTestSSHKey(t *testing.T) (string, string) {
t.Helper()
_, privateKey, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
pkcs8, err := x509.MarshalPKCS8PrivateKey(privateKey)
require.NoError(t, err)
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8})
sshKeyPath := filepath.Join(t.TempDir(), "id_ed25519")
require.NoError(t, os.WriteFile(sshKeyPath, pemBytes, 0o600))
signer, err := ssh.NewSignerFromKey(privateKey)
require.NoError(t, err)
return sshKeyPath, ssh.FingerprintSHA256(signer.PublicKey())
}
+2 -2
View File
@@ -6,9 +6,9 @@ package issues
import ( import (
"context" "context"
"code.gitea.io/tea/cmd/flags" "gitea.dev/sdk"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+11 -9
View File
@@ -5,18 +5,20 @@ package cmd
import ( import (
"bytes" "bytes"
stdctx "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"testing" "testing"
"time" "time"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/context"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/config"
"gitea.dev/tea/modules/context"
) )
const ( const (
@@ -31,7 +33,7 @@ type fakeIssueCommentClient struct {
comments []*gitea.Comment comments []*gitea.Comment
} }
func (f *fakeIssueCommentClient) ListIssueComments(owner, repo string, index int64, _ gitea.ListIssueCommentOptions) ([]*gitea.Comment, *gitea.Response, error) { func (f *fakeIssueCommentClient) ListIssueComments(_ stdctx.Context, owner, repo string, index int64, _ gitea.ListIssueCommentOptions) ([]*gitea.Comment, *gitea.Response, error) {
f.owner = owner f.owner = owner
f.repo = repo f.repo = repo
f.index = index f.index = index
@@ -46,14 +48,14 @@ type fakeIssueDetailClient struct {
reactions []*gitea.Reaction reactions []*gitea.Reaction
} }
func (f *fakeIssueDetailClient) GetIssue(owner, repo string, index int64) (*gitea.Issue, *gitea.Response, error) { func (f *fakeIssueDetailClient) GetIssue(_ stdctx.Context, owner, repo string, index int64) (*gitea.Issue, *gitea.Response, error) {
f.owner = owner f.owner = owner
f.repo = repo f.repo = repo
f.index = index f.index = index
return f.issue, nil, nil return f.issue, nil, nil
} }
func (f *fakeIssueDetailClient) GetIssueReactions(owner, repo string, index int64) ([]*gitea.Reaction, *gitea.Response, error) { func (f *fakeIssueDetailClient) ListIssueReactions(_ stdctx.Context, owner, repo string, index int64, _ gitea.ListIssueReactionsOptions) ([]*gitea.Reaction, *gitea.Response, error) {
f.owner = owner f.owner = owner
f.repo = repo f.repo = repo
f.index = index f.index = index
@@ -220,7 +222,7 @@ func TestRunIssueDetailAsJSON(t *testing.T) {
require.NoError(t, testContext.Set("comments", "false")) require.NoError(t, testContext.Set("comments", "false"))
} }
err := runIssueDetailAsJSONWithClient(&testContext, &testCase.issue, client) err := runIssueDetailAsJSONWithClient(t.Context(), &testContext, &testCase.issue, client)
require.NoError(t, err, "Failed to run issue detail as JSON") require.NoError(t, err, "Failed to run issue detail as JSON")
if testCase.flagComments { if testCase.flagComments {
@@ -350,7 +352,7 @@ func TestRunIssueDetailUsesOwnerFlag(t *testing.T) {
reactions: []*gitea.Reaction{}, reactions: []*gitea.Reaction{},
} }
err = runIssueDetailWithClient(teaCtx, idx, client) err = runIssueDetailWithClient(t.Context(), teaCtx, idx, client)
require.NoError(t, err, "Expected runIssueDetail to succeed") require.NoError(t, err, "Expected runIssueDetail to succeed")
assert.Equal(t, expectedOwner, client.owner) assert.Equal(t, expectedOwner, client.owner)
assert.Equal(t, expectedRepo, client.repo) assert.Equal(t, expectedRepo, client.repo)
+2 -1
View File
@@ -7,8 +7,9 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/labels"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/labels"
) )
// CmdLabels represents to operate repositories' labels. // CmdLabels represents to operate repositories' labels.
+6 -6
View File
@@ -10,10 +10,10 @@ import (
"os" "os"
"strings" "strings"
"code.gitea.io/tea/cmd/flags" "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -45,7 +45,7 @@ var CmdLabelCreate = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runLabelCreate(_ stdctx.Context, cmd *cli.Command) error { func runLabelCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -56,7 +56,7 @@ func runLabelCreate(_ stdctx.Context, cmd *cli.Command) error {
labelFile := ctx.String("file") labelFile := ctx.String("file")
if len(labelFile) == 0 { if len(labelFile) == 0 {
_, _, err := ctx.Login.Client().CreateLabel(ctx.Owner, ctx.Repo, gitea.CreateLabelOption{ _, _, err := ctx.Login.Client().Repositories.CreateLabel(requestCtx, ctx.Owner, ctx.Repo, gitea.CreateLabelOption{
Name: ctx.String("name"), Name: ctx.String("name"),
Color: ctx.String("color"), Color: ctx.String("color"),
Description: ctx.String("description"), Description: ctx.String("description"),
@@ -78,7 +78,7 @@ func runLabelCreate(_ stdctx.Context, cmd *cli.Command) error {
if color == "" || name == "" { if color == "" || name == "" {
log.Printf("Line %d ignored because lack of enough fields: %s\n", i, line) log.Printf("Line %d ignored because lack of enough fields: %s\n", i, line)
} else { } else {
_, _, err = ctx.Login.Client().CreateLabel(ctx.Owner, ctx.Repo, gitea.CreateLabelOption{ _, _, err = ctx.Login.Client().Repositories.CreateLabel(requestCtx, ctx.Owner, ctx.Repo, gitea.CreateLabelOption{
Name: name, Name: name,
Color: color, Color: color,
Description: description, Description: description,
+5 -5
View File
@@ -7,8 +7,8 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -30,7 +30,7 @@ var CmdLabelDelete = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runLabelDelete(_ stdctx.Context, cmd *cli.Command) error { func runLabelDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -43,12 +43,12 @@ func runLabelDelete(_ stdctx.Context, cmd *cli.Command) error {
client := ctx.Login.Client() client := ctx.Login.Client()
// Verify the label exists first // Verify the label exists first
label, _, err := client.GetRepoLabel(ctx.Owner, ctx.Repo, labelID) label, _, err := client.Repositories.GetRepoLabel(requestCtx, ctx.Owner, ctx.Repo, labelID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get label %d: %w", labelID, err) return fmt.Errorf("failed to get label %d: %w", labelID, err)
} }
_, err = client.DeleteLabel(ctx.Owner, ctx.Repo, labelID) _, err = client.Repositories.DeleteLabel(requestCtx, ctx.Owner, ctx.Repo, labelID)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete label '%s' (id: %d): %w", label.Name, labelID, err) return fmt.Errorf("failed to delete label '%s' (id: %d): %w", label.Name, labelID, err)
} }
+56 -9
View File
@@ -5,13 +5,14 @@ package labels
import ( import (
stdctx "context" stdctx "context"
"log"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/task"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/task"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -29,25 +30,37 @@ var CmdLabelsList = cli.Command{
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Save all the labels as a file", Usage: "Save all the labels as a file",
}, },
&cli.StringFlag{
Name: "org",
Usage: "List organization labels",
},
&cli.BoolFlag{
Name: "exclude-org",
Usage: "Exclude organization labels from the list",
},
&flags.PaginationPageFlag, &flags.PaginationPageFlag,
&flags.PaginationLimitFlag, &flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
// RunLabelsList list labels. // RunLabelsList list labels.
func RunLabelsList(_ stdctx.Context, cmd *cli.Command) error { func RunLabelsList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
if cmd.String("org") == "" && cmd.String("repo") == "" {
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil { if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err return err
} }
}
if cmd.String("org") != "" && cmd.String("repo") != "" {
log.Printf("Warning: Both --org and --repo flags are set. Ignoring --org and using --repo value as owner.\n")
}
client := ctx.Login.Client() client := ctx.Login.Client()
labels, _, err := client.ListRepoLabels(ctx.Owner, ctx.Repo, gitea.ListLabelsOptions{ labels, err := collectLabels(requestCtx, client, ctx, cmd)
ListOptions: flags.GetListOptions(cmd),
})
if err != nil { if err != nil {
return err return err
} }
@@ -58,3 +71,37 @@ func RunLabelsList(_ stdctx.Context, cmd *cli.Command) error {
return print.LabelsList(labels, ctx.Output) return print.LabelsList(labels, ctx.Output)
} }
// CollectLabels collects labels based on the provided command flags and context.
func collectLabels(requestCtx stdctx.Context, client *gitea.Client, ctx *context.TeaContext, cmd *cli.Command) ([]*gitea.Label, error) {
var labels []*gitea.Label
var err error
owner := ctx.Owner
// If --org is set but --repo is not, list organization labels only and skip repository labels.
if cmd.String("org") != "" && cmd.String("repo") == "" {
owner = ctx.Org
} else {
labels, _, err = client.Repositories.ListRepoLabels(requestCtx, owner, ctx.Repo, gitea.ListLabelsOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err != nil {
log.Printf("Failed to list repository labels: %v", err)
}
}
// If --exclude is not set and the owner is an organization, also list organization labels and append them to the list.
if !ctx.IsSet("exclude-org") {
if _, _, err = client.Organizations.GetOrg(requestCtx, owner); err == nil {
orgLabels, _, err := client.Organizations.ListOrgLabels(requestCtx, owner, gitea.ListOrgLabelsOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err != nil {
return nil, err
}
labels = append(labels, orgLabels...)
}
}
return labels, nil
}
+5 -5
View File
@@ -6,10 +6,10 @@ package labels
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -40,7 +40,7 @@ var CmdLabelUpdate = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runLabelUpdate(_ stdctx.Context, cmd *cli.Command) error { func runLabelUpdate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -66,7 +66,7 @@ func runLabelUpdate(_ stdctx.Context, cmd *cli.Command) error {
pDescription = &description pDescription = &description
} }
_, _, err = ctx.Login.Client().EditLabel(ctx.Owner, ctx.Repo, id, gitea.EditLabelOption{ _, _, err = ctx.Login.Client().Repositories.EditLabel(requestCtx, ctx.Owner, ctx.Repo, id, gitea.EditLabelOption{
Name: pName, Name: pName,
Color: pColor, Color: pColor,
Description: pDescription, Description: pDescription,
+3 -3
View File
@@ -7,9 +7,9 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/login" "gitea.dev/tea/cmd/login"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+17 -11
View File
@@ -7,9 +7,9 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/modules/auth" "gitea.dev/tea/modules/auth"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/task" "gitea.dev/tea/modules/task"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -18,7 +18,12 @@ import (
var CmdLoginAdd = cli.Command{ var CmdLoginAdd = cli.Command{
Name: "add", Name: "add",
Usage: "Add a Gitea login", Usage: "Add a Gitea login",
Description: `Add a Gitea login, without args it will create one interactively`, Description: `Add a Gitea login, without args it will create one interactively.
By default tea only stores the token for its own API use. Pass --git-credentials
to also register tea as a git credential helper for the login's URL, so that
'git push' and 'git clone' over HTTPS authenticate silently using the stored
token. Equivalent to running 'tea login helper setup' afterwards.`,
ArgsUsage: " ", // command does not accept arguments ArgsUsage: " ", // command does not accept arguments
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
@@ -89,9 +94,9 @@ var CmdLoginAdd = cli.Command{
Usage: "Use SSH public key or SSH fingerprint to login (needs a running ssh-agent with ssh key loaded)", Usage: "Use SSH public key or SSH fingerprint to login (needs a running ssh-agent with ssh key loaded)",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "helper", Name: "git-credentials",
Aliases: []string{"j"}, Aliases: []string{"helper", "j"},
Usage: "Add helper", Usage: "Register tea as a git credential helper for this login's URL, so 'git push' and 'git clone' over HTTPS authenticate silently using the stored token",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "oauth", Name: "oauth",
@@ -110,10 +115,10 @@ var CmdLoginAdd = cli.Command{
Action: runLoginAdd, Action: runLoginAdd,
} }
func runLoginAdd(_ context.Context, cmd *cli.Command) error { func runLoginAdd(requestCtx context.Context, cmd *cli.Command) error {
// if no args create login interactive // if no args create login interactive
if cmd.NumFlags() == 0 { if cmd.NumFlags() == 0 {
if err := interact.CreateLogin(); err != nil && !interact.IsQuitting(err) { if err := interact.CreateLogin(requestCtx); err != nil && !interact.IsQuitting(err) {
return fmt.Errorf("error adding login: %w", err) return fmt.Errorf("error adding login: %w", err)
} }
return nil return nil
@@ -137,7 +142,7 @@ func runLoginAdd(_ context.Context, cmd *cli.Command) error {
opts.RedirectURL = cmd.String("redirect-url") opts.RedirectURL = cmd.String("redirect-url")
} }
return auth.OAuthLoginWithFullOptions(opts) return auth.OAuthLoginWithFullOptions(requestCtx, opts)
} }
sshAgent := false sshAgent := false
@@ -147,6 +152,7 @@ func runLoginAdd(_ context.Context, cmd *cli.Command) error {
// else use args to add login // else use args to add login
return task.CreateLogin( return task.CreateLogin(
requestCtx,
cmd.String("name"), cmd.String("name"),
cmd.String("token"), cmd.String("token"),
cmd.String("user"), cmd.String("user"),
@@ -160,6 +166,6 @@ func runLoginAdd(_ context.Context, cmd *cli.Command) error {
cmd.Bool("insecure"), cmd.Bool("insecure"),
sshAgent, sshAgent,
!cmd.Bool("no-version-check"), !cmd.Bool("no-version-check"),
cmd.Bool("helper"), cmd.Bool("git-credentials"),
) )
} }
+3 -3
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -23,7 +23,7 @@ var CmdLoginSetDefault = cli.Command{
Flags: []cli.Flag{&flags.OutputFlag}, Flags: []cli.Flag{&flags.OutputFlag},
} }
func runLoginSetDefault(_ context.Context, cmd *cli.Command) error { func runLoginSetDefault(requestCtx context.Context, cmd *cli.Command) error {
if cmd.Args().Len() == 0 { if cmd.Args().Len() == 0 {
l, err := config.GetDefaultLogin() l, err := config.GetDefaultLogin()
if err != nil { if err != nil {
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -23,7 +23,7 @@ var CmdLoginDelete = cli.Command{
} }
// RunLoginDelete runs the action of a login delete command // RunLoginDelete runs the action of a login delete command
func RunLoginDelete(_ context.Context, cmd *cli.Command) error { func RunLoginDelete(requestCtx context.Context, cmd *cli.Command) error {
logins, err := config.GetLogins() logins, err := config.GetLogins()
if err != nil { if err != nil {
return err return err
+4 -4
View File
@@ -9,9 +9,9 @@ import (
"os" "os"
"os/exec" "os/exec"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/utils"
"github.com/skratchdot/open-golang/open" "github.com/skratchdot/open-golang/open"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -28,7 +28,7 @@ var CmdLoginEdit = cli.Command{
Flags: []cli.Flag{&flags.OutputFlag}, Flags: []cli.Flag{&flags.OutputFlag},
} }
func runLoginEdit(_ context.Context, _ *cli.Command) error { func runLoginEdit(requestCtx context.Context, _ *cli.Command) error {
ymlPath := config.GetConfigPath() ymlPath := config.GetConfigPath()
if e, ok := os.LookupEnv("EDITOR"); ok && e != "" { if e, ok := os.LookupEnv("EDITOR"); ok && e != "" {
cmd := exec.Command(e, ymlPath) cmd := exec.Command(e, ymlPath)
+21 -11
View File
@@ -11,31 +11,40 @@ import (
"os" "os"
"strings" "strings"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/task"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/modules/config"
"gitea.dev/tea/modules/task"
) )
// CmdLoginHelper represents to login a gitea helper. // CmdLoginHelper represents to login a gitea helper.
var CmdLoginHelper = cli.Command{ var CmdLoginHelper = cli.Command{
Name: "helper", Name: "helper",
Aliases: []string{"git-credential"}, Aliases: []string{"git-credential"},
Usage: "Git helper", Usage: "Act as a git credential helper for stored Gitea logins",
Description: `Git helper`, Description: `Speaks git's credential helper protocol so that HTTPS push and clone
Hidden: true, 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: []*cli.Command{ Commands: []*cli.Command{
{ {
Name: "store", Name: "store",
Description: "Command drops",
Aliases: []string{"erase"}, Aliases: []string{"erase"},
Action: func(_ context.Context, _ *cli.Command) error { Usage: "No-op (git credential protocol store/erase)",
Description: "No-op invoked by git on credential store/erase; tea persists credentials only in its own config",
Action: func(requestCtx context.Context, _ *cli.Command) error {
return nil return nil
}, },
}, },
{ {
Name: "setup", Name: "setup",
Description: "Setup helper to tea authenticate", Usage: "Register tea as a git credential helper for every configured login",
Action: func(_ context.Context, _ *cli.Command) error { Description: "Register tea as a git credential helper in ~/.gitconfig for every configured login",
Action: func(requestCtx context.Context, _ *cli.Command) error {
logins, err := config.GetLogins() logins, err := config.GetLogins()
if err != nil { if err != nil {
return err return err
@@ -55,7 +64,8 @@ var CmdLoginHelper = cli.Command{
}, },
{ {
Name: "get", Name: "get",
Description: "Get token to auth", Usage: "Return the stored token for a URL (git credential protocol)",
Description: "Return the stored token for a given URL in git's credential helper protocol (called by git, reads request from stdin)",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "login", Name: "login",
@@ -63,7 +73,7 @@ var CmdLoginHelper = cli.Command{
Usage: "Use a specific login", Usage: "Use a specific login",
}, },
}, },
Action: func(_ context.Context, cmd *cli.Command) error { Action: func(requestCtx context.Context, cmd *cli.Command) error {
wants := map[string]string{} wants := map[string]string{}
s := bufio.NewScanner(os.Stdin) s := bufio.NewScanner(os.Stdin)
for s.Scan() { for s.Scan() {
+4 -4
View File
@@ -6,9 +6,9 @@ package login
import ( import (
"context" "context"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -25,7 +25,7 @@ var CmdLoginList = cli.Command{
} }
// RunLoginList list all logins // RunLoginList list all logins
func RunLoginList(_ context.Context, cmd *cli.Command) error { func RunLoginList(requestCtx context.Context, cmd *cli.Command) error {
logins, err := config.GetLogins() logins, err := config.GetLogins()
if err != nil { if err != nil {
return err return err
+4 -4
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"fmt" "fmt"
"code.gitea.io/tea/modules/auth" "gitea.dev/tea/modules/auth"
"code.gitea.io/tea/modules/config" "gitea.dev/tea/modules/config"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -22,7 +22,7 @@ var CmdLoginOAuthRefresh = cli.Command{
Action: runLoginOAuthRefresh, Action: runLoginOAuthRefresh,
} }
func runLoginOAuthRefresh(_ context.Context, cmd *cli.Command) error { func runLoginOAuthRefresh(requestCtx context.Context, cmd *cli.Command) error {
var loginName string var loginName string
// Get login name from args or use default // Get login name from args or use default
@@ -62,7 +62,7 @@ func runLoginOAuthRefresh(_ context.Context, cmd *cli.Command) error {
fmt.Printf("Token refresh failed: %s\n", err) fmt.Printf("Token refresh failed: %s\n", err)
fmt.Println("Opening browser for re-authentication...") fmt.Println("Opening browser for re-authentication...")
if err := auth.ReauthenticateLogin(login); err != nil { if err := auth.ReauthenticateLogin(requestCtx, login); err != nil {
return fmt.Errorf("re-authentication failed: %s", err) return fmt.Errorf("re-authentication failed: %s", err)
} }
+1 -1
View File
@@ -4,7 +4,7 @@
package cmd package cmd
import ( import (
"code.gitea.io/tea/cmd/login" "gitea.dev/tea/cmd/login"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+6 -5
View File
@@ -6,10 +6,11 @@ package cmd
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/milestones"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/milestones"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
) )
// CmdMilestones represents to operate repositories milestones. // CmdMilestones represents to operate repositories milestones.
@@ -39,7 +40,7 @@ func runMilestones(ctx stdctx.Context, cmd *cli.Command) error {
return milestones.RunMilestonesList(ctx, cmd) return milestones.RunMilestonesList(ctx, cmd)
} }
func runMilestoneDetail(_ stdctx.Context, cmd *cli.Command, name string) error { func runMilestoneDetail(requestCtx stdctx.Context, cmd *cli.Command, name string) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -49,7 +50,7 @@ func runMilestoneDetail(_ stdctx.Context, cmd *cli.Command, name string) error {
} }
client := ctx.Login.Client() client := ctx.Login.Client()
milestone, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, name) milestone, _, err := client.Repositories.GetMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, name)
if err != nil { if err != nil {
return err return err
} }
+2 -1
View File
@@ -6,8 +6,9 @@ package milestones
import ( import (
"context" "context"
"code.gitea.io/tea/cmd/flags"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
) )
// CmdMilestonesClose represents a sub command of milestones to close an milestone // CmdMilestonesClose represents a sub command of milestones to close an milestone
+9 -9
View File
@@ -8,13 +8,14 @@ import (
stdctx "context" stdctx "context"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/interact"
"code.gitea.io/tea/modules/task"
"github.com/araddon/dateparse" "github.com/araddon/dateparse"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/interact"
"gitea.dev/tea/modules/task"
) )
// CmdMilestonesCreate represents a sub command of milestones to create milestone // CmdMilestonesCreate represents a sub command of milestones to create milestone
@@ -49,7 +50,7 @@ var CmdMilestonesCreate = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runMilestonesCreate(_ stdctx.Context, cmd *cli.Command) error { func runMilestonesCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -71,14 +72,13 @@ func runMilestonesCreate(_ stdctx.Context, cmd *cli.Command) error {
} }
if ctx.IsInteractiveMode() { if ctx.IsInteractiveMode() {
if err := interact.CreateMilestone(ctx.Login, ctx.Owner, ctx.Repo); err != nil && !interact.IsQuitting(err) { if err := interact.CreateMilestone(requestCtx, ctx.Login, ctx.Owner, ctx.Repo); err != nil && !interact.IsQuitting(err) {
return err return err
} }
return nil return nil
} }
return task.CreateMilestone( return task.CreateMilestone(requestCtx, ctx.Login,
ctx.Login,
ctx.Owner, ctx.Owner,
ctx.Repo, ctx.Repo,
ctx.String("title"), ctx.String("title"),
+4 -4
View File
@@ -6,8 +6,8 @@ package milestones
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -23,7 +23,7 @@ var CmdMilestonesDelete = cli.Command{
Flags: flags.AllDefaultFlags, Flags: flags.AllDefaultFlags,
} }
func deleteMilestone(_ stdctx.Context, cmd *cli.Command) error { func deleteMilestone(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -33,6 +33,6 @@ func deleteMilestone(_ stdctx.Context, cmd *cli.Command) error {
} }
client := ctx.Login.Client() client := ctx.Login.Client()
_, err = client.DeleteMilestoneByName(ctx.Owner, ctx.Repo, ctx.Args().First()) _, err = client.Repositories.DeleteMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, ctx.Args().First())
return err return err
} }
+15 -14
View File
@@ -8,12 +8,13 @@ import (
stdctx "context" stdctx "context"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
) )
var msIssuesFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{ var msIssuesFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{
@@ -70,7 +71,7 @@ var CmdMilestoneRemoveIssue = cli.Command{
Flags: flags.AllDefaultFlags, Flags: flags.AllDefaultFlags,
} }
func runMilestoneIssueList(_ stdctx.Context, cmd *cli.Command) error { func runMilestoneIssueList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -96,12 +97,12 @@ func runMilestoneIssueList(_ stdctx.Context, cmd *cli.Command) error {
milestone := ctx.Args().First() milestone := ctx.Args().First()
// make sure milestone exist // make sure milestone exist
_, _, err = client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestone) _, _, err = client.Repositories.GetMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, milestone)
if err != nil { if err != nil {
return err return err
} }
issues, _, err := client.ListRepoIssues(ctx.Owner, ctx.Repo, gitea.ListIssueOption{ issues, _, err := client.Issues.ListRepoIssues(requestCtx, ctx.Owner, ctx.Repo, gitea.ListIssueOption{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
Milestones: []string{milestone}, Milestones: []string{milestone},
Type: kind, Type: kind,
@@ -118,7 +119,7 @@ func runMilestoneIssueList(_ stdctx.Context, cmd *cli.Command) error {
return print.IssuesPullsList(issues, ctx.Output, fields) return print.IssuesPullsList(issues, ctx.Output, fields)
} }
func runMilestoneIssueAdd(_ stdctx.Context, cmd *cli.Command) error { func runMilestoneIssueAdd(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -139,12 +140,12 @@ func runMilestoneIssueAdd(_ stdctx.Context, cmd *cli.Command) error {
} }
// make sure milestone exist // make sure milestone exist
mile, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, mileName) mile, _, err := client.Repositories.GetMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, mileName)
if err != nil { if err != nil {
return fmt.Errorf("failed to get milestone '%s': %w", mileName, err) return fmt.Errorf("failed to get milestone '%s': %w", mileName, err)
} }
_, _, err = client.EditIssue(ctx.Owner, ctx.Repo, idx, gitea.EditIssueOption{ _, _, err = client.Issues.EditIssue(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.EditIssueOption{
Milestone: &mile.ID, Milestone: &mile.ID,
}) })
if err != nil { if err != nil {
@@ -153,7 +154,7 @@ func runMilestoneIssueAdd(_ stdctx.Context, cmd *cli.Command) error {
return nil return nil
} }
func runMilestoneIssueRemove(_ stdctx.Context, cmd *cli.Command) error { func runMilestoneIssueRemove(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -173,7 +174,7 @@ func runMilestoneIssueRemove(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("invalid issue index '%s': %w", issueIndex, err) return fmt.Errorf("invalid issue index '%s': %w", issueIndex, err)
} }
issue, _, err := client.GetIssue(ctx.Owner, ctx.Repo, idx) issue, _, err := client.Issues.GetIssue(requestCtx, ctx.Owner, ctx.Repo, idx)
if err != nil { if err != nil {
return fmt.Errorf("failed to get issue #%d: %w", idx, err) return fmt.Errorf("failed to get issue #%d: %w", idx, err)
} }
@@ -187,7 +188,7 @@ func runMilestoneIssueRemove(_ stdctx.Context, cmd *cli.Command) error {
} }
zero := int64(0) zero := int64(0)
_, _, err = client.EditIssue(ctx.Owner, ctx.Repo, idx, gitea.EditIssueOption{ _, _, err = client.Issues.EditIssue(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.EditIssueOption{
Milestone: &zero, Milestone: &zero,
}) })
if err != nil { if err != nil {
+6 -6
View File
@@ -6,11 +6,11 @@ package milestones
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -39,7 +39,7 @@ var CmdMilestonesList = cli.Command{
} }
// RunMilestonesList list milestones // RunMilestonesList list milestones
func RunMilestonesList(_ stdctx.Context, cmd *cli.Command) error { func RunMilestonesList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -62,7 +62,7 @@ func RunMilestonesList(_ stdctx.Context, cmd *cli.Command) error {
} }
client := ctx.Login.Client() client := ctx.Login.Client()
milestones, _, err := client.ListRepoMilestones(ctx.Owner, ctx.Repo, gitea.ListMilestoneOption{ milestones, _, err := client.Repositories.ListMilestones(requestCtx, ctx.Owner, ctx.Repo, gitea.ListMilestoneOption{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
State: state, State: state,
}) })
+6 -6
View File
@@ -7,11 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -28,7 +28,7 @@ var CmdMilestonesReopen = cli.Command{
Flags: flags.AllDefaultFlags, Flags: flags.AllDefaultFlags,
} }
func editMilestoneStatus(_ stdctx.Context, cmd *cli.Command, close bool) error { func editMilestoneStatus(requestCtx stdctx.Context, cmd *cli.Command, close bool) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -58,7 +58,7 @@ func editMilestoneStatus(_ stdctx.Context, cmd *cli.Command, close bool) error {
State: &state, State: &state,
Title: ms, Title: ms,
} }
milestone, _, err := client.EditMilestoneByName(ctx.Owner, ctx.Repo, ms, opts) milestone, _, err := client.Repositories.EditMilestoneByName(requestCtx, ctx.Owner, ctx.Repo, ms, opts)
if err != nil { if err != nil {
return err return err
} }
+1 -1
View File
@@ -4,7 +4,7 @@
package cmd package cmd
import ( import (
"code.gitea.io/tea/cmd/notifications" "gitea.dev/tea/cmd/notifications"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+7 -7
View File
@@ -6,11 +6,11 @@ package notifications
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/flags" gitea "gitea.dev/sdk"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea" "gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -59,7 +59,7 @@ func RunNotificationsList(ctx stdctx.Context, cmd *cli.Command) error {
} }
// listNotifications will get the notifications based on status and subject type // listNotifications will get the notifications based on status and subject type
func listNotifications(_ stdctx.Context, cmd *cli.Command, status []gitea.NotifyStatus, subjects []gitea.NotifySubjectType) error { func listNotifications(requestCtx stdctx.Context, cmd *cli.Command, status []gitea.NotifyStatus, subjects []gitea.NotifySubjectType) error {
var news []*gitea.NotificationThread var news []*gitea.NotificationThread
var err error var err error
@@ -87,7 +87,7 @@ func listNotifications(_ stdctx.Context, cmd *cli.Command, status []gitea.Notify
fields = append(fields, "repository") fields = append(fields, "repository")
} }
news, _, err = client.ListNotifications(gitea.ListNotificationOptions{ news, _, err = client.Notifications.List(requestCtx, gitea.ListNotificationOptions{
ListOptions: listOpts, ListOptions: listOpts,
Status: status, Status: status,
SubjectTypes: subjects, SubjectTypes: subjects,
@@ -96,7 +96,7 @@ func listNotifications(_ stdctx.Context, cmd *cli.Command, status []gitea.Notify
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil { if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err return err
} }
news, _, err = client.ListRepoNotifications(ctx.Owner, ctx.Repo, gitea.ListNotificationOptions{ news, _, err = client.Notifications.ListByRepo(requestCtx, ctx.Owner, ctx.Repo, gitea.ListNotificationOptions{
ListOptions: listOpts, ListOptions: listOpts,
Status: status, Status: status,
SubjectTypes: subjects, SubjectTypes: subjects,
+18 -17
View File
@@ -7,11 +7,12 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/utils"
) )
// CmdNotificationsMarkRead represents a sub command of notifications to list read notifications // CmdNotificationsMarkRead represents a sub command of notifications to list read notifications
@@ -22,7 +23,7 @@ var CmdNotificationsMarkRead = cli.Command{
Description: "Mark all filtered or a specific notification as read", Description: "Mark all filtered or a specific notification as read",
ArgsUsage: "[all | <notification id>]", ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags, Flags: flags.NotificationFlags,
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -34,7 +35,7 @@ var CmdNotificationsMarkRead = cli.Command{
if !ctx.IsSet(flags.NotificationStateFlag.Name) { if !ctx.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)} filter = []string{string(gitea.NotifyStatusUnread)}
} }
return markNotificationAs(ctx, filter, gitea.NotifyStatusRead) return markNotificationAs(requestCtx, ctx, filter, gitea.NotifyStatusRead)
}, },
} }
@@ -46,7 +47,7 @@ var CmdNotificationsMarkUnread = cli.Command{
Description: "Mark all filtered or a specific notification as unread", Description: "Mark all filtered or a specific notification as unread",
ArgsUsage: "[all | <notification id>]", ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags, Flags: flags.NotificationFlags,
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -58,7 +59,7 @@ var CmdNotificationsMarkUnread = cli.Command{
if !ctx.IsSet(flags.NotificationStateFlag.Name) { if !ctx.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusRead)} filter = []string{string(gitea.NotifyStatusRead)}
} }
return markNotificationAs(ctx, filter, gitea.NotifyStatusUnread) return markNotificationAs(requestCtx, ctx, filter, gitea.NotifyStatusUnread)
}, },
} }
@@ -70,7 +71,7 @@ var CmdNotificationsMarkPinned = cli.Command{
Description: "Mark all filtered or a specific notification as pinned", Description: "Mark all filtered or a specific notification as pinned",
ArgsUsage: "[all | <notification id>]", ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags, Flags: flags.NotificationFlags,
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -82,7 +83,7 @@ var CmdNotificationsMarkPinned = cli.Command{
if !ctx.IsSet(flags.NotificationStateFlag.Name) { if !ctx.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)} filter = []string{string(gitea.NotifyStatusUnread)}
} }
return markNotificationAs(ctx, filter, gitea.NotifyStatusPinned) return markNotificationAs(requestCtx, ctx, filter, gitea.NotifyStatusPinned)
}, },
} }
@@ -93,18 +94,18 @@ var CmdNotificationsUnpin = cli.Command{
Description: "Marks all pinned or a specific notification as read", Description: "Marks all pinned or a specific notification as read",
ArgsUsage: "[all | <notification id>]", ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags, Flags: flags.NotificationFlags,
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
filter := []string{string(gitea.NotifyStatusPinned)} filter := []string{string(gitea.NotifyStatusPinned)}
// NOTE: we implicitly mark it as read, to match web UI semantics. marking as unread might be more useful? // NOTE: we implicitly mark it as read, to match web UI semantics. marking as unread might be more useful?
return markNotificationAs(ctx, filter, gitea.NotifyStatusRead) return markNotificationAs(requestCtx, ctx, filter, gitea.NotifyStatusRead)
}, },
} }
func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetState gitea.NotifyStatus) (err error) { func markNotificationAs(ctx stdctx.Context, cmd *context.TeaContext, filterStates []string, targetState gitea.NotifyStatus) (err error) {
client := cmd.Login.Client() client := cmd.Login.Client()
subject := cmd.Args().First() subject := cmd.Args().First()
allRepos := cmd.Bool("mine") allRepos := cmd.Bool("mine")
@@ -119,12 +120,12 @@ func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetSt
opts := gitea.MarkNotificationOptions{Status: states, ToStatus: targetState} opts := gitea.MarkNotificationOptions{Status: states, ToStatus: targetState}
if allRepos { if allRepos {
_, _, err = client.ReadNotifications(opts) _, _, err = client.Notifications.MarkRead(ctx, opts)
} else { } else {
if err := cmd.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil { if err := cmd.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err return err
} }
_, _, err = client.ReadRepoNotifications(cmd.Owner, cmd.Repo, opts) _, _, err = client.Notifications.MarkReadByRepo(ctx, cmd.Owner, cmd.Repo, opts)
} }
// TODO: print all affected notification subject URLs // TODO: print all affected notification subject URLs
@@ -135,12 +136,12 @@ func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetSt
if err != nil { if err != nil {
return err return err
} }
_, _, err = client.ReadNotification(id, targetState) _, _, err = client.Notifications.MarkReadByID(ctx, id, targetState)
if err != nil { if err != nil {
return err return err
} }
n, _, err := client.GetNotification(id) n, _, err := client.Notifications.GetByID(ctx, id)
if err != nil { if err != nil {
return err return err
} }
+4 -4
View File
@@ -8,9 +8,9 @@ import (
"path" "path"
"strings" "strings"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
local_git "code.gitea.io/tea/modules/git" local_git "gitea.dev/tea/modules/git"
"github.com/skratchdot/open-golang/open" "github.com/skratchdot/open-golang/open"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
@@ -27,7 +27,7 @@ var CmdOpen = cli.Command{
Flags: append([]cli.Flag{}, flags.LoginRepoFlags...), Flags: append([]cli.Flag{}, flags.LoginRepoFlags...),
} }
func runOpen(_ stdctx.Context, cmd *cli.Command) error { func runOpen(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
+6 -10
View File
@@ -6,9 +6,9 @@ package cmd
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/tea/cmd/organizations" "gitea.dev/tea/cmd/organizations"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -36,13 +36,7 @@ func runOrganizations(ctx stdctx.Context, cmd *cli.Command) error {
return err return err
} }
if teaCtx.Args().Len() == 1 { if teaCtx.Args().Len() == 1 {
return runOrganizationDetail(teaCtx) org, _, err := teaCtx.Login.Client().Organizations.GetOrg(ctx, teaCtx.Args().First())
}
return organizations.RunOrganizationList(ctx, cmd)
}
func runOrganizationDetail(ctx *context.TeaContext) error {
org, _, err := ctx.Login.Client().GetOrg(ctx.Args().First())
if err != nil { if err != nil {
return err return err
} }
@@ -50,3 +44,5 @@ func runOrganizationDetail(ctx *context.TeaContext) error {
print.OrganizationDetails(org) print.OrganizationDetails(org)
return nil return nil
} }
return organizations.RunOrganizationList(ctx, cmd)
}
+7 -6
View File
@@ -7,10 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/sdk/gitea" "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -52,7 +53,7 @@ var CmdOrganizationCreate = cli.Command{
} }
// RunOrganizationCreate sets up a new organization // RunOrganizationCreate sets up a new organization
func RunOrganizationCreate(_ stdctx.Context, cmd *cli.Command) error { func RunOrganizationCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -74,7 +75,7 @@ func RunOrganizationCreate(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("unknown visibility '%s'", ctx.String("visibility")) return fmt.Errorf("unknown visibility '%s'", ctx.String("visibility"))
} }
org, _, err := ctx.Login.Client().CreateOrg(gitea.CreateOrgOption{ org, _, err := ctx.Login.Client().Organizations.CreateOrg(requestCtx, gitea.CreateOrgOption{
Name: ctx.Args().First(), Name: ctx.Args().First(),
FullName: ctx.String("full-name"), FullName: ctx.String("full-name"),
Description: ctx.String("description"), Description: ctx.String("description"),
+5 -4
View File
@@ -7,9 +7,10 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
) )
// CmdOrganizationDelete represents a sub command of organizations to delete a given user organization // CmdOrganizationDelete represents a sub command of organizations to delete a given user organization
@@ -27,7 +28,7 @@ var CmdOrganizationDelete = cli.Command{
} }
// RunOrganizationDelete delete user organization // RunOrganizationDelete delete user organization
func RunOrganizationDelete(_ stdctx.Context, cmd *cli.Command) error { func RunOrganizationDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -39,7 +40,7 @@ func RunOrganizationDelete(_ stdctx.Context, cmd *cli.Command) error {
return fmt.Errorf("organization name is required") return fmt.Errorf("organization name is required")
} }
response, err := client.DeleteOrg(ctx.Args().First()) response, err := client.Organizations.DeleteOrg(requestCtx, ctx.Args().First())
if response != nil && response.StatusCode == 404 { if response != nil && response.StatusCode == 404 {
return fmt.Errorf("organization not found: %s", ctx.Args().First()) return fmt.Errorf("organization not found: %s", ctx.Args().First())
} }
+7 -6
View File
@@ -6,11 +6,12 @@ package organizations
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/sdk/gitea" "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
) )
// CmdOrganizationList represents a sub command of organizations to list users organizations // CmdOrganizationList represents a sub command of organizations to list users organizations
@@ -28,14 +29,14 @@ var CmdOrganizationList = cli.Command{
} }
// RunOrganizationList list user organizations // RunOrganizationList list user organizations
func RunOrganizationList(_ stdctx.Context, cmd *cli.Command) error { func RunOrganizationList(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
client := ctx.Login.Client() client := ctx.Login.Client()
userOrganizations, _, err := client.ListUserOrgs(ctx.Login.User, gitea.ListOrgsOptions{ userOrganizations, _, err := client.Organizations.ListUserOrgs(requestCtx, ctx.Login.User, gitea.ListOrgsOptions{
ListOptions: flags.GetListOptions(cmd), ListOptions: flags.GetListOptions(cmd),
}) })
if err != nil { if err != nil {
+17 -15
View File
@@ -8,13 +8,14 @@ import (
"fmt" "fmt"
"time" "time"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/cmd/pulls" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/cmd/pulls"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/print" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -77,6 +78,7 @@ var CmdPulls = cli.Command{
&pulls.CmdPullsApprove, &pulls.CmdPullsApprove,
&pulls.CmdPullsReject, &pulls.CmdPullsReject,
&pulls.CmdPullsMerge, &pulls.CmdPullsMerge,
&pulls.CmdPullsReply,
&pulls.CmdPullsReviewComments, &pulls.CmdPullsReviewComments,
&pulls.CmdPullsResolve, &pulls.CmdPullsResolve,
&pulls.CmdPullsUnresolve, &pulls.CmdPullsUnresolve,
@@ -90,7 +92,7 @@ func runPulls(ctx stdctx.Context, cmd *cli.Command) error {
return pulls.RunPullsList(ctx, cmd) return pulls.RunPullsList(ctx, cmd)
} }
func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error { func runPullDetail(requestCtx stdctx.Context, cmd *cli.Command, index string) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -104,14 +106,14 @@ func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
} }
client := ctx.Login.Client() client := ctx.Login.Client()
pr, _, err := client.GetPullRequest(ctx.Owner, ctx.Repo, idx) pr, _, err := client.PullRequests.GetPullRequest(requestCtx, ctx.Owner, ctx.Repo, idx)
if err != nil { if err != nil {
return err return err
} }
var reviews []*gitea.PullReview var reviews []*gitea.PullReview
for page := 1; ; { for page := 1; ; {
page_reviews, resp, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{ page_reviews, resp, err := client.PullRequests.ListPullReviews(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
ListOptions: gitea.ListOptions{Page: page, PageSize: 50}, ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
}) })
if err != nil { if err != nil {
@@ -128,11 +130,11 @@ func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
if ctx.IsSet("output") { if ctx.IsSet("output") {
switch ctx.String("output") { switch ctx.String("output") {
case "json": case "json":
return runPullDetailAsJSON(ctx, pr, reviews) return runPullDetailAsJSON(requestCtx, ctx, pr, reviews)
} }
} }
ci, _, err := client.GetCombinedStatus(ctx.Owner, ctx.Repo, pr.Head.Sha) ci, _, err := client.Repositories.GetCombinedStatus(requestCtx, ctx.Owner, ctx.Repo, pr.Head.Sha)
if err != nil { if err != nil {
fmt.Printf("error while loading CI: %v\n", err) fmt.Printf("error while loading CI: %v\n", err)
} }
@@ -140,7 +142,7 @@ func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
print.PullDetails(pr, reviews, ci) print.PullDetails(pr, reviews, ci)
if pr.Comments > 0 { if pr.Comments > 0 {
err = interact.ShowCommentsMaybeInteractive(ctx, idx, pr.Comments) err = interact.ShowCommentsMaybeInteractive(requestCtx, ctx, idx, pr.Comments)
if err != nil { if err != nil {
fmt.Printf("error loading comments: %v\n", err) fmt.Printf("error loading comments: %v\n", err)
} }
@@ -149,7 +151,7 @@ func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
return nil return nil
} }
func runPullDetailAsJSON(ctx *context.TeaContext, pr *gitea.PullRequest, reviews []*gitea.PullReview) error { func runPullDetailAsJSON(requestCtx stdctx.Context, ctx *context.TeaContext, pr *gitea.PullRequest, reviews []*gitea.PullReview) error {
c := ctx.Login.Client() c := ctx.Login.Client()
opts := gitea.ListIssueCommentOptions{ListOptions: flags.GetListOptions(ctx.Command)} opts := gitea.ListIssueCommentOptions{ListOptions: flags.GetListOptions(ctx.Command)}
@@ -184,7 +186,7 @@ func runPullDetailAsJSON(ctx *context.TeaContext, pr *gitea.PullRequest, reviews
} }
if ctx.Bool("comments") { if ctx.Bool("comments") {
comments, _, err := c.ListIssueComments(ctx.Owner, ctx.Repo, pr.Index, opts) comments, _, err := c.Issues.ListIssueComments(requestCtx, ctx.Owner, ctx.Repo, pr.Index, opts)
if err != nil { if err != nil {
return err return err
} }
+6 -5
View File
@@ -6,10 +6,11 @@ package pulls
import ( import (
stdctx "context" stdctx "context"
"code.gitea.io/sdk/gitea" gitea "gitea.dev/sdk"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
) )
// CmdPullsApprove approves a PR // CmdPullsApprove approves a PR
@@ -19,12 +20,12 @@ var CmdPullsApprove = cli.Command{
Usage: "Approve a pull request", Usage: "Approve a pull request",
Description: "Approve a pull request", Description: "Approve a pull request",
ArgsUsage: "<pull index> [<comment>]", ArgsUsage: "<pull index> [<comment>]",
Action: func(_ stdctx.Context, cmd *cli.Command) error { Action: func(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
return runPullReview(ctx, gitea.ReviewStateApproved, false) return runPullReview(requestCtx, ctx, gitea.ReviewStateApproved, false)
}, },
Flags: flags.AllDefaultFlags, Flags: flags.AllDefaultFlags,
} }
+7 -7
View File
@@ -7,11 +7,11 @@ import (
stdctx "context" stdctx "context"
"fmt" "fmt"
"code.gitea.io/tea/cmd/flags" "gitea.dev/tea/cmd/flags"
"code.gitea.io/tea/modules/context" "gitea.dev/tea/modules/context"
"code.gitea.io/tea/modules/interact" "gitea.dev/tea/modules/interact"
"code.gitea.io/tea/modules/task" "gitea.dev/tea/modules/task"
"code.gitea.io/tea/modules/utils" "gitea.dev/tea/modules/utils"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
@@ -33,7 +33,7 @@ var CmdPullsCheckout = cli.Command{
}, flags.AllDefaultFlags...), }, flags.AllDefaultFlags...),
} }
func runPullsCheckout(_ stdctx.Context, cmd *cli.Command) error { func runPullsCheckout(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd) ctx, err := context.InitCommand(cmd)
if err != nil { if err != nil {
return err return err
@@ -52,7 +52,7 @@ func runPullsCheckout(_ stdctx.Context, cmd *cli.Command) error {
return err return err
} }
if err := task.PullCheckout(ctx.Login, ctx.Owner, ctx.Repo, ctx.Bool("branch"), idx, interact.PromptPassword); err != nil && !interact.IsQuitting(err) { if err := task.PullCheckout(requestCtx, ctx.Login, ctx.Owner, ctx.Repo, ctx.Bool("branch"), idx, interact.PromptPassword); err != nil && !interact.IsQuitting(err) {
return err return err
} }
return nil return nil

Some files were not shown because too many files have changed in this diff Show More