mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-24 14:05:59 +01:00
Compare commits
16 Commits
add-script
...
fix/error-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bb14b4d22 | ||
|
|
75c0b1bfc9 | ||
|
|
73fd1dd11b | ||
|
|
efcdd65c67 | ||
|
|
8b15af7499 | ||
|
|
13daffdeed | ||
|
|
fd82f5b496 | ||
|
|
83f03d617e | ||
|
|
4c5d5b2030 | ||
|
|
4e1ade4c28 | ||
|
|
e5073d1a4f | ||
|
|
01e956bdf8 | ||
|
|
0cc049edb6 | ||
|
|
ffa1a26b5e | ||
|
|
59ca9c26c9 | ||
|
|
56de2d1e39 |
341
.github/workflows/check-node-versions.yml
generated
vendored
Normal file
341
.github/workflows/check-node-versions.yml
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
name: Check Node.js Version Drift
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Runs weekly on Monday at 06:00 UTC
|
||||
- cron: "0 6 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
check-node-versions:
|
||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq jq curl > /dev/null 2>&1
|
||||
|
||||
- name: Check upstream Node.js versions
|
||||
id: check
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
echo "================================================"
|
||||
echo " Checking Node.js version drift in install scripts"
|
||||
echo "================================================"
|
||||
|
||||
# Alpine version -> Node major cache (populated on demand)
|
||||
declare -A ALPINE_NODE_CACHE
|
||||
|
||||
# Resolve Node.js major version from Alpine package registry
|
||||
# Usage: resolve_alpine_node "3.21" => sets REPLY to major version (e.g. "22")
|
||||
resolve_alpine_node() {
|
||||
local alpine_ver="$1"
|
||||
if [[ -n "${ALPINE_NODE_CACHE[$alpine_ver]+x}" ]]; then
|
||||
REPLY="${ALPINE_NODE_CACHE[$alpine_ver]}"
|
||||
return
|
||||
fi
|
||||
|
||||
local url="https://pkgs.alpinelinux.org/package/v${alpine_ver}/main/x86_64/nodejs"
|
||||
local page
|
||||
page=$(curl -sf "$url" 2>/dev/null || echo "")
|
||||
local full_ver=""
|
||||
if [[ -n "$page" ]]; then
|
||||
# Parse: "Version | 24.13.0-r1" or similar table row
|
||||
full_ver=$(echo "$page" | grep -oP 'Version\s*\|\s*\K[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
if [[ -z "$full_ver" ]]; then
|
||||
# Fallback: look for version pattern after "Version"
|
||||
full_ver=$(echo "$page" | grep -oP '(?<=Version</td><td>)[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
fi
|
||||
fi
|
||||
|
||||
local major=""
|
||||
if [[ -n "$full_ver" ]]; then
|
||||
major="${full_ver%%.*}"
|
||||
fi
|
||||
|
||||
ALPINE_NODE_CACHE[$alpine_ver]="$major"
|
||||
REPLY="$major"
|
||||
}
|
||||
|
||||
# Extract Node major from a Dockerfile content
|
||||
# Sets: DF_NODE_MAJOR, DF_SOURCE (description of where we found it)
|
||||
extract_dockerfile_node() {
|
||||
local content="$1"
|
||||
DF_NODE_MAJOR=""
|
||||
DF_SOURCE=""
|
||||
|
||||
# 1) FROM node:XX (e.g. node:24-alpine, node:22.9.0-bookworm-slim, node:20)
|
||||
local node_from
|
||||
node_from=$(echo "$content" | grep -oP '(?i)FROM\s+(--platform=[^\s]+\s+)?node:\K[0-9]+' | head -1 || echo "")
|
||||
if [[ -n "$node_from" ]]; then
|
||||
DF_NODE_MAJOR="$node_from"
|
||||
DF_SOURCE="FROM node:${node_from}"
|
||||
return
|
||||
fi
|
||||
|
||||
# 2) nodesource/setup_XX.x
|
||||
local nodesource
|
||||
nodesource=$(echo "$content" | grep -oP 'nodesource/setup_\K[0-9]+' | head -1 || echo "")
|
||||
if [[ -n "$nodesource" ]]; then
|
||||
DF_NODE_MAJOR="$nodesource"
|
||||
DF_SOURCE="nodesource/setup_${nodesource}.x"
|
||||
return
|
||||
fi
|
||||
|
||||
# 3) FROM alpine:X.Y — resolve via Alpine packages
|
||||
local alpine_ver
|
||||
alpine_ver=$(echo "$content" | grep -oP '(?i)FROM\s+(--platform=[^\s]+\s+)?alpine:\K[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
if [[ -n "$alpine_ver" ]]; then
|
||||
resolve_alpine_node "$alpine_ver"
|
||||
if [[ -n "$REPLY" ]]; then
|
||||
DF_NODE_MAJOR="$REPLY"
|
||||
DF_SOURCE="alpine:${alpine_ver} (pkg: nodejs ${DF_NODE_MAJOR})"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Extract Node major from engines.node in package.json
|
||||
# Sets: ENGINES_NODE_RAW (raw string), ENGINES_MIN_MAJOR
|
||||
extract_engines_node() {
|
||||
local content="$1"
|
||||
ENGINES_NODE_RAW=""
|
||||
ENGINES_MIN_MAJOR=""
|
||||
|
||||
ENGINES_NODE_RAW=$(echo "$content" | jq -r '.engines.node // empty' 2>/dev/null || echo "")
|
||||
if [[ -z "$ENGINES_NODE_RAW" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Extract the first number (major) from the constraint
|
||||
# Handles: ">=24.13.1", "^22", ">=18.0.0", ">=18.15.0 <19 || ^20", etc.
|
||||
ENGINES_MIN_MAJOR=$(echo "$ENGINES_NODE_RAW" | grep -oP '\d+' | head -1 || echo "")
|
||||
}
|
||||
|
||||
# Collect results
|
||||
declare -a issue_scripts=()
|
||||
declare -a report_lines=()
|
||||
total=0
|
||||
checked=0
|
||||
drift_count=0
|
||||
|
||||
for script in install/*-install.sh; do
|
||||
[[ ! -f "$script" ]] && continue
|
||||
if ! grep -q 'setup_nodejs' "$script"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
total=$((total + 1))
|
||||
slug=$(basename "$script" | sed 's/-install\.sh$//')
|
||||
|
||||
# Extract Source URL (GitHub only)
|
||||
source_url=$(head -20 "$script" | grep -oP '(?<=# Source: )https://github\.com/[^\s]+' | head -1 || echo "")
|
||||
if [[ -z "$source_url" ]]; then
|
||||
report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ No GitHub source |")
|
||||
continue
|
||||
fi
|
||||
|
||||
repo=$(echo "$source_url" | sed -E 's|https://github\.com/||; s|/$||; s|\.git$||')
|
||||
if [[ -z "$repo" || "$repo" != */* ]]; then
|
||||
report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ Invalid repo |")
|
||||
continue
|
||||
fi
|
||||
|
||||
checked=$((checked + 1))
|
||||
|
||||
# Extract our NODE_VERSION
|
||||
our_version=$(grep -oP 'NODE_VERSION="(\d+)"' "$script" | head -1 | grep -oP '\d+' || echo "")
|
||||
if [[ -z "$our_version" ]]; then
|
||||
if grep -q 'NODE_VERSION=\$(' "$script"; then
|
||||
our_version="dynamic"
|
||||
else
|
||||
our_version="unset"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fetch upstream Dockerfile
|
||||
df_content=""
|
||||
for branch in main master dev; do
|
||||
df_content=$(curl -sf "https://raw.githubusercontent.com/${repo}/${branch}/Dockerfile" 2>/dev/null || echo "")
|
||||
[[ -n "$df_content" ]] && break
|
||||
done
|
||||
|
||||
DF_NODE_MAJOR=""
|
||||
DF_SOURCE=""
|
||||
if [[ -n "$df_content" ]]; then
|
||||
extract_dockerfile_node "$df_content"
|
||||
fi
|
||||
|
||||
# Fetch upstream package.json
|
||||
pkg_content=""
|
||||
for branch in main master dev; do
|
||||
pkg_content=$(curl -sf "https://raw.githubusercontent.com/${repo}/${branch}/package.json" 2>/dev/null || echo "")
|
||||
[[ -n "$pkg_content" ]] && break
|
||||
done
|
||||
|
||||
ENGINES_NODE_RAW=""
|
||||
ENGINES_MIN_MAJOR=""
|
||||
if [[ -n "$pkg_content" ]]; then
|
||||
extract_engines_node "$pkg_content"
|
||||
fi
|
||||
|
||||
# Determine upstream recommended major version
|
||||
upstream_major=""
|
||||
upstream_hint=""
|
||||
|
||||
if [[ -n "$DF_NODE_MAJOR" ]]; then
|
||||
upstream_major="$DF_NODE_MAJOR"
|
||||
upstream_hint="$DF_SOURCE"
|
||||
elif [[ -n "$ENGINES_MIN_MAJOR" ]]; then
|
||||
upstream_major="$ENGINES_MIN_MAJOR"
|
||||
upstream_hint="engines: $ENGINES_NODE_RAW"
|
||||
fi
|
||||
|
||||
# Build display values
|
||||
engines_display="${ENGINES_NODE_RAW:-—}"
|
||||
dockerfile_display="${DF_SOURCE:-—}"
|
||||
|
||||
# Compare
|
||||
status="✅"
|
||||
if [[ "$our_version" == "dynamic" ]]; then
|
||||
status="🔄 Dynamic"
|
||||
elif [[ "$our_version" == "unset" ]]; then
|
||||
status="⚠️ NODE_VERSION not set"
|
||||
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||
drift_count=$((drift_count + 1))
|
||||
elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then
|
||||
status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
|
||||
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||
drift_count=$((drift_count + 1))
|
||||
fi
|
||||
|
||||
report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |")
|
||||
|
||||
# Rate-limit to avoid GitHub secondary rate limits
|
||||
sleep 0.3
|
||||
|
||||
done
|
||||
|
||||
# Print summary
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Total scripts with setup_nodejs: $total"
|
||||
echo " Checked (with GitHub source): $checked"
|
||||
echo " Version drift detected: $drift_count"
|
||||
echo "========================================="
|
||||
|
||||
# Export
|
||||
{
|
||||
echo "drift_count=$drift_count"
|
||||
echo "total=$total"
|
||||
echo "checked=$checked"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Save issue details for next step
|
||||
printf '%s\n' "${issue_scripts[@]}" > /tmp/drift_scripts.txt 2>/dev/null || touch /tmp/drift_scripts.txt
|
||||
|
||||
# Save full report
|
||||
{
|
||||
echo "## Node.js Version Drift Report"
|
||||
echo ""
|
||||
echo "**Generated:** $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo "**Scripts checked:** $total | **With GitHub source:** $checked | **Drift detected:** $drift_count"
|
||||
echo ""
|
||||
echo "| Script | Our Version | engines.node | Dockerfile | Upstream Repo | Status |"
|
||||
echo "|--------|-------------|-------------|------------|---------------|--------|"
|
||||
printf '%s\n' "${report_lines[@]}" | sort
|
||||
} > /tmp/drift_report.md
|
||||
|
||||
cat /tmp/drift_report.md
|
||||
|
||||
- name: Create or update summary issue
|
||||
if: steps.check.outputs.drift_count != '0'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
TITLE="[Automated] Node.js Version Drift Report"
|
||||
DATE=$(date -u +%Y-%m-%d)
|
||||
DRIFT_COUNT="${{ steps.check.outputs.drift_count }}"
|
||||
TOTAL="${{ steps.check.outputs.total }}"
|
||||
CHECKED="${{ steps.check.outputs.checked }}"
|
||||
|
||||
# Build checklist from drift data
|
||||
CHECKLIST=""
|
||||
while IFS='|' read -r slug our_version upstream_major upstream_hint repo; do
|
||||
[[ -z "$slug" ]] && continue
|
||||
CHECKLIST+="- [ ] **\`${slug}\`** — ours: \`${our_version}\` → upstream: \`${upstream_major}\` (${upstream_hint}) — [repo](https://github.com/${repo})"$'\n'
|
||||
done < /tmp/drift_scripts.txt
|
||||
|
||||
# Build full report table
|
||||
REPORT=$(cat /tmp/drift_report.md)
|
||||
|
||||
BODY=$(cat <<ISSUE_EOF
|
||||
## Node.js Version Drift Report — ${DATE}
|
||||
|
||||
**${DRIFT_COUNT}** script(s) with version drift detected (out of ${CHECKED} checked / ${TOTAL} total).
|
||||
|
||||
### Scripts requiring investigation
|
||||
|
||||
${CHECKLIST}
|
||||
|
||||
### How to resolve
|
||||
|
||||
1. Check upstream Dockerfile / package.json to confirm the required Node.js version
|
||||
2. Test the script with the new Node version
|
||||
3. Update \`NODE_VERSION\` in \`install/<slug>-install.sh\`
|
||||
4. Update \`NODE_VERSION\` in \`ct/<slug>.sh\` (update section) if applicable
|
||||
5. Check off the item above once done
|
||||
|
||||
<details>
|
||||
<summary>Full report</summary>
|
||||
|
||||
${REPORT}
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
*This issue is automatically created/updated weekly by the Node.js version drift check workflow.*
|
||||
*Last updated: ${DATE}*
|
||||
ISSUE_EOF
|
||||
)
|
||||
|
||||
# Check if a matching open issue already exists
|
||||
EXISTING=$(gh issue list --state open --label "automated,dependencies" --search "\"[Automated] Node.js Version Drift Report\"" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$EXISTING" ]]; then
|
||||
gh issue edit "$EXISTING" --body "$BODY"
|
||||
echo "Updated existing issue #$EXISTING"
|
||||
else
|
||||
gh issue create \
|
||||
--title "$TITLE" \
|
||||
--body "$BODY" \
|
||||
--label "automated,dependencies"
|
||||
echo "Created new summary issue"
|
||||
fi
|
||||
|
||||
- name: Close issue if no drift
|
||||
if: steps.check.outputs.drift_count == '0'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
EXISTING=$(gh issue list --state open --label "automated,dependencies" --search "\"[Automated] Node.js Version Drift Report\"" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
|
||||
if [[ -n "$EXISTING" ]]; then
|
||||
gh issue close "$EXISTING" --comment "All Node.js versions are in sync with upstream. Closing automatically."
|
||||
echo "Closed issue #$EXISTING"
|
||||
fi
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -415,15 +415,31 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264))
|
||||
- Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- Arcane ([#12263](https://github.com/community-scripts/ProxmoxVE/pull/12263))
|
||||
|
||||
### 📂 Github
|
||||
|
||||
- add: workflow to close stale PRs [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12243](https://github.com/community-scripts/ProxmoxVE/pull/12243))
|
||||
- github: add weekly Node.js version drift check workflow [@MickLesk](https://github.com/MickLesk) ([#12267](https://github.com/community-scripts/ProxmoxVE/pull/12267))
|
||||
- add: workflow to close stale PRs [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12243](https://github.com/community-scripts/ProxmoxVE/pull/12243))
|
||||
|
||||
## 2026-02-23
|
||||
|
||||
|
||||
@@ -20,26 +20,28 @@ color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if command -v cross-seed &>/dev/null; then
|
||||
current_version=$(cross-seed --version)
|
||||
latest_version=$(npm show cross-seed version)
|
||||
if [ "$current_version" != "$latest_version" ]; then
|
||||
msg_info "Updating cross-seed from version v${current_version} to v${latest_version}"
|
||||
$STD npm install -g cross-seed@latest
|
||||
systemctl restart cross-seed
|
||||
msg_ok "Updated successfully!"
|
||||
else
|
||||
msg_ok "cross-seed is already at v${current_version}"
|
||||
fi
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if command -v cross-seed &>/dev/null; then
|
||||
current_version=$(cross-seed --version)
|
||||
latest_version=$(npm show cross-seed version)
|
||||
if [ "$current_version" != "$latest_version" ]; then
|
||||
msg_info "Updating cross-seed from version v${current_version} to v${latest_version}"
|
||||
$STD npm install -g cross-seed@latest
|
||||
systemctl restart cross-seed
|
||||
msg_ok "Updated successfully!"
|
||||
else
|
||||
msg_error "No cross-seed Installation Found!"
|
||||
exit
|
||||
msg_ok "cross-seed is already at v${current_version}"
|
||||
fi
|
||||
else
|
||||
msg_error "No cross-seed Installation Found!"
|
||||
exit
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
|
||||
@@ -28,6 +28,8 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
||||
|
||||
if check_for_gh_release "manyfold" "manyfold3d/manyfold"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop manyfold.target manyfold-rails.1 manyfold-default_worker.1 manyfold-performance_worker.1
|
||||
|
||||
@@ -29,7 +29,7 @@ function update_script() {
|
||||
fi
|
||||
$STD apt update
|
||||
$STD apt upgrade -y
|
||||
NODE_VERSION="22" NODE_MODULE="matterbridge" setup_nodejs
|
||||
NODE_VERSION="24" NODE_MODULE="matterbridge" setup_nodejs
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
14
ct/n8n.sh
14
ct/n8n.sh
@@ -27,7 +27,11 @@ function update_script() {
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
ensure_dependencies graphicsmagick
|
||||
|
||||
ensure_dependencies graphicsmagick
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
msg_info "Updating n8n"
|
||||
if [ ! -f /opt/n8n.env ]; then
|
||||
sed -i 's|^Environment="N8N_SECURE_COOKIE=false"$|EnvironmentFile=/opt/n8n.env|' /etc/systemd/system/n8n.service
|
||||
mkdir -p /opt
|
||||
@@ -37,14 +41,12 @@ N8N_PORT=5678
|
||||
N8N_PROTOCOL=http
|
||||
N8N_HOST=$LOCAL_IP
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
|
||||
msg_info "Updating ${APP} LXC"
|
||||
rm -rf /usr/lib/node_modules/.n8n-* /usr/lib/node_modules/n8n
|
||||
$STD npm install -g n8n --force
|
||||
$STD npm update -g n8n
|
||||
systemctl restart n8n
|
||||
msg_ok "Updated n8n"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if check_for_gh_release "pangolin" "fosrl/pangolin"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop pangolin
|
||||
|
||||
82
ct/romm.sh
82
ct/romm.sh
@@ -20,48 +20,50 @@ color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/romm ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "romm" "rommapp/romm"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop romm-backend romm-worker romm-scheduler romm-watcher
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Backing up configuration"
|
||||
cp /opt/romm/.env /opt/romm/.env.backup
|
||||
msg_ok "Backed up configuration"
|
||||
|
||||
fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" "latest" "/opt/romm"
|
||||
|
||||
msg_info "Updating ROMM"
|
||||
cp /opt/romm/.env.backup /opt/romm/.env
|
||||
cd /opt/romm
|
||||
$STD uv sync --all-extras
|
||||
cd /opt/romm/backend
|
||||
$STD uv run alembic upgrade head
|
||||
cd /opt/romm/frontend
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
# Merge static assets into dist folder
|
||||
cp -rf /opt/romm/frontend/assets/* /opt/romm/frontend/dist/assets/
|
||||
mkdir -p /opt/romm/frontend/dist/assets/romm
|
||||
ln -sfn /var/lib/romm/resources /opt/romm/frontend/dist/assets/romm/resources
|
||||
ln -sfn /var/lib/romm/assets /opt/romm/frontend/dist/assets/romm/assets
|
||||
msg_ok "Updated ROMM"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start romm-backend romm-worker romm-scheduler romm-watcher
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully"
|
||||
fi
|
||||
if [[ ! -d /opt/romm ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if check_for_gh_release "romm" "rommapp/romm"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop romm-backend romm-worker romm-scheduler romm-watcher
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Backing up configuration"
|
||||
cp /opt/romm/.env /opt/romm/.env.backup
|
||||
msg_ok "Backed up configuration"
|
||||
|
||||
fetch_and_deploy_gh_release "romm" "rommapp/romm" "tarball" "latest" "/opt/romm"
|
||||
|
||||
msg_info "Updating ROMM"
|
||||
cp /opt/romm/.env.backup /opt/romm/.env
|
||||
cd /opt/romm
|
||||
$STD uv sync --all-extras
|
||||
cd /opt/romm/backend
|
||||
$STD uv run alembic upgrade head
|
||||
cd /opt/romm/frontend
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
# Merge static assets into dist folder
|
||||
cp -rf /opt/romm/frontend/assets/* /opt/romm/frontend/dist/assets/
|
||||
mkdir -p /opt/romm/frontend/dist/assets/romm
|
||||
ln -sfn /var/lib/romm/resources /opt/romm/frontend/dist/assets/romm/resources
|
||||
ln -sfn /var/lib/romm/assets /opt/romm/frontend/dist/assets/romm/assets
|
||||
msg_ok "Updated ROMM"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start romm-backend romm-worker romm-scheduler romm-watcher
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
|
||||
@@ -28,6 +28,8 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if check_for_gh_release "snowshare" "TuroYT/snowshare"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop snowshare
|
||||
|
||||
@@ -33,7 +33,7 @@ function update_script() {
|
||||
$STD apt upgrade -y
|
||||
msg_ok "Updated LXC Container"
|
||||
|
||||
NODE_VERSION="22" NODE_MODULE="verdaccio" setup_nodejs
|
||||
NODE_VERSION="24" NODE_MODULE="verdaccio" setup_nodejs
|
||||
systemctl restart verdaccio
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"categories": [
|
||||
3
|
||||
],
|
||||
"date_created": "2026-02-18",
|
||||
"date_created": "2026-02-24",
|
||||
"type": "addon",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated": "2026-02-24T06:23:39Z",
|
||||
"generated": "2026-02-24T12:15:44Z",
|
||||
"versions": [
|
||||
{
|
||||
"slug": "2fauth",
|
||||
@@ -606,9 +606,9 @@
|
||||
{
|
||||
"slug": "invoiceninja",
|
||||
"repo": "invoiceninja/invoiceninja",
|
||||
"version": "v5.12.65",
|
||||
"version": "v5.12.66",
|
||||
"pinned": false,
|
||||
"date": "2026-02-21T01:03:52Z"
|
||||
"date": "2026-02-24T09:12:50Z"
|
||||
},
|
||||
{
|
||||
"slug": "jackett",
|
||||
@@ -1679,7 +1679,7 @@
|
||||
"repo": "meilisearch/meilisearch",
|
||||
"version": "v1.36.0",
|
||||
"pinned": false,
|
||||
"date": "2026-02-23T08:13:32Z"
|
||||
"date": ""
|
||||
},
|
||||
{
|
||||
"slug": "warracker",
|
||||
|
||||
@@ -13,7 +13,7 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
msg_info "Setup Cross-Seed"
|
||||
$STD npm install cross-seed@latest -g
|
||||
|
||||
@@ -26,7 +26,7 @@ msg_ok "Installed Dependencies"
|
||||
setup_imagemagick
|
||||
PG_VERSION="16" setup_postgresql
|
||||
PG_DB_NAME="manyfold" PG_DB_USER="manyfold" setup_postgresql_db
|
||||
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
|
||||
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
||||
|
||||
fetch_and_deploy_gh_release "manyfold" "manyfold3d/manyfold" "tarball" "latest" "/opt/manyfold/app"
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ update_os
|
||||
|
||||
msg_info "Install Matterbridge"
|
||||
mkdir -p /root/Matterbridge
|
||||
NODE_VERSION="22" NODE_MODULE="matterbridge" setup_nodejs
|
||||
NODE_VERSION="24" NODE_MODULE="matterbridge" setup_nodejs
|
||||
msg_ok "Installed Matterbridge"
|
||||
|
||||
msg_info "Creating Service"
|
||||
|
||||
@@ -15,22 +15,19 @@ update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
graphicsmagick
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
msg_info "Installing n8n (Patience)"
|
||||
$STD npm install --global patch-package
|
||||
$STD npm install --global n8n
|
||||
$STD npm install -g n8n
|
||||
msg_ok "Installed n8n"
|
||||
|
||||
msg_info "Creating Service"
|
||||
mkdir -p /opt
|
||||
cat <<EOF >/opt/n8n.env
|
||||
N8N_SECURE_COOKIE=false
|
||||
N8N_PORT=5678
|
||||
|
||||
@@ -14,7 +14,7 @@ network_check
|
||||
update_os
|
||||
|
||||
fetch_and_deploy_gh_release "nodecast-tv" "technomancer702/nodecast-tv"
|
||||
setup_nodejs
|
||||
NODE_VERSION="20" setup_nodejs
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y ffmpeg
|
||||
|
||||
@@ -19,7 +19,7 @@ $STD apt install -y \
|
||||
iptables
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball"
|
||||
fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_amd64"
|
||||
fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_amd64.tar.gz"
|
||||
|
||||
@@ -42,7 +42,7 @@ $STD apt install -y \
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PYTHON_VERSION="3.13" setup_uv
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
setup_mariadb
|
||||
MARIADB_DB_NAME="romm" MARIADB_DB_USER="romm" setup_mariadb_db
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
PG_VERSION="17" setup_postgresql
|
||||
PG_DB_USER="snowshare" PG_DB_NAME="snowshare" setup_postgresql_db
|
||||
fetch_and_deploy_gh_release "snowshare" "TuroYT/snowshare" "tarball"
|
||||
|
||||
@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
|
||||
$STD apt install -y build-essential
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" NODE_MODULE="verdaccio" setup_nodejs
|
||||
NODE_VERSION="24" NODE_MODULE="verdaccio" setup_nodejs
|
||||
|
||||
msg_info "Configuring Verdaccio"
|
||||
mkdir -p /opt/verdaccio/config
|
||||
|
||||
@@ -23,7 +23,7 @@ $STD apt install -y \
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
setup_rust
|
||||
NODE_MODULE="pnpm" setup_nodejs
|
||||
NODE_VERSION="20" NODE_MODULE="pnpm" setup_nodejs
|
||||
fetch_and_deploy_gh_release "wealthfolio" "afadil/wealthfolio" "tarball"
|
||||
|
||||
msg_info "Building Frontend (patience)"
|
||||
|
||||
@@ -38,17 +38,18 @@
|
||||
# - Captures app-declared resource defaults (CPU, RAM, Disk)
|
||||
# ------------------------------------------------------------------------------
|
||||
variables() {
|
||||
NSAPP=$(echo "${APP,,}" | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces.
|
||||
var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP.
|
||||
INTEGER='^[0-9]+([.][0-9]+)?$' # it defines the INTEGER regular expression pattern.
|
||||
PVEHOST_NAME=$(hostname) # gets the Proxmox Hostname and sets it to Uppercase
|
||||
DIAGNOSTICS="no" # Safe default: no telemetry until user consents via diagnostics_check()
|
||||
METHOD="default" # sets the METHOD variable to "default", used for the API call.
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
|
||||
EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase)
|
||||
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
|
||||
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log
|
||||
combined_log="/tmp/install-${SESSION_ID}-combined.log" # Combined log (build + install) for failed installations
|
||||
NSAPP=$(echo "${APP,,}" | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces.
|
||||
var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP.
|
||||
INTEGER='^[0-9]+([.][0-9]+)?$' # it defines the INTEGER regular expression pattern.
|
||||
PVEHOST_NAME=$(hostname) # gets the Proxmox Hostname and sets it to Uppercase
|
||||
DIAGNOSTICS="no" # Safe default: no telemetry until user consents via diagnostics_check()
|
||||
METHOD="default" # sets the METHOD variable to "default", used for the API call.
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
|
||||
EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase)
|
||||
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
|
||||
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log
|
||||
# NOTE: combined_log is constructed locally in build_container() and ensure_log_on_host()
|
||||
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
|
||||
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
|
||||
|
||||
# Parse dev_mode early
|
||||
@@ -1850,7 +1851,7 @@ advanced_settings() {
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# STEP 2: Root Password
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# ════════════════════════════════════════════════════════════════════════<EFBFBD><EFBFBD><EFBFBD>══
|
||||
2)
|
||||
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
|
||||
--title "ROOT PASSWORD" \
|
||||
@@ -4174,6 +4175,13 @@ EOF'
|
||||
# Report failure to telemetry API (now with log available on host)
|
||||
post_update_to_api "failed" "$install_exit_code"
|
||||
|
||||
# Defense-in-depth: Ensure error handling stays disabled during recovery.
|
||||
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
|
||||
# and trap 'error_handler' ERR. If any code path above called such a function,
|
||||
# the grep/sed pipelines below would trigger error_handler on non-match (exit 1).
|
||||
set +Eeuo pipefail
|
||||
trap - ERR
|
||||
|
||||
# Show combined log location
|
||||
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
|
||||
msg_custom "📋" "${YW}" "Installation log: ${combined_log}"
|
||||
@@ -4287,7 +4295,7 @@ EOF'
|
||||
if [[ "$is_cmd_not_found" == true ]]; then
|
||||
local missing_cmd=""
|
||||
if [[ -f "$combined_log" ]]; then
|
||||
missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" | tail -1 | sed 's/: command not found//')
|
||||
missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" 2>/dev/null | tail -1 | sed 's/: command not found//') || true
|
||||
fi
|
||||
if [[ -n "$missing_cmd" ]]; then
|
||||
echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}"
|
||||
|
||||
@@ -490,6 +490,8 @@ log_section() {
|
||||
# - Executes command with output redirected to active log file
|
||||
# - On error: displays last 20 lines of log and exits with original exit code
|
||||
# - Temporarily disables error trap to capture exit code correctly
|
||||
# - Saves and restores previous error handling state (so callers that
|
||||
# intentionally disabled error handling aren't silently re-enabled)
|
||||
# - Sources explain_exit_code() for detailed error messages
|
||||
# ------------------------------------------------------------------------------
|
||||
silent() {
|
||||
@@ -507,14 +509,23 @@ silent() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Save current error handling state before disabling
|
||||
# This prevents re-enabling error handling when the caller intentionally
|
||||
# disabled it (e.g. build_container recovery section)
|
||||
local _restore_errexit=false
|
||||
[[ "$-" == *e* ]] && _restore_errexit=true
|
||||
|
||||
set +Eeuo pipefail
|
||||
trap - ERR
|
||||
|
||||
"$@" >>"$logfile" 2>&1
|
||||
local rc=$?
|
||||
|
||||
set -Eeuo pipefail
|
||||
trap 'error_handler' ERR
|
||||
# Restore error handling ONLY if it was active before this call
|
||||
if $_restore_errexit; then
|
||||
set -Eeuo pipefail
|
||||
trap 'error_handler' ERR
|
||||
fi
|
||||
|
||||
if [[ $rc -ne 0 ]]; then
|
||||
# Source explain_exit_code if needed
|
||||
|
||||
@@ -1525,6 +1525,82 @@ verify_gpg_fingerprint() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get latest GitHub tag for a repository.
|
||||
#
|
||||
# Description:
|
||||
# - Queries the GitHub API for tags (not releases)
|
||||
# - Useful for repos that only create tags, not full releases
|
||||
# - Supports optional prefix filter and version-only extraction
|
||||
# - Returns the latest tag name (printed to stdout)
|
||||
#
|
||||
# Usage:
|
||||
# MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools")
|
||||
# LATEST=$(get_latest_gh_tag "owner/repo" "v") # only tags starting with "v"
|
||||
# LATEST=$(get_latest_gh_tag "owner/repo" "" "true") # strip leading "v"
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - GitHub repo (owner/repo)
|
||||
# $2 - Tag prefix filter (optional, e.g. "v" or "100.")
|
||||
# $3 - Strip prefix from result (optional, "true" to strip $2 prefix)
|
||||
#
|
||||
# Returns:
|
||||
# 0 on success (tag printed to stdout), 1 on failure
|
||||
#
|
||||
# Notes:
|
||||
# - Skips tags containing "rc", "alpha", "beta", "dev", "test"
|
||||
# - Sorts by version number (sort -V) to find the latest
|
||||
# - Respects GITHUB_TOKEN for rate limiting
|
||||
# ------------------------------------------------------------------------------
|
||||
get_latest_gh_tag() {
|
||||
local repo="$1"
|
||||
local prefix="${2:-}"
|
||||
local strip_prefix="${3:-false}"
|
||||
|
||||
local header_args=()
|
||||
[[ -n "${GITHUB_TOKEN:-}" ]] && header_args=(-H "Authorization: Bearer $GITHUB_TOKEN")
|
||||
|
||||
local http_code=""
|
||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_tags.json \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||
"${header_args[@]}" \
|
||||
"https://api.github.com/repos/${repo}/tags?per_page=100" 2>/dev/null) || true
|
||||
|
||||
if [[ "$http_code" == "403" ]]; then
|
||||
msg_warn "GitHub API rate limit exceeded while fetching tags for ${repo}"
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$http_code" != "200" ]] || [[ ! -s /tmp/gh_tags.json ]]; then
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tags_json
|
||||
tags_json=$(</tmp/gh_tags.json)
|
||||
rm -f /tmp/gh_tags.json
|
||||
|
||||
# Extract tag names, filter by prefix, exclude pre-release patterns, sort by version
|
||||
local latest=""
|
||||
latest=$(echo "$tags_json" | grep -oP '"name":\s*"\K[^"]+' |
|
||||
{ [[ -n "$prefix" ]] && grep "^${prefix}" || cat; } |
|
||||
grep -viE '(rc|alpha|beta|dev|test|preview|snapshot)' |
|
||||
sort -V | tail -n1)
|
||||
|
||||
if [[ -z "$latest" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$strip_prefix" == "true" && -n "$prefix" ]]; then
|
||||
latest="${latest#"$prefix"}"
|
||||
fi
|
||||
|
||||
echo "$latest"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# INSTALL FUNCTIONS
|
||||
# ==============================================================================
|
||||
|
||||
6
tools/headers/arcane
Normal file
6
tools/headers/arcane
Normal file
@@ -0,0 +1,6 @@
|
||||
___
|
||||
/ | ______________ _____ ___
|
||||
/ /| | / ___/ ___/ __ `/ __ \/ _ \
|
||||
/ ___ |/ / / /__/ /_/ / / / / __/
|
||||
/_/ |_/_/ \___/\__,_/_/ /_/\___/
|
||||
|
||||
Reference in New Issue
Block a user