mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
Use one canPrompt and pullNumberArguments for the comment commands, set display preferences instead of the retired environment variables in tests, and delete writeList, writeItem, batch, table, writeRecord(s), the legacy column map, confirm, require, validateMilestoneFlags and listWindow now that every command uses their replacements. Signed-off-by: bircni <bircni@icloud.com>
165 lines
8.1 KiB
Go
165 lines
8.1 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dev/tea/internal/clierr"
|
|
"gitea.dev/tea/internal/terminal"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type milestoneFormFunc func(context.Context) (terminal.MilestoneFormValues, error)
|
|
|
|
func (f milestoneFormFunc) EditMilestone(ctx context.Context, _ string, _ terminal.MilestoneFormValues) (terminal.MilestoneFormValues, error) {
|
|
return f(ctx)
|
|
}
|
|
|
|
func TestMilestoneCreateInteractiveForm(t *testing.T) {
|
|
var body map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(t, "/api/v1/repos/alice/project/milestones", r.URL.Path)
|
|
require.Equal(t, http.MethodPost, r.Method)
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&body))
|
|
_, _ = w.Write([]byte(`{"id":9,"title":"Release","description":"Ship it","state":"open","due_on":"2026-12-31T00:00:00Z"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
|
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
|
due := time.Date(2026, 12, 31, 0, 0, 0, 0, time.UTC)
|
|
deps.MilestoneForm = milestoneFormFunc(func(context.Context) (terminal.MilestoneFormValues, error) {
|
|
return terminal.MilestoneFormValues{Title: "Release", Description: "Ship it", Deadline: &due}, nil
|
|
})
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"milestone", "create", "-R", "alice/project", "--json=id,title,description", "--interactive"}))
|
|
require.JSONEq(t, `{"id":9,"title":"Release","description":"Ship it"}`, out.String())
|
|
require.Empty(t, diagnostics.String())
|
|
require.Equal(t, "Release", body["title"])
|
|
require.Equal(t, "Ship it", body["description"])
|
|
require.Equal(t, "2026-12-31T00:00:00Z", body["due_on"])
|
|
|
|
out.Reset()
|
|
deps.MilestoneForm = milestoneFormFunc(func(context.Context) (terminal.MilestoneFormValues, error) {
|
|
t.Fatal("form should not run when create flags are set")
|
|
return terminal.MilestoneFormValues{}, nil
|
|
})
|
|
require.Equal(t, clierr.Usage, clierr.ExitCode(Execute(context.Background(), deps, []string{"milestone", "create", "-R", "alice/project", "--no-input"})))
|
|
require.Empty(t, out.String())
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"milestone", "create", "-R", "alice/project", "--title", "Flagged", "--json=id", "--interactive"}))
|
|
}
|
|
|
|
func TestMilestoneCreateState(t *testing.T) {
|
|
var payload map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
require.Equal(t, http.MethodPost, r.Method)
|
|
require.Equal(t, "/api/v1/repos/alice/project/milestones", r.URL.Path)
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&payload))
|
|
_, _ = w.Write([]byte(`{"id":9,"title":"Done","state":"closed"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, out, _ := serverDeps(t, server.URL)
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"milestone", "create", "-R", "alice/project", "--title", "Done", "--state", "closed", "--json=id,state", "--no-input"}))
|
|
require.Equal(t, "closed", payload["state"])
|
|
require.JSONEq(t, `{"id":9,"state":"closed"}`, out.String())
|
|
}
|
|
|
|
func TestMilestoneTablesViewsAndDoneLines(t *testing.T) {
|
|
var changed []string
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method + " " + r.URL.Path {
|
|
case "GET /api/v1/repos/alice/project/milestones":
|
|
writeMilestones(w, r, `[{"id":5,"title":"later","state":"open"},{"id":4,"title":"v0.9","state":"closed","closed_issues":3},`+
|
|
`{"id":3,"title":"v1.0","state":"open","description":"First release","due_on":"2026-12-31T00:00:00Z","open_issues":3,"closed_issues":1}]`)
|
|
case "GET /api/v1/repos/alice/project/issues/1", "GET /api/v1/repos/alice/project/issues/2":
|
|
_, _ = w.Write([]byte(`{"number":1,"milestone":{"id":4,"title":"v0.9"}}`))
|
|
case "PATCH /api/v1/repos/alice/project/issues/1", "PATCH /api/v1/repos/alice/project/issues/2":
|
|
changed = append(changed, r.Method+" "+r.URL.Path)
|
|
_, _ = fmt.Fprintf(w, `{"number":%s}`, r.URL.Path[len(r.URL.Path)-1:])
|
|
default:
|
|
changed = append(changed, r.Method+" "+r.URL.Path)
|
|
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0","state":"closed"}`))
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
|
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
|
plainOutput(t, deps)
|
|
run := func(tty bool, args ...string) {
|
|
t.Helper()
|
|
out.Reset()
|
|
diagnostics.Reset()
|
|
deps.Streams.OutTTY = tty
|
|
require.NoError(t, Execute(context.Background(), deps, append(args, "-R", "alice/project", "--no-input")))
|
|
}
|
|
run(true, "milestone", "list", "--state", "all")
|
|
require.Equal(t, "Showing 3 of 3 milestones in alice/project\n\n"+
|
|
"ID TITLE STATE DUE PROGRESS\n"+
|
|
"3 v1.0 open in about 2 months 1/4 (25%)\n"+
|
|
"5 later open 0/0\n"+
|
|
"4 v0.9 closed 3/3 (100%)\n", out.String())
|
|
run(false, "milestone", "list", "--state", "all")
|
|
require.Equal(t, "3\tv1.0\topen\t2026-12-31T00:00:00Z\t1/4 (25%)\n5\tlater\topen\t\t0/0\n4\tv0.9\tclosed\t\t3/3 (100%)\n", out.String())
|
|
run(true, "milestone", "view", "v1.0")
|
|
require.Equal(t, "v1.0 #3\nOpen • due Dec 31, 2026 (in about 2 months) • 1 of 4 closed (25%)\n\nFirst release\n\n"+
|
|
"View this milestone on Gitea: "+server.URL+"/alice/project/milestone/3\n", out.String())
|
|
run(true, "milestone", "close", "v1.0", "v0.9")
|
|
require.Equal(t, "✓ Closed milestone \"v1.0\" in alice/project\n! Milestone \"v0.9\" in alice/project is already closed\n", diagnostics.String())
|
|
run(true, "milestone", "issue", "add", "v1.0", "1", "#2")
|
|
require.Equal(t, "✓ Added #1, #2 to milestone \"v1.0\" in alice/project\n", diagnostics.String())
|
|
run(true, "milestone", "issue", "remove", "v0.9", "1")
|
|
require.Equal(t, "✓ Removed #1 from milestone \"v0.9\" in alice/project\n", diagnostics.String())
|
|
run(false, "milestone", "create", "v2.0")
|
|
require.Equal(t, server.URL+"/alice/project/milestone/3\n", out.String())
|
|
require.Equal(t, []string{
|
|
"GET /api/v1/repos/alice/project/milestones/3",
|
|
"PATCH /api/v1/repos/alice/project/milestones/3",
|
|
"PATCH /api/v1/repos/alice/project/issues/1",
|
|
"PATCH /api/v1/repos/alice/project/issues/2",
|
|
"PATCH /api/v1/repos/alice/project/issues/1",
|
|
"POST /api/v1/repos/alice/project/milestones",
|
|
}, changed)
|
|
}
|
|
|
|
func TestMilestoneEditFormStartsFromTheMilestone(t *testing.T) {
|
|
var edited map[string]any
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method + " " + r.URL.Path {
|
|
case "GET /api/v1/repos/alice/project/milestones":
|
|
writeMilestones(w, r, `[{"id":3,"title":"v1.0","description":"First","due_on":"2026-12-31T00:00:00Z"}]`)
|
|
case "PATCH /api/v1/repos/alice/project/milestones/3":
|
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&edited))
|
|
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0.0"}`))
|
|
default:
|
|
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := serverDeps(t, server.URL)
|
|
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
|
var heading string
|
|
var current terminal.MilestoneFormValues
|
|
deps.MilestoneForm = milestoneFormEditor(func(h string, c terminal.MilestoneFormValues) terminal.MilestoneFormValues {
|
|
heading, current = h, c
|
|
return terminal.MilestoneFormValues{Title: "v1.0.0", Description: c.Description}
|
|
})
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"milestone", "edit", "v1.0", "-R", "alice/project"}))
|
|
require.Equal(t, "Editing milestone \"v1.0\" in alice/project", heading)
|
|
require.Equal(t, "First", current.Description)
|
|
require.Equal(t, "2026-12-31", current.Deadline.Format(time.DateOnly))
|
|
require.Equal(t, "v1.0.0", edited["title"])
|
|
require.Equal(t, "First", edited["description"])
|
|
}
|
|
|
|
type milestoneFormEditor func(string, terminal.MilestoneFormValues) terminal.MilestoneFormValues
|
|
|
|
func (f milestoneFormEditor) EditMilestone(_ context.Context, heading string, current terminal.MilestoneFormValues) (terminal.MilestoneFormValues, error) {
|
|
return f(heading, current), nil
|
|
}
|