mirror of
https://gitea.com/gitea/tea.git
synced 2025-09-19 02:02:55 +02:00
Compare commits
259 Commits
Author | SHA1 | Date | |
---|---|---|---|
6acb29efd7 | |||
4f513ca3e3 | |||
cc20b52ab3 | |||
2ca114e309 | |||
45771265c4 | |||
8faa1d33f4 | |||
ddf5c0a5bb | |||
d3c73cd5dc | |||
6c958eec99 | |||
d531c6fdb0 | |||
cd58296995 | |||
b74405530a | |||
8876fe3cb8 | |||
07ca1ba106 | |||
d643e94a69 | |||
d2ccead88b | |||
449b2e3117 | |||
9e8c71e13e | |||
2ddb3bd4a1 | |||
4c00b8b571 | |||
c0eb30af03 | |||
e462acfcd6 | |||
ee111d7c12 | |||
5f35cebcf1 | |||
a010c9bc7f | |||
ab4ad92d40 | |||
15052b4dcc | |||
8212d5f527 | |||
d536242aa9 | |||
ffff540aa7 | |||
f09d6ca46b | |||
0e54bae0c4 | |||
5420af1dfa | |||
177b7397f3 | |||
11ec662434 | |||
8b1601c955 | |||
213f976dcf | |||
59b35fecfe | |||
d4887f6b9d | |||
c5f398dcd2 | |||
9cb0d8baa1 | |||
662d441e3a | |||
894646a83c | |||
4adc925aa1 | |||
affef1980e | |||
6efa25d0f7 | |||
2e389349e1 | |||
2f9bc0f8d9 | |||
2e4422577b | |||
1ea89f3409 | |||
d2c9df3b17 | |||
21ede75fee | |||
d633e3018d | |||
3447e0b6ab | |||
1681af8a3e | |||
62dc1dde95 | |||
e82dd9e08d | |||
9785f6acf7 | |||
5d78e27542 | |||
e2c199fcd5 | |||
9888ca69b2 | |||
57e3400f0f | |||
60636cd7d8 | |||
47ee397110 | |||
b4655aefc4 | |||
aba2dadcfd | |||
c2ddda6800 | |||
fe1928679a | |||
681e665a59 | |||
72790aa50a | |||
1c24e199f7 | |||
8efa1aaf1f | |||
bc29fa5c9c | |||
f3fe2a0532 | |||
54b3f8e5b2 | |||
4e0fab6e7f | |||
6f924df8ac | |||
66927f8972 | |||
9de3fc8667 | |||
2fb291c6d4 | |||
637b7ea010 | |||
f1cad9dbb1 | |||
f2955a468e | |||
54c198cc84 | |||
3447be6a68 | |||
88628368f6 | |||
768a6fd844 | |||
eb204541f9 | |||
a9293e2f8b | |||
3cef822f22 | |||
f9a08f8d3b | |||
10e53345ed | |||
09aed015f2 | |||
b7191bf6e9 | |||
2984ad4964 | |||
a35bf931ae | |||
edf9f23390 | |||
0297738b33 | |||
1983c3bbd9 | |||
d289c290bb | |||
100c5a9eee | |||
4ba3139224 | |||
dd80463cf5 | |||
93480ac98e | |||
f7e2c6f89b | |||
493b29afbf | |||
723b0553c5 | |||
4c0cef090d | |||
20479663f0 | |||
22370698bf | |||
6d5e8d3b58 | |||
18abf24dca | |||
7cb6a84098 | |||
7e700e36f8 | |||
61bdc14184 | |||
16b37cc6da | |||
b5d7119ab4 | |||
610d04fc85 | |||
6696e945c6 | |||
5158adbcf2 | |||
6e473ec601 | |||
115f25e85f | |||
656d48ec8d | |||
2cb450401c | |||
5236a89d4c | |||
48d2997a63 | |||
75a7d4b7cc | |||
1e3043ce6f | |||
218b991069 | |||
16a3594474 | |||
b1b31da7c8 | |||
36672485d1 | |||
4fedaaafe1 | |||
6ae3718574 | |||
c4f6231c49 | |||
76f7f901fc | |||
005beca233 | |||
e62713f42a | |||
c8c8e9758b | |||
d15af88f83 | |||
c74177556b | |||
02836d8e52 | |||
b8ad55117a | |||
fb4eb8be9c | |||
81b784d7a5 | |||
649b0b1272 | |||
3c9552c531 | |||
f28ddccd90 | |||
5beb5bf56b | |||
17e09a3c2d | |||
58962cbb65 | |||
7029e7e8c5 | |||
3e8047dfe6 | |||
897dc50bfe | |||
2f1ca85b25 | |||
e6a6aa6f49 | |||
bcda543bb8 | |||
9e5db56dcf | |||
92d49e383d | |||
2a666c84cb | |||
32b9f5e836 | |||
33442fd05f | |||
f2cf5b7979 | |||
d80c8ceffd | |||
e3b4d68af7 | |||
0df93dd47a | |||
66b4decdd1 | |||
9e1919ec0a | |||
615cd31eb2 | |||
b868d30434 | |||
2d57e07dc7 | |||
3343fedc17 | |||
f9c67f35a6 | |||
dd8d7fb30f | |||
17453fd7cb | |||
fe4551142a | |||
10bd00d066 | |||
0869c15a6c | |||
e4e8eb07d2 | |||
620f236723 | |||
77837e909e | |||
5582f92df4 | |||
c72c6c0679 | |||
b2d845b8c7 | |||
07039b82e3 | |||
7040c350ae | |||
b02263adb0 | |||
4915862b95 | |||
cd6a7b35c3 | |||
abcaa58312 | |||
d9da952e96 | |||
7f335a2b9c | |||
b510756438 | |||
3640bbac5e | |||
b705188599 | |||
cfce25f0a7 | |||
e783f4ea4a | |||
342b573d45 | |||
1a6d9b343a | |||
faa9858a7e | |||
e51eb1a00e | |||
6a848cb72a | |||
2a8c1daa67 | |||
54b535a527 | |||
c1c7870ceb | |||
a37377d181 | |||
15457f1770 | |||
4487213581 | |||
6a4ba6a689 | |||
4ee5ce4b52 | |||
6c9b2f8745 | |||
1a256291dc | |||
832136b6d4 | |||
99e49991bb | |||
bbb287e29e | |||
5e7c702e07 | |||
b8dbf899d2 | |||
0b8be54186 | |||
2b1bca9e5d | |||
d5a258213d | |||
f83f579dea | |||
65535bd948 | |||
02f5f15269 | |||
883a27b14e | |||
e54b32493d | |||
329200b1ef | |||
6663d9f19b | |||
d06f35482e | |||
9ab36c55fa | |||
40e606561f | |||
0970b94552 | |||
dda94a5dea | |||
16ba594a28 | |||
d8f4273ed0 | |||
637e3f0666 | |||
ced24ccabb | |||
fb3e1f75e9 | |||
0e24009fe9 | |||
cd24fd8e28 | |||
dd300c1269 | |||
44c9e7e664 | |||
268aa06179 | |||
a7d83ee416 | |||
a89f51f9ec | |||
d2295828d0 | |||
dc16643e0d | |||
ac25e89ebf | |||
819cc1ab21 | |||
78a95f1ca4 | |||
5b77345b03 | |||
23ce7b351d | |||
375ece06d2 | |||
4ffd994549 | |||
58aaa17e7e | |||
7a05be436c | |||
3cf084cb96 | |||
1e59dee685 | |||
42e423470c | |||
555f1ae516 |
20
.devcontainer/devcontainer.json
Normal file
20
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Tea DevContainer",
|
||||
"image": "mcr.microsoft.com/devcontainers/go:1.24-bullseye",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/git-lfs:1.2.5": {}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {},
|
||||
"extensions": [
|
||||
"editorconfig.editorconfig",
|
||||
"golang.go",
|
||||
"stylelint.vscode-stylelint",
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"GitHub.vscode-pull-request-github"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
Dockerfile
|
||||
tea
|
189
.drone.yml
189
.drone.yml
@ -1,189 +0,0 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
pull: always
|
||||
image: golang:1.16
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
commands:
|
||||
- make clean
|
||||
- make vet
|
||||
- make lint
|
||||
- make fmt-check
|
||||
- make misspell-check
|
||||
- make test-vendor
|
||||
- make build
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
|
||||
- name: unit-test
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make unit-test-coverage
|
||||
settings:
|
||||
group: test
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: release-test
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make test
|
||||
settings:
|
||||
group: test
|
||||
when:
|
||||
branch:
|
||||
- "release/*"
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: tag-test
|
||||
pull: always
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make test
|
||||
settings:
|
||||
group: test
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: static
|
||||
image: golang:1.16
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
commands:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
- name: gpg-sign
|
||||
pull: always
|
||||
image: plugins/gpgsign:1
|
||||
settings:
|
||||
detach_sign: true
|
||||
excludes:
|
||||
- "dist/release/*.sha256"
|
||||
files:
|
||||
- "dist/release/*"
|
||||
environment:
|
||||
GPGSIGN_KEY:
|
||||
from_secret: gpgsign_key
|
||||
GPGSIGN_PASSPHRASE:
|
||||
from_secret: gpgsign_passphrase
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
- name: tag-release
|
||||
pull: always
|
||||
image: plugins/s3:1
|
||||
settings:
|
||||
acl: public-read
|
||||
bucket: gitea-artifacts
|
||||
endpoint: https://storage.gitea.io
|
||||
path_style: true
|
||||
source: "dist/release/*"
|
||||
strip_prefix: dist/release/
|
||||
target: "/tea/${DRONE_TAG##v}"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: aws_secret_access_key
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: release-branch-release
|
||||
pull: always
|
||||
image: plugins/s3:1
|
||||
settings:
|
||||
acl: public-read
|
||||
bucket: gitea-artifacts
|
||||
endpoint: https://storage.gitea.io
|
||||
path_style: true
|
||||
source: "dist/release/*"
|
||||
strip_prefix: dist/release/
|
||||
target: "/tea/${DRONE_BRANCH##release/v}"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: aws_secret_access_key
|
||||
when:
|
||||
branch:
|
||||
- "release/*"
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: release
|
||||
pull: always
|
||||
image: plugins/s3:1
|
||||
settings:
|
||||
acl: public-read
|
||||
bucket: gitea-artifacts
|
||||
endpoint: https://storage.gitea.io
|
||||
path_style: true
|
||||
source: "dist/release/*"
|
||||
strip_prefix: dist/release/
|
||||
target: /tea/master
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: aws_secret_access_key
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: gitea
|
||||
pull: always
|
||||
image: plugins/gitea-release:1
|
||||
settings:
|
||||
files:
|
||||
- "dist/release/*"
|
||||
base_url: https://gitea.com
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: discord
|
||||
pull: always
|
||||
image: appleboy/drone-discord:1.0.0
|
||||
environment:
|
||||
DISCORD_WEBHOOK_ID:
|
||||
from_secret: discord_webhook_id
|
||||
DISCORD_WEBHOOK_TOKEN:
|
||||
from_secret: discord_webhook_token
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
- pull_request
|
||||
status:
|
||||
- changed
|
||||
- failure
|
30
.gitea/issue_template/bug.md
Normal file
30
.gitea/issue_template/bug.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
name: "Bug Report"
|
||||
about: "Use this template when reporting a bug, so you don't forget important information we'd ask for later."
|
||||
title: "Bug: "
|
||||
labels:
|
||||
- kind/bug
|
||||
---
|
||||
|
||||
### describe your environment
|
||||
- tea version used (`tea -v`):
|
||||
- [ ] I also reproduced the issue [with the latest main build](https://dl.gitea.com/tea/main/)
|
||||
- Gitea version used:
|
||||
- [ ] the issue only occurred after updating gitea recently
|
||||
- operating system:
|
||||
- I make use of...
|
||||
- [ ] non-standard default branch names (no `main`,`master`, or `trunk`)
|
||||
- [ ] .ssh/config or .gitconfig host aliases in my git remotes
|
||||
- [ ] ssh_agent or similar
|
||||
- [ ] non-standard ports for gitea and/or ssh
|
||||
- [ ] something else that's likely to interact badly with tea: ...
|
||||
|
||||
|
||||
Please provide the output of `git remote -v` (if the issue is related to tea not finding resources on Gitea):
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
### describe the issue (observed vs expected behaviour)
|
||||
|
||||
|
76
.gitea/workflows/release-nightly.yml
Normal file
76
.gitea/workflows/release-nightly.yml
Normal file
@ -0,0 +1,76 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
- name: import gpg
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||
- name: goreleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
version: "~> v1"
|
||||
args: release --nightly
|
||||
env:
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.AWS_BUCKET }}
|
||||
GORELEASER_FORCE_TOKEN: 'gitea'
|
||||
GPGSIGN_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
release-image:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_ORG: gitea
|
||||
DOCKER_LATEST: nightly
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker BuildX
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
env:
|
||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gitea/tea:latest
|
81
.gitea/workflows/release-tag.yml
Normal file
81
.gitea/workflows/release-tag.yml
Normal file
@ -0,0 +1,81 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
- name: import gpg
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||
- name: goreleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
version: "~> v1"
|
||||
args: release
|
||||
env:
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.AWS_BUCKET }}
|
||||
GORELEASER_FORCE_TOKEN: 'gitea'
|
||||
GPGSIGN_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
release-image:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_ORG: gitea
|
||||
DOCKER_LATEST: nightly
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker BuildX
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Get tag version without v
|
||||
id: get_version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
env:
|
||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gitea/tea:${{ env.VERSION }}
|
64
.gitea/workflows/test-pr.yml
Normal file
64
.gitea/workflows/test-pr.yml
Normal file
@ -0,0 +1,64 @@
|
||||
name: check-and-test
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
govulncheck_job:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run govulncheck
|
||||
steps:
|
||||
- id: govulncheck
|
||||
uses: golang/govulncheck-action@v1
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
check-and-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@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
- name: lint and build
|
||||
run: |
|
||||
make clean
|
||||
make vet
|
||||
make lint
|
||||
make fmt-check
|
||||
make misspell-check
|
||||
make docs-check
|
||||
make build
|
||||
- run: curl --noproxy "*" http://gitea:3000/api/v1/version # verify connection to instance
|
||||
- name: test and coverage
|
||||
run: |
|
||||
make test
|
||||
make unit-test-coverage
|
||||
services:
|
||||
gitea:
|
||||
image: docker.gitea.com/gitea:1.24.5
|
||||
cmd:
|
||||
- bash
|
||||
- -c
|
||||
- >-
|
||||
mkdir -p /tmp/conf/
|
||||
&& mkdir -p /tmp/data/
|
||||
&& echo "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT = true" > /tmp/conf/app.ini
|
||||
&& echo "[security]" >> /tmp/conf/app.ini
|
||||
&& echo "INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE1NTg4MzY4ODB9.LoKQyK5TN_0kMJFVHWUW0uDAyoGjDP6Mkup4ps2VJN4" >> /tmp/conf/app.ini
|
||||
&& echo "INSTALL_LOCK = true" >> /tmp/conf/app.ini
|
||||
&& echo "SECRET_KEY = 2crAW4UANgvLipDS6U5obRcFosjSJHQANll6MNfX7P0G3se3fKcCwwK3szPyGcbo" >> /tmp/conf/app.ini
|
||||
&& echo "PASSWORD_COMPLEXITY = off" >> /tmp/conf/app.ini
|
||||
&& echo "[database]" >> /tmp/conf/app.ini
|
||||
&& echo "DB_TYPE = sqlite3" >> /tmp/conf/app.ini
|
||||
&& echo "[repository]" >> /tmp/conf/app.ini
|
||||
&& echo "ROOT = /tmp/data/" >> /tmp/conf/app.ini
|
||||
&& echo "[server]" >> /tmp/conf/app.ini
|
||||
&& echo "ROOT_URL = http://gitea:3000" >> /tmp/conf/app.ini
|
||||
&& gitea migrate -c /tmp/conf/app.ini
|
||||
&& gitea admin user create --username=test01 --password=test01 --email=test01@gitea.io --admin=true --must-change-password=false --access-token -c /tmp/conf/app.ini
|
||||
&& gitea web -c /tmp/conf/app.ini
|
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,8 +1,19 @@
|
||||
tea
|
||||
/tea
|
||||
/gitea-vet
|
||||
/gitea-vet.exe
|
||||
|
||||
.idea/
|
||||
.history/
|
||||
dist/
|
||||
|
||||
.vscode/
|
||||
vendor/
|
||||
|
||||
coverage.out
|
||||
|
||||
dist/
|
||||
|
||||
# Nix-specific
|
||||
.direnv/
|
||||
result
|
||||
result-*
|
||||
|
12
.goreleaser.checksum.sh
Normal file
12
.goreleaser.checksum.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "usage: $0 <path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SUM=$(shasum -a 256 "$1" | cut -d' ' -f1)
|
||||
BASENAME=$(basename "$1")
|
||||
echo -n "${SUM} ${BASENAME}" > "$1".sha256
|
124
.goreleaser.yaml
Normal file
124
.goreleaser.yaml
Normal file
@ -0,0 +1,124 @@
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
- windows
|
||||
- freebsd
|
||||
goarch:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
goarm:
|
||||
- "5"
|
||||
- "6"
|
||||
- "7"
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: ppc64le
|
||||
- goos: darwin
|
||||
goarch: s390x
|
||||
- goos: windows
|
||||
goarch: ppc64le
|
||||
- goos: windows
|
||||
goarch: s390x
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "5"
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "6"
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
- goos: freebsd
|
||||
goarch: ppc64le
|
||||
- goos: freebsd
|
||||
goarch: s390x
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "5"
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "6"
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w -X code.gitea.io/tea/cmd.Version={{ .Version }}
|
||||
binary: >-
|
||||
{{ .ProjectName }}-
|
||||
{{- .Version }}-
|
||||
{{- .Os }}-
|
||||
{{- if eq .Arch "amd64" }}amd64
|
||||
{{- else if eq .Arch "amd64_v1" }}amd64
|
||||
{{- else if eq .Arch "386" }}386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}-{{ .Arm }}{{ end }}
|
||||
no_unique_dist_dir: true
|
||||
hooks:
|
||||
post:
|
||||
- cmd: xz -k -9 {{ .Path }}
|
||||
dir: ./dist/
|
||||
- cmd: sh .goreleaser.checksum.sh {{ .Path }}
|
||||
- cmd: sh .goreleaser.checksum.sh {{ .Path }}.xz
|
||||
|
||||
blobs:
|
||||
-
|
||||
provider: s3
|
||||
bucket: "{{ .Env.S3_BUCKET }}"
|
||||
region: "{{ .Env.S3_REGION }}"
|
||||
folder: "tea/{{.Version}}"
|
||||
extra_files:
|
||||
- glob: ./**.xz
|
||||
- glob: ./**.sha256
|
||||
|
||||
archives:
|
||||
- format: binary
|
||||
name_template: "{{ .Binary }}"
|
||||
allow_different_binary_count: true
|
||||
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
extra_files:
|
||||
- glob: ./**.xz
|
||||
|
||||
force_token: gitea
|
||||
|
||||
signs:
|
||||
-
|
||||
signature: "${artifact}.sig"
|
||||
artifacts: checksum
|
||||
stdin: '{{ .Env.GPGSIGN_PASSPHRASE }}'
|
||||
args: ["--batch", "-u", "{{ .Env.GPG_FINGERPRINT }}", "--output", "${signature}", "--detach-sign", "${artifact}"]
|
||||
|
||||
snapshot:
|
||||
name_template: "{{ .Branch }}-devel"
|
||||
|
||||
nightly:
|
||||
name_template: "{{ .Branch }}"
|
||||
|
||||
gitea_urls:
|
||||
api: https://gitea.com/api/v1
|
||||
download: https://gitea.com
|
||||
|
||||
release:
|
||||
extra_files:
|
||||
- glob: ./**.xz
|
||||
- glob: ./**.xz.sha256
|
||||
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
@ -16,7 +16,6 @@ warningCode = 1
|
||||
[rule.increment-decrement]
|
||||
[rule.var-naming]
|
||||
[rule.var-declaration]
|
||||
[rule.package-comments]
|
||||
[rule.range]
|
||||
[rule.receiver-naming]
|
||||
[rule.time-naming]
|
||||
|
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,5 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
## [v0.9.1](https://gitea.com/gitea/tea/releases/tag/v0.9.1) - 2023-02-15
|
||||
|
||||
* BUGFIXES
|
||||
* Print pull dont crash if it has TeamReviewRequests (#517)
|
||||
|
||||
## [v0.9.0](https://gitea.com/gitea/tea/releases/tag/v0.9.0) - 2022-09-13
|
||||
|
||||
* BREAKING
|
||||
* Rename master branch to main (#495)
|
||||
* Return RFC3339 UTC timestamps for machine-readable output (#470)
|
||||
* FEATURES
|
||||
* Allow editing multiline prompts with external text editor (#429)
|
||||
* Add `tea admin user list` (#427)
|
||||
* Add `tea whoami` command (#426)
|
||||
* Add `tea org create <name>` (#420)
|
||||
* Add `tea clone` (#411)
|
||||
* Add `tea repo fork` (#410)
|
||||
* Add `tea repo create-from-template` (#408)
|
||||
* BUGFIXES
|
||||
* Fetch all items where needed. (#475)
|
||||
* Fix running in repos without remote (#472)
|
||||
* Add TSV to machine-readable formats (#467)
|
||||
* Fix create milestone with deadline bug (#462)
|
||||
* Fix resolving of URLs in markdown (#401)
|
||||
* ENHANCEMENTS
|
||||
* Don't emit ANSI sequences when not emitting to TTY for markdown (#491)
|
||||
* Show more version info (#486)
|
||||
* Add preference `flag_defaults.remote`, refactor (#466)
|
||||
* Add `--fields` to notification & milestone listings (#422)
|
||||
* PR listing: add --fields & expose additional fields (#415)
|
||||
* Add more flags to `tea repo create` (#409)
|
||||
* Implement more issue filters (#400)
|
||||
* MISC
|
||||
* Simplify build & update installation instructions (#437)
|
||||
* Clarify command descriptions when no arguments are taken (#496)
|
||||
* Improve Documentation (#433)
|
||||
* Use golang v1.18 and drop vendor folder (#478)
|
||||
* Correct spelling of "wether" to "whether" in usage output (#453)
|
||||
|
||||
## [v0.8.0](https://gitea.com/gitea/tea/releases/tag/v0.8.0) - 2021-09-22
|
||||
|
||||
* BREAKING
|
||||
|
@ -7,7 +7,6 @@
|
||||
- [Bug reports](#bug-reports)
|
||||
- [Discuss your design](#discuss-your-design)
|
||||
- [Testing redux](#testing-redux)
|
||||
- [Vendoring](#vendoring)
|
||||
- [Code review](#code-review)
|
||||
- [Styleguide](#styleguide)
|
||||
- [Sign-off your work](#sign-off-your-work)
|
||||
@ -57,27 +56,13 @@ high-level discussions.
|
||||
|
||||
## Testing redux
|
||||
|
||||
Before sending code out for review, run all the test by execting: `make test`
|
||||
Since TEA is an cli tool it should be obvious to test your feature localy first.
|
||||
|
||||
## Vendoring
|
||||
|
||||
We keep a cached copy of dependencies within the `vendor/` directory,
|
||||
managing updates via [dep](https://github.com/golang/dep).
|
||||
|
||||
Pull requests should only include `vendor/` updates if they are part of
|
||||
the same change, be it a bugfix or a feature addition.
|
||||
|
||||
The `vendor/` update needs to be justified as part of the PR description,
|
||||
and must be verified by the reviewers and/or merger to always reference
|
||||
an existing upstream commit.
|
||||
|
||||
You can find more information on how to get started with it on the [dep project website](https://golang.github.io/dep/docs/introduction.html).
|
||||
Before sending code out for review, run all the test by executing: `make test`
|
||||
Since TEA is an cli tool it should be obvious to test your feature locally first.
|
||||
|
||||
## Code review
|
||||
|
||||
Changes to TEA must be reviewed before they are accepted—no matter who
|
||||
makes the change, even if they are an owner or a maintainer. We use Giteas's
|
||||
makes the change, even if they are an owner or a maintainer. We use Gitea's
|
||||
pull request & review workflow to do that. Gitea ensure every PR is reviewed by at least 2 maintainers.
|
||||
|
||||
Please try to make your pull request easy to review for us. And, please read
|
||||
@ -118,8 +103,8 @@ Some of the key points:
|
||||
- Always make sure that the help texts are properly set, and as concise as possible.
|
||||
|
||||
### Internal Module Structure
|
||||
- `cmd`: only contains comand/flag options for `urfave/cli`
|
||||
- subcomands are in a subpackage named after its parent comand
|
||||
- `cmd`: only contains command/flag options for `urfave/cli`
|
||||
- subcommands are in a subpackage named after its parent command
|
||||
- `modules/task`: contain func for doing something with gitea
|
||||
(e.g. create token by user/passwd)
|
||||
- `modules/print`: contain all functions that print to stdout
|
||||
@ -175,7 +160,7 @@ maintainers](MAINTAINERS). Every PR **MUST** be reviewed by at least
|
||||
two maintainers (or owners) before it can get merged. A maintainer
|
||||
should be a contributor of Gitea (or Gogs) and contributed at least
|
||||
4 accepted PRs. A contributor should apply as a maintainer in the
|
||||
[Discord](https://discord.gg/NsatcWJ) #develop channel. The owners
|
||||
[Discord](https://discord.gg/Gitea) #develop channel. The owners
|
||||
or the team maintainers may invite the contributor. A maintainer
|
||||
should spend some time on code reviews. If a maintainer has no
|
||||
time to do that, they should apply to leave the maintainers team
|
||||
@ -208,7 +193,7 @@ https://help.github.com/articles/securing-your-account-with-two-factor-authentic
|
||||
|
||||
After the election, the new owners should proactively agree
|
||||
with our [CONTRIBUTING](CONTRIBUTING.md) requirements in the
|
||||
[Discord](https://discord.gg/NsatcWJ) #general channel. Below are the
|
||||
[Discord](https://discord.gg/Gitea) #general channel. Below are the
|
||||
words to speak:
|
||||
|
||||
```
|
||||
@ -236,8 +221,8 @@ Code that you contribute should use the standard copyright header:
|
||||
|
||||
```
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
```
|
||||
|
||||
Files in the repository contain copyright from the year they are added
|
||||
|
33
Dockerfile
33
Dockerfile
@ -1,25 +1,12 @@
|
||||
ARG GOVERSION="1.16.2"
|
||||
FROM docker.io/chainguard/go:latest AS build
|
||||
COPY . /build/
|
||||
WORKDIR /build
|
||||
RUN make build && mkdir -p /app/.config/tea
|
||||
|
||||
FROM golang:${GOVERSION}-alpine AS buildenv
|
||||
|
||||
ARG CGO_ENABLED="0"
|
||||
ARG GOOS="linux"
|
||||
|
||||
COPY . $GOPATH/src/
|
||||
WORKDIR $GOPATH/src
|
||||
|
||||
RUN apk add --quiet --no-cache \
|
||||
make \
|
||||
git && \
|
||||
make build
|
||||
|
||||
FROM scratch
|
||||
ARG VERSION="0.7.0"
|
||||
LABEL org.opencontainers.image.title="tea - CLI for Gitea - git with a cup of tea"
|
||||
LABEL org.opencontainers.image.description="A command line tool to interact with Gitea servers"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
LABEL org.opencontainers.image.authors="Tamás Gérczei <tamas@gerczei.eu>"
|
||||
LABEL org.opencontainers.image.vendor="The Gitea Authors"
|
||||
COPY --from=buildenv /go/src/tea /
|
||||
FROM docker.io/chainguard/busybox:latest-glibc
|
||||
COPY --from=build /build/tea /bin/tea
|
||||
COPY --from=build --chown=65532:65532 /app /app
|
||||
VOLUME [ "/app" ]
|
||||
ENV HOME="/app"
|
||||
ENTRYPOINT ["/tea"]
|
||||
ENTRYPOINT ["/bin/sh", "-c"]
|
||||
CMD [ "tea" ]
|
||||
|
@ -1,63 +0,0 @@
|
||||
# comparing git forge commandline interfaces
|
||||
|
||||
[tea]: https://gitea.com/gitea/tea
|
||||
[sip]: https://gitea.com/jolheiser/sip
|
||||
[gitlab]: https://github.com/makkes/gitlab-cli
|
||||
[glab]: https://github.com/profclems/glab
|
||||
[gh]: https://cli.github.com
|
||||
|
||||
last update: 2020-12-11
|
||||
|
||||
## general
|
||||
/ | [tea][tea] | [sip][sip] | [gitlab][gitlab] | [gh][gh]
|
||||
-----------------------|:-----:|:-----:|:-----:|:-----:
|
||||
forge|gitea|gitea|gitlab|github
|
||||
official forge support|✓|✘|✘|✓
|
||||
dev status|adding features|maintenance||
|
||||
platform|any|any|any|any
|
||||
|
||||
## philosophy
|
||||
/ | [tea][tea] | [sip][sip] | [gitlab][gitlab] | [gh][gh]
|
||||
-----------------------|:-----:|:-----:|:-----:|:-----:
|
||||
aims to replace git cli|✘|||✓
|
||||
works with decentralization in mind|✓|✓|✓|✘
|
||||
per-repo setup needed|✘||✓|✘
|
||||
workflow helpers|✓|||
|
||||
interactive mode |[(✓)](https://gitea.com/gitea/tea/issues?type=all&state=open&labels=&milestone=0&assignee=0&q=interactive)|✘| |✓
|
||||
programmatic mode|✓|||✓
|
||||
machine readable output|✓|||
|
||||
follows XDG spec|✓|||
|
||||
|
||||
## features
|
||||
/ | [tea][tea] | [sip][sip] | [gitlab][gitlab] | [gh][gh]
|
||||
-----------------------|:-----:|:-----:|:-----:|:-----:
|
||||
open web UI|✓|||
|
||||
search repos|✓|||
|
||||
search issues|✘|✓||
|
||||
textual item search filter syntax|✘|✓||
|
||||
CRUD repos|[(✓)](https://gitea.com/gitea/tea/issues/239)|||
|
||||
CRUD issues|[(✓)](https://gitea.com/gitea/tea/issues/229)|||
|
||||
CRUD milestones|[(✓)](https://gitea.com/gitea/tea/issues/246)|||
|
||||
CRUD releases|✓|||
|
||||
CRUD labels|✓|||
|
||||
CRUD PRs|✓|||
|
||||
CRUD time tracking|✓|||x
|
||||
CRUD orgs|[(✓)](https://gitea.com/gitea/tea/issues/287)|||
|
||||
create PRs from local repo|✓|||
|
||||
create PRs from remote repo|✓|||
|
||||
code review|[u](https://gitea.com/gitea/tea/issues/131)|||
|
||||
merge PRs||||
|
||||
read comments|[u](https://gitea.com/gitea/tea/issues/172)|||
|
||||
post comments||||
|
||||
manage CI|✘|✘|✓|
|
||||
manage notifications|[(✓)]()|||
|
||||
administration|[u](https://gitea.com/gitea/tea/issues/161)|✘||✘
|
||||
markdown rendering|✓|||✓
|
||||
issue import/export|[u](https://gitea.com/gitea/tea/issues/132)|||
|
||||
checkout PRs|✓|||
|
||||
|
||||
- ✓: supported
|
||||
- (✓): partial support
|
||||
- u: upcoming
|
||||
- ✘: not supported
|
||||
- ?: unknown
|
1
LICENSE
1
LICENSE
@ -1,5 +1,4 @@
|
||||
Copyright (c) 2016 The Gitea Authors
|
||||
Copyright (c) 2015 The Gogs Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
136
Makefile
136
Makefile
@ -1,31 +1,12 @@
|
||||
DIST := dist
|
||||
IMPORT := code.gitea.io/tea
|
||||
export GO111MODULE=on
|
||||
|
||||
GO ?= go
|
||||
SED_INPLACE := sed -i
|
||||
SHASUM ?= shasum -a 256
|
||||
|
||||
export PATH := $($(GO) env GOPATH)/bin:$(PATH)
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
EXECUTABLE := tea.exe
|
||||
else
|
||||
EXECUTABLE := tea
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
SED_INPLACE := sed -i ''
|
||||
endif
|
||||
endif
|
||||
|
||||
GOFILES := $(shell find . -name "*.go" -type f ! -path "./vendor/*" ! -path "*/bindata.go")
|
||||
GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go")
|
||||
GOFMT ?= gofmt -s
|
||||
|
||||
GOFLAGS := -i -v
|
||||
EXTRA_GOFLAGS ?=
|
||||
|
||||
MAKE_VERSION := $(shell make -v | head -n 1)
|
||||
|
||||
ifneq ($(DRONE_TAG),)
|
||||
VERSION ?= $(subst v,,$(DRONE_TAG))
|
||||
TEA_VERSION ?= $(VERSION)
|
||||
@ -33,35 +14,37 @@ else
|
||||
ifneq ($(DRONE_BRANCH),)
|
||||
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
|
||||
else
|
||||
VERSION ?= master
|
||||
VERSION ?= main
|
||||
endif
|
||||
TEA_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
||||
endif
|
||||
|
||||
TEA_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(TEA_VERSION))
|
||||
|
||||
LDFLAGS := -X "main.Version=$(TEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||
TAGS ?=
|
||||
SDK ?= $(shell $(GO) list -f '{{.Version}}' -m code.gitea.io/sdk/gitea)
|
||||
LDFLAGS := -X "code.gitea.io/tea/cmd.Version=$(TEA_VERSION)" -X "code.gitea.io/tea/cmd.Tags=$(TAGS)" -X "code.gitea.io/tea/cmd.SDK=$(SDK)" -s -w
|
||||
|
||||
PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/)
|
||||
# override to allow passing additional goflags via make CLI
|
||||
override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
||||
|
||||
PACKAGES ?= $(shell $(GO) list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
||||
TAGS ?=
|
||||
|
||||
# OS specific vars.
|
||||
ifeq ($(OS), Windows_NT)
|
||||
EXECUTABLE := tea.exe
|
||||
VET_TOOL := gitea-vet.exe
|
||||
else
|
||||
EXECUTABLE := tea
|
||||
VET_TOOL := gitea-vet
|
||||
endif
|
||||
|
||||
# $(call strip-suffix,filename)
|
||||
strip-suffix = $(firstword $(subst ., ,$(1)))
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(GO) clean -mod=vendor -i ./...
|
||||
$(GO) clean -i ./...
|
||||
rm -rf $(EXECUTABLE) $(DIST)
|
||||
|
||||
.PHONY: fmt
|
||||
@ -71,31 +54,22 @@ fmt:
|
||||
.PHONY: vet
|
||||
vet:
|
||||
# Default vet
|
||||
$(GO) vet -mod=vendor $(PACKAGES)
|
||||
$(GO) vet $(PACKAGES)
|
||||
# Custom vet
|
||||
$(GO) build -mod=vendor code.gitea.io/gitea-vet
|
||||
$(GO) vet -vettool=gitea-vet $(PACKAGES)
|
||||
$(GO) build code.gitea.io/gitea-vet
|
||||
$(GO) vet -vettool=$(VET_TOOL) $(PACKAGES)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
cd /tmp && $(GO) get -u github.com/mgechev/revive; \
|
||||
fi
|
||||
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1
|
||||
lint: install-lint-tools
|
||||
$(GO) run github.com/mgechev/revive@v1.3.2 -config .revive.toml ./... || exit 1
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
cd /tmp && $(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error -i unknwon,destory $(GOFILES)
|
||||
misspell-check: install-lint-tools
|
||||
$(GO) run github.com/client9/misspell/cmd/misspell@latest -error -i unknwon,destory $(GOFILES)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
cd /tmp && $(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w -i unknwon $(GOFILES)
|
||||
misspell: install-lint-tools
|
||||
$(GO) run github.com/client9/misspell/cmd/misspell@latest -w -i unknwon $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
@ -107,65 +81,53 @@ fmt-check:
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
$(GO) run docs/docs.go --out docs/CLI.md
|
||||
|
||||
.PHONY: docs-check
|
||||
docs-check:
|
||||
@DIFF=$$($(GO) run docs/docs.go | diff docs/CLI.md -); \
|
||||
if [ -n "$$DIFF" ]; then \
|
||||
echo "Please run 'make docs' and commit the result:"; \
|
||||
echo "$$DIFF"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) test -mod=vendor -tags='sqlite sqlite_unlock_notify' $(PACKAGES)
|
||||
$(GO) test -tags='sqlite sqlite_unlock_notify' $(PACKAGES)
|
||||
|
||||
.PHONY: unit-test-coverage
|
||||
unit-test-coverage:
|
||||
$(GO) test -mod=vendor -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||
$(GO) test -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||
|
||||
.PHONY: vendor
|
||||
vendor:
|
||||
$(GO) mod tidy && $(GO) mod vendor
|
||||
|
||||
.PHONY: test-vendor
|
||||
test-vendor: vendor
|
||||
@diff=$$(git diff vendor/); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make vendor' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
$(GO) mod tidy
|
||||
|
||||
.PHONY: check
|
||||
check: test
|
||||
|
||||
.PHONY: install
|
||||
install: $(wildcard *.go)
|
||||
$(GO) install -mod=vendor -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
|
||||
install: $(SOURCES)
|
||||
@echo "installing to $(shell $(GO) env GOPATH)/bin/$(EXECUTABLE)"
|
||||
$(GO) install -v $(BUILDMODE) $(GOFLAGS)
|
||||
|
||||
.PHONY: build
|
||||
build: $(EXECUTABLE)
|
||||
|
||||
$(EXECUTABLE): $(SOURCES)
|
||||
$(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
||||
$(GO) build $(BUILDMODE) $(GOFLAGS) -o $@
|
||||
|
||||
.PHONY: build-image
|
||||
build-image:
|
||||
docker build --build-arg VERSION=$(TEA_VERSION) -t gitea/tea:$(TEA_VERSION_TAG) .
|
||||
|
||||
.PHONY: release
|
||||
release: release-dirs release-os release-compress release-check
|
||||
|
||||
.PHONY: release-dirs
|
||||
release-dirs:
|
||||
mkdir -p $(DIST)/binaries $(DIST)/release
|
||||
|
||||
.PHONY: release-os
|
||||
release-os:
|
||||
@hash gox > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
cd /tmp && $(GO) get -u github.com/mitchellh/gox; \
|
||||
install-lint-tools:
|
||||
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/mgechev/revive@v1.3.2; \
|
||||
fi
|
||||
CGO_ENABLED=0 gox -verbose -cgo=false -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -osarch='!darwin/386 !darwin/arm' -os="windows linux darwin" -arch="386 amd64 arm arm64" -output="$(DIST)/release/tea-$(VERSION)-{{.OS}}-{{.Arch}}"
|
||||
|
||||
.PHONY: release-compress
|
||||
release-compress:
|
||||
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
GO111MODULE=off $(GO) get -u github.com/ulikunitz/xz/cmd/gxz; \
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/client9/misspell/cmd/misspell@latest; \
|
||||
fi
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
|
||||
|
||||
.PHONY: release-check
|
||||
release-check:
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "checksumming $${file}" && $(SHASUM) `echo $${file} | sed 's/^..//'` > $${file}.sha256; done;
|
||||
|
213
README.md
213
README.md
@ -1,69 +1,89 @@
|
||||
# <img alt='' src='https://gitea.com/repo-avatars/550-80a3a8c2ab0e2c2d69f296b7f8582485' height="40"/> *T E A*
|
||||
# <img alt='tea logo' src='https://gitea.com/repo-avatars/550-80a3a8c2ab0e2c2d69f296b7f8582485' height="40"/> *T E A*
|
||||
|
||||
[](https://opensource.org/licenses/MIT) [](https://gitea.com/gitea/tea/releases) [](https://drone.gitea.com/gitea/tea) [](https://discord.gg/Gitea) [](https://goreportcard.com/report/code.gitea.io/tea) [](https://godoc.org/code.gitea.io/tea)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://gitea.com/gitea/tea/releases)
|
||||
[](https://discord.gg/Gitea)
|
||||
[](https://goreportcard.com/report/code.gitea.io/tea) [](https://godoc.org/code.gitea.io/tea)
|
||||

|
||||
|
||||
### The official CLI for Gitea
|
||||
## The official CLI for Gitea
|
||||
|
||||

|
||||
|
||||
```
|
||||
tea - command line tool to interact with Gitea
|
||||
version 0.7.0-preview
|
||||
NAME:
|
||||
tea - command line tool to interact with Gitea
|
||||
|
||||
USAGE
|
||||
tea command [subcommand] [command options] [arguments...]
|
||||
USAGE:
|
||||
tea [global options] [command [command options]]
|
||||
|
||||
DESCRIPTION
|
||||
tea is a productivity helper for Gitea. It can be used to manage most entities on one
|
||||
or multiple Gitea instances and provides local helpers like 'tea pull checkout'.
|
||||
tea makes use of context provided by the repository in $PWD if available, but is still
|
||||
usable independently of $PWD. Configuration is persisted in $XDG_CONFIG_HOME/tea.
|
||||
VERSION:
|
||||
Version: 0.10.1+15-g8876fe3 golang: 1.25.0 go-sdk: v0.21.0
|
||||
|
||||
COMMANDS
|
||||
help, h Shows a list of commands or help for one command
|
||||
ENTITIES:
|
||||
issues, issue, i List, create and update issues
|
||||
pulls, pull, pr Manage and checkout pull requests
|
||||
labels, label Manage issue labels
|
||||
milestones, milestone, ms List and create milestones
|
||||
releases, release, r Manage releases
|
||||
times, time, t Operate on tracked times of a repository's issues & pulls
|
||||
organizations, organization, org List, create, delete organizations
|
||||
repos, repo Show repository details
|
||||
HELPERS:
|
||||
open, o Open something of the repository in web browser
|
||||
notifications, notification, n Show notifications
|
||||
SETUP:
|
||||
logins, login Log in to a Gitea server
|
||||
logout Log out from a Gitea server
|
||||
shellcompletion, autocomplete Install shell completion for tea
|
||||
DESCRIPTION:
|
||||
tea is a productivity helper for Gitea. It can be used to manage most entities on
|
||||
one or multiple Gitea instances & provides local helpers like 'tea pr checkout'.
|
||||
|
||||
OPTIONS
|
||||
--help, -h show help (default: false)
|
||||
--version, -v print the version (default: false)
|
||||
tea tries to make use of context provided by the repository in $PWD if available.
|
||||
tea works best in a upstream/fork workflow, when the local main branch tracks the
|
||||
upstream repo. tea assumes that local git state is published on the remote before
|
||||
doing operations with tea. Configuration is persisted in $XDG_CONFIG_HOME/tea.
|
||||
|
||||
EXAMPLES
|
||||
tea login add # add a login once to get started
|
||||
COMMANDS:
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
tea pulls # list open pulls for the repo in $PWD
|
||||
tea pulls --repo $HOME/foo # list open pulls for the repo in $HOME/foo
|
||||
tea pulls --remote upstream # list open pulls for the repo pointed at by
|
||||
# your local "upstream" git remote
|
||||
# list open pulls for any gitea repo at the given login instance
|
||||
tea pulls --repo gitea/tea --login gitea.com
|
||||
ENTITIES:
|
||||
issues, issue, i List, create and update issues
|
||||
pulls, pull, pr Manage and checkout pull requests
|
||||
labels, label Manage issue labels
|
||||
milestones, milestone, ms List and create milestones
|
||||
releases, release, r Manage releases
|
||||
times, time, t Operate on tracked times of a repository's issues & pulls
|
||||
organizations, organization, org List, create, delete organizations
|
||||
repos, repo Show repository details
|
||||
branches, branch, b Consult branches
|
||||
comment, c Add a comment to an issue / pr
|
||||
|
||||
tea milestone issues 0.7.0 # view open issues for milestone '0.7.0'
|
||||
tea issue 189 # view contents of issue 189
|
||||
tea open 189 # open web ui for issue 189
|
||||
tea open milestones # open web ui for milestones
|
||||
HELPERS:
|
||||
open, o Open something of the repository in web browser
|
||||
notifications, notification, n Show notifications
|
||||
clone, C Clone a repository locally
|
||||
|
||||
# send gitea desktop notifications every 5 minutes (bash + libnotify)
|
||||
while :; do tea notifications --all -o simple | xargs -i notify-send {}; sleep 300; done
|
||||
MISCELLANEOUS:
|
||||
whoami Show current logged in user
|
||||
admin, a Operations requiring admin access on the Gitea instance
|
||||
|
||||
ABOUT
|
||||
Written & maintained by The Gitea Authors.
|
||||
If you find a bug or want to contribute, we'll welcome you at https://gitea.com/gitea/tea.
|
||||
More info about Gitea itself on https://gitea.io.
|
||||
SETUP:
|
||||
logins, login Log in to a Gitea server
|
||||
logout Log out from a Gitea server
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--debug, --vvv Enable debug mode (default: false)
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
|
||||
EXAMPLES
|
||||
tea login add # add a login once to get started
|
||||
|
||||
tea pulls # list open pulls for the repo in $PWD
|
||||
tea pulls --repo $HOME/foo # list open pulls for the repo in $HOME/foo
|
||||
tea pulls --remote upstream # list open pulls for the repo pointed at by
|
||||
# your local "upstream" git remote
|
||||
# list open pulls for any gitea repo at the given login instance
|
||||
tea pulls --repo gitea/tea --login gitea.com
|
||||
|
||||
tea milestone issues 0.7.0 # view open issues for milestone '0.7.0'
|
||||
tea issue 189 # view contents of issue 189
|
||||
tea open 189 # open web ui for issue 189
|
||||
tea open milestones # open web ui for milestones
|
||||
|
||||
# send gitea desktop notifications every 5 minutes (bash + libnotify)
|
||||
while :; do tea notifications --mine -o simple | xargs -i notify-send {}; sleep 300; done
|
||||
|
||||
ABOUT
|
||||
Written & maintained by The Gitea Authors.
|
||||
If you find a bug or want to contribute, we'll welcome you at https://gitea.com/gitea/tea.
|
||||
More info about Gitea itself on https://about.gitea.com.
|
||||
```
|
||||
|
||||
- [Compare features with other git forge CLIs](./FEATURE-COMPARISON.md)
|
||||
@ -74,34 +94,92 @@
|
||||
There are different ways to get `tea`:
|
||||
|
||||
1. Install via your system package manager:
|
||||
- macOS via `brew` (gitea-maintained):
|
||||
- macOS via `brew` (official):
|
||||
```sh
|
||||
brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea
|
||||
brew install tea
|
||||
```
|
||||
- arch linux ([gitea-tea](https://aur.archlinux.org/packages/gitea-tea), thirdparty)
|
||||
- arch linux ([tea](https://archlinux.org/packages/extra/x86_64/tea/), thirdparty)
|
||||
- alpine linux ([tea](https://pkgs.alpinelinux.org/packages?name=tea&branch=edge), thirdparty)
|
||||
- Windows via `MSYS2` ([tea](https://packages.msys2.org/base/mingw-w64-tea), thirdparty)
|
||||
|
||||
2. Use the prebuilt binaries from [dl.gitea.io](https://dl.gitea.io/tea/)
|
||||
2. Use the prebuilt binaries from [dl.gitea.com](https://dl.gitea.com/tea/)
|
||||
|
||||
3. Install from source (go 1.13 or newer is required):
|
||||
```sh
|
||||
go get code.gitea.io/tea
|
||||
go install code.gitea.io/tea
|
||||
```
|
||||
3. Install from source: [see *Compilation*](#compilation)
|
||||
|
||||
4. Docker (thirdparty): [tgerczei/tea](https://hub.docker.com/r/tgerczei/tea)
|
||||
|
||||
5. asdf (thirdparty): [mvaldes14/asdf-tea](https://github.com/mvaldes14/asdf-tea)
|
||||
|
||||
### Log in to Gitea from tea
|
||||
|
||||
Gitea can use many different authentication schemes, and not every authentication method will work with every Gitea deployment. When you are a Gitea instance administrator you can tweak your settings to fit your use case. For the method that is most likely to work with any Gitea deployment use the following steps:
|
||||
|
||||
1. Open your Gitea instance in a web browser
|
||||
|
||||
2. Log in to Gitea in your web browser. Any MFA, IDP, or whatever else should be available this way.
|
||||
|
||||
3. In your "user settings", generate an application token with at least **user read** permissions. If you want to do anything useful with the token add additional permissions/scopes.
|
||||
|
||||
4. Run `tea login add`, select **application token** authentication when asked for authentication type, and answer **yes** to the question if you have a token. Paste the generated token when asked for one.
|
||||
|
||||
You should now be logged in to your gitea instance from tea.
|
||||
|
||||
Since 0.10 Gitea supports the much simpler oauth workflow but oauth may not be available on all Gitea deployments, and gets much more complex when running tea on a remote system.
|
||||
|
||||
### Shell completion
|
||||
|
||||
If you installed from source or the package does not provide the completions with it you can add them yourself with `tea completion <shell>` command which is not visible in help. To generate the completions run one of the following commands depending on your shell.
|
||||
|
||||
```shell
|
||||
# .bashrc
|
||||
source <(tea completion bash)
|
||||
|
||||
# .zshrc
|
||||
source <(tea completion zsh)
|
||||
|
||||
# fish
|
||||
tea completion fish > ~/.config/fish/completions/tea.fish
|
||||
|
||||
# Powershell
|
||||
Output the script to path/to/autocomplete/tea.ps1 an run it.
|
||||
```
|
||||
|
||||
### Man Page
|
||||
|
||||
The hidden command `tea man` can be used to generate the `tea` man page.
|
||||
|
||||
```shell
|
||||
# for bash or zsh
|
||||
man <(tea man)
|
||||
|
||||
# for fish
|
||||
man (tea man | psub)
|
||||
|
||||
# write man page to a file
|
||||
tea man --out ./tea.man
|
||||
```
|
||||
|
||||
## Compilation
|
||||
|
||||
Make sure you have installed a current go version.
|
||||
To compile the sources yourself run the following:
|
||||
Make sure you have a current go version installed (1.13 or newer).
|
||||
|
||||
```sh
|
||||
git clone https://gitea.com/gitea/tea.git
|
||||
cd tea
|
||||
make
|
||||
```
|
||||
- To compile the source yourself with the recommended flags & tags:
|
||||
```sh
|
||||
git clone https://gitea.com/gitea/tea.git # or: tea clone gitea.com/gitea/tea ;)
|
||||
cd tea
|
||||
make
|
||||
```
|
||||
Note that GNU Make (gmake on OpenBSD) is required.
|
||||
If you want to install the compiled program you have to execute the following command:
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
This installs the binary into the "bin" folder inside of your GOPATH folder (`go env GOPATH`). It is possible that this folder isn't in your PATH Environment Variable.
|
||||
|
||||
- For a quick installation without `git` & `make`, set $version and exec:
|
||||
```sh
|
||||
go install code.gitea.io/tea@${version}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
@ -109,7 +187,6 @@ Fork -> Patch -> Push -> Pull Request
|
||||
|
||||
- `make test` run testsuite
|
||||
- `make vet` run checks (check the order of imports; preventing failure on CI pipeline beforehand)
|
||||
- `make vendor` when adding new dependencies
|
||||
- ... (for other development tasks, check the `Makefile`)
|
||||
|
||||
**Please** read the [CONTRIBUTING](CONTRIBUTING.md) documentation, it will tell you about internal structures and concepts.
|
||||
|
7
build.go
7
build.go
@ -1,7 +1,8 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//+build vendor
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build vendor
|
||||
// +build vendor
|
||||
|
||||
package main
|
||||
|
||||
|
56
cmd/admin.go
Normal file
56
cmd/admin.go
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
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"
|
||||
)
|
||||
|
||||
// CmdAdmin represents the namespace of admin commands.
|
||||
// The command itself has no functionality, but hosts subcommands.
|
||||
var CmdAdmin = cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "Operations requiring admin access on the Gitea instance",
|
||||
Aliases: []string{"a"},
|
||||
Category: catMisc,
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
return cli.ShowSubcommandHelp(cmd)
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
&cmdAdminUsers,
|
||||
},
|
||||
}
|
||||
|
||||
var cmdAdminUsers = cli.Command{
|
||||
Name: "users",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Manage registered users",
|
||||
Action: func(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runAdminUserDetail(ctx, cmd, cmd.Args().First())
|
||||
}
|
||||
return users.RunUserList(ctx, cmd)
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
&users.CmdUserList,
|
||||
},
|
||||
Flags: users.CmdUserList.Flags,
|
||||
}
|
||||
|
||||
func runAdminUserDetail(_ stdctx.Context, cmd *cli.Command, u string) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
user, _, err := client.GetUserInfo(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.UserDetails(user)
|
||||
return nil
|
||||
}
|
55
cmd/admin/users/list.go
Normal file
55
cmd/admin/users/list.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var userFieldsFlag = flags.FieldsFlag(print.UserFields, []string{
|
||||
"id", "login", "full_name", "email", "activated",
|
||||
})
|
||||
|
||||
// CmdUserList represents a sub command of users to list users
|
||||
var CmdUserList = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Users",
|
||||
Description: "List users",
|
||||
Action: RunUserList,
|
||||
Flags: append([]cli.Flag{
|
||||
userFieldsFlag,
|
||||
&flags.PaginationPageFlag,
|
||||
&flags.PaginationLimitFlag,
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
// RunUserList list users
|
||||
func RunUserList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
fields, err := userFieldsFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
users, _, err := client.AdminListUsers(gitea.AdminListUsersOptions{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.UserList(users, ctx.Output, fields)
|
||||
|
||||
return nil
|
||||
}
|
28
cmd/attachments.go
Normal file
28
cmd/attachments.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/attachments"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseAttachments represents a release attachment (file attachment)
|
||||
var CmdReleaseAttachments = cli.Command{
|
||||
Name: "assets",
|
||||
Aliases: []string{"asset", "a"},
|
||||
Category: catEntities,
|
||||
Usage: "Manage release assets",
|
||||
Description: "Manage release assets",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: attachments.RunReleaseAttachmentList,
|
||||
Commands: []*cli.Command{
|
||||
&attachments.CmdReleaseAttachmentList,
|
||||
&attachments.CmdReleaseAttachmentCreate,
|
||||
&attachments.CmdReleaseAttachmentDelete,
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
65
cmd/attachments/create.go
Normal file
65
cmd/attachments/create.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package attachments
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseAttachmentCreate represents a sub command of Release Attachments to create a release attachment
|
||||
var CmdReleaseAttachmentCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create one or more release attachments",
|
||||
Description: `Create one or more release attachments`,
|
||||
ArgsUsage: "<release-tag> <asset> [<asset>...]",
|
||||
Action: runReleaseAttachmentCreate,
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
func runReleaseAttachmentCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
if ctx.Args().Len() < 2 {
|
||||
return fmt.Errorf("No release tag or assets specified.\nUsage:\t%s", ctx.Command.UsageText)
|
||||
}
|
||||
|
||||
tag := ctx.Args().First()
|
||||
if len(tag) == 0 {
|
||||
return fmt.Errorf("Release tag needed to create attachment")
|
||||
}
|
||||
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, asset := range ctx.Args().Slice()[1:] {
|
||||
var file *os.File
|
||||
if file, err = os.Open(asset); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filePath := filepath.Base(asset)
|
||||
|
||||
if _, _, err = ctx.Login.Client().CreateReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, file, filePath); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
101
cmd/attachments/delete.go
Normal file
101
cmd/attachments/delete.go
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package attachments
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseAttachmentDelete represents a sub command of Release Attachments to delete a release attachment
|
||||
var CmdReleaseAttachmentDelete = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete one or more release attachments",
|
||||
Description: `Delete one or more release attachments`,
|
||||
ArgsUsage: "<release tag> <attachment name> [<attachment name>...]",
|
||||
Action: runReleaseAttachmentDelete,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "confirm",
|
||||
Aliases: []string{"y"},
|
||||
Usage: "Confirm deletion (required)",
|
||||
},
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runReleaseAttachmentDelete(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
if ctx.Args().Len() < 2 {
|
||||
return fmt.Errorf("No release tag or attachment names specified.\nUsage:\t%s", ctx.Command.UsageText)
|
||||
}
|
||||
|
||||
tag := ctx.Args().First()
|
||||
if len(tag) == 0 {
|
||||
return fmt.Errorf("Release tag needed to delete attachment")
|
||||
}
|
||||
|
||||
if !ctx.Bool("confirm") {
|
||||
fmt.Println("Are you sure? Please confirm with -y or --confirm.")
|
||||
return nil
|
||||
}
|
||||
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existing, _, err := client.ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
|
||||
ListOptions: gitea.ListOptions{Page: -1},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range ctx.Args().Slice()[1:] {
|
||||
var attachment *gitea.Attachment
|
||||
for _, a := range existing {
|
||||
if a.Name == name {
|
||||
attachment = a
|
||||
}
|
||||
}
|
||||
if attachment == nil {
|
||||
return fmt.Errorf("Release does not have attachment named '%s'", name)
|
||||
}
|
||||
|
||||
_, err = client.DeleteReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, attachment.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getReleaseAttachmentByName(owner, repo string, release int64, name string, client *gitea.Client) (*gitea.Attachment, error) {
|
||||
al, _, err := client.ListReleaseAttachments(owner, repo, release, gitea.ListReleaseAttachmentsOptions{
|
||||
ListOptions: gitea.ListOptions{Page: -1},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(al) == 0 {
|
||||
return nil, fmt.Errorf("Release does not have any attachments")
|
||||
}
|
||||
for _, a := range al {
|
||||
if a.Name == name {
|
||||
return a, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Attachment does not exist")
|
||||
}
|
75
cmd/attachments/list.go
Normal file
75
cmd/attachments/list.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package attachments
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseAttachmentList represents a sub command of release attachment to list release attachments
|
||||
var CmdReleaseAttachmentList = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Release Attachments",
|
||||
Description: "List Release Attachments",
|
||||
ArgsUsage: "<release-tag>", // command does not accept arguments
|
||||
Action: RunReleaseAttachmentList,
|
||||
Flags: append([]cli.Flag{
|
||||
&flags.PaginationPageFlag,
|
||||
&flags.PaginationLimitFlag,
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
// RunReleaseAttachmentList list release attachments
|
||||
func RunReleaseAttachmentList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
tag := ctx.Args().First()
|
||||
if len(tag) == 0 {
|
||||
return fmt.Errorf("Release tag needed to list attachments")
|
||||
}
|
||||
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attachments, _, err := ctx.Login.Client().ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.ReleaseAttachmentsList(attachments, ctx.Output)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
|
||||
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{
|
||||
ListOptions: gitea.ListOptions{Page: -1},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rl) == 0 {
|
||||
return nil, fmt.Errorf("Repo does not have any release")
|
||||
}
|
||||
for _, r := range rl {
|
||||
if r.TagName == tag {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Release tag does not exist")
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CmdAutocomplete manages autocompletion
|
||||
var CmdAutocomplete = cli.Command{
|
||||
Name: "shellcompletion",
|
||||
Aliases: []string{"autocomplete"},
|
||||
Category: catSetup,
|
||||
Usage: "Install shell completion for tea",
|
||||
Description: "Install shell completion for tea",
|
||||
ArgsUsage: "<shell type> (bash, zsh, powershell, fish)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "install",
|
||||
Usage: "Persist in shell config instead of printing commands",
|
||||
},
|
||||
},
|
||||
Action: runAutocompleteAdd,
|
||||
}
|
||||
|
||||
func runAutocompleteAdd(ctx *cli.Context) error {
|
||||
var remoteFile, localFile, cmds string
|
||||
shell := ctx.Args().First()
|
||||
|
||||
switch shell {
|
||||
case "zsh":
|
||||
remoteFile = "contrib/autocomplete.zsh"
|
||||
localFile = "autocomplete.zsh"
|
||||
cmds = "echo 'PROG=tea _CLI_ZSH_AUTOCOMPLETE_HACK=1 source \"%s\"' >> ~/.zshrc && source ~/.zshrc"
|
||||
|
||||
case "bash":
|
||||
remoteFile = "contrib/autocomplete.sh"
|
||||
localFile = "autocomplete.sh"
|
||||
cmds = "echo 'PROG=tea source \"%s\"' >> ~/.bashrc && source ~/.bashrc"
|
||||
|
||||
case "powershell":
|
||||
remoteFile = "contrib/autocomplete.ps1"
|
||||
localFile = "tea.ps1"
|
||||
cmds = "\"& %s\" >> $profile"
|
||||
|
||||
case "fish":
|
||||
// fish is different, in that urfave/cli provides a generator for the shell script needed.
|
||||
// this also means that the fish completion can become out of sync with the tea binary!
|
||||
// writing to this directory suffices, as fish reads files there on startup, no cmds needed.
|
||||
return writeFishAutoCompleteFile(ctx)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Must specify valid %s", ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
localPath, err := xdg.ConfigFile("tea/" + localFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmds = fmt.Sprintf(cmds, localPath)
|
||||
if err = writeRemoteAutoCompleteFile(remoteFile, localPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Bool("install") {
|
||||
fmt.Println("Installing in your shellrc")
|
||||
installer := exec.Command(shell, "-c", cmds)
|
||||
if shell == "powershell" {
|
||||
installer = exec.Command("powershell.exe", "-Command", cmds)
|
||||
}
|
||||
out, err := installer.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't run the commands: %s %s", err, out)
|
||||
}
|
||||
} else {
|
||||
fmt.Println("\n# Run the following commands to install autocompletion (or use --install)")
|
||||
fmt.Println(cmds)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeRemoteAutoCompleteFile(file, destPath string) error {
|
||||
url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file)
|
||||
fmt.Println("Fetching " + url)
|
||||
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
writer, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer writer.Close()
|
||||
|
||||
_, err = io.Copy(writer, res.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeFishAutoCompleteFile(ctx *cli.Context) error {
|
||||
// NOTE: to make sure this file is in sync with tea commands, we'd need to
|
||||
// - check if the file exists
|
||||
// - if it does, check if the tea version that wrote it is the currently running version
|
||||
// - if not, rewrite the file
|
||||
// on each application run
|
||||
// NOTE: this generates a completion that also suggests file names, which looks kinda messy..
|
||||
script, err := ctx.App.ToFishCompletion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
localPath, err := xdg.ConfigFile("fish/conf.d/tea_completion.fish")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer, err := os.Create(localPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = io.WriteString(writer, script); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Installed tab completion to %s\n", localPath)
|
||||
return nil
|
||||
}
|
38
cmd/branches.go
Normal file
38
cmd/branches.go
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/tea/cmd/branches"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdBranches represents to login a gitea server.
|
||||
var CmdBranches = cli.Command{
|
||||
Name: "branches",
|
||||
Aliases: []string{"branch", "b"},
|
||||
Category: catEntities,
|
||||
Usage: "Consult branches",
|
||||
Description: `Lists branches when called without argument. If a branch is provided, will show it in detail.`,
|
||||
ArgsUsage: "[<branch name>]",
|
||||
Action: runBranches,
|
||||
Commands: []*cli.Command{
|
||||
&branches.CmdBranchesList,
|
||||
&branches.CmdBranchesProtect,
|
||||
&branches.CmdBranchesUnprotect,
|
||||
},
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "comments",
|
||||
Usage: "Whether to display comments (will prompt if not provided & run interactively)",
|
||||
},
|
||||
}, branches.CmdBranchesList.Flags...),
|
||||
}
|
||||
|
||||
func runBranches(ctx context.Context, cmd *cli.Command) error {
|
||||
return branches.RunBranchesList(ctx, cmd)
|
||||
}
|
75
cmd/branches/list.go
Normal file
75
cmd/branches/list.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package branches
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var branchFieldsFlag = flags.FieldsFlag(print.BranchFields, []string{
|
||||
"name", "protected", "user-can-merge", "user-can-push",
|
||||
})
|
||||
|
||||
// CmdBranchesListFlags Flags for command list
|
||||
var CmdBranchesListFlags = append([]cli.Flag{
|
||||
branchFieldsFlag,
|
||||
&flags.PaginationPageFlag,
|
||||
&flags.PaginationLimitFlag,
|
||||
}, flags.AllDefaultFlags...)
|
||||
|
||||
// CmdBranchesList represents a sub command of branches to list branches
|
||||
var CmdBranchesList = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List branches of the repository",
|
||||
Description: `List branches of the repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunBranchesList,
|
||||
Flags: CmdBranchesListFlags,
|
||||
}
|
||||
|
||||
// RunBranchesList list branches
|
||||
func RunBranchesList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
owner := ctx.Owner
|
||||
if ctx.IsSet("owner") {
|
||||
owner = ctx.String("owner")
|
||||
}
|
||||
|
||||
var branches []*gitea.Branch
|
||||
var protections []*gitea.BranchProtection
|
||||
var err error
|
||||
branches, _, err = ctx.Login.Client().ListRepoBranches(owner, ctx.Repo, gitea.ListRepoBranchesOptions{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
protections, _, err = ctx.Login.Client().ListBranchProtections(owner, ctx.Repo, gitea.ListBranchProtectionsOptions{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields, err := branchFieldsFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.BranchesList(branches, protections, ctx.Output, fields)
|
||||
return nil
|
||||
}
|
102
cmd/branches/protect.go
Normal file
102
cmd/branches/protect.go
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package branches
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdBranchesProtectFlags Flags for command protect/unprotect
|
||||
var CmdBranchesProtectFlags = append([]cli.Flag{
|
||||
branchFieldsFlag,
|
||||
&flags.PaginationPageFlag,
|
||||
&flags.PaginationLimitFlag,
|
||||
}, flags.AllDefaultFlags...)
|
||||
|
||||
// CmdBranchesProtect represents a sub command of branches to protect a branch
|
||||
var CmdBranchesProtect = cli.Command{
|
||||
Name: "protect",
|
||||
Aliases: []string{"P"},
|
||||
Usage: "Protect branches",
|
||||
Description: `Block actions push/merge on specified branches`,
|
||||
ArgsUsage: "<branch>",
|
||||
Action: RunBranchesProtect,
|
||||
Flags: CmdBranchesProtectFlags,
|
||||
}
|
||||
|
||||
// CmdBranchesUnprotect represents a sub command of branches to protect a branch
|
||||
var CmdBranchesUnprotect = cli.Command{
|
||||
Name: "unprotect",
|
||||
Aliases: []string{"U"},
|
||||
Usage: "Unprotect branches",
|
||||
Description: `Suppress existing protections on specified branches`,
|
||||
ArgsUsage: "<branch>",
|
||||
Action: RunBranchesProtect,
|
||||
Flags: CmdBranchesProtectFlags,
|
||||
}
|
||||
|
||||
// RunBranchesProtect function to protect/unprotect a list of branches
|
||||
func RunBranchesProtect(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
if !cmd.Args().Present() {
|
||||
return fmt.Errorf("must specify at least one branch")
|
||||
}
|
||||
|
||||
owner := ctx.Owner
|
||||
if ctx.IsSet("owner") {
|
||||
owner = ctx.String("owner")
|
||||
}
|
||||
|
||||
for _, branch := range ctx.Args().Slice() {
|
||||
|
||||
var err error
|
||||
command := ctx.Command.Name
|
||||
if command == "protect" {
|
||||
_, _, err = ctx.Login.Client().CreateBranchProtection(owner, ctx.Repo, gitea.CreateBranchProtectionOption{
|
||||
BranchName: branch,
|
||||
RuleName: "",
|
||||
EnablePush: false,
|
||||
EnablePushWhitelist: false,
|
||||
PushWhitelistUsernames: []string{},
|
||||
PushWhitelistTeams: []string{},
|
||||
PushWhitelistDeployKeys: false,
|
||||
EnableMergeWhitelist: false,
|
||||
MergeWhitelistUsernames: []string{},
|
||||
MergeWhitelistTeams: []string{},
|
||||
EnableStatusCheck: false,
|
||||
StatusCheckContexts: []string{},
|
||||
RequiredApprovals: 1,
|
||||
EnableApprovalsWhitelist: false,
|
||||
ApprovalsWhitelistUsernames: []string{},
|
||||
ApprovalsWhitelistTeams: []string{},
|
||||
BlockOnRejectedReviews: false,
|
||||
BlockOnOfficialReviewRequests: false,
|
||||
BlockOnOutdatedBranch: false,
|
||||
DismissStaleApprovals: false,
|
||||
RequireSignedCommits: false,
|
||||
ProtectedFilePatterns: "",
|
||||
UnprotectedFilePatterns: "",
|
||||
})
|
||||
} else if command == "unprotect" {
|
||||
_, err = ctx.Login.Client().DeleteBranchProtection(owner, ctx.Repo, branch)
|
||||
} else {
|
||||
return fmt.Errorf("command %s is not supported", command)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
@ -8,4 +7,5 @@ var (
|
||||
catSetup = "SETUP"
|
||||
catEntities = "ENTITIES"
|
||||
catHelpers = "HELPERS"
|
||||
catMisc = "MISCELLANEOUS"
|
||||
)
|
||||
|
93
cmd/clone.go
Normal file
93
cmd/clone.go
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/debug"
|
||||
"code.gitea.io/tea/modules/git"
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRepoClone represents a sub command of repos to create a local copy
|
||||
var CmdRepoClone = cli.Command{
|
||||
Name: "clone",
|
||||
Aliases: []string{"C"},
|
||||
Usage: "Clone a repository locally",
|
||||
Description: `Clone a repository locally, without a local git installation required.
|
||||
The repo slug can be specified in different formats:
|
||||
gitea/tea
|
||||
tea
|
||||
gitea.com/gitea/tea
|
||||
git@gitea.com:gitea/tea
|
||||
https://gitea.com/gitea/tea
|
||||
ssh://gitea.com:22/gitea/tea
|
||||
When a host is specified in the repo-slug, it will override the login specified with --login.
|
||||
`,
|
||||
Category: catHelpers,
|
||||
Action: runRepoClone,
|
||||
ArgsUsage: "<repo-slug> [target dir]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "depth",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "num commits to fetch, defaults to all",
|
||||
},
|
||||
&flags.LoginFlag,
|
||||
},
|
||||
}
|
||||
|
||||
func runRepoClone(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
teaCmd := context.InitCommand(cmd)
|
||||
|
||||
args := teaCmd.Args()
|
||||
if args.Len() < 1 {
|
||||
return cli.ShowCommandHelp(ctx, cmd, "clone")
|
||||
}
|
||||
dir := args.Get(1)
|
||||
|
||||
var (
|
||||
login *config.Login = teaCmd.Login
|
||||
owner string = teaCmd.Login.User
|
||||
repo string
|
||||
)
|
||||
|
||||
// parse first arg as repo specifier
|
||||
repoSlug := args.Get(0)
|
||||
url, err := git.ParseURL(repoSlug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
debug.Printf("Cloning repository %s into %s", url.String(), dir)
|
||||
|
||||
owner, repo = utils.GetOwnerAndRepo(url.Path, login.User)
|
||||
if url.Host != "" {
|
||||
login = config.GetLoginByHost(url.Host)
|
||||
if login == nil {
|
||||
return fmt.Errorf("No login configured matching host '%s', run `tea login add` first", url.Host)
|
||||
}
|
||||
debug.Printf("Matched login '%s' for host '%s'", login.Name, url.Host)
|
||||
}
|
||||
|
||||
_, err = task.RepoClone(
|
||||
dir,
|
||||
login,
|
||||
owner,
|
||||
repo,
|
||||
interact.PromptPassword,
|
||||
teaCmd.Int("depth"),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
136
cmd/cmd.go
Normal file
136
cmd/cmd.go
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Tea is command line tool for Gitea.
|
||||
package cmd // import "code.gitea.io/tea"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Version holds the current tea version
|
||||
// If the Version is moved to another package or name changed,
|
||||
// build flags in .goreleaser.yaml or Makefile need to be updated accordingly.
|
||||
var Version = "development"
|
||||
|
||||
// Tags holds the build tags used
|
||||
var Tags = ""
|
||||
|
||||
// SDK holds the sdk version from go.mod
|
||||
var SDK = ""
|
||||
|
||||
// App creates and returns a tea Command with all subcommands set
|
||||
// it was separated from main so docs can be generated for it
|
||||
func App() *cli.Command {
|
||||
// make parsing tea --version easier, by printing /just/ the version string
|
||||
cli.VersionPrinter = func(c *cli.Command) { fmt.Fprintln(c.Writer, c.Version) }
|
||||
|
||||
return &cli.Command{
|
||||
Name: "tea",
|
||||
Usage: "command line tool to interact with Gitea",
|
||||
Description: appDescription,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Version: formatVersion(),
|
||||
Commands: []*cli.Command{
|
||||
&CmdLogin,
|
||||
&CmdLogout,
|
||||
&CmdWhoami,
|
||||
|
||||
&CmdIssues,
|
||||
&CmdPulls,
|
||||
&CmdLabels,
|
||||
&CmdMilestones,
|
||||
&CmdReleases,
|
||||
&CmdTrackedTimes,
|
||||
&CmdOrgs,
|
||||
&CmdRepos,
|
||||
&CmdBranches,
|
||||
&CmdAddComment,
|
||||
|
||||
&CmdOpen,
|
||||
&CmdNotifications,
|
||||
&CmdRepoClone,
|
||||
|
||||
&CmdAdmin,
|
||||
|
||||
&CmdGenerateManPage,
|
||||
},
|
||||
EnableShellCompletion: true,
|
||||
}
|
||||
}
|
||||
|
||||
func formatVersion() string {
|
||||
version := fmt.Sprintf("Version: %s\tgolang: %s",
|
||||
bold(Version),
|
||||
strings.ReplaceAll(runtime.Version(), "go", ""))
|
||||
|
||||
if len(Tags) != 0 {
|
||||
version += fmt.Sprintf("\tbuilt with: %s", strings.Replace(Tags, " ", ", ", -1))
|
||||
}
|
||||
|
||||
if len(SDK) != 0 {
|
||||
version += fmt.Sprintf("\tgo-sdk: %s", SDK)
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
var appDescription = `tea is a productivity helper for Gitea. It can be used to manage most entities on
|
||||
one or multiple Gitea instances & provides local helpers like 'tea pr checkout'.
|
||||
|
||||
tea tries to make use of context provided by the repository in $PWD if available.
|
||||
tea works best in a upstream/fork workflow, when the local main branch tracks the
|
||||
upstream repo. tea assumes that local git state is published on the remote before
|
||||
doing operations with tea. Configuration is persisted in $XDG_CONFIG_HOME/tea.
|
||||
`
|
||||
|
||||
var helpTemplate = bold(`
|
||||
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}`) + `
|
||||
{{if .Version}}{{if not .HideVersion}}version {{.Version}}{{end}}{{end}}
|
||||
|
||||
USAGE
|
||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .Commands}} command [subcommand] [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
|
||||
|
||||
DESCRIPTION
|
||||
{{.Description | nindent 3 | trim}}{{end}}{{if .VisibleCommands}}
|
||||
|
||||
COMMANDS{{range .VisibleCategories}}{{if .Name}}
|
||||
{{.Name}}:{{range .VisibleCommands}}
|
||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
|
||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
||||
|
||||
OPTIONS
|
||||
{{range $index, $option := .VisibleFlags}}{{if $index}}
|
||||
{{end}}{{$option}}{{end}}{{end}}
|
||||
|
||||
EXAMPLES
|
||||
tea login add # add a login once to get started
|
||||
|
||||
tea pulls # list open pulls for the repo in $PWD
|
||||
tea pulls --repo $HOME/foo # list open pulls for the repo in $HOME/foo
|
||||
tea pulls --remote upstream # list open pulls for the repo pointed at by
|
||||
# your local "upstream" git remote
|
||||
# list open pulls for any gitea repo at the given login instance
|
||||
tea pulls --repo gitea/tea --login gitea.com
|
||||
|
||||
tea milestone issues 0.7.0 # view open issues for milestone '0.7.0'
|
||||
tea issue 189 # view contents of issue 189
|
||||
tea open 189 # open web ui for issue 189
|
||||
tea open milestones # open web ui for milestones
|
||||
|
||||
# send gitea desktop notifications every 5 minutes (bash + libnotify)
|
||||
while :; do tea notifications --mine -o simple | xargs -i notify-send {}; sleep 300; done
|
||||
|
||||
ABOUT
|
||||
Written & maintained by The Gitea Authors.
|
||||
If you find a bug or want to contribute, we'll welcome you at https://gitea.com/gitea/tea.
|
||||
More info about Gitea itself on https://about.gitea.com.
|
||||
`
|
||||
|
||||
func bold(t string) string {
|
||||
return fmt.Sprintf("\033[1m%s\033[0m", t)
|
||||
}
|
@ -1,22 +1,26 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"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/v2"
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdAddComment is the main command to operate with notifications
|
||||
@ -31,7 +35,7 @@ var CmdAddComment = cli.Command{
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
func runAddComment(cmd *cli.Context) error {
|
||||
func runAddComment(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
@ -48,19 +52,28 @@ func runAddComment(cmd *cli.Context) error {
|
||||
body := strings.Join(ctx.Args().Tail(), " ")
|
||||
if interact.IsStdinPiped() {
|
||||
// custom solution until https://github.com/AlecAivazis/survey/issues/328 is fixed
|
||||
if bodyStdin, err := ioutil.ReadAll(ctx.App.Reader); err != nil {
|
||||
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 body, err = interact.PromptMultiline("Content"); err != nil {
|
||||
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 fmt.Errorf("No comment body provided")
|
||||
return errors.New("no comment content provided")
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package flags
|
||||
|
||||
@ -9,7 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CsvFlag is a wrapper around cli.StringFlag, with an added GetValues() method
|
||||
@ -21,22 +20,26 @@ type CsvFlag struct {
|
||||
|
||||
// NewCsvFlag creates a CsvFlag, while setting its usage string and default values
|
||||
func NewCsvFlag(name, usage string, aliases, availableValues, defaults []string) *CsvFlag {
|
||||
var availableDesc string
|
||||
if len(availableValues) != 0 {
|
||||
availableDesc = " Available values:"
|
||||
}
|
||||
return &CsvFlag{
|
||||
AvailableFields: availableValues,
|
||||
StringFlag: cli.StringFlag{
|
||||
Name: name,
|
||||
Aliases: aliases,
|
||||
Value: strings.Join(defaults, ","),
|
||||
Usage: fmt.Sprintf(`Comma-separated list of %s. Available values:
|
||||
Usage: fmt.Sprintf(`Comma-separated list of %s.%s
|
||||
%s
|
||||
`, usage, strings.Join(availableValues, ",")),
|
||||
`, usage, availableDesc, strings.Join(availableValues, ",")),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetValues returns the value of the flag, parsed as a commaseparated list
|
||||
func (f CsvFlag) GetValues(ctx *cli.Context) ([]string, error) {
|
||||
val := ctx.String(f.Name)
|
||||
func (f CsvFlag) GetValues(cmd *cli.Command) ([]string, error) {
|
||||
val := cmd.String(f.Name)
|
||||
selection := strings.Split(val, ",")
|
||||
if f.AvailableFields != nil && val != "" {
|
||||
for _, field := range selection {
|
||||
|
@ -1,19 +1,13 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"errors"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// LoginFlag provides flag to specify tea login profile
|
||||
@ -41,28 +35,56 @@ var RemoteFlag = cli.StringFlag{
|
||||
var OutputFlag = cli.StringFlag{
|
||||
Name: "output",
|
||||
Aliases: []string{"o"},
|
||||
Usage: "Output format. (csv, simple, table, tsv, yaml)",
|
||||
Usage: "Output format. (simple, table, csv, tsv, yaml, json)",
|
||||
}
|
||||
|
||||
// StateFlag provides flag to specify issue/pr state, defaulting to "open"
|
||||
var StateFlag = cli.StringFlag{
|
||||
Name: "state",
|
||||
Usage: "Filter by state (all|open|closed)",
|
||||
DefaultText: "open",
|
||||
var (
|
||||
paging gitea.ListOptions
|
||||
// ErrPage indicates that the provided page value is invalid (less than -1 or equal to 0).
|
||||
ErrPage = errors.New("page cannot be smaller than 1")
|
||||
// ErrLimit indicates that the provided limit value is invalid (negative).
|
||||
ErrLimit = errors.New("limit cannot be negative")
|
||||
)
|
||||
|
||||
// GetListOptions returns configured paging struct
|
||||
func GetListOptions() gitea.ListOptions {
|
||||
return paging
|
||||
}
|
||||
|
||||
// PaginationFlags provides all pagination related flags
|
||||
var PaginationFlags = []cli.Flag{
|
||||
&PaginationPageFlag,
|
||||
&PaginationLimitFlag,
|
||||
}
|
||||
|
||||
// PaginationPageFlag provides flag for pagination options
|
||||
var PaginationPageFlag = cli.StringFlag{
|
||||
var PaginationPageFlag = cli.IntFlag{
|
||||
Name: "page",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "specify page, default is 1",
|
||||
Usage: "specify page",
|
||||
Value: 1,
|
||||
Validator: func(i int) error {
|
||||
if i < 1 && i != -1 {
|
||||
return ErrPage
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Destination: &paging.Page,
|
||||
}
|
||||
|
||||
// PaginationLimitFlag provides flag for pagination options
|
||||
var PaginationLimitFlag = cli.StringFlag{
|
||||
var PaginationLimitFlag = cli.IntFlag{
|
||||
Name: "limit",
|
||||
Aliases: []string{"lm"},
|
||||
Usage: "specify limit of items per page",
|
||||
Value: 30,
|
||||
Validator: func(i int) error {
|
||||
if i < 0 {
|
||||
return ErrLimit
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Destination: &paging.PageSize,
|
||||
}
|
||||
|
||||
// LoginOutputFlags defines login and output flags that should
|
||||
@ -93,13 +115,6 @@ var AllDefaultFlags = append([]cli.Flag{
|
||||
&RemoteFlag,
|
||||
}, LoginOutputFlags...)
|
||||
|
||||
// IssuePRFlags defines flags that should be available on issue & pr listing flags.
|
||||
var IssuePRFlags = append([]cli.Flag{
|
||||
&StateFlag,
|
||||
&PaginationPageFlag,
|
||||
&PaginationLimitFlag,
|
||||
}, AllDefaultFlags...)
|
||||
|
||||
// NotificationFlags defines flags that should be available on notifications.
|
||||
var NotificationFlags = append([]cli.Flag{
|
||||
NotificationStateFlag,
|
||||
@ -121,82 +136,6 @@ var NotificationStateFlag = NewCsvFlag(
|
||||
[]string{"unread", "pinned"},
|
||||
)
|
||||
|
||||
// IssuePREditFlags defines flags for properties of issues and PRs
|
||||
var IssuePREditFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "title",
|
||||
Aliases: []string{"t"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "description",
|
||||
Aliases: []string{"d"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "assignees",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Comma-separated list of usernames to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "labels",
|
||||
Aliases: []string{"L"},
|
||||
Usage: "Comma-separated list of labels to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "deadline",
|
||||
Aliases: []string{"D"},
|
||||
Usage: "Deadline timestamp to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "milestone",
|
||||
Aliases: []string{"m"},
|
||||
Usage: "Milestone to assign",
|
||||
},
|
||||
}, LoginRepoFlags...)
|
||||
|
||||
// GetIssuePREditFlags parses all IssuePREditFlags
|
||||
func GetIssuePREditFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, error) {
|
||||
opts := gitea.CreateIssueOption{
|
||||
Title: ctx.String("title"),
|
||||
Body: ctx.String("description"),
|
||||
Assignees: strings.Split(ctx.String("assignees"), ","),
|
||||
}
|
||||
var err error
|
||||
|
||||
date := ctx.String("deadline")
|
||||
if date != "" {
|
||||
t, err := dateparse.ParseAny(date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.Deadline = &t
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
|
||||
labelNames := strings.Split(ctx.String("labels"), ",")
|
||||
if len(labelNames) != 0 {
|
||||
if client == nil {
|
||||
client = ctx.Login.Client()
|
||||
}
|
||||
if opts.Labels, err = task.ResolveLabelNames(client, ctx.Owner, ctx.Repo, labelNames); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if milestoneName := ctx.String("milestone"); len(milestoneName) != 0 {
|
||||
if client == nil {
|
||||
client = ctx.Login.Client()
|
||||
}
|
||||
ms, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestoneName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Milestone '%s' not found", milestoneName)
|
||||
}
|
||||
opts.Milestone = ms.ID
|
||||
}
|
||||
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
// FieldsFlag generates a flag selecting printable fields.
|
||||
// To retrieve the value, use f.GetValues()
|
||||
func FieldsFlag(availableFields, defaultFields []string) *CsvFlag {
|
125
cmd/flags/generic_test.go
Normal file
125
cmd/flags/generic_test.go
Normal file
@ -0,0 +1,125 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestPaginationFlags(t *testing.T) {
|
||||
var (
|
||||
defaultPage = PaginationPageFlag.Value
|
||||
defaultLimit = PaginationLimitFlag.Value
|
||||
)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedPage int
|
||||
expectedLimit int
|
||||
}{
|
||||
{
|
||||
name: "no flags",
|
||||
args: []string{"test"},
|
||||
expectedPage: defaultPage,
|
||||
expectedLimit: defaultLimit,
|
||||
},
|
||||
{
|
||||
name: "only paging",
|
||||
args: []string{"test", "--page", "5"},
|
||||
expectedPage: 5,
|
||||
expectedLimit: defaultLimit,
|
||||
},
|
||||
{
|
||||
name: "only limit",
|
||||
args: []string{"test", "--limit", "10"},
|
||||
expectedPage: defaultPage,
|
||||
expectedLimit: 10,
|
||||
},
|
||||
{
|
||||
name: "only limit",
|
||||
args: []string{"test", "--limit", "10"},
|
||||
expectedPage: defaultPage,
|
||||
expectedLimit: 10,
|
||||
},
|
||||
{
|
||||
name: "both flags",
|
||||
args: []string{"test", "--page", "2", "--limit", "20"},
|
||||
expectedPage: 2,
|
||||
expectedLimit: 20,
|
||||
},
|
||||
{ //TODO: Should no paging be applied as -1 or a separate flag? It's not obvious that page=-1 turns off paging and limit is ignored
|
||||
name: "no paging",
|
||||
args: []string{"test", "--limit", "20", "--page", "-1"},
|
||||
expectedPage: -1,
|
||||
expectedLimit: 20,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd := cli.Command{
|
||||
Name: "test-paging",
|
||||
Action: func(_ context.Context, cmd *cli.Command) error {
|
||||
assert.Equal(t, tc.expectedPage, cmd.Int("page"))
|
||||
assert.Equal(t, tc.expectedLimit, cmd.Int("limit"))
|
||||
return nil
|
||||
},
|
||||
Flags: PaginationFlags,
|
||||
}
|
||||
err := cmd.Run(context.Background(), tc.args)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
func TestPaginationFailures(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "negative limit",
|
||||
args: []string{"test", "--limit", "-10"},
|
||||
expectedError: ErrLimit,
|
||||
},
|
||||
{
|
||||
name: "negative paging",
|
||||
args: []string{"test", "--page", "-2"},
|
||||
expectedError: ErrPage,
|
||||
},
|
||||
{
|
||||
name: "zero paging",
|
||||
args: []string{"test", "--page", "0"},
|
||||
expectedError: ErrPage,
|
||||
},
|
||||
{
|
||||
//urfave does not validate all flags in one pass
|
||||
name: "negative paging and paging",
|
||||
args: []string{"test", "--page", "-2", "--limit", "-10"},
|
||||
expectedError: ErrPage,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
cmd := cli.Command{
|
||||
Name: "test-paging",
|
||||
Flags: PaginationFlags,
|
||||
Writer: io.Discard,
|
||||
ErrWriter: io.Discard,
|
||||
}
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := cmd.Run(context.Background(), tc.args)
|
||||
require.ErrorContains(t, err, tc.expectedError.Error())
|
||||
// require.ErrorIs(t, err, tc.expectedError)
|
||||
})
|
||||
}
|
||||
}
|
238
cmd/flags/issue_pr.go
Normal file
238
cmd/flags/issue_pr.go
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// StateFlag provides flag to specify issue/pr state, defaulting to "open"
|
||||
var StateFlag = cli.StringFlag{
|
||||
Name: "state",
|
||||
Usage: "Filter by state (all|open|closed)",
|
||||
DefaultText: "open",
|
||||
}
|
||||
|
||||
// MilestoneFilterFlag is a CSV flag used to filter issues by milestones
|
||||
var MilestoneFilterFlag = NewCsvFlag(
|
||||
"milestones",
|
||||
"milestones to match issues against",
|
||||
[]string{"m"}, nil, nil)
|
||||
|
||||
// LabelFilterFlag is a CSV flag used to filter issues by labels
|
||||
var LabelFilterFlag = NewCsvFlag(
|
||||
"labels",
|
||||
"labels to match issues against",
|
||||
[]string{"L"}, nil, nil)
|
||||
|
||||
// PRListingFlags defines flags that should be available on pr listing flags.
|
||||
var PRListingFlags = append([]cli.Flag{
|
||||
&StateFlag,
|
||||
&PaginationPageFlag,
|
||||
&PaginationLimitFlag,
|
||||
}, AllDefaultFlags...)
|
||||
|
||||
// IssueListingFlags defines flags that should be available on issue listing flags.
|
||||
var IssueListingFlags = append([]cli.Flag{
|
||||
&StateFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "kind",
|
||||
Aliases: []string{"K"},
|
||||
Usage: "Whether to return `issues`, `pulls`, or `all` (you can use this to apply advanced search filters to PRs)",
|
||||
DefaultText: "issues",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "keyword",
|
||||
Aliases: []string{"k"},
|
||||
Usage: "Filter by search string",
|
||||
},
|
||||
LabelFilterFlag,
|
||||
MilestoneFilterFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "author",
|
||||
Aliases: []string{"A"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "assignee",
|
||||
Aliases: []string{"a"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "mentions",
|
||||
Aliases: []string{"M"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner",
|
||||
Aliases: []string{"org"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Aliases: []string{"F"},
|
||||
Usage: "Filter by activity after this date",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "until",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Filter by activity before this date",
|
||||
},
|
||||
&PaginationPageFlag,
|
||||
&PaginationLimitFlag,
|
||||
}, AllDefaultFlags...)
|
||||
|
||||
// issuePRFlags defines shared flags between flags IssuePRCreateFlags and IssuePREditFlags
|
||||
var issuePRFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "title",
|
||||
Aliases: []string{"t"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "description",
|
||||
Aliases: []string{"d"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "referenced-version",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "commit-hash or tag name to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "milestone",
|
||||
Aliases: []string{"m"},
|
||||
Usage: "Milestone to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "deadline",
|
||||
Aliases: []string{"D"},
|
||||
Usage: "Deadline timestamp to assign",
|
||||
},
|
||||
}, LoginRepoFlags...)
|
||||
|
||||
// IssuePRCreateFlags defines flags for creation of issues and PRs
|
||||
var IssuePRCreateFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "assignees",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Comma-separated list of usernames to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "labels",
|
||||
Aliases: []string{"L"},
|
||||
Usage: "Comma-separated list of labels to assign",
|
||||
},
|
||||
}, issuePRFlags...)
|
||||
|
||||
// GetIssuePRCreateFlags parses all IssuePREditFlags
|
||||
func GetIssuePRCreateFlags(ctx *context.TeaContext) (*gitea.CreateIssueOption, error) {
|
||||
opts := gitea.CreateIssueOption{
|
||||
Title: ctx.String("title"),
|
||||
Body: ctx.String("description"),
|
||||
Assignees: strings.Split(ctx.String("assignees"), ","),
|
||||
}
|
||||
var err error
|
||||
|
||||
date := ctx.String("deadline")
|
||||
if date != "" {
|
||||
t, err := dateparse.ParseAny(date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.Deadline = &t
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
|
||||
labelNames := strings.Split(ctx.String("labels"), ",")
|
||||
if len(labelNames) != 0 {
|
||||
if client == nil {
|
||||
client = ctx.Login.Client()
|
||||
}
|
||||
if opts.Labels, err = task.ResolveLabelNames(client, ctx.Owner, ctx.Repo, labelNames); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if milestoneName := ctx.String("milestone"); len(milestoneName) != 0 {
|
||||
if client == nil {
|
||||
client = ctx.Login.Client()
|
||||
}
|
||||
ms, _, err := client.GetMilestoneByName(ctx.Owner, ctx.Repo, milestoneName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Milestone '%s' not found", milestoneName)
|
||||
}
|
||||
opts.Milestone = ms.ID
|
||||
}
|
||||
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
// IssuePREditFlags defines flags for editing properties of issues and PRs
|
||||
var IssuePREditFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "add-assignees",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Comma-separated list of usernames to assign",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "add-labels",
|
||||
Aliases: []string{"L"},
|
||||
Usage: "Comma-separated list of labels to assign. Takes precedence over --remove-labels",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "remove-labels",
|
||||
Usage: "Comma-separated list of labels to remove",
|
||||
},
|
||||
}, issuePRFlags...)
|
||||
|
||||
// GetIssuePREditFlags parses all IssuePREditFlags
|
||||
func GetIssuePREditFlags(ctx *context.TeaContext) (*task.EditIssueOption, error) {
|
||||
opts := task.EditIssueOption{}
|
||||
if ctx.IsSet("title") {
|
||||
val := ctx.String("title")
|
||||
opts.Title = &val
|
||||
}
|
||||
if ctx.IsSet("description") {
|
||||
val := ctx.String("description")
|
||||
opts.Body = &val
|
||||
}
|
||||
if ctx.IsSet("referenced-version") {
|
||||
val := ctx.String("referenced-version")
|
||||
opts.Ref = &val
|
||||
}
|
||||
if ctx.IsSet("milestone") {
|
||||
val := ctx.String("milestone")
|
||||
opts.Milestone = &val
|
||||
}
|
||||
if ctx.IsSet("deadline") {
|
||||
date := ctx.String("deadline")
|
||||
if date == "" {
|
||||
opts.Deadline = &time.Time{}
|
||||
} else {
|
||||
t, err := dateparse.ParseAny(date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.Deadline = &t
|
||||
}
|
||||
}
|
||||
if ctx.IsSet("add-assignees") {
|
||||
val := ctx.String("add-assignees")
|
||||
opts.AddAssignees = strings.Split(val, ",")
|
||||
}
|
||||
if ctx.IsSet("add-labels") {
|
||||
val := ctx.String("add-labels")
|
||||
opts.AddLabels = strings.Split(val, ",")
|
||||
}
|
||||
if ctx.IsSet("remove-labels") {
|
||||
val := ctx.String("remove-labels")
|
||||
opts.RemoveLabels = strings.Split(val, ",")
|
||||
}
|
||||
return &opts, nil
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/issues"
|
||||
@ -13,7 +13,7 @@ import (
|
||||
"code.gitea.io/tea/modules/print"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdIssues represents to login a gitea server.
|
||||
@ -25,28 +25,29 @@ var CmdIssues = cli.Command{
|
||||
Description: `Lists issues when called without argument. If issue index is provided, will show it in detail.`,
|
||||
ArgsUsage: "[<issue index>]",
|
||||
Action: runIssues,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&issues.CmdIssuesList,
|
||||
&issues.CmdIssuesCreate,
|
||||
&issues.CmdIssuesEdit,
|
||||
&issues.CmdIssuesReopen,
|
||||
&issues.CmdIssuesClose,
|
||||
},
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "comments",
|
||||
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
|
||||
Usage: "Whether to display comments (will prompt if not provided & run interactively)",
|
||||
},
|
||||
}, issues.CmdIssuesList.Flags...),
|
||||
}
|
||||
|
||||
func runIssues(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runIssueDetail(ctx, ctx.Args().First())
|
||||
func runIssues(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runIssueDetail(ctx, cmd, cmd.Args().First())
|
||||
}
|
||||
return issues.RunIssuesList(ctx)
|
||||
return issues.RunIssuesList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runIssueDetail(cmd *cli.Context, index string) error {
|
||||
func runIssueDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
@ -54,11 +55,16 @@ func runIssueDetail(cmd *cli.Context, index string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
issue, _, err := ctx.Login.Client().GetIssue(ctx.Owner, ctx.Repo, idx)
|
||||
client := ctx.Login.Client()
|
||||
issue, _, err := client.GetIssue(ctx.Owner, ctx.Repo, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.IssueDetails(issue)
|
||||
reactions, _, err := client.GetIssueReactions(ctx.Owner, ctx.Repo, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.IssueDetails(issue, reactions)
|
||||
|
||||
if issue.Comments > 0 {
|
||||
err = interact.ShowCommentsMaybeInteractive(ctx, idx, issue.Comments)
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -13,40 +13,47 @@ import (
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdIssuesClose represents a sub command of issues to close an issue
|
||||
var CmdIssuesClose = cli.Command{
|
||||
Name: "close",
|
||||
Usage: "Change state of an issue to 'closed'",
|
||||
Description: `Change state of an issue to 'closed'`,
|
||||
ArgsUsage: "<issue index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
Usage: "Change state of one ore more issues to 'closed'",
|
||||
Description: `Change state of one ore more issues to 'closed'`,
|
||||
ArgsUsage: "<issue index> [<issue index>...]",
|
||||
Action: func(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
var s = gitea.StateClosed
|
||||
return editIssueState(ctx, gitea.EditIssueOption{State: &s})
|
||||
return editIssueState(ctx, cmd, gitea.EditIssueOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
// editIssueState abstracts the arg parsing to edit the given issue
|
||||
func editIssueState(cmd *cli.Context, opts gitea.EditIssueOption) error {
|
||||
func editIssueState(_ stdctx.Context, cmd *cli.Command, opts gitea.EditIssueOption) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
if ctx.Args().Len() == 0 {
|
||||
return fmt.Errorf(ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
index, err := utils.ArgToIndex(ctx.Args().First())
|
||||
indices, err := utils.ArgsToIndices(ctx.Args().Slice())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
issue, _, err := ctx.Login.Client().EditIssue(ctx.Owner, ctx.Repo, index, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := ctx.Login.Client()
|
||||
for _, index := range indices {
|
||||
issue, _, err := client.EditIssue(ctx.Owner, ctx.Repo, index, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.IssueDetails(issue)
|
||||
if len(indices) > 1 {
|
||||
fmt.Println(issue.HTMLURL)
|
||||
} else {
|
||||
print.IssueDetails(issue, nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
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/task"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdIssuesCreate represents a sub command of issues to create issue
|
||||
@ -19,19 +20,24 @@ var CmdIssuesCreate = cli.Command{
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create an issue on repository",
|
||||
Description: `Create an issue on repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runIssuesCreate,
|
||||
Flags: flags.IssuePREditFlags,
|
||||
Flags: flags.IssuePRCreateFlags,
|
||||
}
|
||||
|
||||
func runIssuesCreate(cmd *cli.Context) error {
|
||||
func runIssuesCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
if ctx.NumFlags() == 0 {
|
||||
return interact.CreateIssue(ctx.Login, ctx.Owner, ctx.Repo)
|
||||
err := interact.CreateIssue(ctx.Login, ctx.Owner, ctx.Repo)
|
||||
if err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
opts, err := flags.GetIssuePREditFlags(ctx)
|
||||
opts, err := flags.GetIssuePRCreateFlags(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
75
cmd/issues/edit.go
Normal file
75
cmd/issues/edit.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// CmdIssuesEdit is the subcommand of issues to edit issues
|
||||
var CmdIssuesEdit = cli.Command{
|
||||
Name: "edit",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Edit one or more issues",
|
||||
Description: `Edit one or more issues. To unset a property again,
|
||||
use an empty string (eg. --milestone "").`,
|
||||
ArgsUsage: "<idx> [<idx>...]",
|
||||
Action: runIssuesEdit,
|
||||
Flags: flags.IssuePREditFlags,
|
||||
}
|
||||
|
||||
func runIssuesEdit(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
if !cmd.Args().Present() {
|
||||
return fmt.Errorf("must specify at least one issue index")
|
||||
}
|
||||
|
||||
opts, err := flags.GetIssuePREditFlags(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indices, err := utils.ArgsToIndices(ctx.Args().Slice())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
for _, opts.Index = range indices {
|
||||
if ctx.NumFlags() == 0 {
|
||||
var err error
|
||||
opts, err = interact.EditIssue(*ctx, opts.Index)
|
||||
if err != nil {
|
||||
if interact.IsQuitting(err) {
|
||||
return nil // user quit
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
issue, err := task.EditIssue(ctx, client, *opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.Args().Len() > 1 {
|
||||
fmt.Println(issue.HTMLURL)
|
||||
} else {
|
||||
print.IssueDetails(issue, nil)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,20 +1,24 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var issueFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{
|
||||
"index", "title", "state", "author", "milestone", "labels",
|
||||
"index", "title", "state", "author", "milestone", "labels", "owner", "repo",
|
||||
})
|
||||
|
||||
// CmdIssuesList represents a sub command of issues to list issues
|
||||
@ -23,33 +27,99 @@ var CmdIssuesList = cli.Command{
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List issues of the repository",
|
||||
Description: `List issues of the repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunIssuesList,
|
||||
Flags: append([]cli.Flag{issueFieldsFlag}, flags.IssuePRFlags...),
|
||||
Flags: append([]cli.Flag{issueFieldsFlag}, flags.IssueListingFlags...),
|
||||
}
|
||||
|
||||
// RunIssuesList list issues
|
||||
func RunIssuesList(cmd *cli.Context) error {
|
||||
func RunIssuesList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
state := gitea.StateOpen
|
||||
switch ctx.String("state") {
|
||||
case "all":
|
||||
state = gitea.StateAll
|
||||
case "open":
|
||||
case "", "open":
|
||||
state = gitea.StateOpen
|
||||
case "closed":
|
||||
state = gitea.StateClosed
|
||||
default:
|
||||
return fmt.Errorf("unknown state '%s'", ctx.String("state"))
|
||||
}
|
||||
|
||||
issues, _, err := ctx.Login.Client().ListRepoIssues(ctx.Owner, ctx.Repo, gitea.ListIssueOption{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
State: state,
|
||||
Type: gitea.IssueTypeIssue,
|
||||
})
|
||||
kind := gitea.IssueTypeIssue
|
||||
switch ctx.String("kind") {
|
||||
case "", "issues", "issue":
|
||||
kind = gitea.IssueTypeIssue
|
||||
case "pulls", "pull", "pr":
|
||||
kind = gitea.IssueTypePull
|
||||
case "all":
|
||||
kind = gitea.IssueTypeAll
|
||||
default:
|
||||
return fmt.Errorf("unknown kind '%s'", ctx.String("kind"))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
var err error
|
||||
var from, until time.Time
|
||||
if ctx.IsSet("from") {
|
||||
from, err = dateparse.ParseLocal(ctx.String("from"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ctx.IsSet("until") {
|
||||
until, err = dateparse.ParseLocal(ctx.String("until"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
owner := ctx.Owner
|
||||
if ctx.IsSet("owner") {
|
||||
owner = ctx.String("owner")
|
||||
}
|
||||
|
||||
// ignore error, as we don't do any input validation on these flags
|
||||
labels, _ := flags.LabelFilterFlag.GetValues(cmd)
|
||||
milestones, _ := flags.MilestoneFilterFlag.GetValues(cmd)
|
||||
var issues []*gitea.Issue
|
||||
if ctx.Repo != "" {
|
||||
issues, _, err = ctx.Login.Client().ListRepoIssues(owner, ctx.Repo, gitea.ListIssueOption{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
State: state,
|
||||
Type: kind,
|
||||
KeyWord: ctx.String("keyword"),
|
||||
CreatedBy: ctx.String("author"),
|
||||
AssignedBy: ctx.String("assigned-to"),
|
||||
MentionedBy: ctx.String("mentions"),
|
||||
Labels: labels,
|
||||
Milestones: milestones,
|
||||
Since: from,
|
||||
Before: until,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
issues, _, err = ctx.Login.Client().ListIssues(gitea.ListIssueOption{
|
||||
ListOptions: flags.GetListOptions(),
|
||||
State: state,
|
||||
Type: kind,
|
||||
KeyWord: ctx.String("keyword"),
|
||||
CreatedBy: ctx.String("author"),
|
||||
AssignedBy: ctx.String("assigned-to"),
|
||||
MentionedBy: ctx.String("mentions"),
|
||||
Labels: labels,
|
||||
Milestones: milestones,
|
||||
Since: from,
|
||||
Before: until,
|
||||
Owner: owner,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fields, err := issueFieldsFlag.GetValues(cmd)
|
||||
|
@ -1,26 +1,27 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdIssuesReopen represents a sub command of issues to open an issue
|
||||
var CmdIssuesReopen = cli.Command{
|
||||
Name: "reopen",
|
||||
Aliases: []string{"open"},
|
||||
Usage: "Change state of an issue to 'open'",
|
||||
Description: `Change state of an issue to 'open'`,
|
||||
ArgsUsage: "<issue index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
Usage: "Change state of one or more issues to 'open'",
|
||||
Description: `Change state of one or more issues to 'open'`,
|
||||
ArgsUsage: "<issue index> [<issue index>...]",
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var s = gitea.StateOpen
|
||||
return editIssueState(ctx, gitea.EditIssueOption{State: &s})
|
||||
return editIssueState(ctx, cmd, gitea.EditIssueOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/labels"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLabels represents to operate repositories' labels.
|
||||
@ -18,8 +18,9 @@ var CmdLabels = cli.Command{
|
||||
Category: catEntities,
|
||||
Usage: "Manage issue labels",
|
||||
Description: `Manage issue labels`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runLabels,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&labels.CmdLabelsList,
|
||||
&labels.CmdLabelCreate,
|
||||
&labels.CmdLabelUpdate,
|
||||
@ -28,13 +29,13 @@ var CmdLabels = cli.Command{
|
||||
Flags: labels.CmdLabelsList.Flags,
|
||||
}
|
||||
|
||||
func runLabels(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runLabelsDetails(ctx)
|
||||
func runLabels(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runLabelsDetails(cmd)
|
||||
}
|
||||
return labels.RunLabelsList(ctx)
|
||||
return labels.RunLabelsList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runLabelsDetails(ctx *cli.Context) error {
|
||||
func runLabelsDetails(cmd *cli.Command) error {
|
||||
return fmt.Errorf("Not yet implemented")
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
stdctx "context"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@ -14,7 +14,7 @@ import (
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLabelCreate represents a sub command of labels to create label.
|
||||
@ -23,6 +23,7 @@ var CmdLabelCreate = cli.Command{
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a label",
|
||||
Description: `Create a label`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runLabelCreate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@ -44,7 +45,7 @@ var CmdLabelCreate = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runLabelCreate(cmd *cli.Context) error {
|
||||
func runLabelCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package labels
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLabelDelete represents a sub command of labels to delete label.
|
||||
@ -17,6 +18,7 @@ var CmdLabelDelete = cli.Command{
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete a label",
|
||||
Description: `Delete a label`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runLabelDelete,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.IntFlag{
|
||||
@ -26,7 +28,7 @@ var CmdLabelDelete = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runLabelDelete(cmd *cli.Context) error {
|
||||
func runLabelDelete(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
|
@ -1,17 +1,18 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLabelsList represents a sub command of labels to list labels
|
||||
@ -20,6 +21,7 @@ var CmdLabelsList = cli.Command{
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List labels",
|
||||
Description: "List labels",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunLabelsList,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
@ -33,13 +35,13 @@ var CmdLabelsList = cli.Command{
|
||||
}
|
||||
|
||||
// RunLabelsList list labels.
|
||||
func RunLabelsList(cmd *cli.Context) error {
|
||||
func RunLabelsList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
client := ctx.Login.Client()
|
||||
labels, _, err := client.ListRepoLabels(ctx.Owner, ctx.Repo, gitea.ListLabelsOptions{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1,15 +1,16 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLabelUpdate represents a sub command of labels to update label.
|
||||
@ -17,6 +18,7 @@ var CmdLabelUpdate = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "Update a label",
|
||||
Description: `Update a label`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runLabelUpdate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.IntFlag{
|
||||
@ -38,7 +40,7 @@ var CmdLabelUpdate = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runLabelUpdate(cmd *cli.Context) error {
|
||||
func runLabelUpdate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
|
18
cmd/login.go
18
cmd/login.go
@ -1,17 +1,17 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/login"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLogin represents to login a gitea server.
|
||||
@ -23,20 +23,22 @@ var CmdLogin = cli.Command{
|
||||
Description: `Log in to a Gitea server`,
|
||||
ArgsUsage: "[<login name>]",
|
||||
Action: runLogins,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&login.CmdLoginList,
|
||||
&login.CmdLoginAdd,
|
||||
&login.CmdLoginEdit,
|
||||
&login.CmdLoginDelete,
|
||||
&login.CmdLoginSetDefault,
|
||||
&login.CmdLoginHelper,
|
||||
&login.CmdLoginOAuthRefresh,
|
||||
},
|
||||
}
|
||||
|
||||
func runLogins(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runLoginDetail(ctx.Args().First())
|
||||
func runLogins(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runLoginDetail(cmd.Args().First())
|
||||
}
|
||||
return login.RunLoginList(ctx)
|
||||
return login.RunLoginList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runLoginDetail(name string) error {
|
||||
|
120
cmd/login/add.go
120
cmd/login/add.go
@ -1,14 +1,17 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/modules/auth"
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginAdd represents to login a gitea server.
|
||||
@ -16,6 +19,7 @@ var CmdLoginAdd = cli.Command{
|
||||
Name: "add",
|
||||
Usage: "Add a Gitea login",
|
||||
Description: `Add a Gitea login, without args it will create one interactively`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
@ -26,56 +30,136 @@ var CmdLoginAdd = cli.Command{
|
||||
Name: "url",
|
||||
Aliases: []string{"u"},
|
||||
Value: "https://gitea.com",
|
||||
EnvVars: []string{"GITEA_SERVER_URL"},
|
||||
Sources: cli.EnvVars("GITEA_SERVER_URL"),
|
||||
Usage: "Server URL",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-version-check",
|
||||
Aliases: []string{"nv"},
|
||||
Usage: "Do not check version of Gitea instance",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"t"},
|
||||
Value: "",
|
||||
EnvVars: []string{"GITEA_SERVER_TOKEN"},
|
||||
Sources: cli.EnvVars("GITEA_SERVER_TOKEN"),
|
||||
Usage: "Access token. Can be obtained from Settings > Applications",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "user",
|
||||
Value: "",
|
||||
EnvVars: []string{"GITEA_SERVER_USER"},
|
||||
Sources: cli.EnvVars("GITEA_SERVER_USER"),
|
||||
Usage: "User for basic auth (will create token)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "password",
|
||||
Aliases: []string{"pwd"},
|
||||
Value: "",
|
||||
EnvVars: []string{"GITEA_SERVER_PASSWORD"},
|
||||
Sources: cli.EnvVars("GITEA_SERVER_PASSWORD"),
|
||||
Usage: "Password for basic auth (will create token)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "otp",
|
||||
Sources: cli.EnvVars("GITEA_SERVER_OTP"),
|
||||
Usage: "OTP token for auth, if necessary",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "scopes",
|
||||
Sources: cli.EnvVars("GITEA_SCOPES"),
|
||||
Usage: "Token scopes to add when creating a new token, separated by a comma",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ssh-key",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Path to a SSH key to use, overrides auto-discovery",
|
||||
Usage: "Path to a SSH key/certificate to use, overrides auto-discovery",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "insecure",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Disable TLS verification",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ssh-agent-principal",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Use SSH certificate with specified principal to login (needs a running ssh-agent with certificate loaded)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ssh-agent-key",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Use SSH public key or SSH fingerprint to login (needs a running ssh-agent with ssh key loaded)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "helper",
|
||||
Aliases: []string{"j"},
|
||||
Usage: "Add helper",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "oauth",
|
||||
Aliases: []string{"o"},
|
||||
Usage: "Use interactive OAuth2 flow for authentication",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "client-id",
|
||||
Usage: "OAuth client ID (for use with --oauth)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "redirect-url",
|
||||
Usage: "OAuth redirect URL (for use with --oauth)",
|
||||
},
|
||||
},
|
||||
Action: runLoginAdd,
|
||||
}
|
||||
|
||||
func runLoginAdd(ctx *cli.Context) error {
|
||||
func runLoginAdd(_ context.Context, cmd *cli.Command) error {
|
||||
// if no args create login interactive
|
||||
if ctx.NumFlags() == 0 {
|
||||
return interact.CreateLogin()
|
||||
if cmd.NumFlags() == 0 {
|
||||
if err := interact.CreateLogin(); err != nil && !interact.IsQuitting(err) {
|
||||
return fmt.Errorf("error adding login: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// if OAuth flag is provided, use OAuth2 PKCE flow
|
||||
if cmd.Bool("oauth") {
|
||||
opts := auth.OAuthOptions{
|
||||
Name: cmd.String("name"),
|
||||
URL: cmd.String("url"),
|
||||
Insecure: cmd.Bool("insecure"),
|
||||
}
|
||||
|
||||
// Only set clientID if provided
|
||||
if cmd.String("client-id") != "" {
|
||||
opts.ClientID = cmd.String("client-id")
|
||||
}
|
||||
|
||||
// Only set redirect URL if provided
|
||||
if cmd.String("redirect-url") != "" {
|
||||
opts.RedirectURL = cmd.String("redirect-url")
|
||||
}
|
||||
|
||||
return auth.OAuthLoginWithFullOptions(opts)
|
||||
}
|
||||
|
||||
sshAgent := false
|
||||
if cmd.String("ssh-agent-key") != "" || cmd.String("ssh-agent-principal") != "" {
|
||||
sshAgent = true
|
||||
}
|
||||
|
||||
// else use args to add login
|
||||
return task.CreateLogin(
|
||||
ctx.String("name"),
|
||||
ctx.String("token"),
|
||||
ctx.String("user"),
|
||||
ctx.String("password"),
|
||||
ctx.String("ssh-key"),
|
||||
ctx.String("url"),
|
||||
ctx.Bool("insecure"))
|
||||
cmd.String("name"),
|
||||
cmd.String("token"),
|
||||
cmd.String("user"),
|
||||
cmd.String("password"),
|
||||
cmd.String("otp"),
|
||||
cmd.String("scopes"),
|
||||
cmd.String("ssh-key"),
|
||||
cmd.String("url"),
|
||||
cmd.String("ssh-agent-principal"),
|
||||
cmd.String("ssh-agent-key"),
|
||||
cmd.Bool("insecure"),
|
||||
sshAgent,
|
||||
!cmd.Bool("no-version-check"),
|
||||
cmd.Bool("helper"),
|
||||
)
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginSetDefault represents to login a gitea server.
|
||||
@ -23,8 +23,8 @@ var CmdLoginSetDefault = cli.Command{
|
||||
Flags: []cli.Flag{&flags.OutputFlag},
|
||||
}
|
||||
|
||||
func runLoginSetDefault(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 0 {
|
||||
func runLoginSetDefault(_ context.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 0 {
|
||||
l, err := config.GetDefaultLogin()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -33,6 +33,6 @@ func runLoginSetDefault(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
name := ctx.Args().First()
|
||||
name := cmd.Args().First()
|
||||
return config.SetDefaultLogin(name)
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/modules/config"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginDelete is a command to delete a login
|
||||
@ -24,7 +24,7 @@ var CmdLoginDelete = cli.Command{
|
||||
}
|
||||
|
||||
// RunLoginDelete runs the action of a login delete command
|
||||
func RunLoginDelete(ctx *cli.Context) error {
|
||||
func RunLoginDelete(_ context.Context, cmd *cli.Command) error {
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -32,8 +32,8 @@ func RunLoginDelete(ctx *cli.Context) error {
|
||||
|
||||
var name string
|
||||
|
||||
if len(ctx.Args().First()) != 0 {
|
||||
name = ctx.Args().First()
|
||||
if len(cmd.Args().First()) != 0 {
|
||||
name = cmd.Args().First()
|
||||
} else if len(logins) == 1 {
|
||||
name = logins[0].Name
|
||||
} else {
|
||||
|
@ -1,15 +1,19 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginEdit represents to login a gitea server.
|
||||
@ -18,10 +22,20 @@ var CmdLoginEdit = cli.Command{
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Edit Gitea logins",
|
||||
Description: `Edit Gitea logins`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runLoginEdit,
|
||||
Flags: []cli.Flag{&flags.OutputFlag},
|
||||
}
|
||||
|
||||
func runLoginEdit(_ *cli.Context) error {
|
||||
func runLoginEdit(_ context.Context, _ *cli.Command) error {
|
||||
if e, ok := os.LookupEnv("EDITOR"); ok && e != "" {
|
||||
cmd := exec.Command(e, config.GetConfigPath())
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
return open.Start(config.GetConfigPath())
|
||||
}
|
||||
|
131
cmd/login/helper.go
Normal file
131
cmd/login/helper.go
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/tea/modules/auth"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginHelper represents to login a gitea helper.
|
||||
var CmdLoginHelper = cli.Command{
|
||||
Name: "helper",
|
||||
Aliases: []string{"git-credential"},
|
||||
Usage: "Git helper",
|
||||
Description: `Git helper`,
|
||||
Hidden: true,
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "store",
|
||||
Description: "Command drops",
|
||||
Aliases: []string{"erase"},
|
||||
Action: func(_ context.Context, _ *cli.Command) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "setup",
|
||||
Description: "Setup helper to tea authenticate",
|
||||
Action: func(_ context.Context, _ *cli.Command) error {
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, login := range logins {
|
||||
added, err := task.SetupHelper(login)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if added {
|
||||
fmt.Printf("Added \"%s\"\n", login.Name)
|
||||
} else {
|
||||
fmt.Printf("\"%s\" has already been added!\n", login.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "get",
|
||||
Description: "Get token to auth",
|
||||
Action: func(_ context.Context, cmd *cli.Command) error {
|
||||
wants := map[string]string{}
|
||||
s := bufio.NewScanner(os.Stdin)
|
||||
for s.Scan() {
|
||||
line := s.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
key, value := parts[0], parts[1]
|
||||
if key == "url" {
|
||||
u, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wants["protocol"] = u.Scheme
|
||||
wants["host"] = u.Host
|
||||
wants["path"] = u.Path
|
||||
wants["username"] = u.User.Username()
|
||||
wants["password"], _ = u.User.Password()
|
||||
} else {
|
||||
wants[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
if len(wants["host"]) == 0 {
|
||||
log.Fatal("Require hostname")
|
||||
} else if len(wants["protocol"]) == 0 {
|
||||
wants["protocol"] = "http"
|
||||
}
|
||||
|
||||
userConfig := config.GetLoginByHost(wants["host"])
|
||||
if userConfig == nil {
|
||||
log.Fatal("host not exists")
|
||||
} else if len(userConfig.Token) == 0 {
|
||||
log.Fatal("User no set")
|
||||
}
|
||||
|
||||
host, err := url.Parse(userConfig.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if userConfig.TokenExpiry > 0 && time.Now().Unix() > userConfig.TokenExpiry {
|
||||
// Token is expired, refresh it
|
||||
err = auth.RefreshAccessToken(userConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Once token is refreshed, get the latest from the updated config
|
||||
refreshedConfig := config.GetLoginByHost(wants["host"])
|
||||
if refreshedConfig != nil {
|
||||
userConfig = refreshedConfig
|
||||
}
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(os.Stdout, "protocol=%s\nhost=%s\nusername=%s\npassword=%s\n", host.Scheme, host.Host, userConfig.User, userConfig.Token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginList represents to login a gitea server.
|
||||
@ -18,12 +19,13 @@ var CmdLoginList = cli.Command{
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Gitea logins",
|
||||
Description: `List Gitea logins`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunLoginList,
|
||||
Flags: []cli.Flag{&flags.OutputFlag},
|
||||
}
|
||||
|
||||
// RunLoginList list all logins
|
||||
func RunLoginList(cmd *cli.Context) error {
|
||||
func RunLoginList(_ context.Context, cmd *cli.Command) error {
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
return err
|
||||
|
59
cmd/login/oauth_refresh.go
Normal file
59
cmd/login/oauth_refresh.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/modules/auth"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLoginOAuthRefresh represents a command to refresh an OAuth token
|
||||
var CmdLoginOAuthRefresh = cli.Command{
|
||||
Name: "oauth-refresh",
|
||||
Usage: "Refresh an OAuth token",
|
||||
Description: "Manually refresh an expired OAuth token. Usually only used when troubleshooting authentication.",
|
||||
ArgsUsage: "[<login name>]",
|
||||
Action: runLoginOAuthRefresh,
|
||||
}
|
||||
|
||||
func runLoginOAuthRefresh(_ context.Context, cmd *cli.Command) error {
|
||||
var loginName string
|
||||
|
||||
// Get login name from args or use default
|
||||
if cmd.Args().Len() > 0 {
|
||||
loginName = cmd.Args().First()
|
||||
} else {
|
||||
// Get default login
|
||||
login, err := config.GetDefaultLogin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("no login specified and no default login found: %s", err)
|
||||
}
|
||||
loginName = login.Name
|
||||
}
|
||||
|
||||
// Get the login from config
|
||||
login := config.GetLoginByName(loginName)
|
||||
if login == nil {
|
||||
return fmt.Errorf("login '%s' not found", loginName)
|
||||
}
|
||||
|
||||
// Check if the login has a refresh token
|
||||
if login.RefreshToken == "" {
|
||||
return fmt.Errorf("login '%s' does not have a refresh token. It may have been created using a different authentication method", loginName)
|
||||
}
|
||||
|
||||
// Refresh the token
|
||||
err := auth.RefreshAccessToken(login)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to refresh token: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully refreshed OAuth token for %s\n", loginName)
|
||||
return nil
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/login"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdLogout represents to logout a gitea server.
|
||||
|
62
cmd/man.go
Normal file
62
cmd/man.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
docs "github.com/urfave/cli-docs/v3"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// DocRenderFlags are the flags for documentation generation, used by `./docs/docs.go` and the `generate-man-page` sub command
|
||||
var DocRenderFlags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "out",
|
||||
Usage: "Path to output docs to, otherwise prints to stdout",
|
||||
Aliases: []string{"o"},
|
||||
},
|
||||
}
|
||||
|
||||
// CmdGenerateManPage is the sub command to generate the `tea` man page
|
||||
var CmdGenerateManPage = cli.Command{
|
||||
Name: "man",
|
||||
Usage: "Generate man page",
|
||||
Hidden: true,
|
||||
Flags: DocRenderFlags,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
return RenderDocs(cmd, cmd.Root(), docs.ToMan)
|
||||
},
|
||||
}
|
||||
|
||||
// RenderDocs renders the documentation for `target` using the supplied `render` function
|
||||
func RenderDocs(cmd, target *cli.Command, render func(*cli.Command) (string, error)) error {
|
||||
out, err := render(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outPath := cmd.String("out")
|
||||
if outPath == "" {
|
||||
fmt.Print(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(outPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fi, err := os.Create(outPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
if _, err = fi.WriteString(out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/milestones"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMilestones represents to operate repositories milestones.
|
||||
@ -21,7 +21,7 @@ var CmdMilestones = cli.Command{
|
||||
Description: `List and create milestones`,
|
||||
ArgsUsage: "[<milestone name>]",
|
||||
Action: runMilestones,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&milestones.CmdMilestonesList,
|
||||
&milestones.CmdMilestonesCreate,
|
||||
&milestones.CmdMilestonesClose,
|
||||
@ -32,14 +32,14 @@ var CmdMilestones = cli.Command{
|
||||
Flags: milestones.CmdMilestonesList.Flags,
|
||||
}
|
||||
|
||||
func runMilestones(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runMilestoneDetail(ctx, ctx.Args().First())
|
||||
func runMilestones(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runMilestoneDetail(ctx, cmd, cmd.Args().First())
|
||||
}
|
||||
return milestones.RunMilestonesList(ctx)
|
||||
return milestones.RunMilestonesList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runMilestoneDetail(cmd *cli.Context, name string) error {
|
||||
func runMilestoneDetail(_ stdctx.Context, cmd *cli.Command, name string) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
@ -1,26 +1,26 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMilestonesClose represents a sub command of milestones to close an milestone
|
||||
var CmdMilestonesClose = cli.Command{
|
||||
Name: "close",
|
||||
Usage: "Change state of an milestone to 'closed'",
|
||||
Description: `Change state of an milestone to 'closed'`,
|
||||
ArgsUsage: "<milestone name>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
if ctx.Bool("force") {
|
||||
return deleteMilestone(ctx)
|
||||
Usage: "Change state of one or more milestones to 'closed'",
|
||||
Description: `Change state of one or more milestones to 'closed'`,
|
||||
ArgsUsage: "<milestone name> [<milestone name>...]",
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.Bool("force") {
|
||||
return deleteMilestone(ctx, cmd)
|
||||
}
|
||||
return editMilestoneStatus(ctx, true)
|
||||
return editMilestoneStatus(ctx, cmd, true)
|
||||
},
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
|
@ -1,20 +1,20 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMilestonesCreate represents a sub command of milestones to create milestone
|
||||
@ -23,6 +23,7 @@ var CmdMilestonesCreate = cli.Command{
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create an milestone on repository",
|
||||
Description: `Create an milestone on repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runMilestonesCreate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@ -48,14 +49,14 @@ var CmdMilestonesCreate = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runMilestonesCreate(cmd *cli.Context) error {
|
||||
func runMilestonesCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
date := ctx.String("deadline")
|
||||
deadline := &time.Time{}
|
||||
if date != "" {
|
||||
t, err := dateparse.ParseAny(date)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deadline = &t
|
||||
@ -67,7 +68,10 @@ func runMilestonesCreate(cmd *cli.Context) error {
|
||||
}
|
||||
|
||||
if ctx.NumFlags() == 0 {
|
||||
return interact.CreateMilestone(ctx.Login, ctx.Owner, ctx.Repo)
|
||||
if err := interact.CreateMilestone(ctx.Login, ctx.Owner, ctx.Repo); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return task.CreateMilestone(
|
||||
|
@ -1,14 +1,15 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMilestonesDelete represents a sub command of milestones to delete an milestone
|
||||
@ -22,7 +23,7 @@ var CmdMilestonesDelete = cli.Command{
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
func deleteMilestone(cmd *cli.Context) error {
|
||||
func deleteMilestone(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
@ -1,19 +1,19 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var msIssuesFieldsFlag = flags.FieldsFlag(print.IssueFields, []string{
|
||||
@ -28,7 +28,7 @@ var CmdMilestonesIssues = cli.Command{
|
||||
Description: "manage issue/pull of an milestone",
|
||||
ArgsUsage: "<milestone name>",
|
||||
Action: runMilestoneIssueList,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&CmdMilestoneAddIssue,
|
||||
&CmdMilestoneRemoveIssue,
|
||||
},
|
||||
@ -70,7 +70,7 @@ var CmdMilestoneRemoveIssue = cli.Command{
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
func runMilestoneIssueList(cmd *cli.Context) error {
|
||||
func runMilestoneIssueList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
@ -103,7 +103,7 @@ func runMilestoneIssueList(cmd *cli.Context) error {
|
||||
}
|
||||
|
||||
issues, _, err := client.ListRepoIssues(ctx.Owner, ctx.Repo, gitea.ListIssueOption{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
Milestones: []string{milestone},
|
||||
Type: kind,
|
||||
State: state,
|
||||
@ -120,7 +120,7 @@ func runMilestoneIssueList(cmd *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runMilestoneIssueAdd(cmd *cli.Context) error {
|
||||
func runMilestoneIssueAdd(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
@ -147,7 +147,7 @@ func runMilestoneIssueAdd(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func runMilestoneIssueRemove(cmd *cli.Context) error {
|
||||
func runMilestoneIssueRemove(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
@ -1,26 +1,33 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var fieldsFlag = flags.FieldsFlag(print.MilestoneFields, []string{
|
||||
"title", "items", "duedate",
|
||||
})
|
||||
|
||||
// CmdMilestonesList represents a sub command of milestones to list milestones
|
||||
var CmdMilestonesList = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List milestones of the repository",
|
||||
Description: `List milestones of the repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunMilestonesList,
|
||||
Flags: append([]cli.Flag{
|
||||
fieldsFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "state",
|
||||
Usage: "Filter by milestone state (all|open|closed)",
|
||||
@ -32,21 +39,29 @@ var CmdMilestonesList = cli.Command{
|
||||
}
|
||||
|
||||
// RunMilestonesList list milestones
|
||||
func RunMilestonesList(cmd *cli.Context) error {
|
||||
func RunMilestonesList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
fields, err := fieldsFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state := gitea.StateOpen
|
||||
switch ctx.String("state") {
|
||||
case "all":
|
||||
state = gitea.StateAll
|
||||
if !cmd.IsSet("fields") { // add to default fields
|
||||
fields = append(fields, "state")
|
||||
}
|
||||
case "closed":
|
||||
state = gitea.StateClosed
|
||||
}
|
||||
|
||||
client := ctx.Login.Client()
|
||||
milestones, _, err := client.ListRepoMilestones(ctx.Owner, ctx.Repo, gitea.ListMilestoneOption{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
State: state,
|
||||
})
|
||||
|
||||
@ -54,6 +69,6 @@ func RunMilestonesList(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
print.MilestonesList(milestones, ctx.Output, state)
|
||||
print.MilestonesList(milestones, ctx.Output, fields)
|
||||
return nil
|
||||
}
|
||||
|
@ -1,43 +1,61 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package milestones
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdMilestonesReopen represents a sub command of milestones to open an milestone
|
||||
var CmdMilestonesReopen = cli.Command{
|
||||
Name: "reopen",
|
||||
Aliases: []string{"open"},
|
||||
Usage: "Change state of an milestone to 'open'",
|
||||
Description: `Change state of an milestone to 'open'`,
|
||||
ArgsUsage: "<milestone name>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
return editMilestoneStatus(ctx, false)
|
||||
Usage: "Change state of one or more milestones to 'open'",
|
||||
Description: `Change state of one or more milestones to 'open'`,
|
||||
ArgsUsage: "<milestone name> [<milestone name> ...]",
|
||||
Action: func(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
return editMilestoneStatus(ctx, cmd, false)
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
||||
func editMilestoneStatus(cmd *cli.Context, close bool) error {
|
||||
func editMilestoneStatus(_ stdctx.Context, cmd *cli.Command, close bool) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
if ctx.Args().Len() == 0 {
|
||||
return fmt.Errorf(ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
state := gitea.StateOpen
|
||||
if close {
|
||||
state = gitea.StateClosed
|
||||
}
|
||||
_, _, err := client.EditMilestoneByName(ctx.Owner, ctx.Repo, ctx.Args().First(), gitea.EditMilestoneOption{
|
||||
State: &state,
|
||||
Title: ctx.Args().First(),
|
||||
})
|
||||
|
||||
return err
|
||||
client := ctx.Login.Client()
|
||||
for _, ms := range ctx.Args().Slice() {
|
||||
opts := gitea.EditMilestoneOption{
|
||||
State: &state,
|
||||
Title: ms,
|
||||
}
|
||||
milestone, _, err := client.EditMilestoneByName(ctx.Owner, ctx.Repo, ms, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Args().Len() > 1 {
|
||||
fmt.Printf("%s/milestone/%d\n", ctx.GetRemoteRepoHTMLURL(), milestone.ID)
|
||||
} else {
|
||||
print.MilestoneDetails(milestone)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/notifications"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdNotifications is the main command to operate with notifications
|
||||
@ -18,7 +17,7 @@ var CmdNotifications = cli.Command{
|
||||
Usage: "Show notifications",
|
||||
Description: "Show notifications, by default based on the current repo if available",
|
||||
Action: notifications.RunNotificationsList,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
¬ifications.CmdNotificationsList,
|
||||
¬ifications.CmdNotificationsMarkRead,
|
||||
¬ifications.CmdNotificationsMarkUnread,
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -12,10 +12,14 @@ import (
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var notifTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"},
|
||||
var notifyFieldsFlag = flags.FieldsFlag(print.NotificationFields, []string{
|
||||
"id", "status", "index", "type", "state", "title",
|
||||
})
|
||||
|
||||
var notifyTypeFlag = flags.NewCsvFlag("types", "subject types to filter by", []string{"t"},
|
||||
[]string{"issue", "pull", "repository", "commit"}, nil)
|
||||
|
||||
// CmdNotificationsList represents a sub command of notifications to list notifications
|
||||
@ -24,14 +28,18 @@ var CmdNotificationsList = cli.Command{
|
||||
Aliases: []string{"list"},
|
||||
Usage: "List notifications",
|
||||
Description: `List notifications`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunNotificationsList,
|
||||
Flags: append([]cli.Flag{notifTypeFlag}, flags.NotificationFlags...),
|
||||
Flags: append([]cli.Flag{
|
||||
notifyFieldsFlag,
|
||||
notifyTypeFlag,
|
||||
}, flags.NotificationFlags...),
|
||||
}
|
||||
|
||||
// RunNotificationsList list notifications
|
||||
func RunNotificationsList(ctx *cli.Context) error {
|
||||
func RunNotificationsList(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
var states []gitea.NotifyStatus
|
||||
statesStr, err := flags.NotificationStateFlag.GetValues(ctx)
|
||||
statesStr, err := flags.NotificationStateFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -40,7 +48,7 @@ func RunNotificationsList(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
var types []gitea.NotifySubjectType
|
||||
typesStr, err := notifTypeFlag.GetValues(ctx)
|
||||
typesStr, err := notifyTypeFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -48,11 +56,11 @@ func RunNotificationsList(ctx *cli.Context) error {
|
||||
types = append(types, gitea.NotifySubjectType(t))
|
||||
}
|
||||
|
||||
return listNotifications(ctx, states, types)
|
||||
return listNotifications(ctx, cmd, states, types)
|
||||
}
|
||||
|
||||
// listNotifications will get the notifications based on status and subject type
|
||||
func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects []gitea.NotifySubjectType) error {
|
||||
func listNotifications(_ stdctx.Context, cmd *cli.Command, status []gitea.NotifyStatus, subjects []gitea.NotifySubjectType) error {
|
||||
var news []*gitea.NotificationThread
|
||||
var err error
|
||||
|
||||
@ -61,12 +69,22 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [
|
||||
all := ctx.Bool("mine")
|
||||
|
||||
// This enforces pagination (see https://github.com/go-gitea/gitea/issues/16733)
|
||||
listOpts := ctx.GetListOptions()
|
||||
listOpts := flags.GetListOptions()
|
||||
if listOpts.Page == 0 {
|
||||
listOpts.Page = 1
|
||||
}
|
||||
|
||||
fields, err := notifyFieldsFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if all {
|
||||
// add repository to the default fields
|
||||
if !cmd.IsSet("fields") {
|
||||
fields = append(fields, "repository")
|
||||
}
|
||||
|
||||
news, _, err = client.ListNotifications(gitea.ListNotificationOptions{
|
||||
ListOptions: listOpts,
|
||||
Status: status,
|
||||
@ -84,6 +102,6 @@ func listNotifications(cmd *cli.Context, status []gitea.NotifyStatus, subjects [
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
print.NotificationsList(news, ctx.Output, all)
|
||||
print.NotificationsList(news, ctx.Output, fields)
|
||||
return nil
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdNotificationsMarkRead represents a sub command of notifications to list read notifications
|
||||
@ -22,16 +22,16 @@ var CmdNotificationsMarkRead = cli.Command{
|
||||
Description: "Mark all filtered or a specific notification as read",
|
||||
ArgsUsage: "[all | <notification id>]",
|
||||
Flags: flags.NotificationFlags,
|
||||
Action: func(ctx *cli.Context) error {
|
||||
cmd := context.InitCommand(ctx)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(ctx)
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !flags.NotificationStateFlag.IsSet() {
|
||||
if !ctx.IsSet(flags.NotificationStateFlag.Name) {
|
||||
filter = []string{string(gitea.NotifyStatusUnread)}
|
||||
}
|
||||
return markNotificationAs(cmd, filter, gitea.NotifyStatusRead)
|
||||
return markNotificationAs(ctx, filter, gitea.NotifyStatusRead)
|
||||
},
|
||||
}
|
||||
|
||||
@ -43,16 +43,16 @@ var CmdNotificationsMarkUnread = cli.Command{
|
||||
Description: "Mark all filtered or a specific notification as unread",
|
||||
ArgsUsage: "[all | <notification id>]",
|
||||
Flags: flags.NotificationFlags,
|
||||
Action: func(ctx *cli.Context) error {
|
||||
cmd := context.InitCommand(ctx)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(ctx)
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !flags.NotificationStateFlag.IsSet() {
|
||||
if !ctx.IsSet(flags.NotificationStateFlag.Name) {
|
||||
filter = []string{string(gitea.NotifyStatusRead)}
|
||||
}
|
||||
return markNotificationAs(cmd, filter, gitea.NotifyStatusUnread)
|
||||
return markNotificationAs(ctx, filter, gitea.NotifyStatusUnread)
|
||||
},
|
||||
}
|
||||
|
||||
@ -64,16 +64,16 @@ var CmdNotificationsMarkPinned = cli.Command{
|
||||
Description: "Mark all filtered or a specific notification as pinned",
|
||||
ArgsUsage: "[all | <notification id>]",
|
||||
Flags: flags.NotificationFlags,
|
||||
Action: func(ctx *cli.Context) error {
|
||||
cmd := context.InitCommand(ctx)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(ctx)
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
filter, err := flags.NotificationStateFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !flags.NotificationStateFlag.IsSet() {
|
||||
if !ctx.IsSet(flags.NotificationStateFlag.Name) {
|
||||
filter = []string{string(gitea.NotifyStatusUnread)}
|
||||
}
|
||||
return markNotificationAs(cmd, filter, gitea.NotifyStatusPinned)
|
||||
return markNotificationAs(ctx, filter, gitea.NotifyStatusPinned)
|
||||
},
|
||||
}
|
||||
|
||||
@ -84,11 +84,11 @@ var CmdNotificationsUnpin = cli.Command{
|
||||
Description: "Marks all pinned or a specific notification as read",
|
||||
ArgsUsage: "[all | <notification id>]",
|
||||
Flags: flags.NotificationFlags,
|
||||
Action: func(ctx *cli.Context) error {
|
||||
cmd := context.InitCommand(ctx)
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
filter := []string{string(gitea.NotifyStatusPinned)}
|
||||
// NOTE: we implicitly mark it as read, to match web UI semantics. marking as unread might be more useful?
|
||||
return markNotificationAs(cmd, filter, gitea.NotifyStatusRead)
|
||||
return markNotificationAs(ctx, filter, gitea.NotifyStatusRead)
|
||||
},
|
||||
}
|
||||
|
||||
@ -107,10 +107,10 @@ func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetSt
|
||||
opts := gitea.MarkNotificationOptions{Status: states, ToStatus: targetState}
|
||||
|
||||
if allRepos {
|
||||
_, err = client.ReadNotifications(opts)
|
||||
_, _, err = client.ReadNotifications(opts)
|
||||
} else {
|
||||
cmd.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
_, err = client.ReadRepoNotifications(cmd.Owner, cmd.Repo, opts)
|
||||
_, _, err = client.ReadRepoNotifications(cmd.Owner, cmd.Repo, opts)
|
||||
}
|
||||
|
||||
// TODO: print all affected notification subject URLs
|
||||
@ -121,7 +121,7 @@ func markNotificationAs(cmd *context.TeaContext, filterStates []string, targetSt
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = client.ReadNotification(id, targetState)
|
||||
_, _, err = client.ReadNotification(id, targetState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
11
cmd/open.go
11
cmd/open.go
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
local_git "code.gitea.io/tea/modules/git"
|
||||
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdOpen represents a sub command of issues to open issue on the web browser
|
||||
@ -27,7 +27,7 @@ var CmdOpen = cli.Command{
|
||||
Flags: append([]cli.Flag{}, flags.LoginRepoFlags...),
|
||||
}
|
||||
|
||||
func runOpen(cmd *cli.Context) error {
|
||||
func runOpen(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
@ -74,6 +74,5 @@ func runOpen(cmd *cli.Context) error {
|
||||
suffix = number
|
||||
}
|
||||
|
||||
u := path.Join(ctx.Login.URL, ctx.Owner, ctx.Repo, suffix)
|
||||
return open.Run(u)
|
||||
return open.Run(path.Join(ctx.GetRemoteRepoHTMLURL(), suffix))
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/organizations"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdOrgs represents handle organization
|
||||
@ -21,20 +22,28 @@ var CmdOrgs = cli.Command{
|
||||
Description: "Show organization details",
|
||||
ArgsUsage: "[<organization>]",
|
||||
Action: runOrganizations,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&organizations.CmdOrganizationList,
|
||||
&organizations.CmdOrganizationCreate,
|
||||
&organizations.CmdOrganizationDelete,
|
||||
},
|
||||
Flags: organizations.CmdOrganizationList.Flags,
|
||||
}
|
||||
|
||||
func runOrganizations(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runOrganizationDetail(ctx.Args().First())
|
||||
func runOrganizations(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
teaCtx := context.InitCommand(cmd)
|
||||
if teaCtx.Args().Len() == 1 {
|
||||
return runOrganizationDetail(teaCtx)
|
||||
}
|
||||
return organizations.RunOrganizationList(ctx)
|
||||
return organizations.RunOrganizationList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runOrganizationDetail(path string) error {
|
||||
return fmt.Errorf("Not yet implemented")
|
||||
func runOrganizationDetail(ctx *context.TeaContext) error {
|
||||
org, _, err := ctx.Login.Client().GetOrg(ctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.OrganizationDetails(org)
|
||||
return nil
|
||||
}
|
||||
|
90
cmd/organizations/create.go
Normal file
90
cmd/organizations/create.go
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package organizations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
stdctx "context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// CmdOrganizationCreate represents a sub command of organizations to delete a given user organization
|
||||
var CmdOrganizationCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create an organization",
|
||||
Description: "Create an organization",
|
||||
Action: RunOrganizationCreate,
|
||||
ArgsUsage: "<organization name>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "description",
|
||||
Aliases: []string{"d"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "website",
|
||||
Aliases: []string{"w"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "location",
|
||||
Aliases: []string{"L"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "visibility",
|
||||
Aliases: []string{"v"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "repo-admins-can-change-team-access",
|
||||
},
|
||||
&flags.LoginFlag,
|
||||
},
|
||||
}
|
||||
|
||||
// RunOrganizationCreate sets up a new organization
|
||||
func RunOrganizationCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
if ctx.Args().Len() < 1 {
|
||||
return fmt.Errorf("You have to specify the organization name you want to create")
|
||||
}
|
||||
|
||||
var visibility gitea.VisibleType
|
||||
switch ctx.String("visibility") {
|
||||
case "", "public":
|
||||
visibility = gitea.VisibleTypePublic
|
||||
case "private":
|
||||
visibility = gitea.VisibleTypePrivate
|
||||
case "limited":
|
||||
visibility = gitea.VisibleTypeLimited
|
||||
default:
|
||||
return fmt.Errorf("unknown visibility '%s'", ctx.String("visibility"))
|
||||
}
|
||||
|
||||
org, _, err := ctx.Login.Client().CreateOrg(gitea.CreateOrgOption{
|
||||
Name: ctx.Args().First(),
|
||||
// FullName: , // not really meaningful for orgs (not displayed in webui, use description instead?)
|
||||
Description: ctx.String("description"),
|
||||
Website: ctx.String("website"),
|
||||
Location: ctx.String("location"),
|
||||
RepoAdminChangeTeamAccess: ctx.Bool("repo-admins-can-change-team-access"),
|
||||
Visibility: visibility,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.OrganizationDetails(org)
|
||||
|
||||
return err
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package organizations
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdOrganizationDelete represents a sub command of organizations to delete a given user organization
|
||||
@ -27,7 +27,7 @@ var CmdOrganizationDelete = cli.Command{
|
||||
}
|
||||
|
||||
// RunOrganizationDelete delete user organization
|
||||
func RunOrganizationDelete(cmd *cli.Context) error {
|
||||
func RunOrganizationDelete(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
client := ctx.Login.Client()
|
||||
|
@ -1,16 +1,16 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package organizations
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdOrganizationList represents a sub command of organizations to list users organizations
|
||||
@ -19,6 +19,7 @@ var CmdOrganizationList = cli.Command{
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Organizations",
|
||||
Description: "List users organizations",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunOrganizationList,
|
||||
Flags: append([]cli.Flag{
|
||||
&flags.PaginationPageFlag,
|
||||
@ -27,12 +28,12 @@ var CmdOrganizationList = cli.Command{
|
||||
}
|
||||
|
||||
// RunOrganizationList list user organizations
|
||||
func RunOrganizationList(cmd *cli.Context) error {
|
||||
func RunOrganizationList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
|
||||
userOrganizations, _, err := client.ListUserOrgs(ctx.Login.User, gitea.ListOrgsOptions{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
24
cmd/pulls.go
24
cmd/pulls.go
@ -1,10 +1,10 @@
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/pulls"
|
||||
@ -15,7 +15,7 @@ import (
|
||||
"code.gitea.io/tea/modules/workaround"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPulls is the main command to operate on PRs
|
||||
@ -30,10 +30,10 @@ var CmdPulls = cli.Command{
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "comments",
|
||||
Usage: "Wether to display comments (will prompt if not provided & run interactively)",
|
||||
Usage: "Whether to display comments (will prompt if not provided & run interactively)",
|
||||
},
|
||||
}, pulls.CmdPullsList.Flags...),
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&pulls.CmdPullsList,
|
||||
&pulls.CmdPullsCheckout,
|
||||
&pulls.CmdPullsClean,
|
||||
@ -47,14 +47,14 @@ var CmdPulls = cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func runPulls(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runPullDetail(ctx, ctx.Args().First())
|
||||
func runPulls(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runPullDetail(ctx, cmd, cmd.Args().First())
|
||||
}
|
||||
return pulls.RunPullsList(ctx)
|
||||
return pulls.RunPullsList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runPullDetail(cmd *cli.Context, index string) error {
|
||||
func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
idx, err := utils.ArgToIndex(index)
|
||||
@ -71,7 +71,9 @@ func runPullDetail(cmd *cli.Context, index string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
reviews, _, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{})
|
||||
reviews, _, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
|
||||
ListOptions: gitea.ListOptions{Page: -1},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("error while loading reviews: %v\n", err)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
@ -8,13 +7,14 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsApprove approves a PR
|
||||
@ -24,7 +24,7 @@ var CmdPullsApprove = cli.Command{
|
||||
Usage: "Approve a pull request",
|
||||
Description: "Approve a pull request",
|
||||
ArgsUsage: "<pull index> [<comment>]",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -13,7 +13,7 @@ import (
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsCheckout is a command to locally checkout the given PR
|
||||
@ -33,9 +33,12 @@ var CmdPullsCheckout = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runPullsCheckout(cmd *cli.Context) error {
|
||||
func runPullsCheckout(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{LocalRepo: true})
|
||||
ctx.Ensure(context.CtxRequirement{
|
||||
LocalRepo: true,
|
||||
RemoteRepo: true,
|
||||
})
|
||||
if ctx.Args().Len() != 1 {
|
||||
return fmt.Errorf("Must specify a PR index")
|
||||
}
|
||||
@ -44,5 +47,8 @@ func runPullsCheckout(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return task.PullCheckout(ctx.Login, ctx.Owner, ctx.Repo, ctx.Bool("branch"), idx, interact.PromptPassword)
|
||||
if err := task.PullCheckout(ctx.Login, ctx.Owner, ctx.Repo, ctx.Bool("branch"), idx, interact.PromptPassword); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
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/task"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsClean removes the remote and local feature branches, if a PR is merged.
|
||||
@ -31,7 +31,7 @@ var CmdPullsClean = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runPullsClean(cmd *cli.Context) error {
|
||||
func runPullsClean(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{LocalRepo: true})
|
||||
if ctx.Args().Len() != 1 {
|
||||
@ -43,5 +43,8 @@ func runPullsClean(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return task.PullClean(ctx.Login, ctx.Owner, ctx.Repo, idx, ctx.Bool("ignore-sha"), interact.PromptPassword)
|
||||
if err := task.PullClean(ctx.Login, ctx.Owner, ctx.Repo, idx, ctx.Bool("ignore-sha"), interact.PromptPassword); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,25 +1,26 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsClose closes a given open pull request
|
||||
var CmdPullsClose = cli.Command{
|
||||
Name: "close",
|
||||
Usage: "Change state of a pull request to 'closed'",
|
||||
Description: `Change state of a pull request to 'closed'`,
|
||||
ArgsUsage: "<pull index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
Usage: "Change state of one or more pull requests to 'closed'",
|
||||
Description: `Change state of one or more pull requests to 'closed'`,
|
||||
ArgsUsage: "<pull index> [<pull index>...]",
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var s = gitea.StateClosed
|
||||
return editPullState(ctx, gitea.EditPullRequestOption{State: &s})
|
||||
return editPullState(ctx, cmd, gitea.EditPullRequestOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"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/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsCreate creates a pull request
|
||||
@ -18,39 +19,54 @@ var CmdPullsCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a pull-request",
|
||||
Description: "Create a pull-request",
|
||||
Description: "Create a pull-request in the current repo",
|
||||
Action: runPullsCreate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "head",
|
||||
Usage: "Set head branch (default is current one)",
|
||||
Usage: "Branch name of the PR source (default is current one). To specify a different head repo, use <user>:<branch>",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "base",
|
||||
Aliases: []string{"b"},
|
||||
Usage: "Set base branch (default is default branch)",
|
||||
Usage: "Branch name of the PR target (default is repos default branch)",
|
||||
},
|
||||
}, flags.IssuePREditFlags...),
|
||||
&cli.BoolFlag{
|
||||
Name: "allow-maintainer-edits",
|
||||
Aliases: []string{"edits"},
|
||||
Usage: "Enable maintainers to push to the base branch of created pull",
|
||||
Value: true,
|
||||
},
|
||||
}, flags.IssuePRCreateFlags...),
|
||||
}
|
||||
|
||||
func runPullsCreate(cmd *cli.Context) error {
|
||||
func runPullsCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
// no args -> interactive mode
|
||||
if ctx.NumFlags() == 0 {
|
||||
return interact.CreatePull(ctx)
|
||||
if err := interact.CreatePull(ctx); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// else use args to create PR
|
||||
opts, err := flags.GetIssuePREditFlags(ctx)
|
||||
opts, err := flags.GetIssuePRCreateFlags(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var allowMaintainerEdits *bool
|
||||
if ctx.IsSet("allow-maintainer-edits") {
|
||||
allowMaintainerEdits = gitea.OptionalBool(ctx.Bool("allow-maintainer-edits"))
|
||||
}
|
||||
|
||||
return task.CreatePull(
|
||||
ctx,
|
||||
ctx.String("base"),
|
||||
ctx.String("head"),
|
||||
allowMaintainerEdits,
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/modules/context"
|
||||
@ -12,27 +12,34 @@ import (
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// editPullState abstracts the arg parsing to edit the given pull request
|
||||
func editPullState(cmd *cli.Context, opts gitea.EditPullRequestOption) error {
|
||||
func editPullState(_ stdctx.Context, cmd *cli.Command, opts gitea.EditPullRequestOption) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
if ctx.Args().Len() == 0 {
|
||||
return fmt.Errorf("Please provide a Pull Request index")
|
||||
}
|
||||
|
||||
index, err := utils.ArgToIndex(ctx.Args().First())
|
||||
indices, err := utils.ArgsToIndices(ctx.Args().Slice())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pr, _, err := ctx.Login.Client().EditPullRequest(ctx.Owner, ctx.Repo, index, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := ctx.Login.Client()
|
||||
for _, index := range indices {
|
||||
pr, _, err := client.EditPullRequest(ctx.Owner, ctx.Repo, index, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.PullDetails(pr, nil, nil)
|
||||
if len(indices) > 1 {
|
||||
fmt.Println(pr.HTMLURL)
|
||||
} else {
|
||||
print.PullDetails(pr, nil, nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,30 +1,35 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var pullFieldsFlag = flags.FieldsFlag(print.PullFields, []string{
|
||||
"index", "title", "state", "author", "milestone", "updated", "labels",
|
||||
})
|
||||
|
||||
// CmdPullsList represents a sub command of issues to list pulls
|
||||
var CmdPullsList = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List pull requests of the repository",
|
||||
Description: `List pull requests of the repository`,
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunPullsList,
|
||||
Flags: flags.IssuePRFlags,
|
||||
Flags: append([]cli.Flag{pullFieldsFlag}, flags.PRListingFlags...),
|
||||
}
|
||||
|
||||
// RunPullsList return list of pulls
|
||||
func RunPullsList(cmd *cli.Context) error {
|
||||
func RunPullsList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
@ -46,6 +51,11 @@ func RunPullsList(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
print.PullsList(prs, ctx.Output)
|
||||
fields, err := pullFieldsFlag.GetValues(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.PullsList(prs, ctx.Output, fields)
|
||||
return nil
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsMerge merges a PR
|
||||
@ -40,12 +40,16 @@ var CmdPullsMerge = cli.Command{
|
||||
Usage: "Merge commit message",
|
||||
},
|
||||
}, flags.AllDefaultFlags...),
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
if ctx.Args().Len() != 1 {
|
||||
return fmt.Errorf("Must specify a PR index")
|
||||
// If no PR index is provided, try interactive mode
|
||||
if err := interact.MergePull(ctx); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
idx, err := utils.ArgToIndex(ctx.Args().First())
|
||||
@ -53,18 +57,10 @@ var CmdPullsMerge = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
success, _, err := ctx.Login.Client().MergePullRequest(ctx.Owner, ctx.Repo, idx, gitea.MergePullRequestOption{
|
||||
return task.PullMerge(ctx.Login, ctx.Owner, ctx.Repo, idx, gitea.MergePullRequestOption{
|
||||
Style: gitea.MergeStyle(ctx.String("style")),
|
||||
Title: ctx.String("title"),
|
||||
Message: ctx.String("message"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !success {
|
||||
return fmt.Errorf("Failed to merge PR. Is it still open?")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsReject requests changes to a PR
|
||||
@ -23,7 +23,7 @@ var CmdPullsReject = cli.Command{
|
||||
Usage: "Request changes to a pull request",
|
||||
Description: "Request changes to a pull request",
|
||||
ArgsUsage: "<pull index> <reason>",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsReopen reopens a given closed pull request
|
||||
var CmdPullsReopen = cli.Command{
|
||||
Name: "reopen",
|
||||
Aliases: []string{"open"},
|
||||
Usage: "Change state of a pull request to 'open'",
|
||||
Description: `Change state of a pull request to 'open'`,
|
||||
ArgsUsage: "<pull index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
Usage: "Change state of one or more pull requests to 'open'",
|
||||
Description: `Change state of one or more pull requests to 'open'`,
|
||||
ArgsUsage: "<pull index> [<pull index>...]",
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
var s = gitea.StateOpen
|
||||
return editPullState(ctx, gitea.EditPullRequestOption{State: &s})
|
||||
return editPullState(ctx, cmd, gitea.EditPullRequestOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdPullsReview starts an interactive review session
|
||||
@ -21,12 +21,12 @@ var CmdPullsReview = cli.Command{
|
||||
Usage: "Interactively review a pull request",
|
||||
Description: "Interactively review a pull request",
|
||||
ArgsUsage: "<pull index>",
|
||||
Action: func(cmd *cli.Context) error {
|
||||
Action: func(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
if ctx.Args().Len() != 1 {
|
||||
return fmt.Errorf("Must specify a PR index")
|
||||
return fmt.Errorf("must specify a PR index")
|
||||
}
|
||||
|
||||
idx, err := utils.ArgToIndex(ctx.Args().First())
|
||||
@ -34,7 +34,10 @@ var CmdPullsReview = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
return interact.ReviewPull(ctx, idx)
|
||||
if err := interact.ReviewPull(ctx, idx); err != nil && !interact.IsQuitting(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
@ -8,7 +7,7 @@ import (
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/cmd/releases"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleases represents to login a gitea server.
|
||||
@ -19,12 +18,14 @@ var CmdReleases = cli.Command{
|
||||
Category: catEntities,
|
||||
Usage: "Manage releases",
|
||||
Description: "Manage releases",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: releases.RunReleasesList,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&releases.CmdReleaseList,
|
||||
&releases.CmdReleaseCreate,
|
||||
&releases.CmdReleaseDelete,
|
||||
&releases.CmdReleaseEdit,
|
||||
&CmdReleaseAttachments,
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package releases
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -14,7 +14,7 @@ import (
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseCreate represents a sub command of Release to create release
|
||||
@ -22,16 +22,17 @@ var CmdReleaseCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a release",
|
||||
Description: `Create a release`,
|
||||
Description: `Create a release for a new or existing git tag`,
|
||||
ArgsUsage: "[<tag>]",
|
||||
Action: runReleaseCreate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tag",
|
||||
Usage: "Tag name",
|
||||
Usage: "Tag name. If the tag does not exist yet, it will be created by Gitea",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "target",
|
||||
Usage: "Target refs, branch name or commit id",
|
||||
Usage: "Target branch name or commit hash. Defaults to the default branch of the repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "title",
|
||||
@ -43,6 +44,11 @@ var CmdReleaseCreate = cli.Command{
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Release notes",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "note-file",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Release notes file name. If set, --note is ignored.",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "draft",
|
||||
Aliases: []string{"d"},
|
||||
@ -56,24 +62,41 @@ var CmdReleaseCreate = cli.Command{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "asset",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "List of files to attach",
|
||||
Usage: "Path to file attachment. Can be specified multiple times",
|
||||
},
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runReleaseCreate(cmd *cli.Context) error {
|
||||
func runReleaseCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
tag := ctx.String("tag")
|
||||
if cmd.Args().Present() {
|
||||
if len(tag) != 0 {
|
||||
return fmt.Errorf("ambiguous arguments: provide tagname via --tag or argument, but not both")
|
||||
}
|
||||
tag = cmd.Args().First()
|
||||
}
|
||||
|
||||
notestring := ctx.String("note")
|
||||
notefile := ctx.String("note-file")
|
||||
if notefile != "" {
|
||||
notebytes, err := os.ReadFile(notefile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read the note file")
|
||||
}
|
||||
notestring = string(notebytes)
|
||||
}
|
||||
|
||||
release, resp, err := ctx.Login.Client().CreateRelease(ctx.Owner, ctx.Repo, gitea.CreateReleaseOption{
|
||||
TagName: ctx.String("tag"),
|
||||
TagName: tag,
|
||||
Target: ctx.String("target"),
|
||||
Title: ctx.String("title"),
|
||||
Note: ctx.String("note"),
|
||||
Note: notestring,
|
||||
IsDraft: ctx.Bool("draft"),
|
||||
IsPrerelease: ctx.Bool("prerelease"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusConflict {
|
||||
return fmt.Errorf("There already is a release for this tag")
|
||||
|
@ -1,25 +1,25 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package releases
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseDelete represents a sub command of Release to delete a release
|
||||
var CmdReleaseDelete = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete a release",
|
||||
Description: `Delete a release`,
|
||||
ArgsUsage: "<release tag>",
|
||||
Usage: "Delete one or more releases",
|
||||
Description: `Delete one or more releases`,
|
||||
ArgsUsage: "<release tag> [<release tag>...]",
|
||||
Action: runReleaseDelete,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
@ -34,14 +34,13 @@ var CmdReleaseDelete = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runReleaseDelete(cmd *cli.Context) error {
|
||||
func runReleaseDelete(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
tag := ctx.Args().First()
|
||||
if len(tag) == 0 {
|
||||
fmt.Println("Release tag needed to delete")
|
||||
if !ctx.Args().Present() {
|
||||
fmt.Println("Release tag needed to edit")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -50,22 +49,20 @@ func runReleaseDelete(cmd *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if release == nil {
|
||||
return nil
|
||||
}
|
||||
for _, tag := range ctx.Args().Slice() {
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = client.DeleteRelease(ctx.Owner, ctx.Repo, release.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.DeleteRelease(ctx.Owner, ctx.Repo, release.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Bool("delete-tag") {
|
||||
_, err = client.DeleteTag(ctx.Owner, ctx.Repo, tag)
|
||||
return err
|
||||
if ctx.Bool("delete-tag") {
|
||||
_, err = client.DeleteTag(ctx.Owner, ctx.Repo, tag)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package releases
|
||||
|
||||
@ -8,20 +7,21 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseEdit represents a sub command of Release to edit releases
|
||||
var CmdReleaseEdit = cli.Command{
|
||||
Name: "edit",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Edit a release",
|
||||
Description: `Edit a release`,
|
||||
ArgsUsage: "<release tag>",
|
||||
Usage: "Edit one or more releases",
|
||||
Description: `Edit one or more releases`,
|
||||
ArgsUsage: "<release tag> [<release tag>...]",
|
||||
Action: runReleaseEdit,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@ -57,25 +57,11 @@ var CmdReleaseEdit = cli.Command{
|
||||
}, flags.AllDefaultFlags...),
|
||||
}
|
||||
|
||||
func runReleaseEdit(cmd *cli.Context) error {
|
||||
func runReleaseEdit(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
tag := ctx.Args().First()
|
||||
if len(tag) == 0 {
|
||||
fmt.Println("Release tag needed to edit")
|
||||
return nil
|
||||
}
|
||||
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if release == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var isDraft, isPre *bool
|
||||
if ctx.IsSet("draft") {
|
||||
isDraft = gitea.OptionalBool(strings.ToLower(ctx.String("draft"))[:1] == "t")
|
||||
@ -84,13 +70,28 @@ func runReleaseEdit(cmd *cli.Context) error {
|
||||
isPre = gitea.OptionalBool(strings.ToLower(ctx.String("prerelease"))[:1] == "t")
|
||||
}
|
||||
|
||||
_, _, err = client.EditRelease(ctx.Owner, ctx.Repo, release.ID, gitea.EditReleaseOption{
|
||||
TagName: ctx.String("tag"),
|
||||
Target: ctx.String("target"),
|
||||
Title: ctx.String("title"),
|
||||
Note: ctx.String("note"),
|
||||
IsDraft: isDraft,
|
||||
IsPrerelease: isPre,
|
||||
})
|
||||
return err
|
||||
if !ctx.Args().Present() {
|
||||
fmt.Println("Release tag needed to edit")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, tag := range ctx.Args().Slice() {
|
||||
release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err = client.EditRelease(ctx.Owner, ctx.Repo, release.ID, gitea.EditReleaseOption{
|
||||
TagName: ctx.String("tag"),
|
||||
Target: ctx.String("target"),
|
||||
Title: ctx.String("title"),
|
||||
Note: ctx.String("note"),
|
||||
IsDraft: isDraft,
|
||||
IsPrerelease: isPre,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package releases
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdReleaseList represents a sub command of Release to list releases
|
||||
@ -21,6 +21,7 @@ var CmdReleaseList = cli.Command{
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Releases",
|
||||
Description: "List Releases",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: RunReleasesList,
|
||||
Flags: append([]cli.Flag{
|
||||
&flags.PaginationPageFlag,
|
||||
@ -29,12 +30,12 @@ var CmdReleaseList = cli.Command{
|
||||
}
|
||||
|
||||
// RunReleasesList list releases
|
||||
func RunReleasesList(cmd *cli.Context) error {
|
||||
func RunReleasesList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
releases, _, err := ctx.Login.Client().ListReleases(ctx.Owner, ctx.Repo, gitea.ListReleasesOptions{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -45,19 +46,19 @@ func RunReleasesList(cmd *cli.Context) error {
|
||||
}
|
||||
|
||||
func getReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
|
||||
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{})
|
||||
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{
|
||||
ListOptions: gitea.ListOptions{Page: -1},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rl) == 0 {
|
||||
fmt.Println("Repo does not have any release")
|
||||
return nil, nil
|
||||
return nil, fmt.Errorf("Repo does not have any release")
|
||||
}
|
||||
for _, r := range rl {
|
||||
if r.TagName == tag {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
fmt.Println("Release tag does not exist")
|
||||
return nil, nil
|
||||
return nil, fmt.Errorf("Release tag does not exist")
|
||||
}
|
||||
|
23
cmd/repos.go
23
cmd/repos.go
@ -1,17 +1,18 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/repos"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRepos represents to login a gitea server.
|
||||
@ -23,22 +24,26 @@ var CmdRepos = cli.Command{
|
||||
Description: "Show repository details",
|
||||
ArgsUsage: "[<repo owner>/<repo name>]",
|
||||
Action: runRepos,
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
&repos.CmdReposList,
|
||||
&repos.CmdReposSearch,
|
||||
&repos.CmdRepoCreate,
|
||||
&repos.CmdRepoCreateFromTemplate,
|
||||
&repos.CmdRepoFork,
|
||||
&repos.CmdRepoMigrate,
|
||||
&repos.CmdRepoRm,
|
||||
},
|
||||
Flags: repos.CmdReposListFlags,
|
||||
}
|
||||
|
||||
func runRepos(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() == 1 {
|
||||
return runRepoDetail(ctx, ctx.Args().First())
|
||||
func runRepos(ctx stdctx.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() == 1 {
|
||||
return runRepoDetail(ctx, cmd, cmd.Args().First())
|
||||
}
|
||||
return repos.RunReposList(ctx)
|
||||
return repos.RunReposList(ctx, cmd)
|
||||
}
|
||||
|
||||
func runRepoDetail(cmd *cli.Context, path string) error {
|
||||
func runRepoDetail(_ stdctx.Context, cmd *cli.Command, path string) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
repoOwner, repoName := utils.GetOwnerAndRepo(path, ctx.Owner)
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
@ -12,7 +12,7 @@ import (
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRepoCreate represents a sub command of repos to create one
|
||||
@ -21,6 +21,7 @@ var CmdRepoCreate = cli.Command{
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a repository",
|
||||
Description: "Create a repository",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runRepoCreate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@ -79,26 +80,63 @@ var CmdRepoCreate = cli.Command{
|
||||
Required: false,
|
||||
Usage: "use custom default branch (need --init)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "template",
|
||||
Usage: "make repo a template repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "trustmodel",
|
||||
Usage: "select trust model (committer,collaborator,collaborator+committer)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "object-format",
|
||||
Required: false,
|
||||
Usage: "select git object format (sha1,sha256)",
|
||||
Validator: func(v string) error {
|
||||
if v != "sha1" && v != "sha256" {
|
||||
return fmt.Errorf("invalid object format '%s', must be either 'sha1' or 'sha256'", v)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}, flags.LoginOutputFlags...),
|
||||
}
|
||||
|
||||
func runRepoCreate(cmd *cli.Context) error {
|
||||
func runRepoCreate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
var (
|
||||
repo *gitea.Repository
|
||||
err error
|
||||
repo *gitea.Repository
|
||||
err error
|
||||
trustmodel gitea.TrustModel
|
||||
)
|
||||
|
||||
if ctx.IsSet("trustmodel") {
|
||||
switch ctx.String("trustmodel") {
|
||||
case "committer":
|
||||
trustmodel = gitea.TrustModelCommitter
|
||||
case "collaborator":
|
||||
trustmodel = gitea.TrustModelCollaborator
|
||||
case "collaborator+committer":
|
||||
trustmodel = gitea.TrustModelCollaboratorCommitter
|
||||
default:
|
||||
return fmt.Errorf("unknown trustmodel type '%s'", ctx.String("trustmodel"))
|
||||
}
|
||||
}
|
||||
|
||||
opts := gitea.CreateRepoOption{
|
||||
Name: ctx.String("name"),
|
||||
Description: ctx.String("description"),
|
||||
Private: ctx.Bool("private"),
|
||||
AutoInit: ctx.Bool("init"),
|
||||
IssueLabels: ctx.String("labels"),
|
||||
Gitignores: ctx.String("gitignores"),
|
||||
License: ctx.String("license"),
|
||||
Readme: ctx.String("readme"),
|
||||
DefaultBranch: ctx.String("branch"),
|
||||
Name: ctx.String("name"),
|
||||
Description: ctx.String("description"),
|
||||
Private: ctx.Bool("private"),
|
||||
AutoInit: ctx.Bool("init"),
|
||||
IssueLabels: ctx.String("labels"),
|
||||
Gitignores: ctx.String("gitignores"),
|
||||
License: ctx.String("license"),
|
||||
Readme: ctx.String("readme"),
|
||||
DefaultBranch: ctx.String("branch"),
|
||||
Template: ctx.Bool("template"),
|
||||
TrustModel: trustmodel,
|
||||
ObjectFormatName: ctx.String("object-format"),
|
||||
}
|
||||
if len(ctx.String("owner")) != 0 {
|
||||
repo, _, err = client.CreateOrgRepo(ctx.String("owner"), opts)
|
||||
|
121
cmd/repos/create_from_template.go
Normal file
121
cmd/repos/create_from_template.go
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"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"
|
||||
)
|
||||
|
||||
// CmdRepoCreateFromTemplate represents a sub command of repos to generate one from a template repo
|
||||
var CmdRepoCreateFromTemplate = cli.Command{
|
||||
Name: "create-from-template",
|
||||
Aliases: []string{"ct"},
|
||||
Usage: "Create a repository based on an existing template",
|
||||
Description: "Create a repository based on an existing template",
|
||||
Action: runRepoCreateFromTemplate,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "template",
|
||||
Aliases: []string{"t"},
|
||||
Required: true,
|
||||
Usage: "source template to copy from",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
Required: true,
|
||||
Usage: "name of new repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner",
|
||||
Aliases: []string{"O"},
|
||||
Usage: "name of repo owner",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "private",
|
||||
Usage: "make new repo private",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "description",
|
||||
Aliases: []string{"desc"},
|
||||
Usage: "add custom description to repo",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "content",
|
||||
Value: true,
|
||||
Usage: "copy git content from template",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "githooks",
|
||||
Value: true,
|
||||
Usage: "copy git hooks from template",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "avatar",
|
||||
Value: true,
|
||||
Usage: "copy repo avatar from template",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "labels",
|
||||
Value: true,
|
||||
Usage: "copy repo labels from template",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "topics",
|
||||
Value: true,
|
||||
Usage: "copy topics from template",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "webhooks",
|
||||
Usage: "copy webhooks from template",
|
||||
},
|
||||
}, flags.LoginOutputFlags...),
|
||||
}
|
||||
|
||||
func runRepoCreateFromTemplate(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
|
||||
templateOwner, templateRepo := utils.GetOwnerAndRepo(ctx.String("template"), ctx.Login.User)
|
||||
owner := ctx.Login.User
|
||||
if ctx.IsSet("owner") {
|
||||
owner = ctx.String("owner")
|
||||
}
|
||||
|
||||
opts := gitea.CreateRepoFromTemplateOption{
|
||||
Name: ctx.String("name"),
|
||||
Owner: owner,
|
||||
Description: ctx.String("description"),
|
||||
Private: ctx.Bool("private"),
|
||||
GitContent: ctx.Bool("content"),
|
||||
GitHooks: ctx.Bool("githooks"),
|
||||
Avatar: ctx.Bool("avatar"),
|
||||
Labels: ctx.Bool("labels"),
|
||||
Topics: ctx.Bool("topics"),
|
||||
Webhooks: ctx.Bool("webhooks"),
|
||||
}
|
||||
|
||||
repo, _, err := client.CreateRepoFromTemplate(templateOwner, templateRepo, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.RepoDetails(repo, topics)
|
||||
|
||||
fmt.Printf("%s\n", repo.HTMLURL)
|
||||
return nil
|
||||
}
|
88
cmd/repos/create_test.go
Normal file
88
cmd/repos/create_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestCreateRepoObjectFormat(t *testing.T) {
|
||||
giteaURL := os.Getenv("GITEA_TEA_TEST_URL")
|
||||
if giteaURL == "" {
|
||||
t.Skip("GITEA_TEA_TEST_URL is not set, skipping test")
|
||||
}
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
wantOpts gitea.CreateRepoOption
|
||||
wantErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
name: "create repo with sha1 object format",
|
||||
args: []string{"--name", fmt.Sprintf("test-sha1-%d", timestamp), "--object-format", "sha1"},
|
||||
wantOpts: gitea.CreateRepoOption{
|
||||
Name: fmt.Sprintf("test-sha1-%d", timestamp),
|
||||
ObjectFormatName: "sha1",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "create repo with sha256 object format",
|
||||
args: []string{"--name", fmt.Sprintf("test-sha256-%d", timestamp), "--object-format", "sha256"},
|
||||
wantOpts: gitea.CreateRepoOption{
|
||||
Name: fmt.Sprintf("test-sha256-%d", timestamp),
|
||||
ObjectFormatName: "sha256",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "create repo with invalid object format",
|
||||
args: []string{"--name", fmt.Sprintf("test-invalid-%d", timestamp), "--object-format", "invalid"},
|
||||
wantErr: true,
|
||||
errContains: "invalid object format",
|
||||
},
|
||||
}
|
||||
|
||||
giteaUserName := os.Getenv("GITEA_TEA_TEST_USERNAME")
|
||||
giteaUserPasword := os.Getenv("GITEA_TEA_TEST_PASSWORD")
|
||||
|
||||
err := task.CreateLogin("test", "", giteaUserName, giteaUserPasword, "", "", "", giteaURL, "", "", true, false, false, false)
|
||||
if err != nil && err.Error() != "login name 'test' has already been used" {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reposCmd := &cli.Command{
|
||||
Name: "repos",
|
||||
Commands: []*cli.Command{&CmdRepoCreate},
|
||||
}
|
||||
tt.args = append(tt.args, "--login", "test")
|
||||
args := append([]string{"repos", "create"}, tt.args...)
|
||||
|
||||
err := reposCmd.Run(context.Background(), args)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
if tt.errContains != "" {
|
||||
assert.Contains(t, err.Error(), tt.errContains)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
86
cmd/repos/delete.go
Normal file
86
cmd/repos/delete.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRepoRm represents a sub command of repos to delete an existing repo
|
||||
var CmdRepoRm = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete an existing repository",
|
||||
Description: "Removes a repository from Create a repository from an existing repo",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runRepoDelete,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{""},
|
||||
Required: true,
|
||||
Usage: "name of the repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "owner",
|
||||
Aliases: []string{"O"},
|
||||
Required: false,
|
||||
Usage: "owner of the repo",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Required: false,
|
||||
Value: false,
|
||||
Usage: "Force the deletion and don't ask for confirmation",
|
||||
},
|
||||
}, flags.LoginOutputFlags...),
|
||||
}
|
||||
|
||||
func runRepoDelete(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
|
||||
client := ctx.Login.Client()
|
||||
|
||||
var owner string
|
||||
if ctx.IsSet("owner") {
|
||||
owner = ctx.String("owner")
|
||||
} else {
|
||||
owner = ctx.Login.User
|
||||
}
|
||||
|
||||
repoName := ctx.String("name")
|
||||
|
||||
repoSlug := fmt.Sprintf("%s/%s", owner, repoName)
|
||||
|
||||
if !ctx.Bool("force") {
|
||||
var enteredRepoSlug string
|
||||
if err := huh.NewInput().
|
||||
Title(fmt.Sprintf("Confirm the deletion of the repository '%s' by typing its name: ", repoSlug)).
|
||||
Validate(huh.ValidateNotEmpty()).
|
||||
Value(&enteredRepoSlug).
|
||||
Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enteredRepoSlug != repoSlug {
|
||||
return fmt.Errorf("entered wrong repository name '%s', expected '%s'", enteredRepoSlug, repoSlug)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := client.DeleteRepo(owner, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully deleted %s/%s\n", owner, repoName)
|
||||
return nil
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
@ -8,7 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var typeFilterFlag = cli.StringFlag{
|
||||
@ -18,8 +17,8 @@ var typeFilterFlag = cli.StringFlag{
|
||||
Usage: "Filter by type: fork, mirror, source",
|
||||
}
|
||||
|
||||
func getTypeFilter(ctx *cli.Context) (filter gitea.RepoType, err error) {
|
||||
t := ctx.String("type")
|
||||
func getTypeFilter(cmd *cli.Command) (filter gitea.RepoType, err error) {
|
||||
t := cmd.String("type")
|
||||
filter = gitea.RepoTypeNone
|
||||
switch t {
|
||||
case "":
|
||||
|
59
cmd/repos/fork.go
Normal file
59
cmd/repos/fork.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// CmdRepoFork represents a sub command of repos to fork an existing repo
|
||||
var CmdRepoFork = cli.Command{
|
||||
Name: "fork",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Fork an existing repository",
|
||||
Description: "Create a repository from an existing repo",
|
||||
ArgsUsage: " ", // command does not accept arguments
|
||||
Action: runRepoFork,
|
||||
Flags: append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "owner",
|
||||
Aliases: []string{"O"},
|
||||
Usage: "name of fork's owner, defaults to current user",
|
||||
},
|
||||
}, flags.LoginRepoFlags...),
|
||||
}
|
||||
|
||||
func runRepoFork(_ stdctx.Context, cmd *cli.Command) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
client := ctx.Login.Client()
|
||||
|
||||
opts := gitea.CreateForkOption{}
|
||||
if ctx.IsSet("owner") {
|
||||
owner := ctx.String("owner")
|
||||
opts.Organization = &owner
|
||||
}
|
||||
|
||||
repo, _, err := client.CreateFork(ctx.Owner, ctx.Repo, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
print.RepoDetails(repo, topics)
|
||||
|
||||
fmt.Printf("%s\n", repo.HTMLURL)
|
||||
return nil
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
stdctx "context"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var repoFieldsFlag = flags.FieldsFlag(print.RepoFields, []string{
|
||||
@ -48,9 +49,9 @@ var CmdReposList = cli.Command{
|
||||
}
|
||||
|
||||
// RunReposList list repositories
|
||||
func RunReposList(cmd *cli.Context) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
client := ctx.Login.Client()
|
||||
func RunReposList(_ stdctx.Context, cmd *cli.Command) error {
|
||||
teaCmd := context.InitCommand(cmd)
|
||||
client := teaCmd.Login.Client()
|
||||
|
||||
typeFilter, err := getTypeFilter(cmd)
|
||||
if err != nil {
|
||||
@ -58,20 +59,20 @@ func RunReposList(cmd *cli.Context) error {
|
||||
}
|
||||
|
||||
var rps []*gitea.Repository
|
||||
if ctx.Bool("starred") {
|
||||
if teaCmd.Bool("starred") {
|
||||
user, _, err := client.GetMyUserInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rps, _, err = client.SearchRepos(gitea.SearchRepoOptions{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
StarredByUserID: user.ID,
|
||||
})
|
||||
} else if ctx.Bool("watched") {
|
||||
} else if teaCmd.Bool("watched") {
|
||||
rps, _, err = client.GetMyWatchedRepos() // TODO: this does not expose pagination..
|
||||
} else {
|
||||
rps, _, err = client.ListMyRepos(gitea.ListReposOptions{
|
||||
ListOptions: ctx.GetListOptions(),
|
||||
ListOptions: flags.GetListOptions(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -89,7 +90,7 @@ func RunReposList(cmd *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
print.ReposList(reposFiltered, ctx.Output, fields)
|
||||
print.ReposList(reposFiltered, teaCmd.Output, fields)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user