mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
150 lines
7.7 KiB
Go
150 lines
7.7 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dev/tea/internal/clierr"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestReleaseBulkAssetInputAndPartialFailures(t *testing.T) {
|
|
uploads := 0
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodGet {
|
|
_, _ = w.Write([]byte(`{"id":1,"tag_name":"v1"}`))
|
|
return
|
|
}
|
|
uploads++
|
|
if uploads == 1 {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, _ = w.Write([]byte(`{"id":2,"name":"second.txt"}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, out, _ := serverDeps(t, server.URL)
|
|
first, second := filepath.Join(t.TempDir(), "first.txt"), filepath.Join(t.TempDir(), "second.txt")
|
|
require.NoError(t, os.WriteFile(first, []byte("first"), 0o600))
|
|
require.NoError(t, os.WriteFile(second, []byte("second"), 0o600))
|
|
err := Execute(context.Background(), deps, []string{"release", "asset", "upload", "v1", first, second + "missing", "-R", "owner/repo", "--json"})
|
|
require.Error(t, err)
|
|
require.Zero(t, uploads)
|
|
err = Execute(context.Background(), deps, []string{"release", "upload", "v1", first, second, "-R", "owner/repo", "--json"})
|
|
require.ErrorContains(t, err, "first.txt")
|
|
require.Equal(t, 2, uploads)
|
|
require.JSONEq(t, `[{"id":2,"name":"second.txt","size":0,"url":"","created_at":"","download_count":0}]`, out.String())
|
|
}
|
|
|
|
func TestReleaseUploadRefusesDuplicateNamesWithoutClobber(t *testing.T) {
|
|
var requests []string
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requests = append(requests, r.Method+" "+r.URL.Path)
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
_, _ = w.Write([]byte(`{"id":1,"tag_name":"v1","assets":[{"id":7,"name":"hello.txt"}]}`))
|
|
case http.MethodDelete:
|
|
w.WriteHeader(http.StatusNoContent)
|
|
default:
|
|
_, _ = w.Write([]byte(`{"id":8,"name":"hello.txt","size":5}`))
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, _, diagnostics := repoTTYDeps(t, server.URL)
|
|
file := filepath.Join(t.TempDir(), "hello.txt")
|
|
require.NoError(t, os.WriteFile(file, []byte("hello"), 0o600))
|
|
err := Execute(context.Background(), deps, []string{"release", "asset", "upload", "v1", file, "-R", "owner/repo"})
|
|
require.Equal(t, clierr.Usage, clierr.ExitCode(err), "%v", err)
|
|
require.ErrorContains(t, err, "asset hello.txt already exists in release v1; pass --clobber to replace it")
|
|
require.Equal(t, []string{"GET /api/v1/repos/owner/repo/releases/tags/v1"}, requests)
|
|
requests = nil
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"release", "upload", "v1", file, "--clobber", "-R", "owner/repo"}))
|
|
require.Equal(t, []string{"GET /api/v1/repos/owner/repo/releases/tags/v1", "POST /api/v1/repos/owner/repo/releases/1/assets", "DELETE /api/v1/repos/owner/repo/releases/1/assets/7"}, requests)
|
|
require.Equal(t, "✓ Uploaded hello.txt (5 B) to release v1\n", diagnostics.String())
|
|
}
|
|
|
|
func TestReleaseAssetNameSelectionValidatedBeforeDeletion(t *testing.T) {
|
|
var deleted []string
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodDelete {
|
|
deleted = append(deleted, r.URL.Path)
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
_, _ = w.Write([]byte(`{"id":1,"tag_name":"v1","assets":[{"id":1,"name":"one.txt"},{"id":2,"name":"2"}]}`))
|
|
}))
|
|
defer server.Close()
|
|
deps, _, diagnostics := repoTTYDeps(t, server.URL)
|
|
err := Execute(context.Background(), deps, []string{"release", "asset", "delete", "v1", "one.txt", "missing", "--yes", "-R", "owner/repo"})
|
|
require.EqualError(t, err, `asset "missing" not found in release v1`)
|
|
require.Empty(t, deleted)
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"release", "asset", "delete", "v1", "one.txt", "2", "--by-name", "--yes", "-R", "owner/repo"}))
|
|
require.Equal(t, []string{"/api/v1/repos/owner/repo/releases/1/assets/1", "/api/v1/repos/owner/repo/releases/1/assets/2"}, deleted)
|
|
require.Equal(t, "✓ Deleted asset one.txt (ID 1) from release v1\n✓ Deleted asset 2 (ID 2) from release v1\n", diagnostics.String())
|
|
}
|
|
|
|
func TestReleaseDownloadSelectsAssetsOfTheLatestRelease(t *testing.T) {
|
|
var downloads []string
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.URL.Path == "/api/v1/repos/owner/repo/releases/latest", r.URL.Path == "/api/v1/repos/owner/repo/releases/tags/v1":
|
|
_, _ = w.Write([]byte(`{"id":1,"tag_name":"v1","assets":[{"id":1,"name":"tea-linux","size":5,"uuid":"aaa"},{"id":2,"name":"tea-darwin","size":5,"uuid":"bbb"},{"id":3,"name":"notes.txt","size":5,"uuid":"ccc"}]}`))
|
|
case strings.HasPrefix(r.URL.Path, "/api/v1/repos/owner/repo/releases/1/assets/"):
|
|
id := strings.TrimPrefix(r.URL.Path, "/api/v1/repos/owner/repo/releases/1/assets/")
|
|
uuid := map[string]string{"1": "aaa", "2": "bbb", "3": "ccc"}[id]
|
|
_, _ = w.Write([]byte(`{"id":` + id + `,"uuid":"` + uuid + `"}`))
|
|
case strings.HasPrefix(r.URL.Path, "/attachments/"):
|
|
downloads = append(downloads, r.URL.Path)
|
|
_, _ = w.Write([]byte("bytes"))
|
|
default:
|
|
t.Errorf("unexpected request %s", r.URL.Path)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, _, diagnostics := repoTTYDeps(t, server.URL)
|
|
dir := t.TempDir()
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"release", "download", "--pattern", "tea-*", "--dir", dir, "-R", "owner/repo"}))
|
|
require.Equal(t, []string{"/attachments/aaa", "/attachments/bbb"}, downloads)
|
|
content, err := os.ReadFile(filepath.Join(dir, "tea-darwin"))
|
|
require.NoError(t, err)
|
|
require.Equal(t, "bytes", string(content))
|
|
require.Equal(t, "✓ Downloaded tea-linux (5 B) to "+filepath.Join(dir, "tea-linux")+"\n✓ Downloaded tea-darwin (5 B) to "+filepath.Join(dir, "tea-darwin")+"\n", diagnostics.String())
|
|
err = Execute(context.Background(), deps, []string{"release", "asset", "download", "v1", "--pattern", "*.exe", "--dir", dir, "-R", "owner/repo"})
|
|
require.Error(t, err)
|
|
err = Execute(context.Background(), deps, []string{"release", "download", "v1", "notes.txt", "tea-linux", "-O", filepath.Join(dir, "one"), "-R", "owner/repo"})
|
|
require.ErrorContains(t, err, "--output names one file, but 2 assets match; pass --dir")
|
|
}
|
|
|
|
func TestReleaseDownloadCreatesDirAndRefusesDuplicateNames(t *testing.T) {
|
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.URL.Path == "/api/v1/repos/owner/repo/releases/tags/v1":
|
|
_, _ = w.Write([]byte(`{"id":1,"tag_name":"v1","assets":[{"id":1,"name":"app","size":5,"uuid":"aaa"},{"id":2,"name":"app","size":5,"uuid":"bbb"},{"id":3,"name":"other","size":5,"uuid":"ccc"}]}`))
|
|
case strings.HasPrefix(r.URL.Path, "/api/v1/repos/owner/repo/releases/1/assets/"):
|
|
id := strings.TrimPrefix(r.URL.Path, "/api/v1/repos/owner/repo/releases/1/assets/")
|
|
_, _ = w.Write([]byte(`{"id":` + id + `,"uuid":"ccc"}`))
|
|
case strings.HasPrefix(r.URL.Path, "/attachments/"):
|
|
_, _ = w.Write([]byte("bytes"))
|
|
default:
|
|
t.Errorf("unexpected request %s", r.URL.Path)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
deps, _, _ := repoTTYDeps(t, server.URL)
|
|
dir := filepath.Join(t.TempDir(), "new", "dist")
|
|
err := Execute(context.Background(), deps, []string{"release", "download", "v1", "--dir", dir, "-R", "owner/repo"})
|
|
require.ErrorContains(t, err, "assets 1 and 2 are both named app")
|
|
_, statErr := os.Stat(filepath.Join(dir, "other"))
|
|
require.Error(t, statErr, "nothing is downloaded before the duplicate is reported")
|
|
require.NoError(t, Execute(context.Background(), deps, []string{"release", "download", "v1", "other", "--dir", dir, "-R", "owner/repo"}))
|
|
_, statErr = os.Stat(filepath.Join(dir, "other"))
|
|
require.NoError(t, statErr)
|
|
}
|