mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
feat(run): show runs like gh, watch them live, and download artifacts
run list prints a table with a status icon, the workflow name, title, branch, event, elapsed time and age, and the total from the server; runs carry workflow, workflow_path and run_number in JSON. run view shows the run's state and trigger, its jobs with their steps and durations, the next steps and the run's URL; --json includes the jobs, --log prints their logs and --web opens the run. Run commands accept #N and run URLs, and ask for a recent run in a terminal when the argument is left out. run watch redraws the run on the alternate screen, then prints it with a summary; an expired --timeout names the run and suspects a missing runner when no job started. run cancel no longer asks for confirmation, rerun refuses unfinished runs up front, reruns a single job with --job and reports the new attempt, and delete names the run in its prompt. run logs follows several jobs with --follow, prefixing lines with the job's name, selects jobs by name or with --failed, and downloads the archive with --output or --dir. run download extracts the artifacts of a run by name, and artifact list shows sizes and expiry. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
19 files changed
+2636
-646
No files matched your search
@@ -7,51 +7,11 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.dev/tea/internal/clierr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRunTimeBoundsUseOneClockReading(t *testing.T) {
|
||||
now := time.Date(2028, 2, 1, 12, 0, 0, 0, time.UTC)
|
||||
deps, _, _ := testDeps(t)
|
||||
reads := 0
|
||||
deps.Now = func() time.Time { reads++; return now }
|
||||
err := Execute(context.Background(), deps, []string{"run", "list", "--since=1h", "--until=2h"})
|
||||
require.ErrorContains(t, err, "--since must not be later than --until")
|
||||
require.Equal(t, 1, reads)
|
||||
}
|
||||
|
||||
func TestRunWatchExitAndOutputContracts(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name, status, conclusion string
|
||||
code int
|
||||
}{
|
||||
{"success", "completed", "success", 0},
|
||||
{"failed run", "completed", "failure", clierr.Failure},
|
||||
{"timeout", "in_progress", "", clierr.Canceled},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/api/v1/repos/alice/project/actions/runs/7", r.URL.Path)
|
||||
_, _ = w.Write([]byte(`{"id":7,"status":"` + test.status + `","conclusion":"` + test.conclusion + `"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||
err := Execute(context.Background(), deps, []string{"run", "watch", "7", "--repo", "alice/project", "--json=id,status,conclusion", "--interval=1ms", "--timeout=100ms", "--no-input"})
|
||||
require.Equal(t, test.code, clierr.ExitCode(err))
|
||||
if test.code == clierr.Canceled {
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
require.Empty(t, out.String())
|
||||
} else {
|
||||
require.JSONEq(t, `{"id":7,"status":"completed","conclusion":"`+test.conclusion+`"}`, out.String())
|
||||
}
|
||||
require.Contains(t, diagnostics.String(), "run 7:")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkflowRunFollowStreamsFirstJobLogs(t *testing.T) {
|
||||
jobPolls := 0
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in new issue
Block a user