mirror of
https://gitea.com/gitea/tea.git
synced 2026-07-16 11:07:39 +02:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 989651408e | |||
| 7f0213940d | |||
| 3b5703177d | |||
| 2a9c8ff6fd | |||
| 12947f068a | |||
| d4545d8ed7 | |||
| 885381e3e4 | |||
| 6a57af24ad | |||
| 88f5cdcafa | |||
| 5cfee362c8 | |||
| fff82ac723 | |||
| b11d991d1e | |||
| 4b209d68de | |||
| 2b844786f0 | |||
| 67bb0e7789 | |||
| 6de58b2223 | |||
| 27bcbf80ae | |||
| dfbbda83f3 | |||
| df320c74ca | |||
| 09fc09c2f7 | |||
| 5fa24b9a65 | |||
| 18274f1ebc | |||
| d1b9b7735e | |||
| 6dd33b5f4f | |||
| 23a3967e15 | |||
| 06e4d16bf3 | |||
| 28ba9b915b | |||
| 579099f9d9 | |||
| a664449282 | |||
| 8e0666ab85 | |||
| bbe97a5e23 | |||
| 82323c7270 | |||
| 861201541d | |||
| 3d667c1594 | |||
| ef0dc62dd6 | |||
| 70c7ee11f2 | |||
| 6134351048 | |||
| 8be4dae66e | |||
| b8dcb8a442 | |||
| 01632d927e | |||
| 1b79be7cea | |||
| 2cc45f1cce | |||
| 2b64762a32 | |||
| 19dd8b1b4b | |||
| f617f26da0 | |||
| a5ecf06c2a | |||
| e686e8d0bd | |||
| 22ff601988 | |||
| 9d6ae4bf02 | |||
| 2985824ab0 | |||
| 83b718ac34 | |||
| 1f6fd97fc1 | |||
| 27e6083e23 | |||
| 5d2d1a6e0c | |||
| 88421bb888 | |||
| dd81b33cec | |||
| b100d4c939 | |||
| 892905d482 | |||
| 5103496232 | |||
| a58c35c3e2 | |||
| 783ac7684a | |||
| d0b7ea09e8 | |||
| 20914a1375 | |||
| 3c1c9b2904 |
@@ -8,7 +8,7 @@ jobs:
|
|||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: git fetch --force --tags
|
- run: git fetch --force --tags
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||||
- name: get SDK version
|
- name: get SDK version
|
||||||
id: sdk_version
|
id: sdk_version
|
||||||
run: echo "version=$(go list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)" >> "$GITHUB_OUTPUT"
|
run: echo "version=$(go list -f '{{.Version}}' -m gitea.dev/sdk)" >> "$GITHUB_OUTPUT"
|
||||||
- name: goreleaser
|
- name: goreleaser
|
||||||
uses: goreleaser/goreleaser-action@v7
|
uses: goreleaser/goreleaser-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
DOCKER_LATEST: nightly
|
DOCKER_LATEST: nightly
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # all history for all branches and tags
|
fetch-depth: 0 # all history for all branches and tags
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: git fetch --force --tags
|
- run: git fetch --force --tags
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||||
- name: get SDK version
|
- name: get SDK version
|
||||||
id: sdk_version
|
id: sdk_version
|
||||||
run: echo "version=$(go list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)" >> "$GITHUB_OUTPUT"
|
run: echo "version=$(go list -f '{{.Version}}' -m gitea.dev/sdk)" >> "$GITHUB_OUTPUT"
|
||||||
- name: goreleaser
|
- name: goreleaser
|
||||||
uses: goreleaser/goreleaser-action@v7
|
uses: goreleaser/goreleaser-action@v7
|
||||||
with:
|
with:
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
DOCKER_LATEST: nightly
|
DOCKER_LATEST: nightly
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # all history for all branches and tags
|
fetch-depth: 0 # all history for all branches and tags
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,11 @@ jobs:
|
|||||||
# uses: golang/govulncheck-action@v1
|
# uses: golang/govulncheck-action@v1
|
||||||
# with:
|
# with:
|
||||||
# go-version-file: 'go.mod'
|
# go-version-file: 'go.mod'
|
||||||
check-and-test:
|
check-and-unit:
|
||||||
|
name: Lint Build And Unit Coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
HTTP_PROXY: ""
|
|
||||||
GITEA_TEA_TEST_URL: "http://gitea:3000"
|
|
||||||
GITEA_TEA_TEST_USERNAME: "test01"
|
|
||||||
GITEA_TEA_TEST_PASSWORD: "test01"
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
@@ -32,14 +28,30 @@ jobs:
|
|||||||
make fmt-check
|
make fmt-check
|
||||||
make docs-check
|
make docs-check
|
||||||
make build
|
make build
|
||||||
- run: curl --noproxy "*" http://gitea:3000/api/v1/version # verify connection to instance
|
- name: unit test and coverage
|
||||||
- name: test and coverage
|
|
||||||
run: |
|
run: |
|
||||||
make test
|
|
||||||
make unit-test-coverage
|
make unit-test-coverage
|
||||||
|
|
||||||
|
integration-test:
|
||||||
|
name: Integration Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
HTTP_PROXY: ""
|
||||||
|
GITEA_TEA_TEST_URL: "http://gitea:3000"
|
||||||
|
GITEA_TEA_TEST_USERNAME: "test01"
|
||||||
|
GITEA_TEA_TEST_PASSWORD: "test01"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
- run: curl --noproxy "*" http://gitea:3000/api/v1/version # verify connection to instance
|
||||||
|
- name: integration test
|
||||||
|
run: |
|
||||||
|
make integration-test
|
||||||
services:
|
services:
|
||||||
gitea:
|
gitea:
|
||||||
image: docker.gitea.com/gitea:1.25.5
|
image: docker.gitea.com/gitea:1.26.2
|
||||||
cmd:
|
cmd:
|
||||||
- bash
|
- bash
|
||||||
- -c
|
- -c
|
||||||
|
|||||||
@@ -17,3 +17,5 @@ dist/
|
|||||||
.direnv/
|
.direnv/
|
||||||
result
|
result
|
||||||
result-*
|
result-*
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
+1
-1
@@ -56,7 +56,7 @@ builds:
|
|||||||
flags:
|
flags:
|
||||||
- -trimpath
|
- -trimpath
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w -X "code.gitea.io/tea/modules/version.Version={{ trimprefix .Summary "v" }}" -X "code.gitea.io/tea/modules/version.Tags=" -X "code.gitea.io/tea/modules/version.SDK={{ .Env.SDK_VERSION }}"
|
- -s -w -X "gitea.dev/tea/modules/version.Version={{ trimprefix .Summary "v" }}" -X "gitea.dev/tea/modules/version.Tags=" -X "gitea.dev/tea/modules/version.SDK={{ .Env.SDK_VERSION }}"
|
||||||
binary: >-
|
binary: >-
|
||||||
{{ .ProjectName }}-
|
{{ .ProjectName }}-
|
||||||
{{- .Version }}-
|
{{- .Version }}-
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ import (
|
|||||||
|
|
||||||
// local packages
|
// local packages
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/sdk/gitea"
|
"gitea.dev/sdk"
|
||||||
|
|
||||||
// external packages
|
// external packages
|
||||||
"github.com/foo/bar"
|
"github.com/foo/bar"
|
||||||
|
|||||||
@@ -24,13 +24,17 @@ endif
|
|||||||
TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION))
|
TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION))
|
||||||
|
|
||||||
TAGS ?=
|
TAGS ?=
|
||||||
SDK ?= $(shell $(GO) list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)
|
SDK ?= $(shell $(GO) list -f '{{.Version}}' -m gitea.dev/sdk)
|
||||||
LDFLAGS := -X "code.gitea.io/tea/modules/version.Version=$(TEA_VERSION)" -X "code.gitea.io/tea/modules/version.Tags=$(TAGS)" -X "code.gitea.io/tea/modules/version.SDK=$(SDK)" -s -w
|
LDFLAGS := -X "gitea.dev/tea/modules/version.Version=$(TEA_VERSION)" -X "gitea.dev/tea/modules/version.Tags=$(TAGS)" -X "gitea.dev/tea/modules/version.SDK=$(SDK)" -s -w
|
||||||
|
|
||||||
# override to allow passing additional goflags via make CLI
|
# override to allow passing additional goflags via make CLI
|
||||||
override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
||||||
|
|
||||||
PACKAGES ?= $(shell $(GO) list ./...)
|
PACKAGES ?= $(shell $(GO) list ./... | grep -v '^gitea.dev/tea/tests')
|
||||||
|
UNIT_PACKAGES ?= $(PACKAGES)
|
||||||
|
INTEGRATION_PACKAGES ?= $(shell $(GO) list ./tests/... 2>/dev/null)
|
||||||
|
INTEGRATION_TEST_TAGS ?= testtools
|
||||||
|
INTEGRATION_TEST_GOFLAGS ?= -v
|
||||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||||
|
|
||||||
# OS specific vars.
|
# OS specific vars.
|
||||||
@@ -64,11 +68,11 @@ vet:
|
|||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint:
|
lint:
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --build-tags testtools
|
||||||
|
|
||||||
.PHONY: lint-fix
|
.PHONY: lint-fix
|
||||||
lint-fix:
|
lint-fix:
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --build-tags testtools --fix
|
||||||
|
|
||||||
.PHONY: fmt-check
|
.PHONY: fmt-check
|
||||||
fmt-check:
|
fmt-check:
|
||||||
@@ -93,13 +97,24 @@ docs-check:
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
.PHONY: unit-test
|
||||||
|
unit-test:
|
||||||
|
$(GO) test $(UNIT_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: integration-test
|
||||||
|
integration-test:
|
||||||
|
@if [ -n "$(INTEGRATION_PACKAGES)" ]; then \
|
||||||
|
$(GO) test $(INTEGRATION_TEST_GOFLAGS) -tags='$(INTEGRATION_TEST_TAGS)' $(INTEGRATION_PACKAGES); \
|
||||||
|
else \
|
||||||
|
echo "No integration test packages found"; \
|
||||||
|
fi
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test: unit-test integration-test
|
||||||
$(GO) test -tags='sqlite sqlite_unlock_notify' $(PACKAGES)
|
|
||||||
|
|
||||||
.PHONY: unit-test-coverage
|
.PHONY: unit-test-coverage
|
||||||
unit-test-coverage:
|
unit-test-coverage:
|
||||||
$(GO) test -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
$(GO) test -cover -coverprofile coverage.out $(UNIT_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||||
|
|
||||||
.PHONY: tidy
|
.PHONY: tidy
|
||||||
tidy:
|
tidy:
|
||||||
@@ -122,4 +137,3 @@ $(EXECUTABLE): $(SOURCES)
|
|||||||
.PHONY: build-image
|
.PHONY: build-image
|
||||||
build-image:
|
build-image:
|
||||||
docker build --build-arg VERSION=$(TEA_VERSION) -t gitea/tea:$(TEA_VERSION_TAG) .
|
docker build --build-arg VERSION=$(TEA_VERSION) -t gitea/tea:$(TEA_VERSION_TAG) .
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://gitea.com/gitea/tea/releases)
|
[](https://gitea.com/gitea/tea/releases)
|
||||||
[](https://discord.gg/Gitea)
|
[](https://discord.gg/Gitea)
|
||||||
[](https://goreportcard.com/report/code.gitea.io/tea) [](https://godoc.org/code.gitea.io/tea)
|
[](https://goreportcard.com/report/gitea.dev/tea) [](https://godoc.org/gitea.dev/tea)
|
||||||

|

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