mirror of
https://gitea.com/gitea/tea.git
synced 2026-09-10 07:26:33 -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)
111 lines
2.8 KiB
Go
111 lines
2.8 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package deploykeys
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"gitea.dev/sdk"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
func TestCreateCommandMetadata(t *testing.T) {
|
|
cmd := &CmdDeployKeysCreate
|
|
|
|
assert.Equal(t, "create", cmd.Name)
|
|
for _, want := range []string{"add", "c"} {
|
|
assert.Contains(t, cmd.Aliases, want)
|
|
}
|
|
assert.Equal(t, "Create a deploy key", cmd.Usage)
|
|
assert.Equal(t, "<key-title>", cmd.ArgsUsage)
|
|
assert.NotNil(t, cmd.Action)
|
|
}
|
|
|
|
func TestCreateCommandFlags(t *testing.T) {
|
|
cmd := &CmdDeployKeysCreate
|
|
|
|
have := make(map[string]bool, len(cmd.Flags))
|
|
for _, flag := range cmd.Flags {
|
|
have[flag.Names()[0]] = true
|
|
}
|
|
for _, name := range []string{"key", "key-file", "read-only", "read-write", "login", "repo", "remote", "output"} {
|
|
assert.True(t, have[name], "expected flag %q not found", name)
|
|
}
|
|
}
|
|
|
|
func TestCreateReadOnlyDefault(t *testing.T) {
|
|
// The --read-only flag must default to true to match Gitea's "safe" default
|
|
// and the flag-help wording ("(default)").
|
|
for _, flag := range CmdDeployKeysCreate.Flags {
|
|
if bf, ok := flag.(*cli.BoolFlag); ok && bf.Name == "read-only" {
|
|
assert.True(t, bf.Value, "--read-only should default to true")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveKeyMaterial(t *testing.T) {
|
|
const inlineKey = "ssh-ed25519 AAAA-test-key inline"
|
|
|
|
t.Run("inline key", func(t *testing.T) {
|
|
got, err := resolveKeyMaterial(inlineKey, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, inlineKey, got)
|
|
})
|
|
|
|
t.Run("mutually exclusive flags", func(t *testing.T) {
|
|
_, err := resolveKeyMaterial(inlineKey, "/tmp/key.pub")
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("neither flag set", func(t *testing.T) {
|
|
_, err := resolveKeyMaterial("", "")
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("read key from file", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "key.pub")
|
|
want := inlineKey + " trailing-newline\n"
|
|
require := assert.New(t)
|
|
require.NoError(os.WriteFile(path, []byte(want), 0o600))
|
|
|
|
got, err := resolveKeyMaterial("", path)
|
|
require.NoError(err)
|
|
require.Equal(want, got)
|
|
})
|
|
|
|
t.Run("missing file", func(t *testing.T) {
|
|
_, err := resolveKeyMaterial("", filepath.Join(t.TempDir(), "does-not-exist.pub"))
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestCreateKeyOptionConstruction(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
title string
|
|
key string
|
|
readOnly bool
|
|
}{
|
|
{"read-only ed25519", "ci", "ssh-ed25519 AAAA...", true},
|
|
{"read-write rsa", "deploy-bot", "ssh-rsa AAAA...", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
opt := gitea.CreateKeyOption{
|
|
Title: tt.title,
|
|
Key: tt.key,
|
|
ReadOnly: tt.readOnly,
|
|
}
|
|
assert.Equal(t, tt.title, opt.Title)
|
|
assert.Equal(t, tt.key, opt.Key)
|
|
assert.Equal(t, tt.readOnly, opt.ReadOnly)
|
|
})
|
|
}
|
|
}
|