Files
gitea-tea/internal/app/repos_test.go
T
bircni eedbe9893d feat(repo): show repository columns, state and README
repo list and search repo printed bare names. They now render a table
with NAME, DESCRIPTION, INFO (public or private, fork, mirror, template,
archived, empty) and UPDATED under "Showing N of M repositories ...", an
empty-state message on stderr, and tab-separated rows with the URL when
piped. --type, --sort and --order complete and validate their values.

repo view shows the visibility and kind badges, stars, forks, open
issues and pull requests, the parent of a fork, the source of a mirror,
the default branch and the clone URLs, followed by the README of the
default branch (or --branch), rendered on a terminal. The repository
JSON gains empty, stars_count, forks_count, open_issues_count,
open_pr_count, topics and updated_at.

Signed-off-by: bircni <bircni@icloud.com>
2026-10-11 23:51:45 +02:00

119 lines
5.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package app
import (
"bytes"
"context"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// repoTTYDeps returns serverDeps for a 100-column terminal without color or links, as people read
// tea's output, at a fixed time.
func repoTTYDeps(t *testing.T, serverURL string) (Dependencies, *bytes.Buffer, *bytes.Buffer) {
t.Helper()
deps, out, diagnostics := serverDeps(t, serverURL)
deps.Getenv = serverEnv(serverURL, map[string]string{"TERM": "dumb"})
deps.Streams.OutTTY, deps.Streams.Width = true, 100
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
return deps, out, diagnostics
}
const listedRepositories = `[
{"full_name":"alice/old-stuff","description":"Archived repository","archived":true,"html_url":"https://gitea.test/alice/old-stuff","updated_at":"2026-10-11T18:00:00Z"},
{"full_name":"acme/service","private":true,"fork":true,"html_url":"https://gitea.test/acme/service","updated_at":"2026-10-09T18:00:00Z"}
]`
func TestRepoListShowsColumns(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/user/repos", r.URL.Path)
w.Header().Set("X-Total-Count", "2")
_, _ = w.Write([]byte(listedRepositories))
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list"}))
require.Equal(t, `Showing 2 of 2 repositories you can access
NAME DESCRIPTION INFO UPDATED
alice/old-stuff Archived repository public, archived about 2 hours ago
acme/service private, fork about 2 days ago
`, out.String())
deps, out, _ = serverDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list"}))
require.Equal(t, "alice/old-stuff\tArchived repository\tpublic, archived\t2026-10-11T18:00:00Z\thttps://gitea.test/alice/old-stuff\n"+
"acme/service\t\tprivate, fork\t2026-10-09T18:00:00Z\thttps://gitea.test/acme/service\n", out.String())
}
func TestRepoListReportsAnEmptyCollection(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v1/orgs/acme":
_, _ = w.Write([]byte(`{"id":3,"username":"acme"}`))
default:
_, _ = w.Write([]byte(`[]`))
}
}))
defer server.Close()
deps, out, diagnostics := repoTTYDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list", "acme", "--type", "fork"}))
require.Empty(t, out.String())
require.Equal(t, "no forks owned by acme\n", diagnostics.String())
}
func TestRepoViewShowsStateAndReadme(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v1/repos/bob/project":
_, _ = w.Write([]byte(`{"full_name":"bob/project","description":"Demo","fork":true,"archived":true,"default_branch":"main",
"stars_count":1,"forks_count":0,"open_issues_count":2,"open_pr_counter":1,"updated_at":"2026-10-11T19:00:00Z",
"html_url":"https://gitea.test/bob/project","clone_url":"https://gitea.test/bob/project.git",
"parent":{"full_name":"alice/project"}}`))
case "/api/v1/repos/bob/project/contents/":
require.Equal(t, "develop", r.URL.Query().Get("ref"))
_, _ = w.Write([]byte(`[{"name":"docs","type":"dir"},{"name":"README","type":"file"},{"name":"readme.md","type":"file"}]`))
case "/api/v1/repos/bob/project/raw/readme.md":
_, _ = w.Write([]byte("Hello **there**"))
default:
t.Errorf("unexpected request %s", r.URL)
}
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
deps.Getenv = serverEnv(server.URL, map[string]string{"TERM": "dumb", "TEA_MARKDOWN": "raw"})
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "bob/project", "--branch", "develop"}))
require.Equal(t, `bob/project
public • fork • archived (read-only) • ★ 1 · 0 forks · 2 open issues · 1 open pull request · updated about 1 hour ago
Description: Demo
Forked from: alice/project
Default branch: main
Clone: https://gitea.test/bob/project.git
Hello **there**
View this repository on Gitea: https://gitea.test/bob/project
`, out.String())
deps, out, _ = serverDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "bob/project", "-b", "develop"}))
require.Equal(t, "title:\tbob/project\ndescription:\tDemo\nforked from:\talice/project\nmirror of:\t\ndefault branch:\tmain\nwebsite:\t\ntopics:\t\n"+
"clone:\thttps://gitea.test/bob/project.git\nssh:\t\nurl:\thttps://gitea.test/bob/project\n--\nHello **there**\n", out.String())
}
func TestRepoViewOfAnEmptyRepositorySkipsTheReadme(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/repos/alice/empty", r.URL.Path)
_, _ = w.Write([]byte(`{"full_name":"alice/empty","private":true,"empty":true,"html_url":"https://gitea.test/alice/empty"}`))
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
deps.Getenv = serverEnv(server.URL, map[string]string{"TERM": "dumb", "TEA_MARKDOWN": "raw"})
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "alice/empty"}))
require.Contains(t, out.String(), "private • empty • ★ 0")
require.Contains(t, out.String(), "_This repository is empty._")
}