Reviewed-on: #9 Reviewed-by: xtul <mpiasecki720@protonmail.com> Co-authored-by: vickydotbat <vickydotbat@tutamail.com> Co-committed-by: vickydotbat <vickydotbat@tutamail.com>
595 lines
17 KiB
Go
595 lines
17 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/pipeline"
|
|
)
|
|
|
|
func TestParseBuildHAKArgsContentAddressedRoot(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
want string
|
|
}{
|
|
{
|
|
name: "separated",
|
|
args: []string{"--content-addressed-root", "/var/cache/blobs"},
|
|
want: "/var/cache/blobs",
|
|
},
|
|
{
|
|
name: "inline",
|
|
args: []string{"--content-addressed-root=/var/cache/blobs"},
|
|
want: "/var/cache/blobs",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
opts, err := parseBuildHAKArgs(tt.args)
|
|
if err != nil {
|
|
t.Fatalf("parse build-haks args: %v", err)
|
|
}
|
|
if opts.contentAddressedRoot != tt.want {
|
|
t.Fatalf("content-addressed root = %q, want %q", opts.contentAddressedRoot, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseBuildHAKArgsHelpListsContentAddressedRoot(t *testing.T) {
|
|
_, err := parseBuildHAKArgs([]string{"--help"})
|
|
if err == nil {
|
|
t.Fatal("expected help usage error")
|
|
}
|
|
for _, flag := range []string{
|
|
"--hak",
|
|
"--archive",
|
|
"--source-manifest",
|
|
"--content-addressed-root",
|
|
"--plan-only",
|
|
"--skip-music",
|
|
"--music-dataset",
|
|
"--quiet",
|
|
"--verbose",
|
|
"--debug",
|
|
} {
|
|
if !strings.Contains(err.Error(), flag) {
|
|
t.Errorf("help usage missing documented flag %q: %v", flag, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunBuildTopPackageUsesCachedCompiledOutputs(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
mkdirAll(t, filepath.Join(root, ".cache", "2da"))
|
|
mkdirAll(t, filepath.Join(root, "topdata", "assets", "gui"))
|
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "repadjust"))
|
|
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: test_module
|
|
topdata:
|
|
source: topdata
|
|
build: .cache
|
|
package_hak: sow_top.hak
|
|
package_tlk: sow_tlk.tlk
|
|
`)
|
|
writeFile(t, filepath.Join(root, ".cache", "2da", "repadjust.2da"), "2DA V2.0\n\n Label\n0 TEST_LABEL\n")
|
|
writeFile(t, filepath.Join(root, "build", "sow_tlk.tlk"), "compiled tlk")
|
|
writeFile(t, filepath.Join(root, "topdata", "assets", "gui", "testicon.png"), "icon-data")
|
|
writeFile(t, filepath.Join(root, "topdata", "data", "repadjust", "base.json"), `{
|
|
"output": "repadjust.2da",
|
|
"columns": ["Label"],
|
|
"rows": [{"id": 0, "Label": "TEST_LABEL"}]
|
|
}`+"\n")
|
|
|
|
sourceTime := time.Now().Add(-2 * time.Hour)
|
|
outputTime := time.Now().Add(-1 * time.Hour)
|
|
setTreeTime(t, filepath.Join(root, "topdata"), sourceTime)
|
|
setFileTime(t, filepath.Join(root, ".cache", "2da", "repadjust.2da"), outputTime)
|
|
setFileTime(t, filepath.Join(root, "build", "sow_tlk.tlk"), outputTime)
|
|
|
|
ctx := context{
|
|
stdout: &bytes.Buffer{},
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"build-top-package"},
|
|
}
|
|
|
|
if err := runBuildTopPackage(ctx); err != nil {
|
|
t.Fatalf("runBuildTopPackage failed: %v", err)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(root, "build", "sow_top.hak")); err != nil {
|
|
t.Fatalf("expected packaged hak output: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunBuildHAKsNormalOutputOmitsPerFileMappings(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "assets", "envi", "music", "westgate"))
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
mkdirAll(t, filepath.Join(root, "src"))
|
|
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
source: src
|
|
assets: assets
|
|
build: build
|
|
haks:
|
|
- name: envi
|
|
priority: 1
|
|
max_bytes: 1048576
|
|
split: false
|
|
include:
|
|
- envi/**
|
|
`)
|
|
writeFile(t, filepath.Join(root, "assets", "envi", "music", "westgate", "AleandAnecdotes.mp3"), "source-mp3")
|
|
writeFile(t, filepath.Join(root, "assets", "envi", "music", "westgate", "CREDITS.md"), "# NWN Music Pack Credits\n\n| Artist | Title | Output File | Original File | Album | Date | License / Copyright | Notes |\n|---|---|---|---|---|---|---|---|\n| Darren Curtis | Ale and Anecdotes | `mus_wg_andnc.bmu` | `AleandAnecdotes.mp3` | Darren's Commercially Free Music | | Darren Curtis Music | |\n")
|
|
|
|
ffprobePath := filepath.Join(root, "ffprobe")
|
|
writeFile(t, ffprobePath, "#!/bin/sh\nprintf '%s\\n' '{\"format\":{\"tags\":{\"artist\":\"Unknown\",\"title\":\"Broken Metadata\"}}}'\n")
|
|
if err := os.Chmod(ffprobePath, 0o755); err != nil {
|
|
t.Fatalf("chmod ffprobe: %v", err)
|
|
}
|
|
|
|
ffmpegPath := filepath.Join(root, "ffmpeg")
|
|
writeFile(t, ffmpegPath, "#!/bin/sh\nfor last; do :; done\nprintf 'bmu-data' > \"$last\"\n")
|
|
if err := os.Chmod(ffmpegPath, 0o755); err != nil {
|
|
t.Fatalf("chmod ffmpeg: %v", err)
|
|
}
|
|
|
|
t.Setenv("SOW_FFMPEG", ffmpegPath)
|
|
t.Setenv("SOW_FFPROBE", ffprobePath)
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"build-haks"},
|
|
}
|
|
|
|
if err := runBuildHAKs(ctx); err != nil {
|
|
t.Fatalf("runBuildHAKs failed: %v", err)
|
|
}
|
|
|
|
output := stdout.String()
|
|
if strings.Contains(output, "AleandAnecdotes.mp3") || strings.Contains(output, "mus_wg_andnc.bmu") {
|
|
t.Fatalf("did not expect verbose mapping in normal mode, got %q", output)
|
|
}
|
|
}
|
|
|
|
func setTreeTime(t *testing.T, root string, modTime time.Time) {
|
|
t.Helper()
|
|
err := filepath.WalkDir(root, func(path string, d os.DirEntry, walkErr error) error {
|
|
if walkErr != nil {
|
|
return walkErr
|
|
}
|
|
return os.Chtimes(path, modTime, modTime)
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("set tree time under %s: %v", root, err)
|
|
}
|
|
}
|
|
|
|
func TestRunBuildHAKsVerboseListsMappings(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "assets", "envi", "music", "westgate"))
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
mkdirAll(t, filepath.Join(root, "src"))
|
|
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
source: src
|
|
assets: assets
|
|
build: build
|
|
haks:
|
|
- name: envi
|
|
priority: 1
|
|
max_bytes: 1048576
|
|
split: false
|
|
include:
|
|
- envi/**
|
|
`)
|
|
writeFile(t, filepath.Join(root, "assets", "envi", "music", "westgate", "AleandAnecdotes.mp3"), "source-mp3")
|
|
writeFile(t, filepath.Join(root, "assets", "envi", "music", "westgate", "CREDITS.md"), "# NWN Music Pack Credits\n\n| Artist | Title | Output File | Original File | Album | Date | License / Copyright | Notes |\n|---|---|---|---|---|---|---|---|\n| Darren Curtis | Ale and Anecdotes | `mus_wg_andnc.bmu` | `AleandAnecdotes.mp3` | Darren's Commercially Free Music | | Darren Curtis Music | |\n")
|
|
|
|
ffprobePath := filepath.Join(root, "ffprobe")
|
|
writeFile(t, ffprobePath, "#!/bin/sh\nprintf '%s\\n' '{\"format\":{\"tags\":{\"artist\":\"Unknown\",\"title\":\"Broken Metadata\"}}}'\n")
|
|
if err := os.Chmod(ffprobePath, 0o755); err != nil {
|
|
t.Fatalf("chmod ffprobe: %v", err)
|
|
}
|
|
|
|
ffmpegPath := filepath.Join(root, "ffmpeg")
|
|
writeFile(t, ffmpegPath, "#!/bin/sh\nfor last; do :; done\nprintf 'bmu-data' > \"$last\"\n")
|
|
if err := os.Chmod(ffmpegPath, 0o755); err != nil {
|
|
t.Fatalf("chmod ffmpeg: %v", err)
|
|
}
|
|
|
|
t.Setenv("SOW_FFMPEG", ffmpegPath)
|
|
t.Setenv("SOW_FFPROBE", ffprobePath)
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"build-haks", "--verbose"},
|
|
}
|
|
|
|
if err := runBuildHAKs(ctx); err != nil {
|
|
t.Fatalf("runBuildHAKs failed: %v", err)
|
|
}
|
|
|
|
output := stdout.String()
|
|
if !strings.Contains(output, "AleandAnecdotes.mp3") || !strings.Contains(output, "mus_wg_andnc.bmu") {
|
|
t.Fatalf("expected verbose mapping output, got %q", output)
|
|
}
|
|
}
|
|
|
|
func TestTopdataConsoleSuppressesProgressInNormalMode(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
console := &topdataConsole{
|
|
stdout: &stdout,
|
|
projectRoot: "/workspace/project",
|
|
projectName: "Test Module",
|
|
commandName: "build-topdata",
|
|
commandLabel: "Build Topdata",
|
|
level: logLevelNormal,
|
|
}
|
|
|
|
console.progress("Packaging compiled topdata resources into sow_top.hak...")
|
|
|
|
if stdout.String() != "" {
|
|
t.Fatalf("expected no normal-mode progress output, got %q", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestSpinnerEnabledForHonorsPlainTTYMode(t *testing.T) {
|
|
t.Setenv("SOW_TOOLS_TTY_MODE", "plain")
|
|
if spinnerEnabledFor(&bytes.Buffer{}, logLevelNormal) {
|
|
t.Fatal("expected plain tty mode to disable spinner output")
|
|
}
|
|
}
|
|
|
|
func TestTopdataConsoleDebugProgressAndRelativePaths(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
console := &topdataConsole{
|
|
stdout: &stdout,
|
|
projectRoot: "/workspace/project",
|
|
projectName: "Test Module",
|
|
commandName: "deploy-wiki",
|
|
commandLabel: "Deploy Wiki",
|
|
level: logLevelDebug,
|
|
}
|
|
|
|
console.progress("NodeBB wiki plan: create 1, update 2, skip 3, stale 4, archive 5, purge 6, drift 0")
|
|
console.emitWikiDeployResult(10, 1, 2, 3, 4, 5, 6, 0, "/workspace/project/build/wiki/deploy-manifest.json")
|
|
|
|
output := stdout.String()
|
|
if !strings.Contains(output, "NodeBB wiki plan") {
|
|
t.Fatalf("expected debug progress line, got %q", output)
|
|
}
|
|
if !strings.Contains(output, "build/wiki/deploy-manifest.json") || strings.Contains(output, "/workspace/project/") {
|
|
t.Fatalf("expected relative deploy manifest path, got %q", output)
|
|
}
|
|
}
|
|
|
|
func TestParseDeployWikiHelpListsPurgeStalePolicy(t *testing.T) {
|
|
_, err := parseDeployWikiArgs("deploy-wiki", []string{"--help"})
|
|
if err == nil || !strings.Contains(err.Error(), "--stale-policy <report|archive|purge>") {
|
|
t.Fatalf("expected deploy-wiki help to list purge stale policy, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseDeployWikiResetManagedNamespacesFlag(t *testing.T) {
|
|
opts, err := parseDeployWikiArgs("deploy-wiki", []string{"--reset-managed-namespaces"})
|
|
if err != nil {
|
|
t.Fatalf("parse deploy wiki reset flag: %v", err)
|
|
}
|
|
if !opts.ResetManagedNamespaces {
|
|
t.Fatalf("expected --reset-managed-namespaces to enable namespace reset")
|
|
}
|
|
}
|
|
|
|
func TestProjectConsoleSuppressesBuildModuleProgressInNormalMode(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
console := &projectConsole{
|
|
stdout: &stdout,
|
|
projectRoot: "/workspace/project",
|
|
projectName: "Test Module",
|
|
commandName: "build-module",
|
|
commandLabel: "Build Module",
|
|
level: logLevelNormal,
|
|
}
|
|
|
|
console.progress("Writing module archive...")
|
|
|
|
if stdout.String() != "" {
|
|
t.Fatalf("expected no normal-mode progress output, got %q", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestProjectConsoleEmitsRelativePaths(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
console := &projectConsole{
|
|
stdout: &stdout,
|
|
projectRoot: "/workspace/project",
|
|
projectName: "Test Module",
|
|
commandName: "compare",
|
|
commandLabel: "Compare",
|
|
level: logLevelNormal,
|
|
}
|
|
|
|
console.emitCompareResult(pipeline.CompareResult{
|
|
ModulePath: "/workspace/project/build/test.mod",
|
|
HAKPaths: []string{"/workspace/project/build/core.hak"},
|
|
Checked: 42,
|
|
})
|
|
|
|
output := stdout.String()
|
|
if !strings.Contains(output, "build/test.mod") || strings.Contains(output, "/workspace/project/") {
|
|
t.Fatalf("expected relative module path, got %q", output)
|
|
}
|
|
}
|
|
|
|
func TestRunMusicScanUsesConfiguredDatasetsWithoutWriting(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "assets", "audio", "westgate"))
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
assets: assets
|
|
build: build
|
|
music:
|
|
datasets:
|
|
westgate_audio:
|
|
source: audio/westgate
|
|
output: generated/music
|
|
prefix: wg_
|
|
`)
|
|
writeFile(t, filepath.Join(root, "assets", "audio", "westgate", "Theme Song.mp3"), "source-mp3")
|
|
|
|
ctx := context{
|
|
stdout: &bytes.Buffer{},
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"music", "scan", "--dataset", "westgate_audio"},
|
|
}
|
|
|
|
if err := runMusic(ctx); err != nil {
|
|
t.Fatalf("runMusic failed: %v", err)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(root, ".cache", "credits")); !os.IsNotExist(err) {
|
|
t.Fatalf("music scan should not write credits artifacts, stat err=%v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunMusicListDatasets(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "assets"))
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
assets: assets
|
|
music:
|
|
datasets:
|
|
westgate_audio:
|
|
source: audio/westgate
|
|
output: generated/music
|
|
prefix: wg_
|
|
`)
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"music", "list-datasets"},
|
|
}
|
|
|
|
if err := runMusic(ctx); err != nil {
|
|
t.Fatalf("runMusic failed: %v", err)
|
|
}
|
|
for _, value := range []string{"westgate_audio", "audio/westgate", "generated/music", "wg_"} {
|
|
if !strings.Contains(stdout.String(), value) {
|
|
t.Errorf("dataset list missing configured value %q: %q", value, stdout.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunConfigEffectiveJSONShowsDefaultsAndProvenance(t *testing.T) {
|
|
root := t.TempDir()
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
source: src
|
|
`)
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"config", "effective", "--json"},
|
|
}
|
|
|
|
if err := runConfig(ctx); err != nil {
|
|
t.Fatalf("runConfig failed: %v", err)
|
|
}
|
|
var effective map[string]any
|
|
if err := json.Unmarshal(stdout.Bytes(), &effective); err != nil {
|
|
t.Fatalf("effective config is not JSON: %v\n%s", err, stdout.String())
|
|
}
|
|
provenance, ok := effective["provenance"].(map[string]any)
|
|
if !ok || len(provenance) == 0 {
|
|
t.Fatalf("effective config missing provenance: %#v", effective["provenance"])
|
|
}
|
|
if _, ok := provenance["paths.build"]; !ok {
|
|
t.Fatalf("effective config missing provenance for omitted paths.build: %#v", provenance)
|
|
}
|
|
}
|
|
|
|
func TestRunConfigExplainReportsYAMLSource(t *testing.T) {
|
|
root := t.TempDir()
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
build: output
|
|
`)
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"config", "explain", "paths.build"},
|
|
}
|
|
|
|
if err := runConfig(ctx); err != nil {
|
|
t.Fatalf("runConfig failed: %v", err)
|
|
}
|
|
output := stdout.String()
|
|
if !strings.Contains(output, "output") {
|
|
t.Fatalf("expected configured build value, got %q", output)
|
|
}
|
|
if !strings.Contains(strings.ToLower(output), "yaml") {
|
|
t.Fatalf("expected YAML source, got %q", output)
|
|
}
|
|
}
|
|
|
|
func TestRunConfigValidateDoesNotScanSourceInventory(t *testing.T) {
|
|
root := t.TempDir()
|
|
mkdirAll(t, filepath.Join(root, "build"))
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
source: missing-src
|
|
build: build
|
|
`)
|
|
|
|
ctx := context{
|
|
stdout: &bytes.Buffer{},
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"config", "validate"},
|
|
}
|
|
|
|
if err := runConfig(ctx); err != nil {
|
|
t.Fatalf("runConfig failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRunConfigSourcesListsActiveOverrides(t *testing.T) {
|
|
root := t.TempDir()
|
|
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
|
module:
|
|
name: Test Module
|
|
resref: testmod
|
|
paths:
|
|
source: src
|
|
`)
|
|
t.Setenv("SOW_BUILD_HAKS_KEEP_EXISTING", "1")
|
|
|
|
var stdout bytes.Buffer
|
|
ctx := context{
|
|
stdout: &stdout,
|
|
stderr: &bytes.Buffer{},
|
|
cwd: root,
|
|
args: []string{"config", "sources"},
|
|
}
|
|
|
|
if err := runConfig(ctx); err != nil {
|
|
t.Fatalf("runConfig failed: %v", err)
|
|
}
|
|
output := stdout.String()
|
|
if !strings.Contains(output, "build.keep_existing_haks") {
|
|
t.Fatalf("expected keep existing override, got %q", output)
|
|
}
|
|
}
|
|
|
|
func TestInlineFlagParsersRejectEmptyValues(t *testing.T) {
|
|
if _, err := parseBuildHAKArgs([]string{"--hak="}); err == nil {
|
|
t.Fatalf("expected empty --hak inline value error, got %v", err)
|
|
}
|
|
if _, err := parseMusicCommandArgs([]string{"--dataset="}); err == nil {
|
|
t.Fatalf("expected empty --dataset inline value error, got %v", err)
|
|
}
|
|
if _, err := parseDeployWikiArgs("deploy-wiki", []string{"--endpoint="}); err == nil {
|
|
t.Fatalf("expected empty --endpoint inline value error, got %v", err)
|
|
}
|
|
if _, err := parseBuildChangelogArgs("build-changelog", []string{"--output="}); err == nil {
|
|
t.Fatalf("expected empty --output inline value error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseBuildChangelogArgsAcceptsInlineValues(t *testing.T) {
|
|
opts, err := parseBuildChangelogArgs("build-changelog", []string{
|
|
"--config=scripts/changelog.json",
|
|
"--output=CHANGELOG.md",
|
|
"--current-tag=v2",
|
|
"--previous-tag=v1",
|
|
"--api-base-url=https://gitea.example/api/v1",
|
|
"--token=secret",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("parseBuildChangelogArgs failed: %v", err)
|
|
}
|
|
if opts.configPath != "scripts/changelog.json" ||
|
|
opts.outputPath != "CHANGELOG.md" ||
|
|
opts.currentTag != "v2" ||
|
|
opts.previousTag != "v1" ||
|
|
opts.apiBaseURL != "https://gitea.example/api/v1" ||
|
|
opts.token != "secret" {
|
|
t.Fatalf("unexpected changelog opts: %#v", opts)
|
|
}
|
|
}
|
|
|
|
func mkdirAll(t *testing.T, path string) {
|
|
t.Helper()
|
|
if err := os.MkdirAll(path, 0o755); err != nil {
|
|
t.Fatalf("mkdir %s: %v", path, err)
|
|
}
|
|
}
|
|
|
|
func writeFile(t *testing.T, path, content string) {
|
|
t.Helper()
|
|
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
|
t.Fatalf("write %s: %v", path, err)
|
|
}
|
|
}
|
|
|
|
func setFileTime(t *testing.T, path string, modTime time.Time) {
|
|
t.Helper()
|
|
if err := os.Chtimes(path, modTime, modTime); err != nil {
|
|
t.Fatalf("set file time %s: %v", path, err)
|
|
}
|
|
}
|