mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
- **switch tea to the Cobra command tree:** `internal/app` wires the packages from parts 1–4 into explicit noun/verb commands with `--repo`, `--json` / `--jq`, `--sudo` and `--debug`; `main.go` points at it. Build, release and docs tooling (`tools/cli-docs`, Makefile, goreleaser, snap, CI) and README / CONTRIBUTING are updated. - **remove the urfave/cli command tree:** deletes `cmd/`, `modules/`, the old integration tests, contrib completion scripts and the generated `docs/CLI.md`, and drops their dependencies. This commit only deletes. ## Breaking changes This is a breaking release. It requires Gitea 28 or newer; configuration moves to separate `config.yml` and `hosts.yml` files and requires fresh authentication, and command names, aliases, flags and output formats change. `docs/migration-1.0.md` maps every old command, flag and environment variable to its replacement. ## Issues fixes #1118 fixes #1116 fixes #1115 fixes #1094 fixes #1091 fixes #1073 fixes #1052 fixes #1032 fixes #1023 fixes #966 fixes #908 fixes #833 fixes #831 fixes #817 fixes #804 fixes #779 fixes #770 fixes #737 fixes #697 fixes #726 fixes #677 fixes #672 fixes #633 fixes #632 fixes #560 fixes #556 fixes #523 fixes #516 fixes #510 fixes #504 fixes #500 fixes #482 fixes #406 fixes #403 fixes #373 fixes #351 fixes #344 fixes #326 fixes #325 fixes #323 fixes #246 fixes #240 fixes #232 fixes #197 fixes #172 fixes #141 fixes #69 fixes #1110 fixes #569 fixes #480 fixes #666 fixes #670 fixes #457 fixes #643 fixes #498 fixes #490 fixes #1069 fixes #834 fixes #602 fixes #328 fixes #417 fixes #571 fixes #1029 fixes #489 fixes #1050 fixes #162 fixes #430 fixes #1087 fixes #683 Reviewed-on: https://gitea.com/gitea/tea/pulls/1126 Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
492 lines
29 KiB
Go
492 lines
29 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dev/tea/internal/services"
|
|
"gitea.dev/tea/internal/transport"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
func TestGiteaMetadataLifecycle(t *testing.T) {
|
|
_, deps, out, diagnostics := giteaDeps(t)
|
|
execute := outputExecutor(t, &deps, out, diagnostics)
|
|
|
|
adminUsername := fmt.Sprintf("tea-it-admin-%d", time.Now().UnixNano())
|
|
var managedUser services.AdminUser
|
|
adminData := execute("admin", "user", "create", adminUsername, "--email", adminUsername+"@example.test", "--password", "local-admin-test-password", "--admin", "--restricted", "--prohibit-login", "--visibility", "limited", "--json")
|
|
require.NotContains(t, string(adminData), "local-admin-test-password")
|
|
require.NoError(t, json.Unmarshal(adminData, &managedUser))
|
|
require.True(t, managedUser.Admin)
|
|
require.True(t, managedUser.Restricted)
|
|
require.True(t, managedUser.ProhibitLogin)
|
|
require.Equal(t, "limited", managedUser.Visibility)
|
|
userDeleted := false
|
|
t.Cleanup(func() {
|
|
if !userDeleted {
|
|
if err := Execute(context.Background(), deps, []string{"admin", "user", "delete", adminUsername, "--yes"}); err != nil {
|
|
t.Errorf("admin account cleanup: %v", err)
|
|
}
|
|
}
|
|
})
|
|
passwordPath := filepath.Join(t.TempDir(), "password")
|
|
require.NoError(t, os.WriteFile(passwordPath, []byte("updated-local-password\n"), 0o600))
|
|
require.NoError(t, json.Unmarshal(execute("admin", "user", "edit", adminUsername, "--admin=false", "--restricted=false", "--prohibit-login=false", "--active=false", "--full-name", "Managed Account", "--description", "Disposable", "--location", "Test server", "--website", "https://example.test", "--visibility", "private", "--max-repo-creation", "0", "--allow-git-hook=false", "--allow-import-local=false", "--allow-create-organization=false", "--password-file", passwordPath, "--must-change-password=false", "--json"), &managedUser))
|
|
require.False(t, managedUser.Admin)
|
|
require.False(t, managedUser.Restricted)
|
|
require.False(t, managedUser.ProhibitLogin)
|
|
require.False(t, managedUser.Active)
|
|
require.Equal(t, "Managed Account", managedUser.FullName)
|
|
require.Equal(t, "private", managedUser.Visibility)
|
|
require.NoError(t, json.Unmarshal(execute("admin", "user", "view", adminUsername, "--json"), &managedUser))
|
|
require.Equal(t, "Disposable", managedUser.Description)
|
|
var managedUsers []services.AdminUser
|
|
require.NoError(t, json.Unmarshal(execute("admin", "user", "list", "--json"), &managedUsers))
|
|
require.Contains(t, managedUsers, managedUser)
|
|
execute("admin", "user", "delete", adminUsername, "--yes")
|
|
userDeleted = true
|
|
name := fmt.Sprintf("tea-it-%d", time.Now().UnixNano())
|
|
var repo services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("repo", "create", name, "--auto-init", "--private", "--json"), &repo))
|
|
require.Equal(t, name, repo.Name)
|
|
t.Cleanup(func() {
|
|
out.Reset()
|
|
err := Execute(context.Background(), deps, []string{"repo", "delete", "-R", repo.FullName, "--yes"})
|
|
if err != nil {
|
|
t.Errorf("repository cleanup: %v", err)
|
|
}
|
|
})
|
|
require.NoError(t, json.Unmarshal(execute("repo", "edit", "-R", repo.FullName, "--name", name+"-renamed", "--website", "https://example.test", "--default-branch", repo.DefaultBranch, "--json"), &repo))
|
|
require.Equal(t, name+"-renamed", repo.Name)
|
|
require.Equal(t, "https://example.test", repo.Website)
|
|
require.NoError(t, json.Unmarshal(execute("repo", "edit", "-R", repo.FullName, "--website=", "--archived=false", "--json"), &repo))
|
|
require.Empty(t, repo.Website)
|
|
require.False(t, repo.Archived)
|
|
scoped := func(args ...string) []byte { return execute(append(args, "-R", repo.FullName, "--json")...) }
|
|
templateName := fmt.Sprintf("tea-template-%d", time.Now().UnixNano())
|
|
var template, generated services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("repo", "create", templateName, "--as-template", "--auto-init", "--default-branch", "trunk", "--private", "--json"), &template))
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"repo", "delete", "-R", template.FullName, "--yes"}); err != nil {
|
|
t.Errorf("template cleanup: %v", err)
|
|
}
|
|
})
|
|
require.True(t, template.Template)
|
|
generatedName := fmt.Sprintf("tea-generated-%d", time.Now().UnixNano())
|
|
require.NoError(t, json.Unmarshal(execute("repo", "create", generatedName, "--template", template.URL, "--private", "--copy-git-hooks=false", "--json"), &generated))
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"repo", "delete", "-R", generated.FullName, "--yes"}); err != nil {
|
|
t.Errorf("generated repository cleanup: %v", err)
|
|
}
|
|
})
|
|
require.Equal(t, "trunk", generated.DefaultBranch)
|
|
require.False(t, generated.Template)
|
|
var foundRepos []services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("search", "repo", generatedName, "--owner", "integration", "--private", "--archived=false", "--type", "source", "--json"), &foundRepos))
|
|
require.Contains(t, foundRepos, generated)
|
|
execute("api", "user/starred/"+generated.FullName, "--method", "PUT")
|
|
require.NoError(t, json.Unmarshal(execute("repo", "list", "--starred", "--json"), &foundRepos))
|
|
require.Contains(t, foundRepos, generated)
|
|
execute("api", "user/starred/"+generated.FullName, "--method", "DELETE")
|
|
require.NoError(t, json.Unmarshal(execute("repo", "list", "--watched", "--limit", "1", "--page", "2", "--json"), &foundRepos))
|
|
require.Len(t, foundRepos, 1)
|
|
if serverRoot := os.Getenv("GITEA_TEA_TEST_REPOSITORY_ROOT"); serverRoot != "" {
|
|
migrationName := fmt.Sprintf("tea-migrated-%d", time.Now().UnixNano())
|
|
var migrated services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("repo", "migrate", "--server-path", filepath.ToSlash(filepath.Join(serverRoot, repo.FullName+".git")), "--name", migrationName, "--private", "--json"), &migrated))
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"repo", "delete", "-R", migrated.FullName, "--yes"}); err != nil {
|
|
t.Errorf("migrated repository cleanup: %v", err)
|
|
}
|
|
})
|
|
require.Equal(t, repo.DefaultBranch, migrated.DefaultBranch)
|
|
require.True(t, migrated.Private)
|
|
}
|
|
var branch services.Branch
|
|
require.NoError(t, json.Unmarshal(scoped("branch", "create", "feature/initial"), &branch))
|
|
require.Equal(t, "feature/initial", branch.Name)
|
|
execute("branch", "rename", "feature/initial", "feature/renamed", "-R", repo.FullName)
|
|
execute("branch", "protect", "feature/renamed", "-R", repo.FullName)
|
|
require.NoError(t, json.Unmarshal(scoped("branch", "view", "feature/renamed"), &branch))
|
|
require.True(t, branch.Protected)
|
|
require.EqualValues(t, 1, branch.RequiredApprovals)
|
|
execute("branch", "unprotect", "feature/renamed", "-R", repo.FullName, "--yes")
|
|
require.NoError(t, json.Unmarshal(scoped("branch", "view", "feature/renamed"), &branch))
|
|
require.False(t, branch.Protected)
|
|
execute("branch", "delete", "feature/renamed", "-R", repo.FullName, "--yes")
|
|
|
|
var hook services.Webhook
|
|
require.NoError(t, json.Unmarshal(scoped("webhook", "create", "http://127.0.0.1:9/hook?key=private-value", "--secret", "local-signing-secret", "--authorization-header", "Bearer local-header", "--active=false", "--events", "issues,release", "--branch-filter", "feature/*"), &hook))
|
|
require.False(t, hook.Active)
|
|
hookID := strconv.FormatInt(hook.ID, 10)
|
|
hookData := scoped("webhook", "edit", hookID, "--active=false", "--clear-authorization")
|
|
require.NotContains(t, string(hookData), "local-signing-secret")
|
|
require.NotContains(t, string(hookData), "local-header")
|
|
require.NotContains(t, string(hookData), "private-value")
|
|
require.NoError(t, json.Unmarshal(hookData, &hook))
|
|
require.Equal(t, "feature/*", hook.BranchFilter)
|
|
require.Contains(t, hook.Events, "release")
|
|
require.Contains(t, hook.Events, "issues")
|
|
require.NoError(t, json.Unmarshal(scoped("webhook", "edit", hookID, "--events", "push", "--branch-filter=", "--clear-authorization"), &hook))
|
|
require.Empty(t, hook.BranchFilter)
|
|
require.Equal(t, []string{"push"}, hook.Events)
|
|
execute("webhook", "delete", hookID, "-R", repo.FullName, "--yes")
|
|
var hooks []services.Webhook
|
|
require.NoError(t, json.Unmarshal(scoped("webhook", "list"), &hooks))
|
|
require.Empty(t, hooks)
|
|
for _, scope := range []string{"--account", "--global"} {
|
|
require.NoError(t, json.Unmarshal(execute("webhook", "create", "http://127.0.0.1:9/hook", scope, "--active=false", "--json"), &hook))
|
|
hookID := strconv.FormatInt(hook.ID, 10)
|
|
require.NoError(t, json.Unmarshal(execute("webhook", "list", scope, "--json"), &hooks))
|
|
require.Contains(t, hooks, hook)
|
|
execute("webhook", "delete", hookID, scope, "--yes")
|
|
}
|
|
var label services.Label
|
|
require.NoError(t, json.Unmarshal(scoped("label", "create", "--name", "bug", "--color", "ff0000"), &label))
|
|
require.Positive(t, label.ID)
|
|
id := strconv.FormatInt(label.ID, 10)
|
|
require.NoError(t, json.Unmarshal(scoped("label", "edit", id, "--description", "updated"), &label))
|
|
require.Equal(t, "updated", label.Description)
|
|
var labels []services.Label
|
|
require.NoError(t, json.Unmarshal(scoped("label", "list"), &labels))
|
|
require.Len(t, labels, 1)
|
|
var labeledIssue services.Issue
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "create", "--title", "Labeled issue", "--label", "repo:bug"), &labeledIssue))
|
|
require.Positive(t, labeledIssue.Number)
|
|
require.Equal(t, []services.Label{label}, labeledIssue.Labels)
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "edit", strconv.FormatInt(labeledIssue.Number, 10), "--set-labels=", "--title", "Labels cleared"), &labeledIssue))
|
|
require.Empty(t, labeledIssue.Labels)
|
|
require.NotNil(t, labeledIssue.Labels)
|
|
execute("label", "delete", id, "-R", repo.FullName, "--yes")
|
|
var milestone services.Milestone
|
|
require.NoError(t, json.Unmarshal(scoped("milestone", "create", "--title", "v1", "--deadline", "2026-12-01"), &milestone))
|
|
require.Positive(t, milestone.ID)
|
|
ms := strconv.FormatInt(milestone.ID, 10)
|
|
require.NoError(t, json.Unmarshal(scoped("milestone", "close", ms), &milestone))
|
|
require.Equal(t, "closed", milestone.State)
|
|
require.NoError(t, json.Unmarshal(scoped("milestone", "reopen", ms), &milestone))
|
|
require.Equal(t, "open", milestone.State)
|
|
execute("milestone", "delete", ms, "-R", repo.FullName, "--yes")
|
|
var issue services.Issue
|
|
require.NoError(t, json.Unmarshal(executeWithEditorIntegration(t, deps, "", "Body", "issue", "create", "--repo", repo.FullName, "--title", "real API issue"), &issue))
|
|
require.Positive(t, issue.Number)
|
|
require.Equal(t, "real API issue", issue.Title)
|
|
issueNumber := strconv.FormatInt(issue.Number, 10)
|
|
require.Equal(t, "[]\n", string(scoped("issue", "attachment", "list", issueNumber)))
|
|
verifyResourceBrowser(t, deps, repo.URL, "repo", "view", "--repo", repo.FullName)
|
|
verifyResourceBrowser(t, deps, issue.URL, "issue", "view", issueNumber, "--repo", repo.FullName)
|
|
verifyBodyEditorIntegration(t, deps, "issue", repo.FullName, issueNumber, issue.Body)
|
|
verifyIssueAttachmentLifecycle(t, deps, "issue", repo.FullName, issueNumber)
|
|
var searchItems []services.SearchItem
|
|
for range 100 {
|
|
require.NoError(t, json.Unmarshal(scoped("search", "issue", "real API issue", "--authored"), &searchItems))
|
|
if len(searchItems) > 0 {
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
require.Len(t, searchItems, 1)
|
|
require.Equal(t, repo.FullName, searchItems[0].Repository)
|
|
require.Equal(t, "issue", searchItems[0].Type)
|
|
require.NoError(t, json.Unmarshal(execute("search", "issue", "real API issue", "--owner", "integration", "--authored", "--json"), &searchItems))
|
|
foundIssue := false
|
|
for _, item := range searchItems {
|
|
if item.ID == issue.ID {
|
|
foundIssue = true
|
|
}
|
|
}
|
|
require.True(t, foundIssue)
|
|
require.Equal(t, "[]\n", string(execute("search", "pr", name, "--json")))
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "edit", issueNumber, "--title", "edited", "--body=", "--set-assignees", strings.Split(repo.FullName, "/")[0]), &issue))
|
|
require.Equal(t, "edited", issue.Title)
|
|
require.Empty(t, issue.Body)
|
|
var bulkEdited []services.Issue
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "edit", issueNumber, strconv.FormatInt(labeledIssue.Number, 10), "--body", "Bulk edited body"), &bulkEdited))
|
|
require.Len(t, bulkEdited, 2)
|
|
for _, edited := range bulkEdited {
|
|
require.Equal(t, "Bulk edited body", edited.Body)
|
|
var saved services.Issue
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "view", strconv.FormatInt(edited.Number, 10)), &saved))
|
|
require.Equal(t, edited.Body, saved.Body)
|
|
}
|
|
require.NoError(t, json.Unmarshal(scoped("repo", "edit", "--actions=false"), &repo))
|
|
require.False(t, repo.ActionsEnabled)
|
|
var accountStatus services.AccountStatus
|
|
require.NoError(t, json.Unmarshal(scoped("status"), &accountStatus))
|
|
require.Equal(t, "integration", accountStatus.User)
|
|
require.Equal(t, repo.FullName, accountStatus.Repository)
|
|
require.Len(t, accountStatus.AssignedIssues, 1)
|
|
require.Equal(t, issue.ID, accountStatus.AssignedIssues[0].ID)
|
|
require.False(t, accountStatus.RunsIncluded)
|
|
require.Empty(t, accountStatus.FailingRuns)
|
|
scoped("issue", "edit", issueNumber, "--set-assignees=")
|
|
var comment services.Comment
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "comment", "create", issueNumber, "--body", "First comment"), &comment))
|
|
require.Positive(t, comment.ID)
|
|
commentID := strconv.FormatInt(comment.ID, 10)
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "comment", "edit", commentID, "--body", "Edited comment"), &comment))
|
|
require.Equal(t, "Edited comment", comment.Body)
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "comment", "view", commentID), &comment))
|
|
var comments []services.Comment
|
|
require.NoError(t, json.Unmarshal(scoped("issue", "comment", "list", issueNumber), &comments))
|
|
require.Len(t, comments, 1)
|
|
execute("issue", "comment", "delete", commentID, "-R", repo.FullName, "--yes")
|
|
verifyEditorSubmission(t, deps, repo.FullName, issueNumber, false)
|
|
require.Equal(t, "[]\n", string(scoped("issue", "comment", "list", issueNumber)))
|
|
require.NoError(t, json.Unmarshal(scoped("milestone", "create", "--title", "membership"), &milestone))
|
|
ms = strconv.FormatInt(milestone.ID, 10)
|
|
scoped("milestone", "issue", "add", ms, issueNumber)
|
|
var members []services.Issue
|
|
require.NoError(t, json.Unmarshal(scoped("milestone", "issue", "list", ms), &members))
|
|
require.Len(t, members, 1)
|
|
require.Equal(t, issue.Number, members[0].Number)
|
|
scoped("milestone", "issue", "remove", ms, issueNumber)
|
|
require.Equal(t, "[]\n", string(scoped("milestone", "issue", "list", ms)))
|
|
execute("milestone", "delete", ms, "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("wiki", "list")))
|
|
notifier := fmt.Sprintf("tea-notifier-%d", time.Now().UnixNano())
|
|
deps.Streams.In = bytes.NewBufferString(fmt.Sprintf(`{"username":%q,"password":"local-test-password!123","email":%q,"must_change_password":false}`, notifier, notifier+"@example.test"))
|
|
execute("api", "admin/users", "--input", "-")
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"api", "admin/users/" + notifier, "--method", "DELETE"}); err != nil {
|
|
t.Errorf("notifier cleanup: %v", err)
|
|
}
|
|
})
|
|
deps.Streams.In = bytes.NewBufferString(`{"permission":"write"}`)
|
|
execute("api", "repos/"+repo.FullName+"/collaborators/"+notifier, "--method", "PUT", "--input", "-")
|
|
deps.Streams.In = bytes.NewBufferString(`{"body":"Notification event"}`)
|
|
execute("api", "repos/"+repo.FullName+"/issues/"+issueNumber+"/comments?sudo="+notifier, "--input", "-")
|
|
var notifications []services.Notification
|
|
for range 100 {
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "list", "--type", "issue"), ¬ifications))
|
|
if len(notifications) > 0 {
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
require.NotEmpty(t, notifications)
|
|
var boundedNotifications []services.Notification
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "list", "--type", "issue", "--since=24h", "--before=0s"), &boundedNotifications))
|
|
require.NotEmpty(t, boundedNotifications)
|
|
notificationID := strconv.FormatInt(notifications[0].ID, 10)
|
|
var notification services.Notification
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "view", notificationID), ¬ification))
|
|
require.Equal(t, repo.FullName, notification.Repository)
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "pin", notificationID), ¬ification))
|
|
require.True(t, notification.Pinned)
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "unpin", notificationID), ¬ification))
|
|
require.False(t, notification.Pinned)
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "mark-unread", notificationID), ¬ification))
|
|
require.True(t, notification.Unread)
|
|
require.NoError(t, json.Unmarshal(scoped("notification", "watch", "--timeout", "500ms", "--interval", "100ms"), ¬ifications))
|
|
require.NotEmpty(t, notifications)
|
|
scoped("notification", "mark-read", "--all")
|
|
require.Equal(t, "[]\n", string(scoped("notification", "list")))
|
|
var release services.Release
|
|
require.NoError(t, json.Unmarshal(executeWithEditorIntegration(t, deps, "", "Release notes", "release", "create", "v1", "--repo", repo.FullName, "--draft"), &release))
|
|
require.True(t, release.Draft)
|
|
require.Equal(t, "Release notes", release.Body)
|
|
require.NoError(t, json.Unmarshal(executeWithEditorIntegration(t, deps, release.Body, "Edited release notes", "release", "edit", "v1", "--repo", repo.FullName), &release))
|
|
require.Equal(t, "Edited release notes", release.Body)
|
|
require.NoError(t, json.Unmarshal(scoped("release", "view", "v1"), &release))
|
|
require.Equal(t, "Edited release notes", release.Body)
|
|
require.NoError(t, json.Unmarshal(scoped("release", "edit", "v1", "--title", "First release", "--prerelease"), &release))
|
|
require.Equal(t, "First release", release.Title)
|
|
require.True(t, release.Prerelease)
|
|
require.NoError(t, json.Unmarshal(scoped("release", "publish", "v1"), &release))
|
|
require.False(t, release.Draft)
|
|
assetFile := filepath.Join(t.TempDir(), "artifact.txt")
|
|
require.NoError(t, os.WriteFile(assetFile, []byte("release asset bytes"), 0o600))
|
|
var asset services.ReleaseAsset
|
|
require.NoError(t, json.Unmarshal(scoped("release", "asset", "upload", "v1", assetFile), &asset))
|
|
require.Equal(t, int64(19), asset.Size)
|
|
assetID := strconv.FormatInt(asset.ID, 10)
|
|
downloaded := execute("release", "asset", "download", "v1", assetID, "-R", repo.FullName, "--output-file", "-")
|
|
require.Equal(t, "release asset bytes", string(downloaded))
|
|
require.NoError(t, json.Unmarshal(scoped("release", "asset", "edit", "v1", assetID, "--name", "renamed.txt"), &asset))
|
|
require.Equal(t, "renamed.txt", asset.Name)
|
|
var assets []services.ReleaseAsset
|
|
require.NoError(t, json.Unmarshal(scoped("release", "asset", "list", "v1"), &assets))
|
|
require.Len(t, assets, 1)
|
|
execute("release", "asset", "delete", "v1", assetID, "-R", repo.FullName, "--yes")
|
|
secondAssetFile := filepath.Join(t.TempDir(), "second.txt")
|
|
require.NoError(t, os.WriteFile(secondAssetFile, []byte("second attachment"), 0o600))
|
|
var bulkAssets []services.ReleaseAsset
|
|
require.NoError(t, json.Unmarshal(scoped("release", "asset", "upload", "v1", assetFile, secondAssetFile), &bulkAssets))
|
|
require.Len(t, bulkAssets, 2)
|
|
out.Reset()
|
|
diagnostics.Reset()
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"release", "asset", "delete", "v1", bulkAssets[0].Name, bulkAssets[1].Name, "--by-name", "-R", repo.FullName, "--yes"}))
|
|
require.Contains(t, diagnostics.String(), "Deleted asset")
|
|
scoped("release", "create", "v2", "--asset", assetFile)
|
|
require.NoError(t, json.Unmarshal(scoped("release", "asset", "list", "v2"), &assets))
|
|
require.Len(t, assets, 1)
|
|
var releases []services.Release
|
|
require.NoError(t, json.Unmarshal(scoped("release", "edit", "v1", "v2", "--title", "Updated releases"), &releases))
|
|
require.Len(t, releases, 2)
|
|
execute("release", "delete", "v1", "v2", "-R", repo.FullName, "--delete-tag", "--yes")
|
|
var tags []json.RawMessage
|
|
require.NoError(t, json.Unmarshal(execute("api", "repos/"+repo.FullName+"/tags"), &tags))
|
|
require.Empty(t, tags)
|
|
require.Equal(t, "[]\n", string(scoped("release", "list")))
|
|
var variable services.ActionVariable
|
|
require.NoError(t, json.Unmarshal(scoped("variable", "set", "BUILD_MODE", "--value", "first"), &variable))
|
|
require.Equal(t, "first", variable.Value)
|
|
scoped("variable", "set", "BUILD_MODE", "--value", "second")
|
|
require.NoError(t, json.Unmarshal(scoped("variable", "view", "BUILD_MODE"), &variable))
|
|
require.Equal(t, "second", variable.Value)
|
|
var variables []services.ActionVariable
|
|
require.NoError(t, json.Unmarshal(scoped("variable", "list"), &variables))
|
|
require.Len(t, variables, 1)
|
|
execute("variable", "delete", "BUILD_MODE", "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("variable", "list")))
|
|
secretOutput := scoped("secret", "set", "BUILD_TOKEN", "--value", "sensitive-local-test-value")
|
|
require.NotContains(t, string(secretOutput), "sensitive-local-test-value")
|
|
var secrets []services.ActionSecret
|
|
require.NoError(t, json.Unmarshal(scoped("secret", "list"), &secrets))
|
|
require.Len(t, secrets, 1)
|
|
require.Equal(t, "BUILD_TOKEN", secrets[0].Name)
|
|
execute("secret", "delete", "BUILD_TOKEN", "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("secret", "list")))
|
|
accountName := fmt.Sprintf("TEA_IT_%d", time.Now().UnixNano())
|
|
execute("variable", "set", accountName, "--account", "--value", "account value")
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"variable", "delete", accountName, "--account", "--yes"}); err != nil {
|
|
t.Errorf("account variable cleanup: %v", err)
|
|
}
|
|
})
|
|
require.NoError(t, json.Unmarshal(execute("variable", "view", accountName, "--account", "--json"), &variable))
|
|
require.Equal(t, "account value", variable.Value)
|
|
orgName := fmt.Sprintf("tea-it-org-%d", time.Now().UnixNano())
|
|
var organization services.Organization
|
|
require.NoError(t, json.Unmarshal(execute("org", "create", orgName, "--description", "Original", "--visibility", "private", "--json"), &organization))
|
|
require.Equal(t, "private", organization.Visibility)
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"org", "delete", orgName, "--yes"}); err != nil {
|
|
t.Errorf("organization cleanup: %v", err)
|
|
}
|
|
})
|
|
require.NoError(t, json.Unmarshal(execute("webhook", "create", "http://127.0.0.1:9/hook", "--org", orgName, "--active=false", "--json"), &hook))
|
|
execute("webhook", "delete", strconv.FormatInt(hook.ID, 10), "--org", orgName, "--yes")
|
|
require.NoError(t, json.Unmarshal(execute("org", "edit", orgName, "--description=", "--visibility", "limited", "--repo-admins-can-change-team-access", "--json"), &organization))
|
|
require.Empty(t, organization.Description)
|
|
require.True(t, organization.RepoAdminChangeTeamAccess)
|
|
require.NoError(t, json.Unmarshal(execute("org", "view", orgName, "--json"), &organization))
|
|
require.Equal(t, "limited", organization.Visibility)
|
|
var organizations []services.Organization
|
|
require.NoError(t, json.Unmarshal(execute("org", "list", "--json"), &organizations))
|
|
require.Contains(t, organizations, organization)
|
|
username, _, _ := strings.Cut(repo.FullName, "/")
|
|
execute("org", "member", "public", orgName, username)
|
|
var membersList []services.OrganizationMember
|
|
require.NoError(t, json.Unmarshal(execute("org", "member", "list", orgName, "--public", "--json"), &membersList))
|
|
require.Len(t, membersList, 1)
|
|
execute("org", "member", "private", orgName, username)
|
|
out.Reset()
|
|
membershipErr := Execute(context.Background(), deps, []string{"api", "orgs/" + orgName + "/public_members/" + username})
|
|
var missingMembership *transport.APIError
|
|
require.ErrorAs(t, membershipErr, &missingMembership)
|
|
require.Equal(t, 404, missingMembership.Status)
|
|
var team services.Team
|
|
require.NoError(t, json.Unmarshal(execute("team", "create", orgName, "--name", "Developers", "--unit", "repo.code=write,repo.issues=read", "--json"), &team))
|
|
teamID := strconv.FormatInt(team.ID, 10)
|
|
require.Equal(t, "write", team.Units["repo.code"])
|
|
require.NoError(t, json.Unmarshal(execute("team", "edit", teamID, "--description", "Edited team", "--all-repositories", "--json"), &team))
|
|
require.Equal(t, "write", team.Units["repo.code"])
|
|
require.True(t, team.AllRepositories)
|
|
require.NoError(t, json.Unmarshal(execute("team", "edit", teamID, "--all-repositories=false", "--json"), &team))
|
|
require.False(t, team.AllRepositories)
|
|
execute("team", "member", "add", teamID, username)
|
|
var teamMembers []services.OrganizationMember
|
|
require.NoError(t, json.Unmarshal(execute("team", "member", "list", teamID, "--json"), &teamMembers))
|
|
require.Len(t, teamMembers, 1)
|
|
execute("team", "member", "remove", teamID, username, "--yes")
|
|
require.Equal(t, "[]\n", string(execute("team", "member", "list", teamID, "--json")))
|
|
var orgRepo services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("repo", "create", "team-repo", "--org", orgName, "--json"), &orgRepo))
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"repo", "delete", "-R", orgRepo.FullName, "--yes"}); err != nil {
|
|
t.Errorf("organization repository cleanup: %v", err)
|
|
}
|
|
})
|
|
execute("team", "repo", "add", teamID, "-R", orgRepo.FullName)
|
|
var teamRepos []services.Repository
|
|
require.NoError(t, json.Unmarshal(execute("team", "repo", "list", teamID, "--json"), &teamRepos))
|
|
require.Len(t, teamRepos, 1)
|
|
execute("team", "repo", "remove", teamID, "-R", orgRepo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(execute("team", "repo", "list", teamID, "--json")))
|
|
execute("team", "delete", teamID, "--yes")
|
|
execute("variable", "set", "ORG_MODE", "--org", orgName, "--value", "org value")
|
|
require.NoError(t, json.Unmarshal(execute("variable", "view", "ORG_MODE", "--org", orgName, "--json"), &variable))
|
|
require.Equal(t, "org value", variable.Value)
|
|
execute("variable", "delete", "ORG_MODE", "--org", orgName, "--yes")
|
|
execute("secret", "set", "ORG_TOKEN", "--org", orgName, "--value", "org-local-secret")
|
|
require.NoError(t, json.Unmarshal(execute("secret", "list", "--org", orgName, "--json"), &secrets))
|
|
require.Len(t, secrets, 1)
|
|
execute("secret", "delete", "ORG_TOKEN", "--org", orgName, "--yes")
|
|
execute("secret", "set", accountName, "--account", "--value", "account-local-secret")
|
|
execute("secret", "delete", accountName, "--account", "--yes")
|
|
var wiki services.WikiPage
|
|
require.NoError(t, json.Unmarshal(executeWithEditorIntegration(t, deps, "", "# Unicode ü content", "wiki", "create", "--repo", repo.FullName, "--title", "Home", "--message", "Create page"), &wiki))
|
|
require.Equal(t, "# Unicode ü content", wiki.Body)
|
|
require.NoError(t, json.Unmarshal(scoped("wiki", "view", "Home"), &wiki))
|
|
require.Equal(t, "Home", wiki.Title)
|
|
require.NoError(t, json.Unmarshal(executeWithEditorIntegration(t, deps, wiki.Body, "Updated content", "wiki", "edit", "Home", "--repo", repo.FullName, "--message", "Edit page"), &wiki))
|
|
require.Equal(t, "Updated content", wiki.Body)
|
|
var pages []services.WikiPage
|
|
require.NoError(t, json.Unmarshal(scoped("wiki", "list"), &pages))
|
|
require.Len(t, pages, 1)
|
|
var revisions []services.WikiRevision
|
|
require.NoError(t, json.Unmarshal(scoped("wiki", "revisions", "Home"), &revisions))
|
|
require.Len(t, revisions, 2)
|
|
execute("wiki", "delete", "Home", "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("wiki", "list")))
|
|
var record services.TrackedTime
|
|
require.NoError(t, json.Unmarshal(scoped("time", "create", issueNumber, "1h25m"), &record))
|
|
require.Equal(t, int64(5100), record.Seconds)
|
|
timeID := strconv.FormatInt(record.ID, 10)
|
|
var records []services.TrackedTime
|
|
require.NoError(t, json.Unmarshal(scoped("time", "list", "--issue", issueNumber), &records))
|
|
require.Len(t, records, 1)
|
|
execute("time", "delete", issueNumber, timeID, "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("time", "list", "--issue", issueNumber)))
|
|
scoped("time", "create", issueNumber, "30s")
|
|
execute("time", "reset", issueNumber, "-R", repo.FullName, "--yes")
|
|
require.Equal(t, "[]\n", string(scoped("time", "list", "--issue", issueNumber)))
|
|
_, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
|
require.NoError(t, err)
|
|
publicKey, err := ssh.NewPublicKey(privateKey.Public())
|
|
require.NoError(t, err)
|
|
keyFile := filepath.Join(t.TempDir(), "integration.pub")
|
|
require.NoError(t, os.WriteFile(keyFile, ssh.MarshalAuthorizedKey(publicKey), 0o600))
|
|
var key services.SSHKey
|
|
require.NoError(t, json.Unmarshal(execute("ssh-key", "create", keyFile, "--json"), &key))
|
|
require.Positive(t, key.ID)
|
|
keyID := strconv.FormatInt(key.ID, 10)
|
|
t.Cleanup(func() {
|
|
if err := Execute(context.Background(), deps, []string{"ssh-key", "delete", keyID, "--yes"}); err != nil {
|
|
t.Errorf("SSH key cleanup: %v", err)
|
|
}
|
|
})
|
|
require.NoError(t, json.Unmarshal(execute("ssh-key", "view", keyID, "--json"), &key))
|
|
require.Equal(t, "integration", key.Title)
|
|
var keys []services.SSHKey
|
|
require.NoError(t, json.Unmarshal(execute("ssh-key", "list", "--json"), &keys))
|
|
require.Contains(t, keys, key)
|
|
}
|