Files
gitea-tea/docs/migration-1.0.md
T

433 lines
24 KiB
Markdown

# Migrating to tea 1.0
tea 1.0 rebuilds the CLI around explicit, singular `noun verb` commands modeled
on GitHub's `gh` (including its verb aliases and short flags), a split
configuration, and per-instance accounts. Old command names, plural groups and
many old short flags are gone, and scripts need updating. This guide lists what
changed and what to use instead.
Quick checklist:
1. Make sure your instances run Gitea 28 or newer
([Server requirements](#server-requirements)).
2. Move the old configuration away, or point tea 1.0 at a new directory
([Configuration](#old-configuration-file)).
3. Log in again ([Logging in](#logging-in-again)).
4. Run `tea auth setup-git` to replace the old `!tea login helper` Git
credential entries ([Git credential helper](#git-credential-helper)).
5. Regenerate shell completions ([Shell completion](#shell-completion)).
6. Update scripts: [global flags](#global-flags), [commands](#renamed-commands),
[arguments](#changed-positional-arguments) and [output](#output-formats).
Run `tea <command> --help` for the full flag list of any command.
## Server requirements
Requires Gitea 28 or newer. tea no longer probes `/api/v1/version` or
`/swagger.v1.json` to adapt to older servers: on an older instance, commands
that need a newer endpoint fail with the server's HTTP error instead of a
"not supported" message.
## Configuration and login
### Old configuration file
Older releases kept logins and preferences in one file, `config.yml` in the `tea`
directory under the platform configuration directory (`~/.config/tea/config.yml`
on Linux; releases up to 0.16 also fell back to `~/.tea/tea.yml` when that file was missing). tea 1.0 stores preferences in
`config.yml` and instances and accounts in `hosts.yml`, in the same directory by
default; `tea config path` prints both paths. When it finds an old-format file it
stops with:
```text
legacy tea configuration: archive the old config.yml or select a separate TEA_CONFIG_DIR, then run tea auth login; existing files have not been changed
```
Nothing is imported automatically. Either archive the old file:
```sh
mv ~/.config/tea/config.yml ~/.config/tea/config.yml.old # adjust the path on macOS and Windows
mv ~/.tea/tea.yml ~/.tea/tea.yml.old # if you still use the oldest location
```
or keep it and give tea 1.0 its own directory with `TEA_CONFIG_DIR`. Do not run
an old tea against a directory written by tea 1.0: it reads the new `config.yml`
as an empty login list and overwrites it on its next save.
`tea config list` shows effective preferences. Old settings map as follows:
| Old `config.yml` | tea 1.0 |
|---|---|
| `preferences.editor: true` | `tea config set editor "<command>"` (a command, not a switch) |
| `preferences.flag_defaults.remote` | `tea config set remote <name>` |
| login `default: true` | `tea config set default_host <url>` |
| login `insecure`, `ssh_host` | `tea config set --host <url> insecure true`, `... ssh_host <host[:port]>` |
| login `ssh_key`, `ssh_agent`, `ssh_certificate_principal`, `ssh_key_agent_pub` | `tea config set --host <url> --user <name> ssh_key …` (also `ssh_agent`, `ssh_certificate_principal`, `ssh_key_fingerprint`) |
### Logging in again
Accounts are identified by instance URL and username instead of a login name.
`tea auth login --host <url>` replaces `tea login add`:
| Old | tea 1.0 |
|---|---|
| `tea login add --url URL --token TOKEN` | `tea auth login --host URL --with-token < token-file` (the token is read from stdin) |
| `tea login add --oauth` | `tea auth login --host URL --oauth` |
| `tea login add --ssh-key PATH` / `-s` | `tea auth login --host URL --ssh-key PATH` |
| `--ssh-agent-key` / `-a`, `--ssh-agent-principal` / `-c` | same long flags, no shorthands |
| `--insecure` / `-i` | `--insecure` |
| `--user`, `--password`, `--otp`, `--scopes` (create a token with basic auth) | removed: create a token in the web UI (Settings → Applications) or use `--oauth` |
| `--name`, `--no-version-check` | removed |
| `--redirect-url` | removed: OAuth always listens on a random loopback port |
| `--git-credentials` / `--helper` / `-j` | `tea auth setup-git --host URL` |
Token logins of the old release kept the token in plain text under
`logins[].token` in the old `config.yml`, so you can pipe it straight into
`tea auth login --with-token` instead of creating a new one.
Credentials go to the operating-system keyring (service `tea-cli-v2`). Pass
`--credential-store file` to store them in private files under the configuration
directory instead. The old release's OAuth tokens (keyring service `tea-cli`, and
`credentials.json` in the old configuration directory) are not read; delete them once you
have logged in again.
Managing accounts:
| Old | tea 1.0 |
|---|---|
| `tea login list`, `tea login status`, `tea whoami` | `tea auth status` (`--verify` checks each credential) |
| `tea login default NAME` | `tea config set default_host URL`, and `tea auth switch USER --host URL` for the active account |
| `tea login edit` | `tea config set --host URL <key> <value>` |
| `tea login delete NAME`, `tea logout NAME` | `tea auth logout --host URL [--user USER]` |
| `tea login oauth-refresh` | `tea auth refresh` |
### Environment variables
| Variable | tea 1.0 |
|---|---|
| `GITEA_TOKEN`, `GITEA_INSTANCE_URL` | supported; `TEA_HOST` is an alternative to `GITEA_INSTANCE_URL`. A `GITEA_TOKEN` without either was ignored; it now makes authenticated commands fail with exit 4, so set the instance or unset the token to use stored credentials |
| `GITEA_INSTANCE_INSECURE`, `GITEA_INSTANCE_SSH_HOST` | supported |
| `GH_TOKEN` | no longer read: use `GITEA_TOKEN` |
| `GITEA_SERVER_URL`, `GITEA_SERVER_TOKEN`, `GITEA_SERVER_USER`, `GITEA_SERVER_PASSWORD`, `GITEA_SERVER_OTP`, `GITEA_SCOPES` | removed with `tea login add` |
New variables: `TEA_CONFIG_DIR`, `TEA_HOST`, `TEA_USER`, `TEA_REPO`, `TEA_EDITOR`,
`TEA_PAGER` and `TEA_COLOR`; see `tea help environment`. Environment credentials are
never written to disk.
### Git credential helper
`tea login helper setup` and `tea login add --git-credentials` wrote two entries
to `~/.gitconfig` for each instance: an empty `credential.<url>.helper` and
`!tea login helper`. tea 1.0 has no `login` command, so Git now gets an error
from that helper and falls back to prompting. Register the new helper:
```sh
tea auth setup-git --host https://gitea.example.org
```
It replaces every helper configured for the instance URL, the old entry
included. With `--keep-helpers` it adds tea's helper after them instead; then
remove the old entry with
`git config --global --unset-all credential.https://gitea.example.org.helper '^!tea login helper$'`.
`tea repo clone`, `tea pr checkout`, `tea pr clean`, `tea repo sync` and
`tea pr create --agit` authenticate Git without any helper; `tea auth setup-git`
is only needed for plain `git` commands. Add `--local` to configure only the
current repository.
tea 0.16 cloned over SSH when the login had an SSH key; tea 1.0 follows
`git_protocol`, which defaults to `https`. To keep cloning over SSH, run
`tea config set git_protocol ssh` (add `--host <url>` for one instance).
## Global flags
| Old | tea 1.0 |
|---|---|
| `--repo` / `-r` | `--repo` / `-R` |
| `--remote` / `-R` | `--remote` (no shorthand) |
| `--login` / `-l` | `--host URL`, plus `--user NAME` when the instance has several accounts |
| `--output` / `-o`, `--fields` / `-f` | `--json [fields]` and `--jq` / `-q <expression>` |
| `--debug` / `--vvv` | `--debug` |
| `--confirm` / `-y`, `--force` / `-f` on destructive commands | `--yes` / `-y` |
`-R` now means `--repo`, which takes `NAME`, `OWNER/REPO`, `HOST/OWNER/REPO` or
a URL: `tea issue list -R origin` no longer selects the `origin` remote. Inside
a checkout with that remote tea fails and suggests `--remote origin`; elsewhere
`origin` is read as a repository of your account. Use `--remote origin`.
New global flags: `--no-input` disables prompts, editors and browsers, `--yes`
(`-y`) accepts confirmations, `--cwd` selects the directory used for repository
discovery, and `--sudo USER` acts as another user (administrators only).
## Renamed commands
All command groups are singular, and the old built-in aliases (`c`, `e`, `i`,
`ms`, `lgtm`, …) are gone. Subcommands take gh's verb aliases instead (`ls`,
`rm`, `new`, `add`, `co`, `search issues`, `search prs`); `tea <command> --help`
lists them. `tea alias set NAME EXPANSION` defines your own top-level shortcuts, for example
`tea alias set prs 'pr list --author @me'`.
Top-level groups:
| Old | tea 1.0 |
|---|---|
| `issues`, `issue`, `i` | `issue` |
| `pulls`, `pull`, `pr` | `pr` |
| `labels` | `label` |
| `milestones`, `ms` | `milestone` |
| `releases`, `r` | `release` |
| `times`, `t` | `time` |
| `organizations`, `org` | `org` |
| `repos` | `repo` |
| `branches`, `b` | `branch` |
| `actions secrets` | `secret` |
| `actions variables` | `variable` |
| `actions runs` | `run` |
| `actions workflows` | `workflow` |
| `webhooks`, `hooks` | `webhook` |
| `comments`, `c` | `issue comment` / `pr comment` |
| `notifications`, `n` | `notification` |
| `ssh-keys` | `ssh-key` |
| `admin users`, `admin u` | `admin user` |
| `logins`, `login`, `logout`, `whoami` | `auth` (see [Logging in](#logging-in-again)) |
| `clone`, `C` | `repo clone` |
| `open`, `o` | removed (see [Removed features](#removed-features)) |
Groups no longer run a default action: `tea issues` listed issues and
`tea issues 5` showed issue 5; use `tea issue list` and `tea issue view 5`.
The same applies to `pulls`, `notifications` and the other groups.
Subcommands:
| Old | tea 1.0 |
|---|---|
| `issues reopen`, `pulls reopen` (alias `open`) | `issue reopen`, `pr reopen` |
| `pulls approve <n> [comment]` | `pr review <n> --approve [--body TEXT]` (`-a`) |
| `pulls reject <n> <comment>` | `pr review <n> --request-changes --body TEXT` (`-r`) |
| `pulls review <n>` | `pr review <n>` (`--comment` / `-c` for a plain review comment) |
| `pulls review-comments` | `pr review comments` |
| `pulls reply`, `resolve`, `unresolve` | `pr review reply`, `pr review resolve`, `pr review unresolve` |
| `labels update --id ID` | `label edit <name-or-id>` |
| `labels delete --id ID` | `label delete <name-or-id>...` |
| `labels list --save` | `label export` |
| `labels list` (also listed organization labels; `--exclude-org`) | `label list` lists the repository's labels only; use `label list --org OWNER` for an organization's, and drop `--exclude-org` |
| `milestones issues <name>` | `milestone issue list <milestone>` (title or ID) |
| `milestones issues add\|remove` | `milestone issue add\|remove <milestone> <number>...` |
| `releases assets create` | `release asset upload` |
| `times add` | `time create` |
| `times list [user\|#issue]` | `time list [--username USER\|--issue N]` |
| `repos search` | `search repo` |
| `repos create-from-template` | `repo create --template OWNER/REPO` |
| `actions secrets create` | `secret set` (value: see below) |
| `actions variables set` | `variable set` (value: see below) |
| `actions variables list --name NAME` | `variable view NAME` |
| `actions runs delete` (alias `cancel`) | `run delete`; `run cancel` cancels without deleting |
| `actions workflows dispatch` | `workflow run` |
| `webhooks update` | `webhook edit` |
| `comments add <n> [body]` | `issue comment <n> --body TEXT` (also `pr comment`); `--edit-last` and `--delete-last` change your last comment |
| `comments edit <id> [body]`, `comments delete <id>...`, a body piped on stdin | `issue comment edit <id> --body TEXT`, one `issue comment delete <id>` per comment, `--body-file -` to read stdin |
| `notifications read\|unread [all\|id]` | `notification mark-read\|mark-unread [id]...`; use `--all` for every filtered notification |
| `ssh-keys add` | `ssh-key create` |
| `login helper setup` | `auth setup-git` |
| `completion pwsh` | `completion powershell` |
Renamed flags that appear on many commands:
| Old | tea 1.0 |
|---|---|
| `--description` / `-d`, `--description-file` (issues, pulls, comments) | `--body`, `--body-file` |
| `--note` / `-n`, `--note-file` / `-f` (releases) | `--notes` / `-n`, `--notes-file` / `-F` (`--body` and `--body-file` are accepted too) |
| `--content` / `-c` (wiki) | `--body`, `--body-file` |
| `--labels` / `-L`, `--assignees` / `-a`, `--milestones` / `-m` | `--label` / `-l`, `--assignee` / `-a`, `--milestone` / `-m` |
| `--referenced-version` / `-v` | `--ref` |
| `--keyword` / `-k` | `--search` / `-S` |
| `--from` / `-F` (issue list) | `--since` |
| `issues list` outside a repository, `--owner` / `--org` | `tea search issue [--owner OWNER]` |
| `issues edit` / `pulls edit --milestone ""` | `--remove-milestone` (or `--milestone 0`) |
| `--states` / `-s`, `--types` / `-t` (notifications) | `--status`, `--type` |
| `--page` / `-p`, `--limit` / `--lm` | `--page`, `--limit` / `-L` |
| `--style` / `-s` (pr merge) | `--merge`, `--squash` or `--rebase`, or `--method` / `-s`; without one, the repository's default merge style |
| `--owner` / `-O`, `--init`, `--labels`, `--trustmodel`, `--branch`, `--template` (repo create) | `--org`, `--auto-init`, `--label-template`, `--trust-model`, `--default-branch`, `--as-template` |
| `--desc` (repo edit) | `--description` / `-d` |
| `--template true\|false`, `--private true\|false`, `--archived true\|false` (repo edit) | `--as-template`, `--private`, `tea repo archive` / `unarchive`; these are on/off switches, so write `--private=false` (`--private false` names a repository `false`) |
| `--owner` / `-O` (repo fork) | `--org` |
| `--inactive` (webhook) | `--active=false` |
| `--expires` / `-x` (milestones create) | `--deadline` |
| `--kind issue\|pull` (milestones issues) | `--kind issues\|pulls\|all` |
| `--no-admin`, `--no-restricted`, `--inactive`, `--no-allow-git-hook`, `--no-allow-import-local`, `--no-allow-create-organization` (admin users edit) | `--admin=false`, `--restricted=false`, `--active=false`, `--allow-git-hook=false`, and so on |
| `--allow-login` (admin users edit) | `--prohibit-login=false` |
| `--password-stdin`, `--no-must-change-password` (admin users) | `--password-file -`, `--must-change-password=false` |
| `-u`, `-p`, `-e` (admin users create) | the username argument or `--username`, `--password`, `--email` |
| `--out` (man) | `--output-file` / `-o` |
Other long names changed too, mostly on `admin user`, `repo fork`, `repo edit` and
`repo migrate`; an old name fails with an unknown-flag error, so check `--help`
of each command you script. The short flags follow gh
instead of old tea: `-L` limit, `-s` state, `-l` label, `-a` assignee, `-A`
author, `-m` milestone, `-t` title, `-b` body, `-F` body file, `-e` editor, `-w`
web, `-S` search, plus the global `-R`, `-q` and `-y`. Some old shorthands now
mean something else: `-L` is `--limit` (was `--labels`), `-d` on `pr create` is
`--draft` (was `--description`), `-b` on `pr create` is `--body` (was `--base`;
use `-B`, otherwise the pull request silently targets the default branch), `-r`
on `pr create` is `--reviewer` (was `--repo`; use `-R`) and `-o` on `secret` and
`variable` is `--org` (was `--output`). Two flags kept their name but
changed meaning:
- `workflow run`: `-f` was `--follow` and now means `--field KEY=VALUE`;
`--follow` has no shorthand. `-r` (`--ref`) and `-i` (`--input`) are unchanged.
- `api`: `--field` (`-f`) sent a string and `--Field` (`-F`) a typed value. Now
`--raw-field` / `-f` sends a string and `--field` / `-F` a typed value, so the
shorthands behave as before. `--data` / `-d` became `--input FILE` (or `-` for
stdin), and `--output` / `-o` became `--output-file`. `api` exits 1 on a response outside
2xx (0.16 printed the body and exited 0), `-F key=@FILE` keeps the file's trailing newline,
and `--output-file` refuses to replace an existing file.
## Changed positional arguments
| Command | Old | tea 1.0 |
|---|---|---|
| `milestone close\|reopen\|delete\|edit\|view` | milestone name | milestone title or ID |
| `milestone issue list\|add\|remove` | milestone name | milestone title or ID |
| `release asset delete <tag>` | attachment name | asset name or ID |
| `label edit\|delete` | `--id ID` | label name or ID |
| `team view\|edit\|delete`, `team member\|repo ...` | team ID | `ORG/TEAM` or team ID |
| `repo delete` | `--name NAME --owner OWNER` | optional `OWNER/REPO` argument (or `--repo`) |
| `pulls close\|reopen\|edit` | several indexes | `pr close\|reopen\|edit` take one pull request (number, URL or branch); loop to change several |
| `issue comment` | optional body argument | `--body`, `--body-file` or `--editor` |
| `secret set`, `variable set` | optional value argument, `--file`, `--stdin` | `--body VALUE`, `--body-file FILE` (or `-`), or standard input; one trailing line break is removed |
A number is read as an ID; pass `--by-name` to match a milestone, label or asset
whose name is a number. Destructive commands still ask for confirmation unless
`--yes` is given.
## Output formats
`--output` / `-o` (`table`, `simple`, `csv`, `tsv`, `yaml`, `json`) and `--fields`
are gone. Human output is text for people; scripts should use JSON:
```sh
# old: tea issues list --fields index,title -o csv
tea issue list --json number,title --jq '.[] | "\(.number),\(.title)"'
# old: tea notifications --mine -o simple | xargs notify-send
tea notification list -q '.[].title' | xargs -n1 notify-send
```
`--json` alone prints every field; `--json a,b` selects fields and rejects unknown
names; `--jq` / `-q` filters the result and implies `--json`. Commands that
produce no resource, such as deletes, reject `--json` with a usage error instead
of printing nothing.
When stdout is not a terminal, lists print tab-separated values without header,
color or links, with times in RFC 3339 UTC, and a `--page` hint goes to stderr;
prefer `--json` in scripts. Commands that change resources report each change on
stderr only on a terminal; warnings, such as a step that was skipped or failed,
always go to stderr. Create commands print the URL of the new resource on
stdout, so `url=$(tea issue create …)` works; other changes print nothing when
piped. Bodies are rendered as Markdown only on a terminal (`tea config set
markdown raw` turns this off). See `tea help formatting` for the terminal layout.
## Exit codes
| Code | Meaning |
|---|---|
| 0 | success, including an empty list |
| 1 | the command failed |
| 2 | usage error: an unknown command or flag, or a missing or invalid argument |
| 3 | canceled: a declined confirmation, an aborted prompt or a timeout |
| 4 | authentication is missing or was rejected |
| 8 | `tea pr checks`: some checks are still pending |
| 130 | interrupted with Ctrl-C |
`tea help exit-codes` prints this table.
## Removed features
| Feature | Replacement |
|---|---|
| `tea open [number\|issues\|pulls\|releases\|commits\|branches\|wiki\|labels\|milestones\|activity\|settings\|<ref>]` | `tea issue view N --web`, `tea pr view N --web`, `tea repo view --web`; for other pages open `$(tea repo view --json url --jq .url)/releases` and similar |
| Basic-auth token creation (`login add --user/--password/--otp/--scopes`) | create a token in the web UI, or `tea auth login --oauth` |
| `login edit` | `tea config set --host URL <key> <value>` |
| Output formats and `--fields` | `--json` and `--jq` |
| `contrib/autocomplete.*` scripts and the `--generate-shell-completion` protocol | `tea completion <shell>` |
| `GH_TOKEN`, `GITEA_SERVER_*`, `GITEA_SCOPES` | `GITEA_TOKEN`, `tea auth login` |
| `--vvv` | `--debug` |
### Shell completion
Completion scripts saved from an older `tea completion` (or the removed
`contrib/autocomplete.*` files) call tea with `--generate-shell-completion`, which
tea 1.0 rejects, so completion silently stops working. Regenerate them:
```sh
eval "$(tea completion bash)" # ~/.bashrc
autoload -U compinit && compinit; source <(tea completion zsh) # ~/.zshrc
tea completion fish > ~/.config/fish/completions/tea.fish
tea completion powershell | Out-String | Invoke-Expression # PowerShell profile
```
`tea completion <shell> --help` explains each shell's requirements.
Packagers can ship the pre-generated scripts and man pages from the release docs
archive, or run `make docs`.
## Behavior changes
- Short flags changed meaning: `pr create -b` is now `--body` (it was `--base`, now `-B`),
and `release edit --draft` / `--prerelease` are switches, so the 0.16 form
`--draft false` is refused instead of being read as a tag; use `--draft=false`.
- `search repo --private` and `--archived` are switches. Write `--private=false` where
0.16 accepted `--private false`.
- `pr review reply <number> <comment-id>` takes the reply with `--body`, `--body-file` or
`--editor`, not as a third argument. `repo create` names its template options `--template`
and `--trust-model`; see `tea repo create --help`.
- `--repo` takes `OWNER/REPO` or a URL; use `--cwd DIR` to point at a local checkout.
- `pr checkout N` (alias `co`) checks out a local branch named after the PR's
head branch when that name is free or already points at the head; otherwise
it uses `OWNER/BRANCH` for a fork or `pr/N`. The branch tracks the head
branch, so `git push` updates the pull request. Use `--branch NAME` (`-b`) to
choose the name, `--update` to fast-forward an existing branch, or `--detach`
for a detached checkout.
- `pr review` takes the review type as `--approve` / `-a`, `--request-changes` /
`-r` or `--comment` / `-c`; on a terminal, leaving it out starts an
interactive review.
- `label list` shows only the labels of the selected scope: the repository, or
the organization with `--org ORG`. 0.16 also listed the organization labels of
an organization-owned repository; `--exclude-org` was removed.
- `notification` commands act on your whole inbox by default (the old
`--mine`). `-R OWNER/REPO` or `--this-repo` limits them to one repository.
- `config get KEY` prints only the value; `--show-source` adds where it comes
from.
- `auth status` exits with 4 when there is no account or a credential is
missing or rejected. `auth token` prints the active account's token.
- `webhook edit` must be told what to do with the delivery authorization header
on every call, because Gitea replaces it: pass `--authorization-header`,
`--authorization-header-file` or `--clear-authorization`. The signing secret
cannot be edited; recreate the hook to rotate it.
- `admin user edit --password` no longer forces a password change at the next sign-in
(`admin user create` still does); add `--must-change-password` to require one.
- `notification mark-read`, `mark-unread`, `pin` and `unpin` act on the given IDs;
pass `--all` to apply them to every notification matching the filters.
- `--no-input` disables prompts, editors and browsers. With `--json`, tea never
prompts unless `--interactive` is given; required values must come from flags.
- Destructive commands and `pr merge` confirm on a terminal and need `--yes`
(`-y`) elsewhere.
- `--limit` (`-L`) accepts 1 to 1000 and `--page` a positive number; other
values are usage errors instead of being passed to the server. tea pages
through the server's smaller pages to reach the limit.
- In `--json` output, timestamps the server leaves unset print as `""`, or as
`null` for optional fields such as deadlines, instead of
`0001-01-01T00:00:00Z`.
- More input is checked before anything is sent: release titles, issue titles
and comment bodies cannot be empty, a review needs a body or inline comments
(unless it approves), team creation needs a permission, migrations from
GitHub, Gitea, GitLab and Gogs need an access token. `workflow run` uses the
checked-out branch (which must be on the server) or the default branch when
there is no `--ref`, and refuses unknown inputs, missing required inputs and
values that a choice, boolean or number input does not accept.
- `pr merge` merges the head it read and refuses when the branch moved in the
meantime; run it again to merge the new head.
- Preferences follow the git/gh order: an explicit `tea config set` value wins
over `VISUAL`/`EDITOR`, `PAGER` and `BROWSER`, which win over the defaults;
`TEA_EDITOR`, `TEA_PAGER` and `TEA_COLOR` override both.