mirror of
https://gitea.com/gitea/tea.git
synced 2026-09-15 01:46:23 -04:00
Adds a top-level 'tea deploy-keys' command under ENTITIES, providing
list, create, delete, and detail-by-id operations over the existing
Gitea REST API at /repos/{owner}/{repo}/keys.
- New CmdDeployKeys registered alongside tea webhooks/branches/etc.
- Subcommands: list (with pagination + --fingerprint filter),
create (<title> --key|--key-file [--read-only|--read-write]),
delete (<key-id> --confirm|-y), and a default <key-id> detail view.
- The Gitea API has no edit endpoint; 'change' is documented as
delete+create. No update subcommand is added.
- modules/print/deploy_key.go: DeployKeysList and DeployKeyDetails.
- Unit tests covering command metadata, flag wiring, key-material
resolution (--key vs --key-file, mutual exclusion, missing file),
delete confirmation logic, key-id parsing, and prompt formatting.
- README/CHANGELOG/CLI.md updated.
All four Gitea SDK methods used (CreateDeployKey, DeleteDeployKey,
GetDeployKey, ListDeployKeys) are already present in
code.gitea.io/sdk/gitea v0.23.2; no go.mod changes.
Refs #1066.
Signed-off-by: Ross Golder <ross@golder.org>
(cherry picked from commit 384540c91f9703d1e1b37dd6a8e51f502cc5f216)
103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package deploykeys
|
|
|
|
import (
|
|
stdctx "context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
gitea "gitea.dev/sdk"
|
|
|
|
"gitea.dev/tea/cmd/flags"
|
|
"gitea.dev/tea/modules/context"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
// CmdDeployKeysCreate represents a sub command of deploy-keys to create a deploy key
|
|
var CmdDeployKeysCreate = cli.Command{
|
|
Name: "create",
|
|
Aliases: []string{"add", "c"},
|
|
Usage: "Create a deploy key",
|
|
Description: "Create a deploy key in a repository. To replace an existing key, run 'delete' followed by 'create'.",
|
|
ArgsUsage: "<key-title>",
|
|
Action: runDeployKeysCreate,
|
|
Flags: append([]cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "key",
|
|
Usage: "inline armored SSH public key",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "key-file",
|
|
Usage: "path to a file containing the armored SSH public key (e.g. ~/.ssh/id_ed25519.pub)",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "read-only",
|
|
Usage: "restrict the key to read-only access (default)",
|
|
Value: true,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "read-write",
|
|
Usage: "grant the key read/write access",
|
|
},
|
|
}, flags.AllDefaultFlags...),
|
|
}
|
|
|
|
func runDeployKeysCreate(ctx stdctx.Context, cmd *cli.Command) error {
|
|
if cmd.Args().Len() == 0 {
|
|
return errors.New("key title is required")
|
|
}
|
|
|
|
c, err := context.InitCommand(cmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := c.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
|
|
return err
|
|
}
|
|
client := c.Login.Client()
|
|
|
|
keyMaterial, err := resolveKeyMaterial(cmd.String("key"), cmd.String("key-file"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
readOnly := cmd.Bool("read-only")
|
|
if cmd.IsSet("read-write") {
|
|
readOnly = !cmd.Bool("read-write")
|
|
}
|
|
|
|
key, _, err := client.CreateDeployKey(ctx, c.Owner, c.Repo, gitea.CreateKeyOption{
|
|
Title: cmd.Args().First(),
|
|
Key: keyMaterial,
|
|
ReadOnly: readOnly,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Deploy key %d created (title: %s)\n", key.ID, key.Title)
|
|
return nil
|
|
}
|
|
|
|
// resolveKeyMaterial returns the SSH public key from --key (inline) or --key-file.
|
|
// The two flags are mutually exclusive; exactly one must be supplied.
|
|
func resolveKeyMaterial(inline, file string) (string, error) {
|
|
switch {
|
|
case inline != "" && file != "":
|
|
return "", errors.New("--key and --key-file are mutually exclusive")
|
|
case inline == "" && file == "":
|
|
return "", errors.New("either --key or --key-file is required")
|
|
case inline != "":
|
|
return inline, nil
|
|
default:
|
|
data, err := os.ReadFile(file)
|
|
if err != nil {
|
|
return "", fmt.Errorf("reading key file %q: %w", file, err)
|
|
}
|
|
return string(data), nil
|
|
}
|
|
}
|