Skip to content

Commit 8e7ee41

Browse files
author
FolderView Plus Test
committed
Harden dev release flow
1 parent dc5e46a commit 8e7ee41

5 files changed

Lines changed: 173 additions & 14 deletions

File tree

pkg_build.sh

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ detect_git_branch() {
3636
printf '%s' "$detected"
3737
}
3838

39+
detect_manifest_branch() {
40+
local plugin_url=""
41+
if [ ! -f "$plgfile" ]; then
42+
return 0
43+
fi
44+
plugin_url="$(sed -n 's/^<!ENTITY pluginURL "\([^"]*\)".*/\1/p' "$plgfile" | head -n 1 || true)"
45+
if [[ "$plugin_url" =~ /([A-Za-z0-9._-]+)/folderview\.plus\.plg$ ]]; then
46+
printf '%s' "${BASH_REMATCH[1]}"
47+
return 0
48+
fi
49+
return 0
50+
}
51+
3952
detect_git_commit_sha() {
4053
local detected=""
4154
if command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
@@ -490,10 +503,15 @@ if [ -n "$branch_override" ]; then
490503
branch="$branch_override"
491504
else
492505
detected_branch="$(detect_git_branch)"
493-
if [ "$detected_branch" = "dev" ]; then
494-
branch="dev"
506+
if [ "$detected_branch" = "dev" ] || [ "$detected_branch" = "main" ]; then
507+
branch="$detected_branch"
495508
else
496-
branch="main"
509+
manifest_branch="$(detect_manifest_branch)"
510+
if [ "$manifest_branch" = "dev" ]; then
511+
branch="dev"
512+
else
513+
branch="main"
514+
fi
497515
fi
498516
fi
499517

scripts/dev_finalize.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ if [[ "${#UNTRACKED_FILES[@]}" -gt 0 ]]; then
112112
exit 1
113113
fi
114114

115-
bash pkg_build.sh
115+
bash pkg_build.sh --branch "${CURRENT_BRANCH}"
116116

117117
VERSION="$(fvplus::read_plg_version "${ROOT_DIR}/folderview.plus.plg")"
118118
git add folderview.plus.plg folderview.plus.xml archive/

scripts/ensure_plg_changes_entry.sh

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ version_greater_than() {
104104
head_manifest_version() {
105105
local version_line=""
106106
if ! command -v git >/dev/null 2>&1 || ! git -C "${ROOT_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
107-
return
107+
return 0
108108
fi
109109
version_line="$(
110110
git -C "${ROOT_DIR}" show HEAD:folderview.plus.plg 2>/dev/null \
@@ -131,7 +131,7 @@ list_changes_versions() {
131131
remove_changes_block_for_version() {
132132
local target_version="${1:-}"
133133
local tmp_file=""
134-
[[ -n "${target_version}" ]] || return
134+
[[ -n "${target_version}" ]] || return 0
135135
tmp_file="$(mktemp)"
136136
awk -v version="${target_version}" '
137137
BEGIN { skip = 0 }
@@ -158,9 +158,9 @@ prune_unreleased_retry_blocks() {
158158
local head_version=""
159159
local stale_version=""
160160
local removed=0
161-
[[ -n "${target_version}" ]] || return
161+
[[ -n "${target_version}" ]] || return 0
162162
head_version="$(head_manifest_version)"
163-
[[ -n "${head_version}" ]] || return
163+
[[ -n "${head_version}" ]] || return 0
164164
while IFS= read -r stale_version; do
165165
[[ -n "${stale_version}" ]] || continue
166166
if ! version_greater_than "${stale_version}" "${head_version}"; then
@@ -321,12 +321,12 @@ resolve_changes_anchor_ref() {
321321
local anchor_ref=""
322322

323323
if ! command -v git >/dev/null 2>&1 || ! git -C "${ROOT_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
324-
return
324+
return 0
325325
fi
326326

327327
if [[ -n "${previous_version}" ]] && git -C "${ROOT_DIR}" rev-parse -q --verify "refs/tags/v${previous_version}^{tag}" >/dev/null 2>&1; then
328328
printf 'v%s\n' "${previous_version}"
329-
return
329+
return 0
330330
fi
331331

332332
if [[ -n "${previous_version}" ]]; then
@@ -336,6 +336,7 @@ resolve_changes_anchor_ref() {
336336
if [[ -n "${anchor_ref}" ]]; then
337337
printf '%s\n' "${anchor_ref}"
338338
fi
339+
return 0
339340
}
340341

341342
collect_changed_files() {
@@ -344,7 +345,7 @@ collect_changed_files() {
344345
local range=""
345346

346347
if ! command -v git >/dev/null 2>&1 || ! git -C "${ROOT_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
347-
return
348+
return 0
348349
fi
349350

350351
anchor_ref="$(resolve_changes_anchor_ref "${previous_version}")"
@@ -654,13 +655,13 @@ build_diff_based_notes() {
654655
declare -A seen_subsystems=()
655656

656657
if ! command -v git >/dev/null 2>&1 || ! git -C "${ROOT_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
657-
return
658+
return 0
658659
fi
659660

660661
mapfile -t changed_files < <(collect_changed_files "${previous_version}" || true)
661662

662663
if [[ ${#changed_files[@]} -eq 0 ]]; then
663-
return
664+
return 0
664665
fi
665666

666667
for changed in "${changed_files[@]}"; do
@@ -681,7 +682,7 @@ build_diff_based_notes() {
681682
done
682683

683684
if [[ ${#notes[@]} -eq 0 ]]; then
684-
return
685+
return 0
685686
fi
686687

687688
printf '%s\n' "${notes[@]}" | head -n "${MAX_AUTO_LINES}"
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import test from 'node:test';
2+
import assert from 'node:assert/strict';
3+
import fs from 'node:fs';
4+
import os from 'node:os';
5+
import path from 'node:path';
6+
import { execFileSync } from 'node:child_process';
7+
8+
const repoRoot = path.resolve(process.cwd());
9+
10+
function writeFile(targetPath, contents) {
11+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
12+
fs.writeFileSync(targetPath, contents);
13+
}
14+
15+
function cleanupTempDir(targetPath) {
16+
try {
17+
fs.chmodSync(targetPath, 0o755);
18+
} catch {}
19+
for (const entry of fs.readdirSync(targetPath, { withFileTypes: true })) {
20+
const entryPath = path.join(targetPath, entry.name);
21+
if (entry.isDirectory()) {
22+
cleanupTempDir(entryPath);
23+
continue;
24+
}
25+
try {
26+
fs.chmodSync(entryPath, 0o644);
27+
} catch {}
28+
}
29+
fs.rmSync(targetPath, { recursive: true, force: true });
30+
}
31+
32+
function copyFileIntoTemp(tempRoot, relativePath) {
33+
const sourcePath = path.join(repoRoot, relativePath);
34+
const targetPath = path.join(tempRoot, relativePath);
35+
writeFile(targetPath, fs.readFileSync(sourcePath, 'utf8'));
36+
}
37+
38+
function createBrokenGitBin(tempRoot) {
39+
const binDir = path.join(tempRoot, 'fake-bin');
40+
const gitPath = path.join(binDir, 'git');
41+
fs.mkdirSync(binDir, { recursive: true });
42+
fs.writeFileSync(gitPath, '#!/usr/bin/env bash\nexit 128\n');
43+
fs.chmodSync(gitPath, 0o755);
44+
return binDir;
45+
}
46+
47+
function runBash(args, cwd, extraEnv = {}) {
48+
return execFileSync('bash', args, {
49+
cwd,
50+
encoding: 'utf8',
51+
env: {
52+
...process.env,
53+
...extraEnv
54+
},
55+
stdio: ['ignore', 'pipe', 'pipe']
56+
});
57+
}
58+
59+
test('ensure_plg_changes_entry tolerates unavailable git metadata when curated notes exist', (t) => {
60+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'fvplus-ensure-changes-'));
61+
t.after(() => {
62+
cleanupTempDir(tempRoot);
63+
});
64+
65+
copyFileIntoTemp(tempRoot, 'scripts/ensure_plg_changes_entry.sh');
66+
copyFileIntoTemp(tempRoot, 'scripts/lib.sh');
67+
68+
writeFile(path.join(tempRoot, 'folderview.plus.plg'), `<?xml version="1.0" standalone="yes"?>
69+
<!DOCTYPE PLUGIN [
70+
<!ENTITY name "folderview.plus">
71+
<!ENTITY author "alexphillips-dev">
72+
<!ENTITY github "alexphillips-dev/FolderView-Plus">
73+
<!ENTITY launch "Settings/FolderViewPlus">
74+
<!ENTITY plugdir "/usr/local/emhttp/plugins/&name;">
75+
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/dev/folderview.plus.plg">
76+
<!ENTITY version "2026.04.15.02">
77+
<!ENTITY md5 "placeholder">
78+
]>
79+
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" icon="folder-icon.png" support="https://forums.unraid.net/topic/197631-plugin-folderview-plus/" min="7.0.0">
80+
<CHANGES>
81+
82+
###2026.04.15.01
83+
- Fix: Previous release.
84+
</CHANGES>
85+
</PLUGIN>
86+
`);
87+
writeFile(path.join(tempRoot, 'docs', 'releases', '2026.04.15.02.md'), `- Fix: Prevent release-note insertion from failing when git metadata is unavailable.
88+
- Quality: Allow curated notes to seed the new release block even when git probes fail.
89+
`);
90+
91+
const brokenGitBin = createBrokenGitBin(tempRoot);
92+
runBash(['scripts/ensure_plg_changes_entry.sh', '--version', '2026.04.15.02'], tempRoot, {
93+
PATH: `${brokenGitBin}${path.delimiter}${process.env.PATH ?? ''}`
94+
});
95+
96+
const updatedPlg = fs.readFileSync(path.join(tempRoot, 'folderview.plus.plg'), 'utf8');
97+
assert.match(updatedPlg, /###2026\.04\.15\.02/);
98+
assert.match(updatedPlg, /Prevent release-note insertion from failing when git metadata is unavailable/);
99+
});
100+
101+
test('pkg_build dry-run falls back to manifest branch when git branch detection is unavailable', (t) => {
102+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'fvplus-pkg-build-'));
103+
t.after(() => {
104+
cleanupTempDir(tempRoot);
105+
});
106+
107+
copyFileIntoTemp(tempRoot, 'pkg_build.sh');
108+
writeFile(path.join(tempRoot, 'folderview.plus.plg'), `<?xml version="1.0" standalone="yes"?>
109+
<!DOCTYPE PLUGIN [
110+
<!ENTITY name "folderview.plus">
111+
<!ENTITY author "alexphillips-dev">
112+
<!ENTITY github "alexphillips-dev/FolderView-Plus">
113+
<!ENTITY launch "Settings/FolderViewPlus">
114+
<!ENTITY plugdir "/usr/local/emhttp/plugins/&name;">
115+
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/dev/folderview.plus.plg">
116+
<!ENTITY version "2026.04.15.01">
117+
<!ENTITY md5 "placeholder">
118+
]>
119+
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" icon="folder-icon.png" support="https://forums.unraid.net/topic/197631-plugin-folderview-plus/" min="7.0.0">
120+
<FILE Name="/tmp/folderview.plus.txz">
121+
<URL>https://raw.githubusercontent.com/&github;/dev/archive/&name;-&version;.txz</URL>
122+
</FILE>
123+
</PLUGIN>
124+
`);
125+
writeFile(path.join(tempRoot, 'folderview.plus.xml'), `<FILE Name="folderview.plus.plg"><Date>2026-04-15</Date><PluginURL>https://raw.githubusercontent.com/alexphillips-dev/FolderView-Plus/dev/folderview.plus.plg</PluginURL><Icon>https://raw.githubusercontent.com/alexphillips-dev/FolderView-Plus/dev/src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/images/folder-icon.png</Icon><Beta>False</Beta><Name>FolderView Plus</Name></FILE>`);
126+
writeFile(path.join(tempRoot, 'scripts', 'release_guard.sh'), '#!/usr/bin/env bash\nexit 0\n');
127+
writeFile(path.join(tempRoot, 'scripts', 'ensure_plg_changes_entry.sh'), '#!/usr/bin/env bash\nexit 0\n');
128+
fs.chmodSync(path.join(tempRoot, 'scripts', 'release_guard.sh'), 0o755);
129+
fs.chmodSync(path.join(tempRoot, 'scripts', 'ensure_plg_changes_entry.sh'), 0o755);
130+
writeFile(path.join(tempRoot, 'src', 'folderview.plus', 'usr', 'local', 'emhttp', 'plugins', 'folderview.plus', 'README.md'), 'placeholder\n');
131+
132+
const brokenGitBin = createBrokenGitBin(tempRoot);
133+
const output = runBash(['pkg_build.sh', '--dry-run'], tempRoot, {
134+
PATH: `${brokenGitBin}${path.delimiter}${process.env.PATH ?? ''}`
135+
});
136+
137+
assert.match(output, /Branch: dev/);
138+
});

tests/versioning-guard.test.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ test('pkg_build includes dependency preflight, safe temp cleanup, dry-run, and c
147147
assert.match(pkgBuild, /<URL>https:\/\/raw\.githubusercontent\.com\/\.\*\?\/archive\/\.\*<\/URL>/);
148148
assert.match(pkgBuild, /rewrite_manifest_branch_metadata/);
149149
assert.match(pkgBuild, /validate_manifest_branch_matrix/);
150+
assert.match(pkgBuild, /detect_manifest_branch/);
150151
assert.match(pkgBuild, /expected_entity_url="https:\/\/raw\.githubusercontent\.com\/&github;\/\$\{branch_name\}\/folderview\.plus\.plg"/);
151152
assert.match(pkgBuild, /expected_archive_url="https:\/\/raw\.githubusercontent\.com\/&github;\/\$\{branch_name\}\/archive\/&name;-&version;\.txz"/);
152153
assert.match(pkgBuild, /canonical entity form/);
@@ -263,6 +264,7 @@ test('dev finalize script validates, packages, commits, and pushes dev safely',
263264
assert.match(devFinalize, /git ls-files --others --exclude-standard \|\| true/);
264265
assert.match(devFinalize, /Stage the intended source changes before running dev_finalize\.sh/);
265266
assert.match(devFinalize, /bash pkg_build\.sh/);
267+
assert.match(devFinalize, /bash pkg_build\.sh --branch "\$\{CURRENT_BRANCH\}"/);
266268
assert.match(devFinalize, /git add folderview\.plus\.plg folderview\.plus\.xml archive\//);
267269
assert.match(devFinalize, /git commit -m "\$\{COMMIT_MESSAGE\}"/);
268270
assert.match(devFinalize, /git push -u origin dev/);

0 commit comments

Comments
 (0)