76 Commits

Author SHA1 Message Date
f28f199e85 Changelog for v0.9.1 (#535)
Reviewed-on: https://gitea.com/gitea/tea/pulls/535
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
2023-02-16 06:22:31 +08:00
c00418e74c Print pull dont crash if it has TeamReviewRequests (#517)
partial backport of #515

Reviewed-on: https://gitea.com/gitea/tea/pulls/517
Reviewed-by: Norwin <noerw@noreply.gitea.io>
2022-09-29 20:35:57 +08:00
6c9b2f8745 move s3 endpoint to secrets 2022-09-13 22:36:45 +02:00
1a256291dc Changelog 0.9.0 (#503)
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/503
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
2022-09-14 03:52:46 +08:00
832136b6d4 Add user list command (#427)
Co-authored-by: Matti R <matti@mdranta.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/427
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-committed-by: techknowlogick <techknowlogick@gitea.io>
2022-09-14 03:49:34 +08:00
99e49991bb Add --fields to notification & milestone listings (#422)
Together with #415 this finally adds the field flag to all entity listings.
closes #342

### ⚠️ breaking changes ⚠️
This changes the column names of `tea milestones ls`:

```diff
 - TITLE  | OPEN/CLOSED ISSUES | DUEDATE
 + TITLE  | ITEMS | DUEDATE
```

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/422
Reviewed-by: delvh <dev.lh@web.de>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-09-14 03:08:18 +08:00
bbb287e29e markdown: dont emit ansi sequences when not emitting to tty (#491)
Allows generating a plain text version of an issue (i.e. without colors and other terminal formatting) when storing stdout in a file.
```
tea issue --comments 1 > issue1.txt
```

`IsInteractive()` had to be moved to avoid a recursive import chain.

---

In the future, it would be nice to also respect the `--output` flag. This flag is currently designed for tabular output, but we could add more supported values like `markdown` `ansi`, `plain` to it

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/491
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: delvh <dev.lh@web.de>
2022-09-14 02:35:15 +08:00
5e7c702e07 Clarify command descriptions when no arguments are taken (#496)
This changes the command help string from eg
```
NAME:
   tea label create - Create a label

USAGE:
   tea label [command options] [arguments...]
```
to
```
NAME:
   tea label create - Create a label

USAGE:
   tea label [command options]
```

Hopefully improving usability.

---

edit: this also changes `tea release create` to take the `--tag` flag value optionally via the first argument, as this seems to be a clear UX improvement.

fixes #483

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/496
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: delvh <delvh@noreply.gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-09-14 02:14:02 +08:00
b8dbf899d2 Update dependencies (#501)
- The go-sdk update fixes #463

- To review the other updates:
  - glamour [changelog](https://github.com/charmbracelet/glamour/releases), [diff](https://github.com/charmbracelet/glamour/compare/v0.3.0...v0.5.0)
    - enhancement: we now can use `WithPreservedNewLines()` to render markdow the same way as the web ui
  - termenv [changelog](https://github.com/muesli/termenv/releases), [diff](https://github.com/muesli/termenv/compare/v0.9.0...v0.12.0)
    - enhancement: correct feature detection for more terminals
  - xdg [changelog](https://github.com/adrg/xdg/releases), [diff](https://github.com/adrg/xdg/compare/v0.3.3...v0.4.0)
    - no notable changes for us, but good to stay up to date 🤷
  - survey [changelog](https://github.com/AlecAivazis/survey/releases), [diff](https://github.com/AlecAivazis/survey/compare/v2.3.1...v2.3.6)
    - bugfixes
  - cli [changelog](https://github.com/urfave/cli/releases), [diff](https://github.com/urfave/cli/compare/v2.3.0...v2.16.3)
    - bugfixes?

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/501
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-09-14 01:52:44 +08:00
0b8be54186 Rename master branch to main (#495)
This updates drone CI to use the new main branch name `main`.

### ⚠️ breaking

The download URLs on https://dl.gitea.io/tea/master will no longer be updated.

@Owners: is there a way to add a redirect for these URLs from `/tea/master` to `/tea/main`?

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/495
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-08-26 23:34:40 +08:00
2b1bca9e5d Add license for gitea.com/noerw/unidiff-comments (#493)
The updated version just clarifies the license to be MIT, as [added by the original author](865648740d).
fixes #492

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/493
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-08-22 21:14:09 +08:00
d5a258213d Fix CI: disable package-comments lint rule (#494)
There was an unintended change to the rule in revive that now makes our CI trip:
https://github.com/mgechev/revive/pull/694
The package-comments now expected are not really worth writing as these are tiny internal packages, so this change just disables that rule for now.

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/494
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-08-22 20:53:19 +08:00
f83f579dea Show more version info (#486)
Reviewed-on: https://gitea.com/gitea/tea/pulls/486
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Wim <42wim@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2022-06-18 22:34:18 +08:00
65535bd948 Use latest go-sdk and bump golang to 1.18 (#485)
Reviewed-on: https://gitea.com/gitea/tea/pulls/485
Reviewed-by: KN4CK3R <kn4ck3r@noreply.gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2022-06-10 22:31:24 +08:00
02f5f15269 Fix go install for go 1.17 (#481)
Reviewed-on: https://gitea.com/gitea/tea/pulls/481
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Sandro <supersandro2000@noreply.gitea.io>
Co-committed-by: Sandro <supersandro2000@noreply.gitea.io>
2022-04-26 14:07:15 +08:00
883a27b14e Fetch all items where needed. (#475)
Disable pagination in all places where we need all items.
Ideally we'd do multiple paginated requests until the needed items are local, but this is blocked by https://gitea.com/gitea/go-sdk/pulls/473. So this is a stopgap to get correct behaviour.

Fixes #464

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/475
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-04-08 03:44:16 +08:00
e54b32493d fix pipeline to release builds (#479)
fix regression of #478

Reviewed-on: https://gitea.com/gitea/tea/pulls/479
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: John Olheiser <john.olheiser@gmail.com>
2022-03-29 08:29:47 +08:00
329200b1ef Fix running in repos without remote (#472)
For tea, the case of no remotes in the local repo context is equal to `errNotAGiteaRepo`.
This error type is already gracefully handled, so with this change, tea doesn't reject working from a repo without remotes.

fixes #455, closes #465

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/472
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-29 08:01:37 +08:00
6663d9f19b Add preference flag_defaults.remote, refactor (#466)
This is a refactor of the code last touched in #458, making the control flow less backwards.

Additionally, this adds a preference `preferences.flag_defaults.remote` that allows to skip this heuristic and set a custom fixed default value for the `--remote` flag.
I'm not sure this is actually needed, I can revert that commit.

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Andrew Thornton <art27@cantab.net>
Reviewed-on: https://gitea.com/gitea/tea/pulls/466
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-29 07:34:14 +08:00
d06f35482e Use golang v1.18 and drop vendor folder (#478)
* remove vendor folder
* use golang v1.18 in ci
* use "go install"
* use vendor folder as cache

Reviewed-on: https://gitea.com/gitea/tea/pulls/478
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: John Olheiser <john.olheiser@gmail.com>
2022-03-29 07:11:11 +08:00
9ab36c55fa Return RFC3339 UTC timestamps for machine-readable output (#470)
### ⚠️ breaking changes ⚠️

- unset timestamps will not be printed as `"0001-01-01 00:00"`, but as empty value `""`
- output formats `csv`, `tsv`, `yaml` output timestamps in UTC instead of local time, and adhere to [RFC3339](https://datatracker.ietf.org/doc/html/rfc3339)

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/470
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-29 06:37:13 +08:00
40e606561f GOPROXY: https://goproxy.io 2022-03-28 23:59:48 +02:00
0970b94552 Fix context requirements of subcommands (#474)
`tea repo fork` and `tea pr checkout` were missing the requirement of a remote repo.

fixes https://gitea.com/gitea/tea/issues/444

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/474
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-26 15:32:53 +08:00
dda94a5dea Refactor errorhandling in getReleaseByTag() (#477)
small refactor for consistency

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/477
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-25 21:41:08 +08:00
16ba594a28 Interactive issue/pr posting: properly fetch assignees (#476)
Gitea 1.15.0 added a proper API for listing assignee candidates.
imho that release is old enough that tea can start using this without workarounds.

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/476
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-19 19:08:58 +08:00
d8f4273ed0 Add TSV to machine-readable formats (#467)
...so no ansi formatting (colors) is emitted in that format (eg `tea labels -o tsv`)

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/467
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-13 12:00:21 +08:00
637e3f0666 Fix CI: run make fmt (#469)
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/469
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2022-03-13 08:53:18 +08:00
ced24ccabb update to new s3 location (#468)
Reviewed-on: https://gitea.com/gitea/tea/pulls/468
2022-03-11 05:01:29 +08:00
fb3e1f75e9 Prefer origin if there are multiple remotes (#458)
Usually, `origin` is the name of a default remote, which corresponds with upstream. This change improves remote selection when non of `main`, `master` nor `trunk` local branches is present.

Co-authored-by: Petr Vaněk <arkamar@atlas.cz>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/458
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: arkamar <arkamar@noreply.gitea.io>
Co-committed-by: arkamar <arkamar@noreply.gitea.io>
2022-03-09 09:35:51 +08:00
0e24009fe9 Fix create milestone with deadline bug (#462)
Fix #461

Reviewed-on: https://gitea.com/gitea/tea/pulls/462
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-committed-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-09 08:47:58 +08:00
cd24fd8e28 Fix few typos in contribution guidelines (#459)
I found few typos in `CONTRIBUTING.md` file.

Co-authored-by: Petr Vaněk <arkamar@atlas.cz>
Reviewed-on: https://gitea.com/gitea/tea/pulls/459
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: arkamar <arkamar@noreply.gitea.io>
Co-committed-by: arkamar <arkamar@noreply.gitea.io>
2022-02-22 22:34:58 +08:00
dd300c1269 Fix typo in bug.md (#460)
occured -> occurred

Reviewed-on: https://gitea.com/gitea/tea/pulls/460
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Ikko Ashimine <eltociear@noreply.gitea.io>
Co-committed-by: Ikko Ashimine <eltociear@noreply.gitea.io>
2022-02-20 00:30:58 +08:00
44c9e7e664 Correct spelling of "wether" to "whether" in usage output (#453)
Noticed "whether" misspelled as "wether" in the output of `tea issues --help` and corrected it in a few locations.

Co-authored-by: Alex Kelly <kellya@arachnitech.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/453
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: kellya <kellya@noreply.gitea.io>
Co-committed-by: kellya <kellya@noreply.gitea.io>
2022-02-01 07:11:37 +08:00
268aa06179 Add bug report issue template (#448)
As we repeatedly ask for information about users' environments, I added this template

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/448
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-12-04 11:20:36 +08:00
a7d83ee416 Simplify build & update installation instructions (#437)
- "revert" the work done in #349. It turns out that this elaborate workaround to get statically built PIEs was only needed due to a bug in go, which got fixed in go 1.16.
- Add an exception to the `-buildmode=pie` flag for OpenBSD, as discovered in #436
- Simplify & update README installation instructions (the Arch AUR package got deleted as it wasn't maintained, so we link to `gitea-tea-git` now.)

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/437
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-12-03 04:01:10 +08:00
a89f51f9ec Implement more issue filters (#400)
This adds new filters to `tea issues ls` and `tea pr ls`, made available in SDK 0.15:

```
--state value                 Filter by state (all|open|closed) (default: open)
--keyword value, -k value     Filter by search string
--labels value, -L value      Comma-separated list of labels to match issues against.
--milestones value, -m value  Comma-separated list of milestones to match issues against.
--author value, -A value
--assignee value, -a value
--mentions value, -M value
--from value, -F value        Filter by activity after this date
--until value, -u value       Filter by activity before this date
```

Note: I felt free to change parameter names as exposed by SDK & API, as the names exposed by them are partially bollocks (eg `mentioned_by`) and or inconsistent with usage in other commands (eg `tea times --until`)

fixes #376, related #323

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/400
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-12-03 03:26:48 +08:00
d2295828d0 Fix resolving of URLs in markdown (#401)
Path-only URLs need an absolute reference to be resolved against for printing in markdown
Previously we resolved against the URL to the resource we were operating on (eg comment or issue URL).
The markdown renderer in the web UI resolves all such URLs relative to the repo base URL. This PR adopts this behaviour in tea, by trimming the URL to a repo base URL via regex.

This makes a custom patch to our markdown renderer `glamour` obsolete, which turned out to be an incorrect patch, meaning we can make use of upstream glamour again.

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/401
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-12-03 02:59:02 +08:00
dc16643e0d Improve Documentation (#433)
- document more assumptions about usage context of gitea
- improve some flag descriptions (#432, #377)

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/433
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-12-03 02:33:56 +08:00
ac25e89ebf Add tea repo create-from-template (#408)
I went with a new subcommand instead of `tea repo create --template`, as the options are quite different (bool instead of values, partially different set)

fixes #362

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/408
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-20 09:31:35 +08:00
819cc1ab21 Add tea clone (#411)
Adds a new subcommand to clone repos:
```
tea clone --login try --depth 1 norwin/test
tea clone gitea/tea
tea clone noerw/tea           # will set up `master` to track `upstream` remote
tea clone try.gitea.io/noerw/test # will automatically set --login
```

This is just a replacement for `git clone` with small benefits:
- [x] does not depend on `git`, as tea ships with go-git
- [x] spares you typing of URLs and autoselects https/ssh based on your login config
- [x] forked repos: set up origin + upstream remote

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-on: https://gitea.com/gitea/tea/pulls/411
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-18 20:09:27 +08:00
78a95f1ca4 Allow editing multiline prompts with external text editor (#429)
- Adds a new `Preferences` struct to the config, initially only containing `Editor: bool (default false)`.
  This struct will be serialized to configs once there is a first tea induced change to the config (eg `tea login default <name>` or `tea login add`).
- Use external editor for all multiline prompts if preferred.

We already had a function for starting a texteditor for diff reviews; it does not really make sense to replace it with `survey.Editor`, as there is a big interface mismatch: survey expects strings as inputs, while our diff functions operate on files,

fixes #424

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/429
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-14 22:36:08 +08:00
5b77345b03 Add tea repo fork (#410)
Adds a new subcommand to fork repos.

To specify the repo to fork, use the `--repo` flag. This feels a bit weird, other tea commands would put this as the first argument.
I decided to follow the flag style, as this is what all other subcommands of `tea repo` do. We might want to reconsider and make the primary subject of such commands an argument, instead of an required flag.. see #430

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-on: https://gitea.com/gitea/tea/pulls/410
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-14 15:27:39 +08:00
23ce7b351d fix CI release upload: switch to woodpecker/plugin-s3 (#428)
- this fixes the CI release upload issues, as the docker image for this is freshly built (unlike the mostly unmaintained "official" drone plugins), thus containing current CA certs needed for letsencrypt since 2021-09-31.
- woodpecker is a drone-ci fork maintained partially by @6543. it's API compatible with current drone plugins afaik

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/428
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-10 20:48:51 +08:00
375ece06d2 fix lint regression (#425)
On PR #421 CI did not work and it was force merged. Thus we managed to have failing CI on master.. :( sorry

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/425
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-05 01:43:06 +08:00
4ffd994549 Add tea whoami command (#426)
The User print will be used in future for list of users for admin

Co-authored-by: Matti R <matti@mdranta.net>
Reviewed-on: https://gitea.com/gitea/tea/pulls/426
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-committed-by: techknowlogick <techknowlogick@gitea.io>
2021-10-05 01:41:59 +08:00
58aaa17e7e Show issue reactions (#421)
```
$ tea issue 230

   #230 issue/pull details: show reactions (open)

  @6543 created 2020-10-22 16:39

  since reactions are utf8 now and most terminals too, we can display them nicely :)

  https://gitea.com/api/v1/repos/gitea/tea/issues/230/reactions

  --------

  1x 🎉  |  1x 👀  |  1x :gitea:  |  1x 👍  |  1x 👎  |  1x 😆  |  1x 😕  |  1x ❤️
```

caveats:
- reactions are not returned as UTF8 (as was claimed in #230), so they need to be parsed. the library I use doesn't (and can't → :gitea:) support all reactions available in gitea
- currently only for issues, as reactions for comments mean an additional API request for each comment..

fixes #230

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/421
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-10-01 16:13:32 +08:00
7a05be436c Add more flags to tea repo create (#409)
adds the `--template` and `--trustmodel` flags

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/409
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-29 04:42:51 +08:00
3cf084cb96 PR listing: add --fields & expose additional fields (#415)
This PR adds the `--fields` flag to `tea pr ls` (#342), and exposes more fields specific to the `PullRequest` type:
```
   --fields value, -f value   Comma-separated list of fields to print.
                              Available values:
                              index,state,author,author-id,url,title,body,mergeable,base,base-commit,head,diff,patch,created,updated,deadline,assignees,milestone,labels,comments
                              (default: "index,title,state,author,milestone,updated,labels")

```

Co-authored-by: justusbunsi <61625851+justusbunsi@users.noreply.github.com>
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/415
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: justusbunsi <justusbunsi@noreply.gitea.io>
Co-committed-by: justusbunsi <justusbunsi@noreply.gitea.io>
2021-09-29 04:36:33 +08:00
1e59dee685 Add tea org create <name> (#420)
fixes #287, fixes #363

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/420
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-29 04:32:16 +08:00
42e423470c Fix notification example (#416)
Co-authored-by: justusbunsi <61625851+justusbunsi@users.noreply.github.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/416
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: justusbunsi <justusbunsi@noreply.gitea.io>
Co-committed-by: justusbunsi <justusbunsi@noreply.gitea.io>
2021-09-29 03:29:48 +08:00
555f1ae516 Makefile: add STATIC=true for static PIE builds (#349)
- `make build` + `make install` now support the `STATIC=true` parameter, creating statically linked builds that are also position independent executables
- this requires CGO and a static libc on the build system
- `CGO_ENABLED=0` is set for all make build targets, unless `STATIC=true` is set
- Debug symbols are stripped (`-s -w`) for all make build targets
- Release binaries are built statically by gox (no PIE), as before.

I also took the liberty to declutter the makefile from unused & duplicated variables.

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/349
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-24 00:01:07 +08:00
1c690c5ff8 Changelog v0.8.0 (#404)
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/404
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2021-09-23 03:53:33 +08:00
802bdf7dc5 Don't require a body for comment PR reviews (#399)
fixes #372

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/399
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-23 02:18:25 +08:00
1731e00ebd Don't skip reading the local repo when --repo specifies a repo slug (#398)
I added this check in #327, but it wasn't needed at all
as the error case it intended to catch where already handled by checking if the path exists.

fixes #378

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/398
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-23 00:12:56 +08:00
7b7c7f57be tea pr create: make local repo optional (#393)
this is a partial fix to #378, making the command available outside of a local repo.

new behaviour:
- when run interactively without local repo context, the head repo prompt is not pre-populated
- when run with flags without local repo context, it will complain unless `--head` is specified

refactor:
- pass TeaContext down to task.CreatePull

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/393
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-22 23:48:21 +08:00
6e728cf812 Accept more main branch names for login detection (#396)
Also consider `main` and `trunk` as options
to determine a login through its configured remote

fixes #381

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/396
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-14 14:59:11 +08:00
808e8b1c5a Correctly match login by ssh host with port (#391)
fixes #380

note: It seems like it was expected that `SSHHost` only contains the host portion.  So this may be breaking (although I don't believe many people used the feature like that with a custom ssh port). I can't think of a good reason to *not* specify the port in that field, including the port seems more intuitive

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/391
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-06 18:52:34 +08:00
9201250f74 fix printing issue deadline (#388)
fixes #387

Reviewed-on: https://gitea.com/gitea/tea/pulls/388
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-06 18:45:24 +08:00
5b28a05eb7 Implement notification subcommands (#389)
- [x] enhance notification listing
  - add `--states` and `--type` filters
  - toggle per-user or per-repo listing via `--mine` flag
  - print more fields
- [x] add subcommands to mark notifications as read, unread, pinned, unpinned. operates on
  - all notifications matching the `--state` and `--mine` filter flags, or
  - a notification specified by ID.
- [ ] ~~add a `--fields` flag for notifications listing.~~ *not in this PR*
- [ ] ~~interactive mode~~ *not in this PR*. this would go well together with #324

fixes #243, fixes #155

based on initial work in #283 and #386, but opening a new PR for @6543 to review as I changed quite a lot

---

### ⚠️ breaking ⚠️
- `tea notifications --all` has moved to `tea notifications --mine`
- `tea notifications` now only works with the context of a remote repo.
  To run this outside of a local git dir, run either `tea n --mine` or `tea n --repo <my/repo>`

---

Co-authored-by: Karl Heinz Marbaise <kama@soebes.de>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin Roosen <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/389
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Alexey 〒erentyev <axifive@noreply.gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-09-06 01:11:17 +08:00
3fca309f2c Fix adding login without token on private instances (#392)
fixes #365

Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/392
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-08-30 23:19:45 +08:00
d6df0a53b5 Update Dependencies (#390)
Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: Norwin <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/390
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-08-30 23:18:50 +08:00
4b9907fb54 Notifications Add State Field (#384)
Reviewed-on: https://gitea.com/gitea/tea/pulls/384
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2021-08-16 21:23:16 +08:00
ab4e11ae4d Update gitea go-sdk to v0.15.0 (#385)
Update "code.gitea.io/sdk/gitea" to latest release

Reviewed-on: https://gitea.com/gitea/tea/pulls/385
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2021-08-16 20:46:15 +08:00
546fcc16de Handle XDG directories with spaces in autocomplete commands (#383)
On some OSs ([i.e. macOS](https://github.com/adrg/xdg#xdg-base-directory)), XDG directories contain spaces, so we need to wrap the resulting path used in autocomplete sourcing commands in quotation marks.

Co-authored-by: Matthew Daley <mattd@bugfuzz.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/383
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: nukuta <nukuta@noreply.gitea.io>
Co-committed-by: nukuta <nukuta@noreply.gitea.io>
2021-07-24 00:14:23 +08:00
0f4f669cf0 Fix parsing of --description for issue/pr create (#371)
The `--description` flag didn't work; regression of #331

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/371
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: KN4CK3R <kn4ck3r@noreply.gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-07-03 23:23:38 +08:00
2bdd72dfff Improve error messages (#370)
fixes #367

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/370
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: KN4CK3R <kn4ck3r@noreply.gitea.io>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-07-03 22:39:05 +08:00
64770a771f rename s3 bucket name (#375)
Reviewed-on: https://gitea.com/gitea/tea/pulls/375
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-committed-by: techknowlogick <techknowlogick@gitea.io>
2021-06-30 04:36:05 +08:00
ebb2c38a0a Return useful error on wrong sshkey path (#374)
close #366

Reviewed-on: https://gitea.com/gitea/tea/pulls/374
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-committed-by: 6543 <6543@obermui.de>
2021-06-29 15:54:43 +08:00
616127cedc Add missing flags (#369)
fixes #368

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/369
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-06-22 22:23:09 +08:00
3129e60a73 text editor selection: follow unix defacto standards (#356)
Currently, `tea` only supports the $EDITOR env var to open the user's preferred editor (used for reviewing pull requests).

Standard \*nix practice is, however, to check for $VISUAL first and only then use $EDITOR as fallback.
This is also done by Git itself, see man git-var(1).
(Actually, the order there is $GIT_EDITOR > core.editor > $VISUAL > $EDITOR > vi)

Co-authored-by: plgruener <pl.gruener@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/356
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: plgruener <plgruener@noreply.gitea.io>
Co-committed-by: plgruener <plgruener@noreply.gitea.io>
2021-06-21 20:08:27 +08:00
df724b4006 Add tab completion for fish shell (#364)
as title, fixes #361

Handling of fish shell is different in urfave/cli; urfave/cli provides a generator for the shell script needed (probably because the fish `completion` syntax isn't flexible enough to let the application handle the completion at runtime? idk)

This means that the fish completion can become out of sync with the tea binary.
If we want to account for that, on each application run we need to
- check if `~/.config/fish/conf.d/tea_completion.fish` exists; if so
- check if the tea version that wrote it is the currently running version
- if not, rewrite the file.

Not sure this is worth the complexity & cost

It generates a completion that also suggests file names, which looks kinda messy: Didn't find a way around this, but [there may be a way](5bb54ace57/fish.go (L160-L180))
![grafik](/attachments/b08541c9-0f37-4c70-a2e3-1ec9da15a430)

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/364
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-05-24 04:42:21 +08:00
ffdbdb3d02 Check negative limit command parameter (#358) (#359)
fix #358

Co-authored-by: Brahim Hamdouni <brahim@hamdouni.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/359
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Co-authored-by: Brahim HAMDOUNI <hamdouni@noreply.gitea.io>
Co-committed-by: Brahim HAMDOUNI <hamdouni@noreply.gitea.io>
2021-05-15 22:16:24 +08:00
568fde1ce5 Add missing flags to org & labels subcommands (#357)
The `tea orgs` command is an alias to `tea orgs list`, and as such should have the same flags.

fixes #354

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/357
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-05-13 02:32:20 +08:00
46945415c9 Enable release builds for darwin/arm64 (#360)
Co-authored-by: Norwin Roosen <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/360
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-05-11 08:03:39 +08:00
195bd2199c contributed container build definition (#350)
as discussed with @noerw on Discord

Co-authored-by: Tamás Gérczei <tamas@gerczei.eu>
Reviewed-on: https://gitea.com/gitea/tea/pulls/350
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Norwin <noerw@noreply.gitea.io>
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Tamás Gérczei <tgerczei@noreply.gitea.io>
Co-committed-by: Tamás Gérczei <tgerczei@noreply.gitea.io>
2021-03-30 19:13:23 +08:00
0bf844018c Add tea pr merge (#348)
fixes #343

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/348
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
2021-03-18 03:56:05 +08:00
1732 changed files with 2754 additions and 429308 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
Dockerfile
tea

View File

@ -7,18 +7,25 @@ platform:
arch: amd64
steps:
- name: vendor
pull: always
image: golang:1.18
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
commands:
- make vendor # use vendor folder as cache
- name: build
pull: always
image: golang:1.16
image: golang:1.18
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
commands:
- make clean
- make vet
- make lint
- make fmt-check
- make misspell-check
- make test-vendor
- make build
when:
event:
@ -27,24 +34,28 @@ steps:
- pull_request
- name: unit-test
image: golang:1.16
image: golang:1.18
commands:
- make unit-test-coverage
settings:
group: test
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
when:
branch:
- master
- main
event:
- push
- pull_request
- name: release-test
image: golang:1.16
image: golang:1.18
commands:
- make test
settings:
group: test
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
when:
branch:
- "release/*"
@ -54,21 +65,22 @@ steps:
- name: tag-test
pull: always
image: golang:1.16
image: golang:1.18
commands:
- make test
settings:
group: test
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
when:
event:
- tag
- name: static
image: golang:1.16
image: golang:1.18
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
commands:
- export PATH=$PATH:$GOPATH/bin
- make release
when:
event:
@ -96,11 +108,12 @@ steps:
- name: tag-release
pull: always
image: plugins/s3:1
image: woodpeckerci/plugin-s3:latest
settings:
acl: public-read
bucket: releases
endpoint: https://storage.gitea.io
bucket: gitea-artifacts
endpoint:
from_secret: aws_endpoint
path_style: true
source: "dist/release/*"
strip_prefix: dist/release/
@ -116,12 +129,12 @@ steps:
- name: release-branch-release
pull: always
image: plugins/s3:1
image: woodpeckerci/plugin-s3:latest
settings:
acl: public-read
bucket: releases
endpoint: https://storage.gitea.io
path_style: true
bucket: gitea-artifacts
endpoint:
from_secret: aws_endpoint
source: "dist/release/*"
strip_prefix: dist/release/
target: "/tea/${DRONE_BRANCH##release/v}"
@ -138,15 +151,15 @@ steps:
- name: release
pull: always
image: plugins/s3:1
image: woodpeckerci/plugin-s3:latest
settings:
acl: public-read
bucket: releases
endpoint: https://storage.gitea.io
path_style: true
bucket: gitea-artifacts
endpoint:
from_secret: aws_endpoint
source: "dist/release/*"
strip_prefix: dist/release/
target: /tea/master
target: /tea/main
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
@ -154,7 +167,7 @@ steps:
from_secret: aws_secret_access_key
when:
branch:
- master
- main
event:
- push

View File

@ -0,0 +1,30 @@
---
name: "Bug Report"
about: "Use this template when reporting a bug, so you don't forget important information we'd ask for later."
title: "Bug: "
labels:
- kind/bug
---
### describe your environment
- tea version used (`tea -v`):
- [ ] I also reproduced the issue [with the latest master build](https://dl.gitea.io/tea/master)
- Gitea version used:
- [ ] the issue only occurred after updating gitea recently
- operating system:
- I make use of...
- [ ] non-standard default branch names (no `main`,`master`, or `trunk`)
- [ ] .ssh/config or .gitconfig host aliases in my git remotes
- [ ] ssh_agent or similar
- [ ] non-standard ports for gitea and/or ssh
- [ ] something else that's likely to interact badly with tea: ...
Please provide the output of `git remote -v` (if the issue is related to tea not finding resources on Gitea):
```
```
### describe the issue (observed vs expected behaviour)

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ tea
dist/
.vscode/
vendor/

View File

@ -16,7 +16,6 @@ warningCode = 1
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]

View File

@ -1,5 +1,78 @@
# Changelog
## [v0.9.1](https://gitea.com/gitea/tea/releases/tag/v0.9.1) - 2023-02-15
* BUGFIXES
* Print pull dont crash if it has TeamReviewRequests (#517)
## [v0.9.0](https://gitea.com/gitea/tea/releases/tag/v0.9.0) - 2022-09-13
* BREAKING
* Rename master branch to main (#495)
* Return RFC3339 UTC timestamps for machine-readable output (#470)
* FEATURES
* Allow editing multiline prompts with external text editor (#429)
* Add `tea admin user list` (#427)
* Add `tea whoami` command (#426)
* Add `tea org create <name>` (#420)
* Add `tea clone` (#411)
* Add `tea repo fork` (#410)
* Add `tea repo create-from-template` (#408)
* BUGFIXES
* Fetch all items where needed. (#475)
* Fix running in repos without remote (#472)
* Add TSV to machine-readable formats (#467)
* Fix create milestone with deadline bug (#462)
* Fix resolving of URLs in markdown (#401)
* ENHANCEMENTS
* Don't emit ANSI sequences when not emitting to TTY for markdown (#491)
* Show more version info (#486)
* Add preference `flag_defaults.remote`, refactor (#466)
* Add `--fields` to notification & milestone listings (#422)
* PR listing: add --fields & expose additional fields (#415)
* Add more flags to `tea repo create` (#409)
* Implement more issue filters (#400)
* MISC
* Simplify build & update installation instructions (#437)
* Clarify command descriptions when no arguments are taken (#496)
* Improve Documentation (#433)
* Use golang v1.18 and drop vendor folder (#478)
* Correct spelling of "wether" to "whether" in usage output (#453)
## [v0.8.0](https://gitea.com/gitea/tea/releases/tag/v0.8.0) - 2021-09-22
* BREAKING
* `tea notifications --all` has moved to `tea notifications --mine` (#389)
* `tea notifications` now only works with the context of a remote repo. (#389)
To run this outside of a local git dir, run either tea n `--mine` or `tea n --repo <my/repo>`
* FEATURES
* Add `tea pr merge` (#348)
* BUGFIXES
* Don't skip reading the local repo when `--repo` specifies a repo slug (#398)
* Fix adding login without token on private instances (#392)
* Correctly match login by ssh host with port (#391)
* Fix printing issue deadline (#388)
* Return useful error on wrong sshkey path (#374)
* Fix parsing of `--description` for issue/pr create (#371)
* Add missing flags (#369)
* Check negative limit command parameter (#358) (#359)
* Add missing flags to org & labels subcommands (#357)
* ENHANCEMENTS
* Don't require a body for comment PR reviews (#399)
* Accept more main branch names for login detection (#396)
* Make local repo optional for `tea pr create`(#393)
* Notifications Add State Field (#384)
* Improve error messages (#370)
* Add tab completion for fish shell (#364)
* Text editor selection: follow unix defacto standards (#356)
* MISC
* Update Dependencies (#390)
## [v0.7.1](https://gitea.com/gitea/tea/releases/tag/v0.7.1) - 2021-08-27
* BUILD
* Enable release builds for darwin/arm64 (#360)
## [v0.7.0](https://gitea.com/gitea/tea/releases/tag/v0.7.0) - 2021-03-12
* BREAKING

View File

@ -57,8 +57,8 @@ high-level discussions.
## Testing redux
Before sending code out for review, run all the test by execting: `make test`
Since TEA is an cli tool it should be obvious to test your feature localy first.
Before sending code out for review, run all the test by executing: `make test`
Since TEA is an cli tool it should be obvious to test your feature locally first.
## Vendoring
@ -77,7 +77,7 @@ You can find more information on how to get started with it on the [dep project
## Code review
Changes to TEA must be reviewed before they are accepted—no matter who
makes the change, even if they are an owner or a maintainer. We use Giteas's
makes the change, even if they are an owner or a maintainer. We use Gitea's
pull request & review workflow to do that. Gitea ensure every PR is reviewed by at least 2 maintainers.
Please try to make your pull request easy to review for us. And, please read
@ -118,8 +118,8 @@ Some of the key points:
- Always make sure that the help texts are properly set, and as concise as possible.
### Internal Module Structure
- `cmd`: only contains comand/flag options for `urfave/cli`
- subcomands are in a subpackage named after its parent comand
- `cmd`: only contains command/flag options for `urfave/cli`
- subcommands are in a subpackage named after its parent command
- `modules/task`: contain func for doing something with gitea
(e.g. create token by user/passwd)
- `modules/print`: contain all functions that print to stdout

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
ARG GOVERSION="1.16.2"
FROM golang:${GOVERSION}-alpine AS buildenv
ARG GOOS="linux"
COPY . $GOPATH/src/
WORKDIR $GOPATH/src
RUN apk add --quiet --no-cache \
build-base \
make \
git && \
make clean build STATIC=true
FROM scratch
ARG VERSION="0.7.0"
LABEL org.opencontainers.image.title="tea - CLI for Gitea - git with a cup of tea"
LABEL org.opencontainers.image.description="A command line tool to interact with Gitea servers"
LABEL org.opencontainers.image.version="${VERSION}"
LABEL org.opencontainers.image.authors="Tamás Gérczei <tamas@gerczei.eu>"
LABEL org.opencontainers.image.vendor="The Gitea Authors"
COPY --from=buildenv /go/src/tea /
ENV HOME="/app"
ENTRYPOINT ["/tea"]

101
Makefile
View File

@ -1,31 +1,15 @@
DIST := dist
IMPORT := code.gitea.io/tea
export GO111MODULE=on
export CGO_ENABLED=0
GO ?= go
SED_INPLACE := sed -i
SHASUM ?= shasum -a 256
export PATH := $($(GO) env GOPATH)/bin:$(PATH)
ifeq ($(OS), Windows_NT)
EXECUTABLE := tea.exe
else
EXECUTABLE := tea
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SED_INPLACE := sed -i ''
endif
endif
GOFILES := $(shell find . -name "*.go" -type f ! -path "./vendor/*" ! -path "*/bindata.go")
GOFMT ?= gofmt -s
GOFLAGS := -i -v
EXTRA_GOFLAGS ?=
MAKE_VERSION := $(shell make -v | head -n 1)
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
TEA_VERSION ?= $(VERSION)
@ -37,23 +21,28 @@ else
endif
TEA_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
endif
TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION))
LDFLAGS := -X "main.Version=$(TEA_VERSION)" -X "main.Tags=$(TAGS)"
TAGS ?=
SDK ?= $(shell $(GO) list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)
LDFLAGS := -X "main.Version=$(TEA_VERSION)" -X "main.Tags=$(TAGS)" -X "main.SDK=$(SDK)" -s -w
# override to allow passing additional goflags via make CLI
override GOFLAGS := $(GOFLAGS) -mod=vendor -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/)
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
# OS specific vars.
ifeq ($(OS), Windows_NT)
EXECUTABLE := tea.exe
else
EXECUTABLE := tea
ifneq ($(shell uname -s), OpenBSD)
override BUILDMODE := -buildmode=pie
endif
endif
# $(call strip-suffix,filename)
strip-suffix = $(firstword $(subst ., ,$(1)))
.PHONY: all
all: build
@ -75,24 +64,15 @@ vet:
$(GO) vet -vettool=gitea-vet $(PACKAGES)
.PHONY: lint
lint:
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
cd /tmp && $(GO) get -u github.com/mgechev/revive; \
fi
lint: install-lint-tools
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
cd /tmp && $(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell-check: install-lint-tools
misspell -error -i unknwon,destory $(GOFILES)
.PHONY: misspell
misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
cd /tmp && $(GO) get -u github.com/client9/misspell/cmd/misspell; \
fi
misspell: install-lint-tools
misspell -w -i unknwon $(GOFILES)
.PHONY: fmt-check
@ -117,30 +97,26 @@ unit-test-coverage:
vendor:
$(GO) mod tidy && $(GO) mod vendor
.PHONY: test-vendor
test-vendor: vendor
@diff=$$(git diff vendor/); \
if [ -n "$$diff" ]; then \
echo "Please run 'make vendor' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: check
check: test
.PHONY: install
install: $(wildcard *.go)
$(GO) install -mod=vendor -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
install: $(SOURCES)
@echo "installing to $(GOPATH)/bin/$(EXECUTABLE)"
$(GO) install -v $(BUILDMODE) $(GOFLAGS)
.PHONY: build
build: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
$(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
$(GO) build $(BUILDMODE) $(GOFLAGS) -o $@
.PHONY: build-image
build-image:
docker build --build-arg VERSION=$(TEA_VERSION) -t gitea/tea:$(TEA_VERSION_TAG) .
.PHONY: release
release: release-dirs release-os release-compress release-check
release: release-dirs install-release-tools release-os release-compress release-check
.PHONY: release-dirs
release-dirs:
@ -148,18 +124,29 @@ release-dirs:
.PHONY: release-os
release-os:
@hash gox > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
cd /tmp && $(GO) get -u github.com/mitchellh/gox; \
fi
CGO_ENABLED=0 gox -verbose -cgo=false -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -osarch='!darwin/386 !darwin/arm64 !darwin/arm' -os="windows linux darwin" -arch="386 amd64 arm arm64" -output="$(DIST)/release/tea-$(VERSION)-{{.OS}}-{{.Arch}}"
CGO_ENABLED=0 gox -verbose -cgo=false $(GOFLAGS) -osarch='!darwin/386 !darwin/arm' -os="windows linux darwin" -arch="386 amd64 arm arm64" -output="$(DIST)/release/tea-$(VERSION)-{{.OS}}-{{.Arch}}"
.PHONY: release-compress
release-compress:
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
GO111MODULE=off $(GO) get -u github.com/ulikunitz/xz/cmd/gxz; \
fi
release-compress: install-release-tools
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
.PHONY: release-check
release-check:
release-check: install-release-tools
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
### tools
install-release-tools:
@hash gox > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/mitchellh/gox@latest; \
fi
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/ulikunitz/xz/cmd/gxz@latest; \
fi
install-lint-tools:
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/mgechev/revive@latest; \
fi
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/client9/misspell/cmd/misspell@latest; \
fi

View File

@ -8,16 +8,19 @@
```
tea - command line tool to interact with Gitea
version 0.7.0-preview
version 0.8.0-preview
USAGE
tea command [subcommand] [command options] [arguments...]
DESCRIPTION
tea is a productivity helper for Gitea. It can be used to manage most entities on one
or multiple Gitea instances and provides local helpers like 'tea pull checkout'.
tea makes use of context provided by the repository in $PWD if available, but is still
usable independently of $PWD. Configuration is persisted in $XDG_CONFIG_HOME/tea.
tea is a productivity helper for Gitea. It can be used to manage most entities on
one or multiple Gitea instances & provides local helpers like 'tea pr checkout'.
tea tries to make use of context provided by the repository in $PWD if available.
tea works best in a upstream/fork workflow, when the local main branch tracks the
upstream repo. tea assumes that local git state is published on the remote before
doing operations with tea. Configuration is persisted in $XDG_CONFIG_HOME/tea.
COMMANDS
help, h Shows a list of commands or help for one command
@ -30,13 +33,16 @@
times, time, t Operate on tracked times of a repository's issues & pulls
organizations, organization, org List, create, delete organizations
repos, repo Show repository details
comment, c Add a comment to an issue / pr
HELPERS:
open, o Open something of the repository in web browser
notifications, notification, n Show notifications
clone, C Clone a repository locally
SETUP:
logins, login Log in to a Gitea server
logout Log out from a Gitea server
shellcompletion, autocomplete Install shell completion for tea
whoami Show current logged in user
OPTIONS
--help, -h show help (default: false)
@ -58,7 +64,7 @@
tea open milestones # open web ui for milestones
# send gitea desktop notifications every 5 minutes (bash + libnotify)
while :; do tea notifications --all -o simple | xargs -i notify-send {}; sleep 300; done
while :; do tea notifications --mine -o simple | xargs -i notify-send {}; sleep 300; done
ABOUT
Written & maintained by The Gitea Authors.
@ -79,29 +85,31 @@ There are different ways to get `tea`:
brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea
brew install tea
```
- arch linux ([gitea-tea](https://aur.archlinux.org/packages/gitea-tea), thirdparty)
- arch linux ([gitea-tea-git](https://aur.archlinux.org/packages/gitea-tea-git), thirdparty)
- alpine linux ([tea](https://pkgs.alpinelinux.org/packages?name=tea&branch=edge), thirdparty)
2. Use the prebuilt binaries from [dl.gitea.io](https://dl.gitea.io/tea/)
3. Install from source (go 1.13 or newer is required):
```sh
go get code.gitea.io/tea
go install code.gitea.io/tea
```
3. Install from source: [see *Compilation*](#compilation)
4. Docker (thirdparty): [tgerczei/tea](https://hub.docker.com/r/tgerczei/tea)
## Compilation
Make sure you have installed a current go version.
To compile the sources yourself run the following:
Make sure you have a current go version installed (1.13 or newer).
```sh
git clone https://gitea.com/gitea/tea.git
cd tea
make
```
- To compile the source yourself with the recommended flags & tags:
```sh
git clone https://gitea.com/gitea/tea.git # or: tea clone gitea.com/gitea/tea ;)
cd tea
make
```
Note that GNU Make (gmake on OpenBSD) is required.
- For a quick installation without `git` & `make`:
```sh
go install code.gitea.io/tea@latest
```
## Contributing

View File

@ -1,7 +1,8 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//+build vendor
//go:build vendor
// +build vendor
package main

55
cmd/admin.go Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"code.gitea.io/tea/cmd/admin/users"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v2"
)
// CmdAdmin represents the namespace of admin commands.
// The command itself has no functionality, but hosts subcommands.
var CmdAdmin = cli.Command{
Name: "admin",
Usage: "Operations requiring admin access on the Gitea instance",
Aliases: []string{"a"},
Category: catMisc,
Action: func(cmd *cli.Context) error {
return cli.ShowSubcommandHelp(cmd)
},
Subcommands: []*cli.Command{
&cmdAdminUsers,
},
}
var cmdAdminUsers = cli.Command{
Name: "users",
Aliases: []string{"u"},
Usage: "Manage registered users",
Action: func(ctx *cli.Context) error {
if ctx.Args().Len() == 1 {
return runAdminUserDetail(ctx, ctx.Args().First())
}
return users.RunUserList(ctx)
},
Subcommands: []*cli.Command{
&users.CmdUserList,
},
Flags: users.CmdUserList.Flags,
}
func runAdminUserDetail(cmd *cli.Context, u string) error {
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
user, _, err := client.GetUserInfo(u)
if err != nil {
return err
}
print.UserDetails(user)
return nil
}

54
cmd/admin/users/list.go Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package users
import (
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
var userFieldsFlag = flags.FieldsFlag(print.UserFields, []string{
"id", "login", "full_name", "email", "activated",
})
// CmdUserList represents a sub command of users to list users
var CmdUserList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List Users",
Description: "List users",
Action: RunUserList,
Flags: append([]cli.Flag{
userFieldsFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...),
}
// RunUserList list users
func RunUserList(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
fields, err := userFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
client := ctx.Login.Client()
users, _, err := client.AdminListUsers(gitea.AdminListUsersOptions{
ListOptions: ctx.GetListOptions(),
})
if err != nil {
return err
}
print.UserList(users, ctx.Output, fields)
return nil
}

View File

@ -22,7 +22,7 @@ var CmdAutocomplete = cli.Command{
Category: catSetup,
Usage: "Install shell completion for tea",
Description: "Install shell completion for tea",
ArgsUsage: "<shell type> (bash, zsh, powershell)",
ArgsUsage: "<shell type> (bash, zsh, powershell, fish)",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "install",
@ -40,20 +40,26 @@ func runAutocompleteAdd(ctx *cli.Context) error {
case "zsh":
remoteFile = "contrib/autocomplete.zsh"
localFile = "autocomplete.zsh"
cmds = "echo 'PROG=tea _CLI_ZSH_AUTOCOMPLETE_HACK=1 source %s' >> ~/.zshrc && source ~/.zshrc"
cmds = "echo 'PROG=tea _CLI_ZSH_AUTOCOMPLETE_HACK=1 source \"%s\"' >> ~/.zshrc && source ~/.zshrc"
case "bash":
remoteFile = "contrib/autocomplete.sh"
localFile = "autocomplete.sh"
cmds = "echo 'PROG=tea source %s' >> ~/.bashrc && source ~/.bashrc"
cmds = "echo 'PROG=tea source \"%s\"' >> ~/.bashrc && source ~/.bashrc"
case "powershell":
remoteFile = "contrib/autocomplete.ps1"
localFile = "tea.ps1"
cmds = "\"& %s\" >> $profile"
case "fish":
// fish is different, in that urfave/cli provides a generator for the shell script needed.
// this also means that the fish completion can become out of sync with the tea binary!
// writing to this directory suffices, as fish reads files there on startup, no cmds needed.
return writeFishAutoCompleteFile(ctx)
default:
return fmt.Errorf("Must specify valid shell type")
return fmt.Errorf("Must specify valid %s", ctx.Command.ArgsUsage)
}
localPath, err := xdg.ConfigFile("tea/" + localFile)
@ -62,8 +68,7 @@ func runAutocompleteAdd(ctx *cli.Context) error {
}
cmds = fmt.Sprintf(cmds, localPath)
if err := saveAutoCompleteFile(remoteFile, localPath); err != nil {
if err = writeRemoteAutoCompleteFile(remoteFile, localPath); err != nil {
return err
}
@ -85,7 +90,7 @@ func runAutocompleteAdd(ctx *cli.Context) error {
return nil
}
func saveAutoCompleteFile(file, destPath string) error {
func writeRemoteAutoCompleteFile(file, destPath string) error {
url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file)
fmt.Println("Fetching " + url)
@ -104,3 +109,30 @@ func saveAutoCompleteFile(file, destPath string) error {
_, err = io.Copy(writer, res.Body)
return err
}
func writeFishAutoCompleteFile(ctx *cli.Context) error {
// NOTE: to make sure this file is in sync with tea commands, we'd need to
// - check if the file exists
// - if it does, check if the tea version that wrote it is the currently running version
// - if not, rewrite the file
// on each application run
// NOTE: this generates a completion that also suggests file names, which looks kinda messy..
script, err := ctx.App.ToFishCompletion()
if err != nil {
return err
}
localPath, err := xdg.ConfigFile("fish/conf.d/tea_completion.fish")
if err != nil {
return err
}
writer, err := os.Create(localPath)
if err != nil {
return err
}
if _, err = io.WriteString(writer, script); err != nil {
return err
}
fmt.Printf("Installed tab completion to %s\n", localPath)
return nil
}

View File

@ -8,4 +8,5 @@ var (
catSetup = "SETUP"
catEntities = "ENTITIES"
catHelpers = "HELPERS"
catMisc = "MISCELLANEOUS"
)

89
cmd/clone.go Normal file
View File

@ -0,0 +1,89 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/interact"
"code.gitea.io/tea/modules/task"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v2"
)
// CmdRepoClone represents a sub command of repos to create a local copy
var CmdRepoClone = cli.Command{
Name: "clone",
Aliases: []string{"C"},
Usage: "Clone a repository locally",
Description: `Clone a repository locally, without a local git installation required.
The repo slug can be specified in different formats:
gitea/tea
tea
gitea.com/gitea/tea
git@gitea.com:gitea/tea
https://gitea.com/gitea/tea
ssh://gitea.com:22/gitea/tea
When a host is specified in the repo-slug, it will override the login specified with --login.
`,
Category: catHelpers,
Action: runRepoClone,
ArgsUsage: "<repo-slug> [target dir]",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "depth",
Aliases: []string{"d"},
Usage: "num commits to fetch, defaults to all",
},
&flags.LoginFlag,
},
}
func runRepoClone(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
args := ctx.Args()
if args.Len() < 1 {
return cli.ShowCommandHelp(cmd, "clone")
}
dir := args.Get(1)
var (
login *config.Login = ctx.Login
owner string = ctx.Login.User
repo string
)
// parse first arg as repo specifier
repoSlug := args.Get(0)
url, err := git.ParseURL(repoSlug)
if err != nil {
return err
}
owner, repo = utils.GetOwnerAndRepo(url.Path, login.User)
if url.Host != "" {
login = config.GetLoginByHost(url.Host)
if login == nil {
return fmt.Errorf("No login configured matching host '%s', run `tea login add` first", url.Host)
}
}
_, err = task.RepoClone(
dir,
login,
owner,
repo,
interact.PromptPassword,
ctx.Int("depth"),
)
return err
}

View File

@ -9,13 +9,15 @@ import (
"io/ioutil"
"strings"
"code.gitea.io/tea/modules/interact"
"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/utils"
"code.gitea.io/sdk/gitea"
"github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2"
)
@ -54,7 +56,11 @@ func runAddComment(cmd *cli.Context) error {
body = strings.Join([]string{body, string(bodyStdin)}, "\n\n")
}
} else if len(body) == 0 {
if body, err = interact.PromptMultiline("Content"); err != nil {
if err = survey.AskOne(interact.NewMultiline(interact.Multiline{
Message: "Comment:",
Syntax: "md",
UseEditor: config.GetPreferences().Editor,
}), &body); err != nil {
return err
}
}

53
cmd/flags/csvflag.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package flags
import (
"fmt"
"strings"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v2"
)
// CsvFlag is a wrapper around cli.StringFlag, with an added GetValues() method
// to retrieve comma separated string values as a slice.
type CsvFlag struct {
cli.StringFlag
AvailableFields []string
}
// NewCsvFlag creates a CsvFlag, while setting its usage string and default values
func NewCsvFlag(name, usage string, aliases, availableValues, defaults []string) *CsvFlag {
var availableDesc string
if len(availableValues) != 0 {
availableDesc = " Available values:"
}
return &CsvFlag{
AvailableFields: availableValues,
StringFlag: cli.StringFlag{
Name: name,
Aliases: aliases,
Value: strings.Join(defaults, ","),
Usage: fmt.Sprintf(`Comma-separated list of %s.%s
%s
`, usage, availableDesc, strings.Join(availableValues, ",")),
},
}
}
// GetValues returns the value of the flag, parsed as a commaseparated list
func (f CsvFlag) GetValues(ctx *cli.Context) ([]string, error) {
val := ctx.String(f.Name)
selection := strings.Split(val, ",")
if f.AvailableFields != nil && val != "" {
for _, field := range selection {
if !utils.Contains(f.AvailableFields, field) {
return nil, fmt.Errorf("Invalid field '%s'", field)
}
}
}
return selection, nil
}

View File

@ -1,205 +0,0 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package flags
import (
"fmt"
"strings"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/task"
"code.gitea.io/tea/modules/utils"
"github.com/araddon/dateparse"
"github.com/urfave/cli/v2"
)
// LoginFlag provides flag to specify tea login profile
var LoginFlag = cli.StringFlag{
Name: "login",
Aliases: []string{"l"},
Usage: "Use a different Gitea Login. Optional",
}
// RepoFlag provides flag to specify repository
var RepoFlag = cli.StringFlag{
Name: "repo",
Aliases: []string{"r"},
Usage: "Override local repository path or gitea repository slug to interact with. Optional",
}
// RemoteFlag provides flag to specify remote repository
var RemoteFlag = cli.StringFlag{
Name: "remote",
Aliases: []string{"R"},
Usage: "Discover Gitea login from remote. Optional",
}
// OutputFlag provides flag to specify output type
var OutputFlag = cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Output format. (csv, simple, table, tsv, yaml)",
}
// StateFlag provides flag to specify issue/pr state, defaulting to "open"
var StateFlag = cli.StringFlag{
Name: "state",
Usage: "Filter by state (all|open|closed)",
DefaultText: "open",
}
// PaginationPageFlag provides flag for pagination options
var PaginationPageFlag = cli.StringFlag{
Name: "page",
Aliases: []string{"p"},
Usage: "specify page, default is 1",
}
// PaginationLimitFlag provides flag for pagination options
var PaginationLimitFlag = cli.StringFlag{
Name: "limit",
Aliases: []string{"lm"},
Usage: "specify limit of items per page",
}
// LoginOutputFlags defines login and output flags that should
// added to all subcommands and appended to the flags of the
// subcommand to work around issue and provide --login and --output:
// https://github.com/urfave/cli/issues/585
var LoginOutputFlags = []cli.Flag{
&LoginFlag,
&OutputFlag,
}
// LoginRepoFlags defines login and repo flags that should
// be used for all subcommands and appended to the flags of
// the subcommand to work around issue and provide --login and --repo:
// https://github.com/urfave/cli/issues/585
var LoginRepoFlags = []cli.Flag{
&LoginFlag,
&RepoFlag,
&RemoteFlag,
}
// AllDefaultFlags defines flags that should be available
// for all subcommands working with dedicated repositories
// to work around issue and provide --login, --repo and --output:
// https://github.com/urfave/cli/issues/585
var AllDefaultFlags = append([]cli.Flag{
&RepoFlag,
&RemoteFlag,
}, LoginOutputFlags...)
// IssuePRFlags defines flags that should be available on issue & pr listing flags.
var IssuePRFlags = append([]cli.Flag{
&StateFlag,
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...)
// IssuePREditFlags defines flags for properties of issues and PRs
var IssuePREditFlags = append([]cli.Flag{
&cli.StringFlag{
Name: "title",
Aliases: []string{"t"},
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
},
&cli.StringFlag{
Name: "assignees",
Aliases: []string{"a"},
Usage: "Comma-separated list of usernames to assign",
},
&cli.StringFlag{
Name: "labels",
Aliases: []string{"L"},
Usage: "Comma-separated list of labels to assign",
},
&cli.StringFlag{
Name: "deadline",
Aliases: []string{"D"},
Usage: "Deadline timestamp to assign",
},
&cli.StringFlag{
Name: "milestone",
Aliases: []string{"m"},
Usage: "Milestone to assign",
},
}, LoginRepoFlags...)
// GetIssuePREditFlags parses all IssuePREditFlags
func GetIssuePREditFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, error) {
opts := gitea.CreateIssueOption{
Title: ctx.String("title"),
Body: ctx.String("body"),
Assignees: strings.Split(ctx.String("assignees"), ","),
}
var err error
date := ctx.String("deadline")
if date != "" {
t, err := dateparse.ParseAny(date)
if err != nil {
return nil, err
}
opts.Deadline = &t
}
client := ctx.Login.Client()
labelNames := strings.Split(ctx.String("labels"), ",")
if len(labelNames) != 0 {
if client == nil {
client = ctx.Login.Client()
}
if opts.Labels, err = task.ResolveLabelNames(client, ctx.Owner, ctx.Repo, labelNames); err != nil {
return nil, err
}
}
if milestoneName := ctx.String("milestone"); len(milestoneName) != 0 {
if client == nil {
client = ctx.Login.Client()
}
ms, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestoneName)
if err != nil {
return nil, fmt.Errorf("Milestone '%s' not found", milestoneName)
}
opts.Milestone = ms.ID
}
return &opts, nil
}
// FieldsFlag generates a flag selecting printable fields.
// To retrieve the value, use GetFields()
func FieldsFlag(availableFields, defaultFields []string) *cli.StringFlag {
return &cli.StringFlag{
Name: "fields",
Aliases: []string{"f"},
Usage: fmt.Sprintf(`Comma-separated list of fields to print. Available values:
%s
`, strings.Join(availableFields, ",")),
Value: strings.Join(defaultFields, ","),
}
}
// GetFields parses the values provided in a fields flag, and
// optionally validates against valid values.
func GetFields(ctx *cli.Context, validFields []string) ([]string, error) {
selection := strings.Split(ctx.String("fields"), ",")
if validFields != nil {
for _, field := range selection {
if !utils.Contains(validFields, field) {
return nil, fmt.Errorf("Invalid field '%s'", field)
}
}
}
return selection, nil
}

106
cmd/flags/generic.go Normal file
View File

@ -0,0 +1,106 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package flags
import (
"github.com/urfave/cli/v2"
)
// LoginFlag provides flag to specify tea login profile
var LoginFlag = cli.StringFlag{
Name: "login",
Aliases: []string{"l"},
Usage: "Use a different Gitea Login. Optional",
}
// RepoFlag provides flag to specify repository
var RepoFlag = cli.StringFlag{
Name: "repo",
Aliases: []string{"r"},
Usage: "Override local repository path or gitea repository slug to interact with. Optional",
}
// RemoteFlag provides flag to specify remote repository
var RemoteFlag = cli.StringFlag{
Name: "remote",
Aliases: []string{"R"},
Usage: "Discover Gitea login from remote. Optional",
}
// OutputFlag provides flag to specify output type
var OutputFlag = cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Output format. (csv, simple, table, tsv, yaml)",
}
// PaginationPageFlag provides flag for pagination options
var PaginationPageFlag = cli.StringFlag{
Name: "page",
Aliases: []string{"p"},
Usage: "specify page, default is 1",
}
// PaginationLimitFlag provides flag for pagination options
var PaginationLimitFlag = cli.StringFlag{
Name: "limit",
Aliases: []string{"lm"},
Usage: "specify limit of items per page",
}
// LoginOutputFlags defines login and output flags that should
// added to all subcommands and appended to the flags of the
// subcommand to work around issue and provide --login and --output:
// https://github.com/urfave/cli/issues/585
var LoginOutputFlags = []cli.Flag{
&LoginFlag,
&OutputFlag,
}
// LoginRepoFlags defines login and repo flags that should
// be used for all subcommands and appended to the flags of
// the subcommand to work around issue and provide --login and --repo:
// https://github.com/urfave/cli/issues/585
var LoginRepoFlags = []cli.Flag{
&LoginFlag,
&RepoFlag,
&RemoteFlag,
}
// AllDefaultFlags defines flags that should be available
// for all subcommands working with dedicated repositories
// to work around issue and provide --login, --repo and --output:
// https://github.com/urfave/cli/issues/585
var AllDefaultFlags = append([]cli.Flag{
&RepoFlag,
&RemoteFlag,
}, LoginOutputFlags...)
// NotificationFlags defines flags that should be available on notifications.
var NotificationFlags = append([]cli.Flag{
NotificationStateFlag,
&cli.BoolFlag{
Name: "mine",
Aliases: []string{"m"},
Usage: "Show notifications across all your repositories instead of the current repository only",
},
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...)
// NotificationStateFlag is a csv flag applied to all notification subcommands as filter
var NotificationStateFlag = NewCsvFlag(
"states",
"notification states to filter by",
[]string{"s"},
[]string{"pinned", "unread", "read"},
[]string{"unread", "pinned"},
)
// FieldsFlag generates a flag selecting printable fields.
// To retrieve the value, use f.GetValues()
func FieldsFlag(availableFields, defaultFields []string) *CsvFlag {
return NewCsvFlag("fields", "fields to print", []string{"f"}, availableFields, defaultFields)
}

161
cmd/flags/issue_pr.go Normal file
View File

@ -0,0 +1,161 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package flags
import (
"fmt"
"strings"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/task"
"github.com/araddon/dateparse"
"github.com/urfave/cli/v2"
)
// StateFlag provides flag to specify issue/pr state, defaulting to "open"
var StateFlag = cli.StringFlag{
Name: "state",
Usage: "Filter by state (all|open|closed)",
DefaultText: "open",
}
// MilestoneFilterFlag is a CSV flag used to filter issues by milestones
var MilestoneFilterFlag = NewCsvFlag(
"milestones",
"milestones to match issues against",
[]string{"m"}, nil, nil)
// LabelFilterFlag is a CSV flag used to filter issues by labels
var LabelFilterFlag = NewCsvFlag(
"labels",
"labels to match issues against",
[]string{"L"}, nil, nil)
// PRListingFlags defines flags that should be available on pr listing flags.
var PRListingFlags = append([]cli.Flag{
&StateFlag,
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...)
// IssueListingFlags defines flags that should be available on issue listing flags.
var IssueListingFlags = append([]cli.Flag{
&StateFlag,
&cli.StringFlag{
Name: "kind",
Aliases: []string{"K"},
Usage: "Whether to return `issues`, `pulls`, or `all` (you can use this to apply advanced search filters to PRs)",
DefaultText: "issues",
},
&cli.StringFlag{
Name: "keyword",
Aliases: []string{"k"},
Usage: "Filter by search string",
},
LabelFilterFlag,
MilestoneFilterFlag,
&cli.StringFlag{
Name: "author",
Aliases: []string{"A"},
},
&cli.StringFlag{
Name: "assignee",
Aliases: []string{"a"},
},
&cli.StringFlag{
Name: "mentions",
Aliases: []string{"M"},
},
&cli.StringFlag{
Name: "from",
Aliases: []string{"F"},
Usage: "Filter by activity after this date",
},
&cli.StringFlag{
Name: "until",
Aliases: []string{"u"},
Usage: "Filter by activity before this date",
},
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...)
// IssuePREditFlags defines flags for properties of issues and PRs
var IssuePREditFlags = append([]cli.Flag{
&cli.StringFlag{
Name: "title",
Aliases: []string{"t"},
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
},
&cli.StringFlag{
Name: "assignees",
Aliases: []string{"a"},
Usage: "Comma-separated list of usernames to assign",
},
&cli.StringFlag{
Name: "labels",
Aliases: []string{"L"},
Usage: "Comma-separated list of labels to assign",
},
&cli.StringFlag{
Name: "deadline",
Aliases: []string{"D"},
Usage: "Deadline timestamp to assign",
},
&cli.StringFlag{
Name: "milestone",
Aliases: []string{"m"},
Usage: "Milestone to assign",
},
}, LoginRepoFlags...)
// GetIssuePREditFlags parses all IssuePREditFlags
func GetIssuePREditFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, error) {
opts := gitea.CreateIssueOption{
Title: ctx.String("title"),
Body: ctx.String("description"),
Assignees: strings.Split(ctx.String("assignees"), ","),
}
var err error
date := ctx.String("deadline")
if date != "" {
t, err := dateparse.ParseAny(date)
if err != nil {
return nil, err
}
opts.Deadline = &t
}
client := ctx.Login.Client()
labelNames := strings.Split(ctx.String("labels"), ",")
if len(labelNames) != 0 {
if client == nil {
client = ctx.Login.Client()
}
if opts.Labels, err = task.ResolveLabelNames(client, ctx.Owner, ctx.Repo, labelNames); err != nil {
return nil, err
}
}
if milestoneName := ctx.String("milestone"); len(milestoneName) != 0 {
if client == nil {
client = ctx.Login.Client()
}
ms, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestoneName)
if err != nil {
return nil, fmt.Errorf("Milestone '%s' not found", milestoneName)
}
opts.Milestone = ms.ID
}
return &opts, nil
}

View File

@ -34,7 +34,7 @@ var CmdIssues = cli.Command{
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "comments",
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
Usage: "Whether to display comments (will prompt if not provided & run interactively)",
},
}, issues.CmdIssuesList.Flags...),
}
@ -54,11 +54,16 @@ func runIssueDetail(cmd *cli.Context, index string) error {
if err != nil {
return err
}
issue, _, err := ctx.Login.Client().GetIssue(ctx.Owner, ctx.Repo, idx)
client := ctx.Login.Client()
issue, _, err := client.GetIssue(ctx.Owner, ctx.Repo, idx)
if err != nil {
return err
}
print.IssueDetails(issue)
reactions, _, err := client.GetIssueReactions(ctx.Owner, ctx.Repo, idx)
if err != nil {
return err
}
print.IssueDetails(issue, reactions)
if issue.Comments > 0 {
err = interact.ShowCommentsMaybeInteractive(ctx, idx, issue.Comments)

View File

@ -47,6 +47,6 @@ func editIssueState(cmd *cli.Context, opts gitea.EditIssueOption) error {
return err
}
print.IssueDetails(issue)
print.IssueDetails(issue, nil)
return nil
}

View File

@ -19,6 +19,7 @@ var CmdIssuesCreate = cli.Command{
Aliases: []string{"c"},
Usage: "Create an issue on repository",
Description: `Create an issue on repository`,
ArgsUsage: " ", // command does not accept arguments
Action: runIssuesCreate,
Flags: flags.IssuePREditFlags,
}

View File

@ -5,26 +5,31 @@
package issues
import (
"fmt"
"time"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/araddon/dateparse"
"github.com/urfave/cli/v2"
)
var issueFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{
"index", "title", "state", "author", "milestone", "labels",
})
// CmdIssuesList represents a sub command of issues to list issues
var CmdIssuesList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List issues of the repository",
Description: `List issues of the repository`,
ArgsUsage: " ", // command does not accept arguments
Action: RunIssuesList,
Flags: append([]cli.Flag{
flags.FieldsFlag(print.IssueFields, []string{
"index", "title", "state", "author", "milestone", "labels",
}),
}, flags.IssuePRFlags...),
Flags: append([]cli.Flag{issueFieldsFlag}, flags.IssueListingFlags...),
}
// RunIssuesList list issues
@ -36,23 +41,64 @@ func RunIssuesList(cmd *cli.Context) error {
switch ctx.String("state") {
case "all":
state = gitea.StateAll
case "open":
case "", "open":
state = gitea.StateOpen
case "closed":
state = gitea.StateClosed
default:
return fmt.Errorf("unknown state '%s'", ctx.String("state"))
}
kind := gitea.IssueTypeIssue
switch ctx.String("kind") {
case "", "issues", "issue":
kind = gitea.IssueTypeIssue
case "pulls", "pull", "pr":
kind = gitea.IssueTypePull
case "all":
kind = gitea.IssueTypeAll
default:
return fmt.Errorf("unknown kind '%s'", ctx.String("kind"))
}
var err error
var from, until time.Time
if ctx.IsSet("from") {
from, err = dateparse.ParseLocal(ctx.String("from"))
if err != nil {
return err
}
}
if ctx.IsSet("until") {
until, err = dateparse.ParseLocal(ctx.String("until"))
if err != nil {
return err
}
}
// ignore error, as we don't do any input validation on these flags
labels, _ := flags.LabelFilterFlag.GetValues(cmd)
milestones, _ := flags.MilestoneFilterFlag.GetValues(cmd)
issues, _, err := ctx.Login.Client().ListRepoIssues(ctx.Owner, ctx.Repo, gitea.ListIssueOption{
ListOptions: ctx.GetListOptions(),
State: state,
Type: gitea.IssueTypeIssue,
Type: kind,
KeyWord: ctx.String("keyword"),
CreatedBy: ctx.String("author"),
AssignedBy: ctx.String("assigned-to"),
MentionedBy: ctx.String("mentions"),
Labels: labels,
Milestones: milestones,
Since: from,
Before: until,
})
if err != nil {
return err
}
fields, err := flags.GetFields(cmd, print.IssueFields)
fields, err := issueFieldsFlag.GetValues(cmd)
if err != nil {
return err
}

View File

@ -18,6 +18,7 @@ var CmdLabels = cli.Command{
Category: catEntities,
Usage: "Manage issue labels",
Description: `Manage issue labels`,
ArgsUsage: " ", // command does not accept arguments
Action: runLabels,
Subcommands: []*cli.Command{
&labels.CmdLabelsList,
@ -25,6 +26,7 @@ var CmdLabels = cli.Command{
&labels.CmdLabelUpdate,
&labels.CmdLabelDelete,
},
Flags: labels.CmdLabelsList.Flags,
}
func runLabels(ctx *cli.Context) error {

View File

@ -10,6 +10,7 @@ import (
"os"
"strings"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea"
@ -22,8 +23,9 @@ var CmdLabelCreate = cli.Command{
Aliases: []string{"c"},
Usage: "Create a label",
Description: `Create a label`,
ArgsUsage: " ", // command does not accept arguments
Action: runLabelCreate,
Flags: []cli.Flag{
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "label name",
@ -40,7 +42,7 @@ var CmdLabelCreate = cli.Command{
Name: "file",
Usage: "indicate a label file",
},
},
}, flags.AllDefaultFlags...),
}
func runLabelCreate(cmd *cli.Context) error {

View File

@ -5,6 +5,7 @@
package labels
import (
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"github.com/urfave/cli/v2"
@ -16,13 +17,14 @@ var CmdLabelDelete = cli.Command{
Aliases: []string{"rm"},
Usage: "Delete a label",
Description: `Delete a label`,
ArgsUsage: " ", // command does not accept arguments
Action: runLabelDelete,
Flags: []cli.Flag{
Flags: append([]cli.Flag{
&cli.IntFlag{
Name: "id",
Usage: "label id",
},
},
}, flags.AllDefaultFlags...),
}
func runLabelDelete(cmd *cli.Context) error {

View File

@ -20,6 +20,7 @@ var CmdLabelsList = cli.Command{
Aliases: []string{"ls"},
Usage: "List labels",
Description: "List labels",
ArgsUsage: " ", // command does not accept arguments
Action: RunLabelsList,
Flags: append([]cli.Flag{
&cli.BoolFlag{

View File

@ -5,6 +5,7 @@
package labels
import (
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/sdk/gitea"
@ -16,8 +17,9 @@ var CmdLabelUpdate = cli.Command{
Name: "update",
Usage: "Update a label",
Description: `Update a label`,
ArgsUsage: " ", // command does not accept arguments
Action: runLabelUpdate,
Flags: []cli.Flag{
Flags: append([]cli.Flag{
&cli.IntFlag{
Name: "id",
Usage: "label id",
@ -34,7 +36,7 @@ var CmdLabelUpdate = cli.Command{
Name: "description",
Usage: "label description",
},
},
}, flags.AllDefaultFlags...),
}
func runLabelUpdate(cmd *cli.Context) error {

View File

@ -16,6 +16,7 @@ var CmdLoginAdd = cli.Command{
Name: "add",
Usage: "Add a Gitea login",
Description: `Add a Gitea login, without args it will create one interactively`,
ArgsUsage: " ", // command does not accept arguments
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",

View File

@ -18,6 +18,7 @@ var CmdLoginEdit = cli.Command{
Aliases: []string{"e"},
Usage: "Edit Gitea logins",
Description: `Edit Gitea logins`,
ArgsUsage: " ", // command does not accept arguments
Action: runLoginEdit,
Flags: []cli.Flag{&flags.OutputFlag},
}

View File

@ -18,6 +18,7 @@ var CmdLoginList = cli.Command{
Aliases: []string{"ls"},
Usage: "List Gitea logins",
Description: `List Gitea logins`,
ArgsUsage: " ", // command does not accept arguments
Action: RunLoginList,
Flags: []cli.Flag{&flags.OutputFlag},
}

View File

@ -23,6 +23,7 @@ var CmdMilestonesCreate = cli.Command{
Aliases: []string{"c"},
Usage: "Create an milestone on repository",
Description: `Create an milestone on repository`,
ArgsUsage: " ", // command does not accept arguments
Action: runMilestonesCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
@ -55,7 +56,7 @@ func runMilestonesCreate(cmd *cli.Context) error {
deadline := &time.Time{}
if date != "" {
t, err := dateparse.ParseAny(date)
if err == nil {
if err != nil {
return err
}
deadline = &t

View File

@ -16,6 +16,10 @@ import (
"github.com/urfave/cli/v2"
)
var msIssuesFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{
"index", "kind", "title", "state", "updated", "labels",
})
// CmdMilestonesIssues represents a sub command of milestones to manage issue/pull of an milestone
var CmdMilestonesIssues = cli.Command{
Name: "issues",
@ -40,9 +44,7 @@ var CmdMilestonesIssues = cli.Command{
},
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
flags.FieldsFlag(print.IssueFields, []string{
"index", "kind", "title", "state", "updated", "labels",
}),
msIssuesFieldsFlag,
}, flags.AllDefaultFlags...),
}
@ -110,7 +112,7 @@ func runMilestoneIssueList(cmd *cli.Context) error {
return err
}
fields, err := flags.GetFields(cmd, print.IssueFields)
fields, err := msIssuesFieldsFlag.GetValues(cmd)
if err != nil {
return err
}

View File

@ -13,14 +13,20 @@ import (
"github.com/urfave/cli/v2"
)
var fieldsFlag = flags.FieldsFlag(print.MilestoneFields, []string{
"title", "items", "duedate",
})
// CmdMilestonesList represents a sub command of milestones to list milestones
var CmdMilestonesList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List milestones of the repository",
Description: `List milestones of the repository`,
ArgsUsage: " ", // command does not accept arguments
Action: RunMilestonesList,
Flags: append([]cli.Flag{
fieldsFlag,
&cli.StringFlag{
Name: "state",
Usage: "Filter by milestone state (all|open|closed)",
@ -36,10 +42,18 @@ func RunMilestonesList(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
fields, err := fieldsFlag.GetValues(cmd)
if err != nil {
return err
}
state := gitea.StateOpen
switch ctx.String("state") {
case "all":
state = gitea.StateAll
if !cmd.IsSet("fields") { // add to default fields
fields = append(fields, "state")
}
case "closed":
state = gitea.StateClosed
}
@ -54,6 +68,6 @@ func RunMilestonesList(cmd *cli.Context) error {
return err
}
print.MilestonesList(milestones, ctx.Output, state)
print.MilestonesList(milestones, ctx.Output, fields)
return nil
}

View File

@ -5,11 +5,8 @@
package cmd
import (
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/cmd/notifications"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
@ -19,65 +16,14 @@ var CmdNotifications = cli.Command{
Aliases: []string{"notification", "n"},
Category: catHelpers,
Usage: "Show notifications",
Description: "Show notifications, by default based of the current repo and unread one",
Action: runNotifications,
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "all",
Aliases: []string{"a"},
Usage: "show all notifications of related gitea instance",
},
&cli.BoolFlag{
Name: "read",
Aliases: []string{"rd"},
Usage: "show read notifications instead unread",
},
&cli.BoolFlag{
Name: "pinned",
Aliases: []string{"pd"},
Usage: "show pinned notifications instead unread",
},
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...),
}
func runNotifications(cmd *cli.Context) error {
var news []*gitea.NotificationThread
var err error
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
listOpts := ctx.GetListOptions()
if listOpts.Page == 0 {
listOpts.Page = 1
}
var status []gitea.NotifyStatus
if ctx.Bool("read") {
status = []gitea.NotifyStatus{gitea.NotifyStatusRead}
}
if ctx.Bool("pinned") {
status = append(status, gitea.NotifyStatusPinned)
}
if ctx.Bool("all") {
news, _, err = client.ListNotifications(gitea.ListNotificationOptions{
ListOptions: listOpts,
Status: status,
})
} else {
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
news, _, err = client.ListRepoNotifications(ctx.Owner, ctx.Repo, gitea.ListNotificationOptions{
ListOptions: listOpts,
Status: status,
})
}
if err != nil {
return err
}
print.NotificationsList(news, ctx.Output, ctx.Bool("all"))
return nil
Description: "Show notifications, by default based on the current repo if available",
Action: notifications.RunNotificationsList,
Subcommands: []*cli.Command{
&notifications.CmdNotificationsList,
&notifications.CmdNotificationsMarkRead,
&notifications.CmdNotificationsMarkUnread,
&notifications.CmdNotificationsMarkPinned,
&notifications.CmdNotificationsUnpin,
},
Flags: notifications.CmdNotificationsList.Flags,
}

107
cmd/notifications/list.go Normal file
View File

@ -0,0 +1,107 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package notifications
import (
"log"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
var notifyFieldsFlag = flags.FieldsFlag(print.NotificationFields, []string{
"id", "status", "index", "type", "state", "title",
})
var notifyTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"},
[]string{"issue", "pull", "repository", "commit"}, nil)
// CmdNotificationsList represents a sub command of notifications to list notifications
var CmdNotificationsList = cli.Command{
Name: "ls",
Aliases: []string{"list"},
Usage: "List notifications",
Description: `List notifications`,
ArgsUsage: " ", // command does not accept arguments
Action: RunNotificationsList,
Flags: append([]cli.Flag{
notifyFieldsFlag,
notifyTypeFlag,
}, flags.NotificationFlags...),
}
// RunNotificationsList list notifications
func RunNotificationsList(ctx *cli.Context) error {
var states []gitea.NotifyStatus
statesStr, err := flags.NotificationStateFlag.GetValues(ctx)
if err != nil {
return err
}
for _, s := range statesStr {
states = append(states, gitea.NotifyStatus(s))
}
var types []gitea.NotifySubjectType
typesStr, err := notifyTypeFlag.GetValues(ctx)
if err != nil {
return err
}
for _, t := range typesStr {
types = append(types, gitea.NotifySubjectType(t))
}
return listNotifications(ctx, states, types)
}
// listNotifications will get the notifications based on status and subject type
func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects []gitea.NotifySubjectType) error {
var news []*gitea.NotificationThread
var err error
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
all := ctx.Bool("mine")
// This enforces pagination (see https://github.com/go-gitea/gitea/issues/16733)
listOpts := ctx.GetListOptions()
if listOpts.Page == 0 {
listOpts.Page = 1
}
fields, err := notifyFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
if all {
// add repository to the default fields
if !cmd.IsSet("fields") {
fields = append(fields, "repository")
}
news, _, err = client.ListNotifications(gitea.ListNotificationOptions{
ListOptions: listOpts,
Status: status,
SubjectTypes: subjects,
})
} else {
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
news, _, err = client.ListRepoNotifications(ctx.Owner, ctx.Repo, gitea.ListNotificationOptions{
ListOptions: listOpts,
Status: status,
SubjectTypes: subjects,
})
}
if err != nil {
log.Fatal(err)
}
print.NotificationsList(news, ctx.Output, fields)
return nil
}

View File

@ -0,0 +1,139 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package notifications
import (
"fmt"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v2"
)
// CmdNotificationsMarkRead represents a sub command of notifications to list read notifications
var CmdNotificationsMarkRead = cli.Command{
Name: "read",
Aliases: []string{"r"},
Usage: "Mark all filtered or a specific notification as read",
Description: "Mark all filtered or a specific notification as read",
ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags,
Action: func(ctx *cli.Context) error {
cmd := context.InitCommand(ctx)
filter, err := flags.NotificationStateFlag.GetValues(ctx)
if err != nil {
return err
}
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusRead)
},
}
// CmdNotificationsMarkUnread will mark notifications as unread.
var CmdNotificationsMarkUnread = cli.Command{
Name: "unread",
Aliases: []string{"u"},
Usage: "Mark all filtered or a specific notification as unread",
Description: "Mark all filtered or a specific notification as unread",
ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags,
Action: func(ctx *cli.Context) error {
cmd := context.InitCommand(ctx)
filter, err := flags.NotificationStateFlag.GetValues(ctx)
if err != nil {
return err
}
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusRead)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusUnread)
},
}
// CmdNotificationsMarkPinned will mark notifications as unread.
var CmdNotificationsMarkPinned = cli.Command{
Name: "pin",
Aliases: []string{"p"},
Usage: "Mark all filtered or a specific notification as pinned",
Description: "Mark all filtered or a specific notification as pinned",
ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags,
Action: func(ctx *cli.Context) error {
cmd := context.InitCommand(ctx)
filter, err := flags.NotificationStateFlag.GetValues(ctx)
if err != nil {
return err
}
if !cmd.IsSet(flags.NotificationStateFlag.Name) {
filter = []string{string(gitea.NotifyStatusUnread)}
}
return markNotificationAs(cmd, filter, gitea.NotifyStatusPinned)
},
}
// CmdNotificationsUnpin will mark pinned notifications as unread.
var CmdNotificationsUnpin = cli.Command{
Name: "unpin",
Usage: "Unpin all pinned or a specific notification",
Description: "Marks all pinned or a specific notification as read",
ArgsUsage: "[all | <notification id>]",
Flags: flags.NotificationFlags,
Action: func(ctx *cli.Context) error {
cmd := context.InitCommand(ctx)
filter := []string{string(gitea.NotifyStatusPinned)}
// NOTE: we implicitly mark it as read, to match web UI semantics. marking as unread might be more useful?
return markNotificationAs(cmd, filter, gitea.NotifyStatusRead)
},
}
func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetState gitea.NotifyStatus) (err error) {
client := cmd.Login.Client()
subject := cmd.Args().First()
allRepos := cmd.Bool("mine")
states := []gitea.NotifyStatus{}
for _, s := range filterStates {
states = append(states, gitea.NotifyStatus(s))
}
switch subject {
case "", "all":
opts := gitea.MarkNotificationOptions{Status: states, ToStatus: targetState}
if allRepos {
_, _, err = client.ReadNotifications(opts)
} else {
cmd.Ensure(context.CtxRequirement{RemoteRepo: true})
_, _, err = client.ReadRepoNotifications(cmd.Owner, cmd.Repo, opts)
}
// TODO: print all affected notification subject URLs
// (not supported by API currently, https://github.com/go-gitea/gitea/issues/16797)
default:
id, err := utils.ArgToIndex(subject)
if err != nil {
return err
}
_, _, err = client.ReadNotification(id, targetState)
if err != nil {
return err
}
n, _, err := client.GetNotification(id)
if err != nil {
return err
}
// FIXME: this is an API URL, we want to display a web ui link..
fmt.Println(n.Subject.URL)
return nil
}
return err
}

View File

@ -5,9 +5,9 @@
package cmd
import (
"fmt"
"code.gitea.io/tea/cmd/organizations"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v2"
)
@ -23,17 +23,26 @@ var CmdOrgs = cli.Command{
Action: runOrganizations,
Subcommands: []*cli.Command{
&organizations.CmdOrganizationList,
&organizations.CmdOrganizationCreate,
&organizations.CmdOrganizationDelete,
},
Flags: organizations.CmdOrganizationList.Flags,
}
func runOrganizations(ctx *cli.Context) error {
func runOrganizations(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
if ctx.Args().Len() == 1 {
return runOrganizationDetail(ctx.Args().First())
return runOrganizationDetail(ctx)
}
return organizations.RunOrganizationList(ctx)
return organizations.RunOrganizationList(cmd)
}
func runOrganizationDetail(path string) error {
return fmt.Errorf("Not yet implemented")
func runOrganizationDetail(ctx *context.TeaContext) error {
org, _, err := ctx.Login.Client().GetOrg(ctx.Args().First())
if err != nil {
return err
}
print.OrganizationDetails(org)
return nil
}

View File

@ -0,0 +1,90 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package organizations
import (
"fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// CmdOrganizationCreate represents a sub command of organizations to delete a given user organization
var CmdOrganizationCreate = cli.Command{
Name: "create",
Aliases: []string{"c"},
Usage: "Create an organization",
Description: "Create an organization",
Action: RunOrganizationCreate,
ArgsUsage: "<organization name>",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
},
&cli.StringFlag{
Name: "website",
Aliases: []string{"w"},
},
&cli.StringFlag{
Name: "location",
Aliases: []string{"L"},
},
&cli.StringFlag{
Name: "visibility",
Aliases: []string{"v"},
},
&cli.BoolFlag{
Name: "repo-admins-can-change-team-access",
},
&flags.LoginFlag,
},
}
// RunOrganizationCreate sets up a new organization
func RunOrganizationCreate(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
if ctx.Args().Len() < 1 {
return fmt.Errorf("You have to specify the organization name you want to create")
}
var visibility gitea.VisibleType
switch ctx.String("visibility") {
case "", "public":
visibility = gitea.VisibleTypePublic
case "private":
visibility = gitea.VisibleTypePrivate
case "limited":
visibility = gitea.VisibleTypeLimited
default:
return fmt.Errorf("unknown visibility '%s'", ctx.String("visibility"))
}
org, _, err := ctx.Login.Client().CreateOrg(gitea.CreateOrgOption{
Name: ctx.Args().First(),
// FullName: , // not really meaningful for orgs (not displayed in webui, use description instead?)
Description: ctx.String("description"),
Website: ctx.String("website"),
Location: ctx.String("location"),
RepoAdminChangeTeamAccess: ctx.Bool("repo-admins-can-change-team-access"),
Visibility: visibility,
})
if err != nil {
return err
}
print.OrganizationDetails(org)
return err
}

View File

@ -7,6 +7,7 @@ package organizations
import (
"fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"github.com/urfave/cli/v2"
)
@ -19,6 +20,10 @@ var CmdOrganizationDelete = cli.Command{
Description: "Delete users organizations",
ArgsUsage: "<organization name>",
Action: RunOrganizationDelete,
Flags: []cli.Flag{
&flags.LoginFlag,
&flags.RemoteFlag,
},
}
// RunOrganizationDelete delete user organization

View File

@ -19,6 +19,7 @@ var CmdOrganizationList = cli.Command{
Aliases: []string{"ls"},
Usage: "List Organizations",
Description: "List users organizations",
ArgsUsage: " ", // command does not accept arguments
Action: RunOrganizationList,
Flags: append([]cli.Flag{
&flags.PaginationPageFlag,

View File

@ -30,7 +30,7 @@ var CmdPulls = cli.Command{
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "comments",
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
Usage: "Whether to display comments (will prompt if not provided & run interactively)",
},
}, pulls.CmdPullsList.Flags...),
Subcommands: []*cli.Command{
@ -43,6 +43,7 @@ var CmdPulls = cli.Command{
&pulls.CmdPullsReview,
&pulls.CmdPullsApprove,
&pulls.CmdPullsReject,
&pulls.CmdPullsMerge,
},
}
@ -70,7 +71,9 @@ func runPullDetail(cmd *cli.Context, index string) error {
return err
}
reviews, _, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{})
reviews, _, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil {
fmt.Printf("error while loading reviews: %v\n", err)
}

View File

@ -35,7 +35,10 @@ var CmdPullsCheckout = cli.Command{
func runPullsCheckout(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{LocalRepo: true})
ctx.Ensure(context.CtxRequirement{
LocalRepo: true,
RemoteRepo: true,
})
if ctx.Args().Len() != 1 {
return fmt.Errorf("Must specify a PR index")
}

View File

@ -18,28 +18,27 @@ var CmdPullsCreate = cli.Command{
Name: "create",
Aliases: []string{"c"},
Usage: "Create a pull-request",
Description: "Create a pull-request",
Description: "Create a pull-request in the current repo",
Action: runPullsCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "head",
Usage: "Set head branch (default is current one)",
Usage: "Branch name of the PR source (default is current one). To specify a different head repo, use <user>:<branch>",
},
&cli.StringFlag{
Name: "base",
Aliases: []string{"b"},
Usage: "Set base branch (default is default branch)",
Usage: "Branch name of the PR target (default is repos default branch)",
},
}, flags.IssuePREditFlags...),
}
func runPullsCreate(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{LocalRepo: true})
// no args -> interactive mode
if ctx.NumFlags() == 0 {
return interact.CreatePull(ctx.Login, ctx.Owner, ctx.Repo)
return interact.CreatePull(ctx)
}
// else use args to create PR
@ -49,9 +48,7 @@ func runPullsCreate(cmd *cli.Context) error {
}
return task.CreatePull(
ctx.Login,
ctx.Owner,
ctx.Repo,
ctx,
ctx.String("base"),
ctx.String("head"),
opts,

View File

@ -13,14 +13,19 @@ import (
"github.com/urfave/cli/v2"
)
var pullFieldsFlag = flags.FieldsFlag(print.PullFields, []string{
"index", "title", "state", "author", "milestone", "updated", "labels",
})
// CmdPullsList represents a sub command of issues to list pulls
var CmdPullsList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List pull requests of the repository",
Description: `List pull requests of the repository`,
ArgsUsage: " ", // command does not accept arguments
Action: RunPullsList,
Flags: flags.IssuePRFlags,
Flags: append([]cli.Flag{pullFieldsFlag}, flags.PRListingFlags...),
}
// RunPullsList return list of pulls
@ -46,6 +51,11 @@ func RunPullsList(cmd *cli.Context) error {
return err
}
print.PullsList(prs, ctx.Output)
fields, err := pullFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
print.PullsList(prs, ctx.Output, fields)
return nil
}

70
cmd/pulls/merge.go Normal file
View File

@ -0,0 +1,70 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pulls
import (
"fmt"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v2"
)
// CmdPullsMerge merges a PR
var CmdPullsMerge = cli.Command{
Name: "merge",
Aliases: []string{"m"},
Usage: "Merge a pull request",
Description: "Merge a pull request",
ArgsUsage: "<pull index>",
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "style",
Aliases: []string{"s"},
Usage: "Kind of merge to perform: merge, rebase, squash, rebase-merge",
Value: "merge",
},
&cli.StringFlag{
Name: "title",
Aliases: []string{"t"},
Usage: "Merge commit title",
},
&cli.StringFlag{
Name: "message",
Aliases: []string{"m"},
Usage: "Merge commit message",
},
}, flags.AllDefaultFlags...),
Action: func(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
if ctx.Args().Len() != 1 {
return fmt.Errorf("Must specify a PR index")
}
idx, err := utils.ArgToIndex(ctx.Args().First())
if err != nil {
return err
}
success, _, err := ctx.Login.Client().MergePullRequest(ctx.Owner, ctx.Repo, idx, gitea.MergePullRequestOption{
Style: gitea.MergeStyle(ctx.String("style")),
Title: ctx.String("title"),
Message: ctx.String("message"),
})
if err != nil {
return err
}
if !success {
return fmt.Errorf("Failed to merge PR. Is it still open?")
}
return nil
},
}

View File

@ -19,6 +19,7 @@ var CmdReleases = cli.Command{
Category: catEntities,
Usage: "Manage releases",
Description: "Manage releases",
ArgsUsage: " ", // command does not accept arguments
Action: releases.RunReleasesList,
Subcommands: []*cli.Command{
&releases.CmdReleaseList,

View File

@ -22,16 +22,17 @@ var CmdReleaseCreate = cli.Command{
Name: "create",
Aliases: []string{"c"},
Usage: "Create a release",
Description: `Create a release`,
Description: `Create a release for a new or existing git tag`,
ArgsUsage: "[<tag>]",
Action: runReleaseCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "tag",
Usage: "Tag name",
Usage: "Tag name. If the tag does not exist yet, it will be created by Gitea",
},
&cli.StringFlag{
Name: "target",
Usage: "Target refs, branch name or commit id",
Usage: "Target branch name or commit hash. Defaults to the default branch of the repo",
},
&cli.StringFlag{
Name: "title",
@ -56,7 +57,7 @@ var CmdReleaseCreate = cli.Command{
&cli.StringSliceFlag{
Name: "asset",
Aliases: []string{"a"},
Usage: "List of files to attach",
Usage: "Path to file attachment. Can be specified multiple times",
},
}, flags.AllDefaultFlags...),
}
@ -65,8 +66,16 @@ func runReleaseCreate(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
tag := ctx.String("tag")
if cmd.Args().Present() {
if len(tag) != 0 {
return fmt.Errorf("ambiguous arguments: provide tagname via --tag or argument, but not both")
}
tag = cmd.Args().First()
}
release, resp, err := ctx.Login.Client().CreateRelease(ctx.Owner, ctx.Repo, gitea.CreateReleaseOption{
TagName: ctx.String("tag"),
TagName: tag,
Target: ctx.String("target"),
Title: ctx.String("title"),
Note: ctx.String("note"),

View File

@ -54,10 +54,6 @@ func runReleaseDelete(cmd *cli.Context) error {
if err != nil {
return err
}
if release == nil {
return nil
}
_, err = client.DeleteRelease(ctx.Owner, ctx.Repo, release.ID)
if err != nil {
return err

View File

@ -72,10 +72,6 @@ func runReleaseEdit(cmd *cli.Context) error {
if err != nil {
return err
}
if release == nil {
return nil
}
var isDraft, isPre *bool
if ctx.IsSet("draft") {
isDraft = gitea.OptionalBool(strings.ToLower(ctx.String("draft"))[:1] == "t")

View File

@ -21,6 +21,7 @@ var CmdReleaseList = cli.Command{
Aliases: []string{"ls"},
Usage: "List Releases",
Description: "List Releases",
ArgsUsage: " ", // command does not accept arguments
Action: RunReleasesList,
Flags: append([]cli.Flag{
&flags.PaginationPageFlag,
@ -45,19 +46,19 @@ func RunReleasesList(cmd *cli.Context) error {
}
func getReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{})
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil {
return nil, err
}
if len(rl) == 0 {
fmt.Println("Repo does not have any release")
return nil, nil
return nil, fmt.Errorf("Repo does not have any release")
}
for _, r := range rl {
if r.TagName == tag {
return r, nil
}
}
fmt.Println("Release tag does not exist")
return nil, nil
return nil, fmt.Errorf("Release tag does not exist")
}

View File

@ -27,6 +27,8 @@ var CmdRepos = cli.Command{
&repos.CmdReposList,
&repos.CmdReposSearch,
&repos.CmdRepoCreate,
&repos.CmdRepoCreateFromTemplate,
&repos.CmdRepoFork,
},
Flags: repos.CmdReposListFlags,
}

View File

@ -21,6 +21,7 @@ var CmdRepoCreate = cli.Command{
Aliases: []string{"c"},
Usage: "Create a repository",
Description: "Create a repository",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
@ -79,6 +80,14 @@ var CmdRepoCreate = cli.Command{
Required: false,
Usage: "use custom default branch (need --init)",
},
&cli.BoolFlag{
Name: "template",
Usage: "make repo a template repo",
},
&cli.StringFlag{
Name: "trustmodel",
Usage: "select trust model (committer,collaborator,collaborator+committer)",
},
}, flags.LoginOutputFlags...),
}
@ -86,9 +95,24 @@ func runRepoCreate(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
var (
repo *gitea.Repository
err error
repo *gitea.Repository
err error
trustmodel gitea.TrustModel
)
if ctx.IsSet("trustmodel") {
switch ctx.String("trustmodel") {
case "committer":
trustmodel = gitea.TrustModelCommitter
case "collaborator":
trustmodel = gitea.TrustModelCollaborator
case "collaborator+committer":
trustmodel = gitea.TrustModelCollaboratorCommitter
default:
return fmt.Errorf("unknown trustmodel type '%s'", ctx.String("trustmodel"))
}
}
opts := gitea.CreateRepoOption{
Name: ctx.String("name"),
Description: ctx.String("description"),
@ -99,6 +123,8 @@ func runRepoCreate(cmd *cli.Context) error {
License: ctx.String("license"),
Readme: ctx.String("readme"),
DefaultBranch: ctx.String("branch"),
Template: ctx.Bool("template"),
TrustModel: trustmodel,
}
if len(ctx.String("owner")) != 0 {
repo, _, err = client.CreateOrgRepo(ctx.String("owner"), opts)

View File

@ -0,0 +1,121 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repos
import (
"fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/utils"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// CmdRepoCreateFromTemplate represents a sub command of repos to generate one from a template repo
var CmdRepoCreateFromTemplate = cli.Command{
Name: "create-from-template",
Aliases: []string{"ct"},
Usage: "Create a repository based on an existing template",
Description: "Create a repository based on an existing template",
Action: runRepoCreateFromTemplate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "template",
Aliases: []string{"t"},
Required: true,
Usage: "source template to copy from",
},
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Required: true,
Usage: "name of new repo",
},
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Usage: "name of repo owner",
},
&cli.BoolFlag{
Name: "private",
Usage: "make new repo private",
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"desc"},
Usage: "add custom description to repo",
},
&cli.BoolFlag{
Name: "content",
Value: true,
Usage: "copy git content from template",
},
&cli.BoolFlag{
Name: "githooks",
Value: true,
Usage: "copy git hooks from template",
},
&cli.BoolFlag{
Name: "avatar",
Value: true,
Usage: "copy repo avatar from template",
},
&cli.BoolFlag{
Name: "labels",
Value: true,
Usage: "copy repo labels from template",
},
&cli.BoolFlag{
Name: "topics",
Value: true,
Usage: "copy topics from template",
},
&cli.BoolFlag{
Name: "webhooks",
Usage: "copy webhooks from template",
},
}, flags.LoginOutputFlags...),
}
func runRepoCreateFromTemplate(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
templateOwner, templateRepo := utils.GetOwnerAndRepo(ctx.String("template"), ctx.Login.User)
owner := ctx.Login.User
if ctx.IsSet("owner") {
owner = ctx.String("owner")
}
opts := gitea.CreateRepoFromTemplateOption{
Name: ctx.String("name"),
Owner: owner,
Description: ctx.String("description"),
Private: ctx.Bool("private"),
GitContent: ctx.Bool("content"),
GitHooks: ctx.Bool("githooks"),
Avatar: ctx.Bool("avatar"),
Labels: ctx.Bool("labels"),
Topics: ctx.Bool("topics"),
Webhooks: ctx.Bool("webhooks"),
}
repo, _, err := client.CreateRepoFromTemplate(templateOwner, templateRepo, opts)
if err != nil {
return err
}
topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}

59
cmd/repos/fork.go Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repos
import (
"fmt"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// CmdRepoFork represents a sub command of repos to fork an existing repo
var CmdRepoFork = cli.Command{
Name: "fork",
Aliases: []string{"f"},
Usage: "Fork an existing repository",
Description: "Create a repository from an existing repo",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoFork,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Usage: "name of fork's owner, defaults to current user",
},
}, flags.LoginRepoFlags...),
}
func runRepoFork(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
client := ctx.Login.Client()
opts := gitea.CreateForkOption{}
if ctx.IsSet("owner") {
owner := ctx.String("owner")
opts.Organization = &owner
}
repo, _, err := client.CreateFork(ctx.Owner, ctx.Repo, opts)
if err != nil {
return err
}
topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}

View File

@ -13,6 +13,10 @@ import (
"github.com/urfave/cli/v2"
)
var repoFieldsFlag = flags.FieldsFlag(print.RepoFields, []string{
"owner", "name", "type", "ssh",
})
// CmdReposListFlags contains all flags needed for repo listing
var CmdReposListFlags = append([]cli.Flag{
&cli.BoolFlag{
@ -27,9 +31,7 @@ var CmdReposListFlags = append([]cli.Flag{
Required: false,
Usage: "List your starred repos instead",
},
flags.FieldsFlag(print.RepoFields, []string{
"owner", "name", "type", "ssh",
}),
repoFieldsFlag,
&typeFilterFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
@ -82,7 +84,7 @@ func RunReposList(cmd *cli.Context) error {
reposFiltered = filterReposByType(rps, typeFilter)
}
fields, err := flags.GetFields(cmd, print.RepoFields)
fields, err := repoFieldsFlag.GetValues(cmd)
if err != nil {
return err
}

View File

@ -50,9 +50,7 @@ var CmdReposSearch = cli.Command{
Required: false,
Usage: "Filter archived repos (true|false)",
},
flags.FieldsFlag(print.RepoFields, []string{
"owner", "name", "type", "ssh",
}),
repoFieldsFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.LoginOutputFlags...),
@ -125,7 +123,7 @@ func runReposSearch(cmd *cli.Context) error {
return err
}
fields, err := flags.GetFields(cmd, nil)
fields, err := repoFieldsFlag.GetValues(cmd)
if err != nil {
return err
}

View File

@ -19,6 +19,17 @@ import (
"github.com/urfave/cli/v2"
)
// NOTE: not using NewCsvFlag, as we don't want an alias & default value.
var timeFieldsFlag = &flags.CsvFlag{
AvailableFields: print.TrackedTimeFields,
StringFlag: cli.StringFlag{
Name: "fields",
Usage: fmt.Sprintf(`Comma-separated list of fields to print. Available values:
%s
`, strings.Join(print.TrackedTimeFields, ",")),
},
}
// CmdTrackedTimesList represents a sub command of times to list them
var CmdTrackedTimesList = cli.Command{
Name: "list",
@ -53,12 +64,7 @@ Depending on your permissions on the repository, only your own tracked times mig
Aliases: []string{"m"},
Usage: "Show all times tracked by you across all repositories (overrides command arguments)",
},
&cli.StringFlag{
Name: "fields",
Usage: fmt.Sprintf(`Comma-separated list of fields to print. Available values:
%s
`, strings.Join(print.TrackedTimeFields, ",")),
},
timeFieldsFlag,
}, flags.AllDefaultFlags...),
}
@ -116,7 +122,7 @@ func RunTimesList(cmd *cli.Context) error {
}
if ctx.IsSet("fields") {
if fields, err = flags.GetFields(cmd, print.TrackedTimeFields); err != nil {
if fields, err = timeFieldsFlag.GetValues(cmd); err != nil {
return err
}
}

28
cmd/whoami.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/urfave/cli/v2"
)
// CmdWhoami represents the command to show current logged in user
var CmdWhoami = cli.Command{
Name: "whoami",
Category: catMisc,
Description: `For debugging purposes, show the user that is currently logged in.`,
Usage: "Show current logged in user",
ArgsUsage: " ", // command does not accept arguments
Action: func(cmd *cli.Context) error {
ctx := context.InitCommand(cmd)
client := ctx.Login.Client()
user, _, _ := client.GetMyUserInfo()
print.UserDetails(user)
return nil
},
}

84
go.mod
View File

@ -1,38 +1,68 @@
module code.gitea.io/tea
go 1.13
go 1.18
require (
code.gitea.io/gitea-vet v0.2.1
code.gitea.io/sdk/gitea v0.13.1-0.20210304201955-ff82113459b5
gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b
github.com/AlecAivazis/survey/v2 v2.2.8
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/adrg/xdg v0.3.1
github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e
github.com/charmbracelet/glamour v0.2.0
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/go-git/go-git/v5 v5.2.0
github.com/imdario/mergo v0.3.11 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/muesli/termenv v0.7.4
code.gitea.io/sdk/gitea v0.15.1-0.20220831004139-a0127ed0e7fe
gitea.com/noerw/unidiff-comments v0.0.0-20220822113322-50f4daa0e35c
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/adrg/xdg v0.4.0
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
github.com/charmbracelet/glamour v0.5.0
github.com/enescakir/emoji v1.0.0
github.com/go-git/go-git/v5 v5.4.2
github.com/muesli/termenv v0.12.0
github.com/olekukonko/tablewriter v0.0.5
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/stretchr/testify v1.7.0
github.com/urfave/cli/v2 v2.3.0
github.com/xanzy/ssh-agent v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
golang.org/x/sys v0.0.0-20210305034016-7844c3c200c3 // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/tools v0.1.0 // indirect
github.com/urfave/cli/v2 v2.16.3
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
gopkg.in/yaml.v2 v2.4.0
)
replace github.com/charmbracelet/glamour => github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2
require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/cloudflare/circl v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/microcosm-cc/bluemonday v1.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yuin/goldmark v1.4.14 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect
golang.org/x/sys v0.0.0-20220913153101-76c7481b5158 // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.12 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

257
go.sum
View File

@ -1,122 +1,132 @@
code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s=
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
code.gitea.io/sdk/gitea v0.13.1-0.20210304201955-ff82113459b5 h1:va0KddYHN8bH6MCUaWf5e4p+il55blUw5J0ha5vTMaQ=
code.gitea.io/sdk/gitea v0.13.1-0.20210304201955-ff82113459b5/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs=
gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b h1:CLYsMGcGLohESQDMth+RgJ4cB3CCHToxnj0zBbvB3sE=
gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b/go.mod h1:Fc8iyPm4NINRWujeIk2bTfcbGc4ZYY29/oMAAGcr4qI=
github.com/AlecAivazis/survey/v2 v2.2.8 h1:TgxCwybKdBckmC+/P9/5h49rw/nAHe/itZL0dgHs+Q0=
github.com/AlecAivazis/survey/v2 v2.2.8/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
code.gitea.io/sdk/gitea v0.15.1-0.20220831004139-a0127ed0e7fe h1:PeLyxnUZE85QuJtBZ4P8qCQcgWG5Ked67mlNgr0WkCQ=
code.gitea.io/sdk/gitea v0.15.1-0.20220831004139-a0127ed0e7fe/go.mod h1:aRmrQC3CAHdJAU1LQt0C9zqzqI8tUB/5oQtNE746aYE=
gitea.com/noerw/unidiff-comments v0.0.0-20220822113322-50f4daa0e35c h1:8fTkq2UaVkLHZCF+iB4wTxINmVAToe2geZGayk9LMbA=
gitea.com/noerw/unidiff-comments v0.0.0-20220822113322-50f4daa0e35c/go.mod h1:Fc8iyPm4NINRWujeIk2bTfcbGc4ZYY29/oMAAGcr4qI=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/adrg/xdg v0.3.1 h1:uIyL9BYfXaFgDyVRKE8wjtm6ETQULweQqTofphEFJYY=
github.com/adrg/xdg v0.3.1/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE=
github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 h1:NsReiLpErIPzRrnogAXYwSoU7txA977LjDGrbkewJbg=
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e h1:OjdSMCht0ZVX7IH0nTdf00xEustvbtUGRgMh3gbdmOg=
github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/enescakir/emoji v1.0.0 h1:W+HsNql8swfCQFtioDGDHCHri8nudlK1n5p2rHCJoog=
github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI=
github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y=
github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/muesli/reflow v0.2.0 h1:2o0UBJPHHH4fa2GCXU4Rg4DwOtWPMekCeyc5EWbAQp0=
github.com/muesli/reflow v0.2.0/go.mod h1:qT22vjVmM9MIUeLgsVYe/Ye7eZlbv9dZjL3dVhUqLX8=
github.com/muesli/termenv v0.7.4 h1:/pBqvU5CpkY53tU0vVn+xgs2ZTX63aH5nY+SSps5Xa8=
github.com/muesli/termenv v0.7.4/go.mod h1:pZ7qY9l3F7e5xsAOS0zCew2tME+p7bWeBkotCEcIIcc=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw=
github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc=
github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2 h1:ACjOTGUGi7rt3JQU9GIFFs8sueFGShy6GcGjQhMmKjs=
github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2/go.mod h1:WIVFX8Y2VIK1Y/1qtXYL/Vvzqlcbo3VgVop9i2piPkE=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -125,111 +135,124 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597 h1:nZY1S2jo+VtDrUfjO9XYI137O41hhRkxZNV5Fb5ixCA=
github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597/go.mod h1:F8CBHSOjnzjx9EeXyWJTAzJyVxN+Y8JH2WjLMn4utiw=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk=
github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/xanzy/ssh-agent v0.3.2 h1:eKj4SX2Fe7mui28ZgnFW5fmTz1EIr7ugo5s6wDxdHBM=
github.com/xanzy/ssh-agent v0.3.2/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I=
github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.14 h1:jwww1XQfhJN7Zm+/a1ZA/3WUiEBEroYFNTiV3dKwM8U=
github.com/yuin/goldmark v1.4.14/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305034016-7844c3c200c3 h1:RdE7htvBru4I4VZQofQjCZk5W9+aLNlSF5n0zgVwm8s=
golang.org/x/sys v0.0.0-20210305034016-7844c3c200c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220913153101-76c7481b5158 h1:XQphkCZeKYaMRSo28HqvvNYuLOoM5CIOOvTZfthvTgI=
golang.org/x/sys v0.0.0-20220913153101-76c7481b5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

39
main.go
View File

@ -8,6 +8,7 @@ package main // import "code.gitea.io/tea"
import (
"fmt"
"os"
"runtime"
"strings"
"code.gitea.io/tea/cmd"
@ -21,6 +22,9 @@ var Version = "development"
// Tags holds the build tags used
var Tags = ""
// SDK holds the sdk version from go.mod
var SDK = ""
func main() {
// make parsing tea --version easier, by printing /just/ the version string
cli.VersionPrinter = func(c *cli.Context) { fmt.Fprintln(c.App.Writer, c.App.Version) }
@ -30,11 +34,12 @@ func main() {
app.Usage = "command line tool to interact with Gitea"
app.Description = appDescription
app.CustomAppHelpTemplate = helpTemplate
app.Version = Version + formatBuiltWith(Tags)
app.Version = formatVersion()
app.Commands = []*cli.Command{
&cmd.CmdLogin,
&cmd.CmdLogout,
&cmd.CmdAutocomplete,
&cmd.CmdWhoami,
&cmd.CmdIssues,
&cmd.CmdPulls,
@ -48,6 +53,9 @@ func main() {
&cmd.CmdOpen,
&cmd.CmdNotifications,
&cmd.CmdRepoClone,
&cmd.CmdAdmin,
}
app.EnableBashCompletion = true
err := app.Run(os.Args)
@ -59,18 +67,29 @@ func main() {
}
}
func formatBuiltWith(Tags string) string {
if len(Tags) == 0 {
return ""
func formatVersion() string {
version := fmt.Sprintf("Version: %s\tgolang: %s",
bold(Version),
strings.ReplaceAll(runtime.Version(), "go", ""))
if len(Tags) != 0 {
version += fmt.Sprintf("\tbuilt with: %s", strings.Replace(Tags, " ", ", ", -1))
}
return " built with: " + strings.Replace(Tags, " ", ", ", -1)
if len(SDK) != 0 {
version += fmt.Sprintf("\tgo-sdk: %s", SDK)
}
return version
}
var appDescription = `tea is a productivity helper for Gitea. It can be used to manage most entities on one
or multiple Gitea instances and provides local helpers like 'tea pull checkout'.
tea makes use of context provided by the repository in $PWD if available, but is still
usable independently of $PWD. Configuration is persisted in $XDG_CONFIG_HOME/tea.
var appDescription = `tea is a productivity helper for Gitea. It can be used to manage most entities on
one or multiple Gitea instances & provides local helpers like 'tea pr checkout'.
tea tries to make use of context provided by the repository in $PWD if available.
tea works best in a upstream/fork workflow, when the local main branch tracks the
upstream repo. tea assumes that local git state is published on the remote before
doing operations with tea. Configuration is persisted in $XDG_CONFIG_HOME/tea.
`
var helpTemplate = bold(`
@ -108,7 +127,7 @@ var helpTemplate = bold(`
tea open milestones # open web ui for milestones
# send gitea desktop notifications every 5 minutes (bash + libnotify)
while :; do tea notifications --all -o simple | xargs -i notify-send {}; sleep 300; done
while :; do tea notifications --mine -o simple | xargs -i notify-send {}; sleep 300; done
ABOUT
Written & maintained by The Gitea Authors.

View File

@ -17,9 +17,26 @@ import (
"gopkg.in/yaml.v2"
)
// FlagDefaults defines all flags that can be overridden with a default value
// via the config file
type FlagDefaults struct {
// Prefer a specific git remote to use for selecting a repository on gitea,
// instead of relying on the remote associated with main/master/trunk branch.
// The --remote flag still has precedence over this value.
Remote string `yaml:"remote"`
}
// Preferences that are stored in and read from the config file
type Preferences struct {
// Prefer using an external text editor over inline multiline prompts
Editor bool `yaml:"editor"`
FlagDefaults FlagDefaults `yaml:"flag_defaults"`
}
// LocalConfig represents local configurations
type LocalConfig struct {
Logins []Login `yaml:"logins"`
Logins []Login `yaml:"logins"`
Prefs Preferences `yaml:"preferences"`
}
var (
@ -55,6 +72,12 @@ func GetConfigPath() string {
return configFilePath
}
// GetPreferences returns preferences based on the config file
func GetPreferences() Preferences {
loadConfig()
return config.Prefs
}
// loadConfig load config from file
func loadConfig() (err error) {
loadConfigOnce.Do(func() {

View File

@ -111,6 +111,25 @@ func GetLoginByToken(token string) *Login {
return nil
}
// GetLoginByHost finds a login by it's server URL
func GetLoginByHost(host string) *Login {
err := loadConfig()
if err != nil {
log.Fatal(err)
}
for _, l := range config.Logins {
loginURL, err := url.Parse(l.URL)
if err != nil {
log.Fatal(err)
}
if loginURL.Host == host {
return &l
}
}
return nil
}
// DeleteLogin delete a login by name from config
func DeleteLogin(name string) error {
var idx = -1
@ -142,8 +161,9 @@ func AddLogin(login *Login) error {
return saveConfig()
}
// Client returns a client to operate Gitea API
func (l *Login) Client() *gitea.Client {
// Client returns a client to operate Gitea API. You may provide additional modifiers
// for the client like gitea.SetBasicAuth() for customization
func (l *Login) Client(options ...gitea.ClientOption) *gitea.Client {
httpClient := &http.Client{}
if l.Insecure {
cookieJar, _ := cookiejar.New(nil)
@ -155,10 +175,9 @@ func (l *Login) Client() *gitea.Client {
}}
}
client, err := gitea.NewClient(l.URL,
gitea.SetToken(l.Token),
gitea.SetHTTPClient(httpClient),
)
options = append(options, gitea.SetToken(l.Token), gitea.SetHTTPClient(httpClient))
client, err := gitea.NewClient(l.URL, options...)
if err != nil {
log.Fatal(err)
}

View File

@ -39,6 +39,9 @@ type TeaContext struct {
func (ctx *TeaContext) GetListOptions() gitea.ListOptions {
page := ctx.Int("page")
limit := ctx.Int("limit")
if limit < 0 {
limit = 0
}
if limit != 0 && page == 0 {
page = 1
}
@ -96,14 +99,17 @@ func InitCommand(ctx *cli.Context) *TeaContext {
}
}
if len(repoFlag) == 0 || repoFlagPathExists {
// try to read git repo & extract context, ignoring if PWD is not a repo
if c.LocalRepo, c.Login, c.RepoSlug, err = contextFromLocalRepo(repoPath, remoteFlag); err != nil {
if err == errNotAGiteaRepo || err == gogit.ErrRepositoryNotExists {
// we can deal with that, commands needing the optional values use ctx.Ensure()
} else {
log.Fatal(err.Error())
}
if len(remoteFlag) == 0 {
remoteFlag = config.GetPreferences().FlagDefaults.Remote
}
// try to read local git repo & extract context: if repoFlag specifies a valid path, read repo in that dir,
// otherwise attempt PWD. if no repo is found, continue with default login
if c.LocalRepo, c.Login, c.RepoSlug, err = contextFromLocalRepo(repoPath, remoteFlag); err != nil {
if err == errNotAGiteaRepo || err == gogit.ErrRepositoryNotExists {
// we can deal with that, commands needing the optional values use ctx.Ensure()
} else {
log.Fatal(err.Error())
}
}
@ -120,8 +126,16 @@ func InitCommand(ctx *cli.Context) *TeaContext {
}
} else if c.Login == nil {
if c.Login, err = config.GetDefaultLogin(); err != nil {
log.Fatal(err.Error())
if err.Error() == "No available login" {
// TODO: maybe we can directly start interact.CreateLogin() (only if
// we're sure we can interactively!), as gh cli does.
fmt.Println(`No gitea login configured. To start using tea, first run
tea login add
and then run your command again.`)
}
os.Exit(1)
}
fmt.Printf("NOTE: no gitea login detected, falling back to login '%s'\n", c.Login.Name)
}
// parse reposlug (owner falling back to login owner if reposlug contains only repo name)
@ -143,25 +157,39 @@ func contextFromLocalRepo(repoPath, remoteValue string) (*git.TeaRepo, *config.L
return repo, nil, "", err
}
// if no remote
if len(gitConfig.Remotes) == 0 {
return repo, nil, "", errors.New("No remote(s) found in this Git repository")
return repo, nil, "", errNotAGiteaRepo
}
// if only one remote exists
if len(gitConfig.Remotes) >= 1 && len(remoteValue) == 0 {
for remote := range gitConfig.Remotes {
remoteValue = remote
}
if len(gitConfig.Remotes) > 1 {
// if master branch is present, use it as the default remote
masterBranch, ok := gitConfig.Branches["master"]
// When no preferred value is given, choose a remote to find a
// matching login based on its URL.
if len(gitConfig.Remotes) > 1 && len(remoteValue) == 0 {
// if master branch is present, use it as the default remote
mainBranches := []string{"main", "master", "trunk"}
for _, b := range mainBranches {
masterBranch, ok := gitConfig.Branches[b]
if ok {
if len(masterBranch.Remote) > 0 {
remoteValue = masterBranch.Remote
}
break
}
}
// if no branch has matched, default to origin or upstream remote.
if len(remoteValue) == 0 {
if _, ok := gitConfig.Remotes["upstream"]; ok {
remoteValue = "upstream"
} else if _, ok := gitConfig.Remotes["origin"]; ok {
remoteValue = "origin"
}
}
}
// make sure a remote is selected
if len(remoteValue) == 0 {
for remote := range gitConfig.Remotes {
remoteValue = remote
break
}
}
remoteConfig, ok := gitConfig.Remotes[remoteValue]
@ -174,8 +202,9 @@ func contextFromLocalRepo(repoPath, remoteValue string) (*git.TeaRepo, *config.L
return repo, nil, "", err
}
for _, l := range logins {
sshHost := l.GetSSHHost()
for _, u := range remoteConfig.URLs {
p, err := git.ParseURL(strings.TrimSpace(u))
p, err := git.ParseURL(u)
if err != nil {
return repo, nil, "", fmt.Errorf("Git remote URL parse failed: %s", err.Error())
}
@ -186,8 +215,8 @@ func contextFromLocalRepo(repoPath, remoteValue string) (*git.TeaRepo, *config.L
return repo, &l, strings.TrimSuffix(path, ".git"), nil
}
} else if strings.EqualFold(p.Scheme, "ssh") {
if l.GetSSHHost() == strings.Split(p.Host, ":")[0] {
return repo, &l, strings.TrimLeft(strings.TrimSuffix(p.Path, ".git"), "/"), nil
if sshHost == p.Host {
return repo, &l, strings.TrimLeft(p.Path, "/"), nil
}
}
}

View File

@ -55,7 +55,7 @@ func readSSHPrivKey(keyFile string, passwordCallback pwCallback) (sig ssh.Signer
}
sshKey, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
return nil, fmt.Errorf("can not read ssh key '%s'", keyFile)
}
sig, err = ssh.ParsePrivateKey(sshKey)
if _, ok := err.(*ssh.PassphraseMissingError); ok && passwordCallback != nil {

View File

@ -20,11 +20,20 @@ type URLParser struct {
// Parse parses the git URL
func (p *URLParser) Parse(rawURL string) (u *url.URL, err error) {
if !protocolRe.MatchString(rawURL) &&
strings.Contains(rawURL, ":") &&
// not a Windows path
!strings.Contains(rawURL, "\\") {
rawURL = "ssh://" + strings.Replace(rawURL, ":", "/", 1)
rawURL = strings.TrimSpace(rawURL)
if !protocolRe.MatchString(rawURL) {
// convert the weird git ssh url format to a canonical url:
// git@gitea.com:gitea/tea -> ssh://git@gitea.com/gitea/tea
if strings.Contains(rawURL, ":") &&
// not a Windows path
!strings.Contains(rawURL, "\\") {
rawURL = "ssh://" + strings.Replace(rawURL, ":", "/", 1)
} else if !strings.Contains(rawURL, "@") &&
strings.Count(rawURL, "/") == 2 {
// match cases like gitea.com/gitea/tea
rawURL = "https://" + rawURL
}
}
u, err = url.Parse(rawURL)

56
modules/git/url_test.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseUrl(t *testing.T) {
u, err := ParseURL("ssh://git@gitea.com:3000/gitea/tea")
assert.NoError(t, err)
assert.Equal(t, "gitea.com:3000", u.Host)
assert.Equal(t, "ssh", u.Scheme)
assert.Equal(t, "/gitea/tea", u.Path)
u, err = ParseURL("https://gitea.com/gitea/tea")
assert.NoError(t, err)
assert.Equal(t, "gitea.com", u.Host)
assert.Equal(t, "https", u.Scheme)
assert.Equal(t, "/gitea/tea", u.Path)
u, err = ParseURL("git@gitea.com:gitea/tea")
assert.NoError(t, err)
assert.Equal(t, "gitea.com", u.Host)
assert.Equal(t, "ssh", u.Scheme)
assert.Equal(t, "/gitea/tea", u.Path)
u, err = ParseURL("gitea.com/gitea/tea")
assert.NoError(t, err)
assert.Equal(t, "gitea.com", u.Host)
assert.Equal(t, "https", u.Scheme)
assert.Equal(t, "/gitea/tea", u.Path)
u, err = ParseURL("foo/bar")
assert.NoError(t, err)
assert.Equal(t, "", u.Host)
assert.Equal(t, "", u.Scheme)
assert.Equal(t, "foo/bar", u.Path)
u, err = ParseURL("/foo/bar")
assert.NoError(t, err)
assert.Equal(t, "", u.Host)
assert.Equal(t, "https", u.Scheme)
assert.Equal(t, "/foo/bar", u.Path)
// this case is unintuitive, but to ambiguous to be handled differently
u, err = ParseURL("gitea.com")
assert.NoError(t, err)
assert.Equal(t, "", u.Host)
assert.Equal(t, "", u.Scheme)
assert.Equal(t, "gitea.com", u.Path)
}

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/print"
"github.com/AlecAivazis/survey/v2"
"golang.org/x/crypto/ssh/terminal"
)
@ -26,7 +27,7 @@ func ShowCommentsMaybeInteractive(ctx *context.TeaContext, idx int64, totalComme
return err
}
print.Comments(comments)
} else if IsInteractive() && !ctx.IsSet("comments") {
} else if print.IsInteractive() && !ctx.IsSet("comments") {
// if we're interactive, but --comments hasn't been explicitly set to false
if err := ShowCommentsPaginated(ctx, idx, totalComments); err != nil {
fmt.Printf("error while loading comments: %v\n", err)
@ -69,11 +70,6 @@ func ShowCommentsPaginated(ctx *context.TeaContext, idx int64, totalComments int
return nil
}
// IsInteractive checks if the output is piped, but NOT if the session is run interactively..
func IsInteractive() bool {
return terminal.IsTerminal(int(os.Stdout.Fd()))
}
// IsStdinPiped checks if stdin is piped
func IsStdinPiped() bool {
return !terminal.IsTerminal(int(os.Stdin.Fd()))

View File

@ -43,7 +43,12 @@ func promptIssueProperties(login *config.Login, owner, repo string, o *gitea.Cre
}
// description
promptD := &survey.Multiline{Message: "Issue description:", Default: o.Body}
promptD := NewMultiline(Multiline{
Message: "Issue description:",
Default: o.Body,
Syntax: "md",
UseEditor: config.GetPreferences().Editor,
})
if err = survey.AskOne(promptD, &o.Body); err != nil {
return err
}
@ -60,7 +65,7 @@ func promptIssueProperties(login *config.Login, owner, repo string, o *gitea.Cre
}
// assignees
if o.Assignees, err = promptMultiSelect("Assignees:", selectables.Collaborators, "[other]"); err != nil {
if o.Assignees, err = promptMultiSelect("Assignees:", selectables.Assignees, "[other]"); err != nil {
return err
}
@ -94,7 +99,7 @@ func promptIssueProperties(login *config.Login, owner, repo string, o *gitea.Cre
type issueSelectables struct {
Repo *gitea.Repository
Collaborators []string
Assignees []string
MilestoneList []string
MilestoneMap map[string]int64
LabelList []string
@ -119,17 +124,15 @@ func fetchIssueSelectables(login *config.Login, owner, repo string, done chan is
return
}
// FIXME: this should ideally be ListAssignees(), https://github.com/go-gitea/gitea/issues/14856
colabs, _, err := c.ListCollaborators(owner, repo, gitea.ListCollaboratorsOptions{})
assignees, _, err := c.GetAssignees(owner, repo)
if err != nil {
r.Err = err
done <- r
return
}
r.Collaborators = make([]string, len(colabs)+1)
r.Collaborators[0] = login.User
for i, u := range colabs {
r.Collaborators[i+1] = u.UserName
r.Assignees = make([]string, len(assignees))
for i, u := range assignees {
r.Assignees[i] = u.UserName
}
milestones, _, err := c.ListRepoMilestones(owner, repo, gitea.ListMilestoneOption{})
@ -145,7 +148,9 @@ func fetchIssueSelectables(login *config.Login, owner, repo string, done chan is
r.MilestoneList[i] = m.Title
}
labels, _, err := c.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{})
labels, _, err := c.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil {
r.Err = err
done <- r

View File

@ -33,7 +33,11 @@ func CreateMilestone(login *config.Login, owner, repo string) error {
}
// description
promptM := &survey.Multiline{Message: "Milestone description:"}
promptM := NewMultiline(Multiline{
Message: "Milestone description:",
Syntax: "md",
UseEditor: config.GetPreferences().Editor,
})
if err := survey.AskOne(promptM, &description); err != nil {
return err
}

View File

@ -14,9 +14,26 @@ import (
"github.com/araddon/dateparse"
)
// PromptMultiline runs a textfield-style prompt and blocks until input was made.
func PromptMultiline(message string) (content string, err error) {
err = survey.AskOne(&survey.Multiline{Message: message}, &content)
// Multiline represents options for a prompt that expects multiline input
type Multiline struct {
Message string
Default string
Syntax string
UseEditor bool
}
// NewMultiline creates a prompt that switches between the inline multiline text
// and a texteditor based prompt
func NewMultiline(opts Multiline) (prompt survey.Prompt) {
if opts.UseEditor {
prompt = &survey.Editor{
Message: opts.Message,
Default: opts.Default,
FileName: "*." + opts.Syntax,
}
} else {
prompt = &survey.Multiline{Message: opts.Message, Default: opts.Default}
}
return
}

View File

@ -6,26 +6,23 @@ package interact
import (
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/task"
"github.com/AlecAivazis/survey/v2"
)
// CreatePull interactively creates a PR
func CreatePull(login *config.Login, owner, repo string) error {
func CreatePull(ctx *context.TeaContext) (err error) {
var base, head string
// owner, repo
owner, repo, err := promptRepoSlug(owner, repo)
if err != nil {
if ctx.Owner, ctx.Repo, err = promptRepoSlug(ctx.Owner, ctx.Repo); err != nil {
return err
}
// base
base, err = task.GetDefaultPRBase(login, owner, repo)
if err != nil {
if base, err = task.GetDefaultPRBase(ctx.Login, ctx.Owner, ctx.Repo); err != nil {
return err
}
promptI := &survey.Input{Message: "Target branch:", Default: base}
@ -34,14 +31,14 @@ func CreatePull(login *config.Login, owner, repo string) error {
}
// head
localRepo, err := git.RepoForWorkdir()
if err != nil {
return err
}
var headOwner, headBranch string
promptOpts := survey.WithValidator(survey.Required)
headOwner, headBranch, err := task.GetDefaultPRHead(localRepo)
if err == nil {
promptOpts = nil
if ctx.LocalRepo != nil {
headOwner, headBranch, err = task.GetDefaultPRHead(ctx.LocalRepo)
if err == nil {
promptOpts = nil
}
}
promptI = &survey.Input{Message: "Source repo owner:", Default: headOwner}
if err := survey.AskOne(promptI, &headOwner); err != nil {
@ -52,17 +49,15 @@ func CreatePull(login *config.Login, owner, repo string) error {
return err
}
head = task.GetHeadSpec(headOwner, headBranch, owner)
head = task.GetHeadSpec(headOwner, headBranch, ctx.Owner)
opts := gitea.CreateIssueOption{Title: task.GetDefaultPRTitle(head)}
if err = promptIssueProperties(login, owner, repo, &opts); err != nil {
if err = promptIssueProperties(ctx.Login, ctx.Owner, ctx.Repo, &opts); err != nil {
return err
}
return task.CreatePull(
login,
owner,
repo,
ctx,
base,
head,
&opts)

View File

@ -8,6 +8,7 @@ import (
"fmt"
"os"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/context"
"code.gitea.io/tea/modules/task"
@ -52,10 +53,14 @@ func ReviewPull(ctx *context.TeaContext, idx int64) error {
// comment
var promptOpts survey.AskOpt
if state == gitea.ReviewStateComment || state == gitea.ReviewStateRequestChanges {
if (state == gitea.ReviewStateComment && len(codeComments) == 0) || state == gitea.ReviewStateRequestChanges {
promptOpts = survey.WithValidator(survey.Required)
}
err = survey.AskOne(&survey.Multiline{Message: "Concluding comment:"}, &comment, promptOpts)
err = survey.AskOne(NewMultiline(Multiline{
Message: "Concluding comment:",
Syntax: "md",
UseEditor: config.GetPreferences().Editor,
}), &comment, promptOpts)
if err != nil {
return err
}
@ -63,8 +68,9 @@ func ReviewPull(ctx *context.TeaContext, idx int64) error {
return task.CreatePullReview(ctx, idx, state, comment, codeComments)
}
// DoDiffReview (1) fetches & saves diff in tempfile, (2) starts $EDITOR to comment on diff,
// DoDiffReview (1) fetches & saves diff in tempfile, (2) starts $VISUAL or $EDITOR to comment on diff,
// (3) parses resulting file into code comments.
// It doesn't really make sense to use survey.Editor() here, as we'd read the file content at least twice.
func DoDiffReview(ctx *context.TeaContext, idx int64) ([]gitea.CreatePullReviewComment, error) {
tmpFile, err := task.SavePullDiff(ctx, idx)
if err != nil {

View File

@ -15,7 +15,7 @@ import (
func Comments(comments []*gitea.Comment) {
var baseURL string
if len(comments) != 0 {
baseURL = comments[0].HTMLURL
baseURL = getRepoURL(comments[0].HTMLURL)
}
var out = make([]string, len(comments))
@ -32,18 +32,18 @@ func Comments(comments []*gitea.Comment) {
// Comment renders a comment to stdout
func Comment(c *gitea.Comment) {
outputMarkdown(formatComment(c), c.HTMLURL)
outputMarkdown(formatComment(c), getRepoURL(c.HTMLURL))
}
func formatComment(c *gitea.Comment) string {
edited := ""
if c.Updated.After(c.Created) {
edited = fmt.Sprintf(" *(edited on %s)*", FormatTime(c.Updated))
edited = fmt.Sprintf(" *(edited on %s)*", FormatTime(c.Updated, false))
}
return fmt.Sprintf(
"---\n\n**@%s** wrote on %s%s:\n\n%s\n",
c.Poster.UserName,
FormatTime(c.Created),
FormatTime(c.Created, false),
edited,
c.Body,
)

View File

@ -6,12 +6,27 @@ package print
import (
"fmt"
"os"
"regexp"
"time"
"code.gitea.io/sdk/gitea"
"github.com/muesli/termenv"
"golang.org/x/crypto/ssh/terminal"
)
// IsInteractive checks if the output is piped, but NOT if the session is run interactively..
func IsInteractive() bool {
return terminal.IsTerminal(int(os.Stdout.Fd()))
}
// captures the repo URL part <host>/<owner>/<repo> of an url
var repoURLRegex = regexp.MustCompile("^([[:alnum:]]+://[^/]+(?:/[[:alnum:]]+){2})/.*")
func getRepoURL(resourceURL string) string {
return repoURLRegex.ReplaceAllString(resourceURL, "$1/")
}
// formatSize get kb in int and return string
func formatSize(kb int64) string {
if kb < 1024 {
@ -28,8 +43,18 @@ func formatSize(kb int64) string {
return fmt.Sprintf("%d Tb", gb/1024)
}
// FormatTime give a date-time in local timezone if available
func FormatTime(t time.Time) string {
// FormatTime provides a string for the given time value.
// If machineReadable is set, a UTC RFC3339 string is returned,
// otherwise a simplified string in local time is used.
func FormatTime(t time.Time, machineReadable bool) string {
if t.IsZero() {
return ""
}
if machineReadable {
return t.UTC().Format(time.RFC3339)
}
location, err := time.LoadLocation("Local")
if err != nil {
return t.Format("2006-01-02 15:04 UTC")
@ -72,3 +97,16 @@ func formatUserName(u *gitea.User) string {
}
return u.FullName
}
func formatBoolean(b bool, allowIcons bool) string {
if !allowIcons {
return fmt.Sprintf("%v", b)
}
styled := "✔"
if !b {
styled = "✖"
}
return styled
}

View File

@ -9,19 +9,40 @@ import (
"strings"
"code.gitea.io/sdk/gitea"
"github.com/enescakir/emoji"
)
// IssueDetails print an issue rendered to stdout
func IssueDetails(issue *gitea.Issue) {
outputMarkdown(fmt.Sprintf(
func IssueDetails(issue *gitea.Issue, reactions []*gitea.Reaction) {
out := fmt.Sprintf(
"# #%d %s (%s)\n@%s created %s\n\n%s\n",
issue.Index,
issue.Title,
issue.State,
issue.Poster.UserName,
FormatTime(issue.Created),
FormatTime(issue.Created, false),
issue.Body,
), issue.HTMLURL)
)
if len(reactions) > 0 {
out += fmt.Sprintf("\n---\n\n%s\n", formatReactions(reactions))
}
outputMarkdown(out, getRepoURL(issue.HTMLURL))
}
func formatReactions(reactions []*gitea.Reaction) string {
reactionCounts := make(map[string]uint16)
for _, r := range reactions {
reactionCounts[r.Reaction]++
}
reactionStrings := make([]string, 0, len(reactionCounts))
for reaction, count := range reactionCounts {
reactionStrings = append(reactionStrings, fmt.Sprintf("%dx :%s:", count, reaction))
}
return emoji.Parse(strings.Join(reactionStrings, " | "))
}
// IssuesPullsList prints a listing of issues & pulls
@ -54,19 +75,20 @@ var IssueFields = []string{
func printIssues(issues []*gitea.Issue, output string, fields []string) {
labelMap := map[int64]string{}
var printables = make([]printable, len(issues))
machineReadable := isMachineReadable(output)
for i, x := range issues {
// pre-serialize labels for performance
for _, label := range x.Labels {
if _, ok := labelMap[label.ID]; !ok {
labelMap[label.ID] = formatLabel(label, !isMachineReadable(output), "")
labelMap[label.ID] = formatLabel(label, !machineReadable, "")
}
}
// store items with printable interface
printables[i] = &printableIssue{x, &labelMap}
}
t := tableFromItems(fields, printables)
t := tableFromItems(fields, printables, machineReadable)
t.print(output)
}
@ -75,7 +97,7 @@ type printableIssue struct {
formattedLabels *map[int64]string
}
func (x printableIssue) FormatField(field string) string {
func (x printableIssue) FormatField(field string, machineReadable bool) string {
switch field {
case "index":
return fmt.Sprintf("%d", x.Index)
@ -97,11 +119,14 @@ func (x printableIssue) FormatField(field string) string {
case "body":
return x.Body
case "created":
return FormatTime(x.Created)
return FormatTime(x.Created, machineReadable)
case "updated":
return FormatTime(x.Updated)
return FormatTime(x.Updated, machineReadable)
case "deadline":
return FormatTime(*x.Deadline)
if x.Deadline == nil {
return ""
}
return FormatTime(*x.Deadline, machineReadable)
case "milestone":
if x.Milestone != nil {
return x.Milestone.Title

View File

@ -16,9 +16,17 @@ import (
// If the input could not be parsed, it is printed unformatted, the error
// is returned anyway.
func outputMarkdown(markdown string, baseURL string) error {
var styleOption glamour.TermRendererOption
if IsInteractive() {
styleOption = glamour.WithAutoStyle()
} else {
styleOption = glamour.WithStandardStyle("notty")
}
renderer, err := glamour.NewTermRenderer(
glamour.WithAutoStyle(),
styleOption,
glamour.WithBaseURL(baseURL),
glamour.WithPreservedNewLines(),
glamour.WithWordWrap(getWordWrap()),
)
if err != nil {

View File

@ -19,45 +19,70 @@ func MilestoneDetails(milestone *gitea.Milestone) {
fmt.Printf("\n%s\n", milestone.Description)
}
if milestone.Deadline != nil && !milestone.Deadline.IsZero() {
fmt.Printf("\nDeadline: %s\n", FormatTime(*milestone.Deadline))
fmt.Printf("\nDeadline: %s\n", FormatTime(*milestone.Deadline, false))
}
}
// MilestonesList prints a listing of milestones
func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateType) {
headers := []string{
"Title",
func MilestonesList(news []*gitea.Milestone, output string, fields []string) {
var printables = make([]printable, len(news))
for i, x := range news {
printables[i] = &printableMilestone{x}
}
if state == gitea.StateAll {
headers = append(headers, "State")
}
headers = append(headers,
"Open/Closed Issues",
"DueDate",
)
t := table{headers: headers}
for _, m := range miles {
var deadline = ""
if m.Deadline != nil && !m.Deadline.IsZero() {
deadline = FormatTime(*m.Deadline)
}
item := []string{
m.Title,
}
if state == gitea.StateAll {
item = append(item, string(m.State))
}
item = append(item,
fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues),
deadline,
)
t.addRowSlice(item)
}
t := tableFromItems(fields, printables, isMachineReadable(output))
t.sort(0, true)
t.print(output)
}
// MilestoneFields are all available fields to print with MilestonesList
var MilestoneFields = []string{
"title",
"state",
"items_open",
"items_closed",
"items",
"duedate",
"description",
"created",
"updated",
"closed",
"id",
}
type printableMilestone struct {
*gitea.Milestone
}
func (m printableMilestone) FormatField(field string, machineReadable bool) string {
switch field {
case "title":
return m.Title
case "state":
return string(m.State)
case "items_open":
return fmt.Sprintf("%d", m.OpenIssues)
case "items_closed":
return fmt.Sprintf("%d", m.ClosedIssues)
case "items":
return fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues)
case "duedate":
if m.Deadline != nil && !m.Deadline.IsZero() {
return FormatTime(*m.Deadline, machineReadable)
}
case "id":
return fmt.Sprintf("%d", m.ID)
case "description":
return m.Description
case "created":
return FormatTime(m.Created, machineReadable)
case "updated":
if m.Updated != nil {
return FormatTime(*m.Updated, machineReadable)
}
case "closed":
if m.Closed != nil {
return FormatTime(*m.Closed, machineReadable)
}
}
return ""
}

View File

@ -5,29 +5,58 @@
package print
import (
"fmt"
"strings"
"code.gitea.io/sdk/gitea"
)
// NotificationsList prints a listing of notification threads
func NotificationsList(news []*gitea.NotificationThread, output string, showRepository bool) {
headers := []string{
"Type",
"Index",
"Title",
}
if showRepository {
headers = append(headers, "Repository")
func NotificationsList(news []*gitea.NotificationThread, output string, fields []string) {
var printables = make([]printable, len(news))
for i, x := range news {
printables[i] = &printableNotification{x}
}
t := tableFromItems(fields, printables, isMachineReadable(output))
t.print(output)
}
t := table{headers: headers}
// NotificationFields are all available fields to print with NotificationsList
var NotificationFields = []string{
"id",
"status",
"updated",
for _, n := range news {
if n.Subject == nil {
continue
// these are about the notification subject
"index",
"type",
"state",
"title",
"repository",
}
type printableNotification struct {
*gitea.NotificationThread
}
func (n printableNotification) FormatField(field string, machineReadable bool) string {
switch field {
case "id":
return fmt.Sprintf("%d", n.ID)
case "status":
status := "read"
if n.Pinned {
status = "pinned"
} else if n.Unread {
status = "unread"
}
// if pull or Issue get Index
return status
case "updated":
return FormatTime(n.UpdatedAt, machineReadable)
case "index":
var index string
if n.Subject.Type == "Issue" || n.Subject.Type == "Pull" {
index = n.Subject.URL
@ -35,17 +64,20 @@ func NotificationsList(news []*gitea.NotificationThread, output string, showRepo
if len(urlParts) != 0 {
index = urlParts[len(urlParts)-1]
}
index = "#" + index
}
return index
item := []string{n.Subject.Type, index, n.Subject.Title}
if showRepository {
item = append(item, n.Repository.FullName)
}
t.addRowSlice(item)
}
case "type":
return string(n.Subject.Type)
if t.Len() != 0 {
t.print(output)
case "state":
return string(n.Subject.State)
case "title":
return n.Subject.Title
case "repo", "repository":
return n.Repository.FullName
}
return ""
}

View File

@ -10,6 +10,18 @@ import (
"code.gitea.io/sdk/gitea"
)
// OrganizationDetails prints details of an org with formatting
func OrganizationDetails(org *gitea.Organization) {
outputMarkdown(fmt.Sprintf(
"# %s\n%s\n\n- Visibility: %s\n- Location: %s\n- Website: %s\n",
org.UserName,
org.Description,
org.Visibility,
org.Location,
org.Website,
), "")
}
// OrganizationsList prints a listing of the organizations
func OrganizationsList(organizations []*gitea.Organization, output string) {
if len(organizations) == 0 {

View File

@ -6,7 +6,6 @@ package print
import (
"fmt"
"strconv"
"strings"
"code.gitea.io/sdk/gitea"
@ -23,19 +22,8 @@ var ciStatusSymbols = map[gitea.StatusState]string{
// PullDetails print an pull rendered to stdout
func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview, ciStatus *gitea.CombinedStatus) {
base := pr.Base.Name
head := pr.Head.Name
if pr.Head.RepoID != pr.Base.RepoID {
if pr.Head.Repository != nil {
head = pr.Head.Repository.Owner.UserName + ":" + head
} else {
head = "delete:" + head
}
}
state := pr.State
if pr.Merged != nil {
state = "merged"
}
head := formatPRHead(pr)
state := formatPRState(pr)
out := fmt.Sprintf(
"# #%d %s (%s)\n@%s created %s\t**%s** <- **%s**\n\n%s\n\n",
@ -43,7 +31,7 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview, ciStatus *g
pr.Title,
state,
pr.Poster.UserName,
FormatTime(*pr.Created),
FormatTime(*pr.Created, false),
base,
head,
pr.Body,
@ -76,7 +64,26 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview, ciStatus *g
}
}
outputMarkdown(out, pr.HTMLURL)
outputMarkdown(out, getRepoURL(pr.HTMLURL))
}
func formatPRHead(pr *gitea.PullRequest) string {
head := pr.Head.Name
if pr.Head.RepoID != pr.Base.RepoID {
if pr.Head.Repository != nil {
head = pr.Head.Repository.Owner.UserName + ":" + head
} else {
head = "delete:" + head
}
}
return head
}
func formatPRState(pr *gitea.PullRequest) string {
if pr.Merged != nil {
return "merged"
}
return string(pr.State)
}
func formatReviews(reviews []*gitea.PullReview) string {
@ -92,8 +99,11 @@ func formatReviews(reviews []*gitea.PullReview) string {
case gitea.ReviewStateApproved,
gitea.ReviewStateRequestChanges,
gitea.ReviewStateRequestReview:
if r, ok := reviewByUser[review.Reviewer.ID]; !ok || review.Submitted.After(r.Submitted) {
reviewByUser[review.Reviewer.ID] = review
// only user reviews are supported no team review requests
if review.Reviewer != nil {
if r, ok := reviewByUser[review.Reviewer.ID]; !ok || review.Submitted.After(r.Submitted) {
reviewByUser[review.Reviewer.ID] = review
}
}
}
}
@ -114,37 +124,120 @@ func formatReviews(reviews []*gitea.PullReview) string {
}
// PullsList prints a listing of pulls
func PullsList(prs []*gitea.PullRequest, output string) {
t := tableWithHeader(
"Index",
"Title",
"State",
"Author",
"Milestone",
"Updated",
)
func PullsList(prs []*gitea.PullRequest, output string, fields []string) {
printPulls(prs, output, fields)
}
for _, pr := range prs {
if pr == nil {
continue
// PullFields are all available fields to print with PullsList()
var PullFields = []string{
"index",
"state",
"author",
"author-id",
"url",
"title",
"body",
"mergeable",
"base",
"base-commit",
"head",
"diff",
"patch",
"created",
"updated",
"deadline",
"assignees",
"milestone",
"labels",
"comments",
}
func printPulls(pulls []*gitea.PullRequest, output string, fields []string) {
labelMap := map[int64]string{}
var printables = make([]printable, len(pulls))
machineReadable := isMachineReadable(output)
for i, x := range pulls {
// pre-serialize labels for performance
for _, label := range x.Labels {
if _, ok := labelMap[label.ID]; !ok {
labelMap[label.ID] = formatLabel(label, !machineReadable, "")
}
}
author := pr.Poster.FullName
if len(author) == 0 {
author = pr.Poster.UserName
}
mile := ""
if pr.Milestone != nil {
mile = pr.Milestone.Title
}
t.addRow(
strconv.FormatInt(pr.Index, 10),
pr.Title,
string(pr.State),
author,
mile,
FormatTime(*pr.Updated),
)
// store items with printable interface
printables[i] = &printablePull{x, &labelMap}
}
t := tableFromItems(fields, printables, machineReadable)
t.print(output)
}
type printablePull struct {
*gitea.PullRequest
formattedLabels *map[int64]string
}
func (x printablePull) FormatField(field string, machineReadable bool) string {
switch field {
case "index":
return fmt.Sprintf("%d", x.Index)
case "state":
return formatPRState(x.PullRequest)
case "author":
return formatUserName(x.Poster)
case "author-id":
return x.Poster.UserName
case "url":
return x.HTMLURL
case "title":
return x.Title
case "body":
return x.Body
case "created":
return FormatTime(*x.Created, machineReadable)
case "updated":
return FormatTime(*x.Updated, machineReadable)
case "deadline":
if x.Deadline == nil {
return ""
}
return FormatTime(*x.Deadline, machineReadable)
case "milestone":
if x.Milestone != nil {
return x.Milestone.Title
}
return ""
case "labels":
var labels = make([]string, len(x.Labels))
for i, l := range x.Labels {
labels[i] = (*x.formattedLabels)[l.ID]
}
return strings.Join(labels, " ")
case "assignees":
var assignees = make([]string, len(x.Assignees))
for i, a := range x.Assignees {
assignees[i] = formatUserName(a)
}
return strings.Join(assignees, " ")
case "comments":
return fmt.Sprintf("%d", x.Comments)
case "mergeable":
isMergeable := x.Mergeable && x.State == gitea.StateOpen
return formatBoolean(isMergeable, !machineReadable)
case "base":
return x.Base.Ref
case "base-commit":
return x.MergeBase
case "head":
return formatPRHead(x.PullRequest)
case "diff":
return x.DiffURL
case "patch":
return x.PatchURL
}
return ""
}

View File

@ -28,7 +28,7 @@ func ReleasesList(releases []*gitea.Release, output string) {
t.addRow(
release.TagName,
release.Title,
FormatTime(release.PublishedAt),
FormatTime(release.PublishedAt, isMachineReadable(output)),
status,
release.TarURL,
)

View File

@ -18,7 +18,7 @@ func ReposList(repos []*gitea.Repository, output string, fields []string) {
for i, r := range repos {
printables[i] = &printableRepo{r}
}
t := tableFromItems(fields, printables)
t := tableFromItems(fields, printables, isMachineReadable(output))
t.print(output)
}
@ -107,7 +107,7 @@ var RepoFields = []string{
type printableRepo struct{ *gitea.Repository }
func (x printableRepo) FormatField(field string) string {
func (x printableRepo) FormatField(field string, machineReadable bool) string {
switch field {
case "description":
return x.Description
@ -124,7 +124,7 @@ func (x printableRepo) FormatField(field string) string {
case "ssh":
return x.SSHURL
case "updated":
return FormatTime(x.Updated)
return FormatTime(x.Updated, machineReadable)
case "url":
return x.HTMLURL
case "permission":

View File

@ -24,16 +24,16 @@ type table struct {
// printable can be implemented for structs to put fields dynamically into a table
type printable interface {
FormatField(field string) string
FormatField(field string, machineReadable bool) string
}
// high level api to print a table of items with dynamic fields
func tableFromItems(fields []string, values []printable) table {
func tableFromItems(fields []string, values []printable, machineReadable bool) table {
t := table{headers: fields}
for _, v := range values {
row := make([]string, len(fields))
for i, f := range fields {
row[i] = v.FormatField(f)
row[i] = v.FormatField(f, machineReadable)
}
t.addRowSlice(row)
}
@ -140,7 +140,7 @@ func outputyaml(headers []string, values [][]string) {
func isMachineReadable(outputFormat string) bool {
switch outputFormat {
case "yml", "yaml", "csv":
case "yml", "yaml", "csv", "tsv":
return true
}
return false

View File

@ -18,7 +18,7 @@ func TrackedTimesList(times []*gitea.TrackedTime, outputType string, fields []st
totalDuration += t.Time
printables[i] = &printableTrackedTime{t, outputType}
}
t := tableFromItems(fields, printables)
t := tableFromItems(fields, printables, isMachineReadable(outputType))
if printTotal {
total := make([]string, len(fields))
@ -45,12 +45,12 @@ type printableTrackedTime struct {
outputFormat string
}
func (t printableTrackedTime) FormatField(field string) string {
func (t printableTrackedTime) FormatField(field string, machineReadable bool) string {
switch field {
case "id":
return fmt.Sprintf("%d", t.ID)
case "created":
return FormatTime(t.Created)
return FormatTime(t.Created, machineReadable)
case "repo":
return t.Issue.Repository.FullName
case "issue":

135
modules/print/user.go Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package print
import (
"fmt"
"code.gitea.io/sdk/gitea"
)
// UserDetails print a formatted user to stdout
func UserDetails(user *gitea.User) {
title := "# " + user.UserName
if user.IsAdmin {
title += " (admin)"
}
if !user.IsActive {
title += " (disabled)"
}
if user.Restricted {
title += " (restricted)"
}
if user.ProhibitLogin {
title += " (login prohibited)"
}
title += "\n"
var desc string
if len(user.Description) != 0 {
desc = fmt.Sprintf("*%s*\n\n", user.Description)
}
var website string
if len(user.Website) != 0 {
website = fmt.Sprintf("%s\n\n", user.Website)
}
stats := fmt.Sprintf(
"Follower Count: %d, Following Count: %d, Starred Repos: %d\n",
user.FollowerCount,
user.FollowingCount,
user.StarredRepoCount,
)
outputMarkdown(fmt.Sprintf(
"%s%s\n%s\n%s",
title,
desc,
website,
stats,
), "")
}
// UserList prints a listing of the users
func UserList(user []*gitea.User, output string, fields []string) {
var printables = make([]printable, len(user))
for i, u := range user {
printables[i] = &printableUser{u}
}
t := tableFromItems(fields, printables, isMachineReadable(output))
t.print(output)
}
// UserFields are the available fields to print with UserList()
var UserFields = []string{
"id",
"login",
"full_name",
"email",
"avatar_url",
"language",
"is_admin",
"restricted",
"prohibit_login",
"location",
"website",
"description",
"visibility",
"activated",
"lastlogin_at",
"created_at",
}
type printableUser struct{ *gitea.User }
func (x printableUser) FormatField(field string, machineReadable bool) string {
switch field {
case "id":
return fmt.Sprintf("%d", x.ID)
case "login":
if x.IsAdmin {
return fmt.Sprintf("%s (admin)", x.UserName)
}
if !x.IsActive {
return fmt.Sprintf("%s (disabled)", x.UserName)
}
if x.Restricted {
return fmt.Sprintf("%s (restricted)", x.UserName)
}
if x.ProhibitLogin {
return fmt.Sprintf("%s (login prohibited)", x.UserName)
}
return x.UserName
case "full_name":
return x.FullName
case "email":
return x.Email
case "avatar_url":
return x.AvatarURL
case "language":
return x.Language
case "is_admin":
return formatBoolean(x.IsAdmin, !machineReadable)
case "restricted":
return formatBoolean(x.Restricted, !machineReadable)
case "prohibit_login":
return formatBoolean(x.ProhibitLogin, !machineReadable)
case "activated":
return formatBoolean(x.IsActive, !machineReadable)
case "location":
return x.Location
case "website":
return x.Website
case "description":
return x.Description
case "visibility":
return string(x.Visibility)
case "created_at":
return FormatTime(x.Created, machineReadable)
case "lastlogin_at":
return FormatTime(x.LastLogin, machineReadable)
}
return ""
}

View File

@ -25,7 +25,7 @@ func CreateIssue(login *config.Login, repoOwner, repoName string, opts gitea.Cre
return fmt.Errorf("could not create issue: %s", err)
}
print.IssueDetails(issue)
print.IssueDetails(issue, nil)
fmt.Println(issue.HTMLURL)

View File

@ -12,7 +12,9 @@ import (
// ResolveLabelNames returns a list of label IDs for a given list of label names
func ResolveLabelNames(client *gitea.Client, owner, repo string, labelNames []string) ([]int64, error) {
labelIDs := make([]int64, len(labelNames))
labels, _, err := client.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{})
labels, _, err := client.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil {
return nil, err
}

View File

@ -56,14 +56,14 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
Created: time.Now().Unix(),
}
client := login.Client()
if len(token) == 0 {
if login.Token, err = generateToken(client, user, passwd); err != nil {
if login.Token, err = generateToken(login, user, passwd); err != nil {
return err
}
}
client := login.Client()
// Verify if authentication works and get user info
u, _, err := client.GetMyUserInfo()
if err != nil {
@ -98,16 +98,19 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
}
// generateToken creates a new token when given BasicAuth credentials
func generateToken(client *gitea.Client, user, pass string) (string, error) {
gitea.SetBasicAuth(user, pass)(client)
func generateToken(login config.Login, user, pass string) (string, error) {
client := login.Client(gitea.SetBasicAuth(user, pass))
host, _ := os.Hostname()
tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{})
tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil {
return "", err
}
host, _ := os.Hostname()
tokenName := host + "-tea"
// append timestamp, if a token with this hostname already exists
for i := range tl {
if tl[i].Name == tokenName {
tokenName += time.Now().Format("2006-01-02_15-04-05")

View File

@ -20,7 +20,9 @@ import (
// a matching private key in ~/.ssh/. If no match is found, path is empty.
func findSSHKey(client *gitea.Client) (string, error) {
// get keys registered on gitea instance
keys, _, err := client.ListMyPublicKeys(gitea.ListPublicKeysOptions{})
keys, _, err := client.ListMyPublicKeys(gitea.ListPublicKeysOptions{
ListOptions: gitea.ListOptions{Page: -1},
})
if err != nil || len(keys) == 0 {
return "", err
}

View File

@ -28,7 +28,7 @@ func PullCheckout(
client := login.Client()
pr, _, err := client.GetPullRequest(repoOwner, repoName, index)
if err != nil {
return err
return fmt.Errorf("couldn't fetch PR: %s", err)
}
if err := workaround.FixPullHeadSha(client, pr); err != nil {
return err

View File

@ -10,22 +10,17 @@ import (
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/config"
"code.gitea.io/tea/modules/context"
local_git "code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/print"
"code.gitea.io/tea/modules/utils"
)
// CreatePull creates a PR in the given repo and prints the result
func CreatePull(login *config.Login, repoOwner, repoName, base, head string, opts *gitea.CreateIssueOption) error {
// open local git repo
localRepo, err := local_git.RepoForWorkdir()
if err != nil {
return fmt.Errorf("Could not open local repo: %s", err)
}
func CreatePull(ctx *context.TeaContext, base, head string, opts *gitea.CreateIssueOption) (err error) {
// default is default branch
if len(base) == 0 {
base, err = GetDefaultPRBase(login, repoOwner, repoName)
base, err = GetDefaultPRBase(ctx.Login, ctx.Owner, ctx.Repo)
if err != nil {
return err
}
@ -33,12 +28,15 @@ func CreatePull(login *config.Login, repoOwner, repoName, base, head string, opt
// default is current one
if len(head) == 0 {
headOwner, headBranch, err := GetDefaultPRHead(localRepo)
if ctx.LocalRepo == nil {
return fmt.Errorf("no local git repo detected, please specify head branch")
}
headOwner, headBranch, err := GetDefaultPRHead(ctx.LocalRepo)
if err != nil {
return err
}
head = GetHeadSpec(headOwner, headBranch, repoOwner)
head = GetHeadSpec(headOwner, headBranch, ctx.Owner)
}
// head & base may not be the same
@ -52,10 +50,10 @@ func CreatePull(login *config.Login, repoOwner, repoName, base, head string, opt
}
// title is required
if len(opts.Title) == 0 {
return fmt.Errorf("Title is required")
return fmt.Errorf("title is required")
}
pr, _, err := login.Client().CreatePullRequest(repoOwner, repoName, gitea.CreatePullRequestOption{
pr, _, err := ctx.Login.Client().CreatePullRequest(ctx.Owner, ctx.Repo, gitea.CreatePullRequestOption{
Head: head,
Base: base,
Title: opts.Title,
@ -67,7 +65,7 @@ func CreatePull(login *config.Login, repoOwner, repoName, base, head string, opt
})
if err != nil {
return fmt.Errorf("Could not create PR from %s to %s:%s: %s", head, repoOwner, base, err)
return fmt.Errorf("could not create PR from %s to %s:%s: %s", head, ctx.Owner, base, err)
}
print.PullDetails(pr, nil, nil)
@ -110,7 +108,7 @@ func GetDefaultPRHead(localRepo *local_git.TeaRepo) (owner, branch string, err e
if err != nil {
return
}
owner, _ = utils.GetOwnerAndRepo(strings.TrimLeft(url.Path, "/"), "")
owner, _ = utils.GetOwnerAndRepo(url.Path, "")
return
}

View File

@ -49,7 +49,7 @@ func CreatePullReview(ctx *context.TeaContext, idx int64, status gitea.ReviewSta
// SavePullDiff fetches the diff of a pull request and stores it as a temporary file.
// The path to the file is returned.
func SavePullDiff(ctx *context.TeaContext, idx int64) (string, error) {
diff, _, err := ctx.Login.Client().GetPullRequestDiff(ctx.Owner, ctx.Repo, idx)
diff, _, err := ctx.Login.Client().GetPullRequestDiff(ctx.Owner, ctx.Repo, idx, gitea.PullRequestDiffOptions{})
if err != nil {
return "", err
}
@ -107,10 +107,13 @@ func ParseDiffComments(diffFile string) ([]gitea.CreatePullReviewComment, error)
// OpenFileInEditor opens filename in a text editor, and blocks until the editor terminates.
func OpenFileInEditor(filename string) error {
editor := os.Getenv("EDITOR")
editor := os.Getenv("VISUAL")
if editor == "" {
fmt.Println("No $EDITOR env is set, defaulting to vim")
editor = "vim"
editor = os.Getenv("EDITOR")
if editor == "" {
fmt.Println("No $VISUAL or $EDITOR env is set, defaulting to vim")
editor = "vi"
}
}
// Get the full executable path for the editor.

View File

@ -0,0 +1,93 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package task
import (
"fmt"
"net/url"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/modules/config"
local_git "code.gitea.io/tea/modules/git"
"github.com/go-git/go-git/v5"
git_config "github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
)
// RepoClone creates a local git clone in the given path, and sets up upstream remote
// for fork repos, for good usability with tea.
func RepoClone(
path string,
login *config.Login,
repoOwner, repoName string,
callback func(string) (string, error),
depth int,
) (*local_git.TeaRepo, error) {
repoMeta, _, err := login.Client().GetRepo(repoOwner, repoName)
if err != nil {
return nil, err
}
originURL, err := cloneURL(repoMeta, login)
if err != nil {
return nil, err
}
auth, err := local_git.GetAuthForURL(originURL, login.Token, login.SSHKey, callback)
if err != nil {
return nil, err
}
// default path behaviour as native git
if path == "" {
path = repoName
}
repo, err := git.PlainClone(path, false, &git.CloneOptions{
URL: originURL.String(),
Auth: auth,
Depth: depth,
InsecureSkipTLS: login.Insecure,
})
if err != nil {
return nil, err
}
// set up upstream remote for forks
if repoMeta.Fork && repoMeta.Parent != nil {
upstreamURL, err := cloneURL(repoMeta.Parent, login)
if err != nil {
return nil, err
}
upstreamBranch := repoMeta.Parent.DefaultBranch
repo.CreateRemote(&git_config.RemoteConfig{
Name: "upstream",
URLs: []string{upstreamURL.String()},
})
repoConf, err := repo.Config()
if err != nil {
return nil, err
}
if b, ok := repoConf.Branches[upstreamBranch]; ok {
b.Remote = "upstream"
b.Merge = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", upstreamBranch))
}
if err = repo.SetConfig(repoConf); err != nil {
return nil, err
}
}
return &local_git.TeaRepo{Repository: repo}, nil
}
func cloneURL(repo *gitea.Repository, login *config.Login) (*url.URL, error) {
urlStr := repo.CloneURL
if login.SSHKey != "" {
urlStr = repo.SSHURL
}
return local_git.ParseURL(urlStr)
}

View File

@ -33,7 +33,7 @@ func GetOwnerAndRepo(repoPath, user string) (string, string) {
if len(repoPath) == 0 {
return "", ""
}
p := strings.Split(repoPath, "/")
p := strings.Split(strings.TrimLeft(repoPath, "/"), "/")
if len(p) >= 2 {
return p[0], p[1]
}

View File

@ -1,30 +0,0 @@
# The full repository name
repo: gitea/gitea-vet
# Service type (gitea or github)
service: gitea
# Base URL for Gitea instance if using gitea service type (optional)
base-url: https://gitea.com
# Changelog groups and which labeled PRs to add to each group
groups:
-
name: BREAKING
labels:
- breaking
-
name: FEATURES
labels:
- feature
-
name: BUGFIXES
labels:
- bug
-
name: ENHANCEMENTS
labels:
- enhancement
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+

View File

@ -1,45 +0,0 @@
---
kind: pipeline
name: compliance
platform:
os: linux
arch: arm64
trigger:
event:
- pull_request
steps:
- name: check
pull: always
image: golang:1.14
environment:
GOPROXY: https://goproxy.cn
commands:
- make build
- make lint
- make vet
---
kind: pipeline
name: build-master
platform:
os: linux
arch: amd64
trigger:
branch:
- master
event:
- push
steps:
- name: build
pull: always
image: techknowlogick/xgo:latest
environment:
GOPROXY: https://goproxy.cn
commands:
- make build

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