Compare commits

...

13 Commits

Author SHA1 Message Date
Aiirondev_dev bf0a50ad57 Add module detection for dynamic navbar rendering 2026-04-10 16:22:03 +02:00
Aiirondev_dev 9212ad04f5 Add asset versioning for cache-busting in templates and configuration 2026-04-10 16:10:30 +02:00
Aiirondev_dev 1931e07013 Add function to refresh runtime scripts from main repository and update image tags 2026-04-10 16:02:18 +02:00
Maximilian G. c81aa882e9 Add badges for CI and coding activity
Added badges for GitHub Actions and Wakatime to README.
2026-04-10 15:57:44 +02:00
Aiirondev_dev 142e6e990e Update repository slug and image repository in update script 2026-04-10 15:56:42 +02:00
Aiirondev_dev 9333b5cdd0 Add versioning to CSS file links in base template 2026-04-10 15:51:35 +02:00
Aiirondev_dev b11739de3b Add compatibility alias for legacy compose bundles in installer script 2026-04-10 15:37:01 +02:00
Aiirondev_dev 269f084227 Add function to pin application image in docker-compose file 2026-04-10 15:33:15 +02:00
Aiirondev_dev 46b9e0b3b2 Add function to refresh start script from main repository 2026-04-10 15:29:56 +02:00
Aiirondev_dev 4554e5ee02 Refactor installation scripts to use consistent repository slug and improve temporary directory cleanup 2026-04-10 15:21:24 +02:00
Aiirondev_dev ecea6740f5 Update installation script URLs to reflect correct GitHub user slug 2026-04-10 15:16:59 +02:00
Aiirondev_dev a8122f9afd Refactor installer script to update repository slug and correct application image path 2026-04-10 15:14:00 +02:00
Aiirondev_dev 71026b8eab Update Docker release workflow and correct version in config 2026-04-10 15:09:33 +02:00
10 changed files with 207 additions and 98 deletions
+5 -2
View File
@@ -19,6 +19,9 @@ permissions:
contents: write
packages: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
release-docker:
runs-on: ubuntu-latest
@@ -221,11 +224,11 @@ jobs:
cp start.sh release-bundle/start.sh
cp stop.sh release-bundle/stop.sh
cp restart.sh release-bundle/restart.sh
cp backup-docker.sh release-bundle/backup-docker.sh
cp backup.sh release-bundle/backup.sh
cp update.sh release-bundle/update.sh
cp init-admin.sh release-bundle/init-admin.sh
chmod +x release-bundle/start.sh release-bundle/stop.sh release-bundle/restart.sh release-bundle/backup-docker.sh release-bundle/update.sh release-bundle/init-admin.sh
chmod +x release-bundle/start.sh release-bundle/stop.sh release-bundle/restart.sh release-bundle/backup.sh release-bundle/update.sh release-bundle/init-admin.sh
tar -czf inventarsystem-docker-bundle.tar.gz -C release-bundle .
- name: Create or update GitHub Release
+2 -1
View File
@@ -1,4 +1,5 @@
dist
logs
certs
build
build
.venv
+5 -3
View File
@@ -1,5 +1,7 @@
# Inventarsystem
[![https://github.com/AIIrondev/legendary-octo-garbanzo](https://github.com/AIIrondev/legendary-octo-garbanzo/actions/workflows/release-docker.yml/badge.svg)](https://github.com/AIIrondev/legendary-octo-garbanzo/actions/workflows/release-docker.yml)
[![wakatime](https://wakatime.com/badge/user/30b8509f-5e17-4d16-b6b8-3ca0f3f936d3/project/8a380b7f-389f-4a7e-8877-0fe9e1a4c243.svg)](https://wakatime.com/badge/user/30b8509f-5e17-4d16-b6b8-3ca0f3f936d3/project/8a380b7f-389f-4a7e-8877-0fe9e1a4c243)
**Aktuelle Version: 3.2.1**
@@ -120,19 +122,19 @@ Das Inventarsystem stellt folgende Wartungsskripte bereit:
**Option 1**
```bash
wget -O - https://raw.githubusercontent.com/aiirondev/legendary-octo-garbanzo/main/install.sh | sudo bash
wget -O - https://raw.githubusercontent.com/AIIrondev/legendary-octo-garbanzo/main/install.sh | sudo bash
```
**Option 2**
```bash
curl -s https://raw.githubusercontent.com/aiirondev/legendary-octo-garbanzo/main/install.sh | sudo bash
curl -s https://raw.githubusercontent.com/AIIrondev/legendary-octo-garbanzo/main/install.sh | sudo bash
```
Legacy-MongoDB uebernehmen und altes Host-System aufraeumen:
```bash
curl -s https://raw.githubusercontent.com/aiirondev/legendary-octo-garbanzo/main/install.sh | \
curl -s https://raw.githubusercontent.com/AIIrondev/legendary-octo-garbanzo/main/install.sh | \
sudo bash -s -- --migrate-legacy-db --remove-legacy-system
```
Binary file not shown.
+45
View File
@@ -92,6 +92,45 @@ SCHOOL_PERIODS = cfg.SCHOOL_PERIODS
# Apply the configuration for general use throughout the app
APP_VERSION = __version__
RELEASE_STATE_FILE = os.path.join(os.path.dirname(BASE_DIR), '.release-version')
def _get_asset_version():
"""Return a cache-busting asset version tied to deployment state."""
env_version = os.getenv('INVENTAR_ASSET_VERSION', '').strip()
if env_version:
return env_version
try:
if os.path.exists(RELEASE_STATE_FILE):
with open(RELEASE_STATE_FILE, 'r', encoding='utf-8') as f:
release_tag = f.read().strip()
if release_tag:
return release_tag
except Exception:
pass
return APP_VERSION
def _is_library_module_path(path):
"""Return True when the current request path belongs to the library module."""
if not path:
return False
library_prefixes = (
'/library',
'/library_',
'/student_cards',
)
return path.startswith(library_prefixes)
def _get_current_module(path):
"""Resolve the active UI module for navbar separation."""
if cfg.LIBRARY_MODULE_ENABLED and _is_library_module_path(path):
return 'library'
return 'inventory'
def _parse_money_value(value):
@@ -293,13 +332,19 @@ def _prepare_invoice_pdf_payload(invoice_data, borrow_doc=None, item_doc=None):
def inject_version():
"""Inject global template variables."""
is_admin = False
asset_version = _get_asset_version()
if 'username' in session:
try:
is_admin = us.check_admin(session['username'])
except Exception:
is_admin = False
current_module = _get_current_module(request.path)
return {
'APP_VERSION': APP_VERSION,
'ASSET_VERSION': asset_version,
'CURRENT_MODULE': current_module,
'school_periods': SCHOOL_PERIODS,
'library_module_enabled': cfg.LIBRARY_MODULE_ENABLED,
'student_cards_module_enabled': cfg.STUDENT_CARDS_MODULE_ENABLED,
+9 -66
View File
@@ -7,7 +7,7 @@
For commercial licensing inquiries: https://github.com/AIIrondev
-->
<!DOCTYPE html>
<html lang="en" data-module="inventory">
<html lang="en" data-module="{{ CURRENT_MODULE }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
@@ -20,8 +20,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/planned_appointments.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css', v=ASSET_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/planned_appointments.css', v=ASSET_VERSION) }}">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<style>
@@ -369,7 +369,7 @@
<span class="module-label">Module:</span>
<div class="module-tabs">
<a href="{{ url_for('home') }}"
class="module-tab"
class="module-tab {% if CURRENT_MODULE == 'inventory' %}active{% endif %}"
id="inventoryModule"
data-module="inventory">
📦 Inventarsystem
@@ -377,7 +377,7 @@
{% if library_module_enabled %}
<div class="module-separator"></div>
<a href="{{ url_for('library_view') }}"
class="module-tab"
class="module-tab {% if CURRENT_MODULE == 'library' %}active{% endif %}"
id="libraryModule"
data-module="library">
📚 Bibliothek
@@ -386,48 +386,7 @@
</div>
</div>
{% endif %}
<script>
(function() {
// Detect current module based on URL and update data-module attribute
const currentPath = window.location.pathname;
const htmlTag = document.documentElement;
// Detect module and pages
const isLibraryModule = currentPath.includes('/library') ||
currentPath.includes('/library_admin') ||
currentPath.includes('/library_loans') ||
currentPath.includes('/student_cards');
const currentModule = isLibraryModule ? 'library' : 'inventory';
htmlTag.setAttribute('data-module', currentModule);
// Update module selector tabs
const invModule = document.getElementById('inventoryModule');
const libModule = document.getElementById('libraryModule');
if (currentModule === 'library') {
if (libModule) libModule.classList.add('active');
if (invModule) invModule.classList.remove('active');
} else {
if (invModule) invModule.classList.add('active');
if (libModule) libModule.classList.remove('active');
}
// Show/hide appropriate navbar based on current module
const invNavbar = document.getElementById('inventoryNavbar');
const libNavbar = document.getElementById('libraryNavbar');
if (currentModule === 'library') {
if (invNavbar) invNavbar.style.display = 'none';
if (libNavbar) libNavbar.style.display = '';
} else {
if (invNavbar) invNavbar.style.display = '';
if (libNavbar) libNavbar.style.display = 'none';
}
})();
</script>
{% if CURRENT_MODULE != 'library' %}
<nav class="navbar navbar-expand-lg navbar-dark" id="inventoryNavbar">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('home') }}" data-icon="📦">Inventarsystem</a>
@@ -490,9 +449,10 @@
</div>
</div>
</nav>
{% endif %}
{% if library_module_enabled %}
<nav class="navbar navbar-expand-lg navbar-dark" id="libraryNavbar" style="display: none;">
{% if library_module_enabled and CURRENT_MODULE == 'library' %}
<nav class="navbar navbar-expand-lg navbar-dark" id="libraryNavbar">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('library_view') }}" data-icon="📚">Bibliothek</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#libraryNavContent">
@@ -555,23 +515,6 @@
</div>
</nav>
{% endif %}
<script>
(function() {
// Show/hide appropriate navbar based on current module
const currentPath = window.location.pathname;
const invNavbar = document.getElementById('inventoryNavbar');
const libNavbar = document.getElementById('libraryNavbar');
if (currentPath.includes('/library')) {
if (invNavbar) invNavbar.style.display = 'none';
if (libNavbar) libNavbar.style.display = '';
} else {
if (invNavbar) invNavbar.style.display = '';
if (libNavbar) libNavbar.style.display = 'none';
}
})();
</script>
<div class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"dbg": false,
"key": "InventarsystemSecureKey2026XYZ789abcdef012",
"ver": "3.2.1",
"ver": "0.0.2",
"host": "0.0.0.0",
"port": 443,
+113 -18
View File
@@ -1,9 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALLER_SOURCE="${BASH_SOURCE[0]-$0}"
if [ -n "$INSTALLER_SOURCE" ] && [ "$INSTALLER_SOURCE" != "bash" ] && [ "$INSTALLER_SOURCE" != "-bash" ] && [ "$INSTALLER_SOURCE" != "sh" ] && [ "$INSTALLER_SOURCE" != "-" ] && [ -e "$INSTALLER_SOURCE" ]; then
INSTALLER_DIR="$(cd "$(dirname "$INSTALLER_SOURCE")" && pwd)"
else
INSTALLER_DIR="$(pwd)"
fi
PROJECT_DIR="/opt/Inventarsystem"
REPO_SLUG="AIIrondev/Inventarsystem"
REPO_SLUG="AIIrondev/legendary-octo-garbanzo"
API_URL="https://api.github.com/repos/$REPO_SLUG/releases/latest"
BUNDLE_ASSET="inventarsystem-docker-bundle.tar.gz"
APP_IMAGE_ASSET_PREFIX="inventarsystem-image-"
@@ -16,6 +21,13 @@ LEGACY_SYSTEM_DIR=""
LEGACY_BACKUP_ARCHIVE=""
CLEANUP_OLD_SERVICES=true
CLEANUP_OLD_REMOVE_CRON=false
TMP_DIR=""
cleanup_tmp_dir() {
if [ -n "${TMP_DIR:-}" ] && [ -d "$TMP_DIR" ]; then
rm -rf "$TMP_DIR"
fi
}
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
@@ -24,6 +36,83 @@ need_cmd() {
fi
}
refresh_start_script_from_main() {
local start_url
start_url="https://raw.githubusercontent.com/$REPO_SLUG/main/start.sh"
if curl -fsSL "$start_url" -o "$TMP_DIR/start.sh"; then
sudo install -m 755 "$TMP_DIR/start.sh" "$PROJECT_DIR/start.sh"
else
echo "Warning: failed to refresh start.sh from main; using bundled start.sh"
fi
}
pin_compose_app_image() {
local tag="$1"
local compose_file
compose_file="$PROJECT_DIR/docker-compose.yml"
if [ ! -f "$compose_file" ]; then
echo "Warning: $compose_file not found; cannot pin app image"
return 0
fi
python3 - <<'PY' "$compose_file" "$tag"
import re
import sys
compose_file, tag = sys.argv[1], sys.argv[2]
target_image = f"ghcr.io/aiirondev/legendary-octo-garbanzo:{tag}"
with open(compose_file, "r", encoding="utf-8") as f:
lines = f.readlines()
out = []
in_app = False
in_build = False
image_set = False
for line in lines:
stripped = line.lstrip(" ")
indent = len(line) - len(stripped)
if not in_app and re.match(r"^\s{2}app:\s*$", line):
in_app = True
image_set = False
out.append(line)
out.append(f" image: {target_image}\n")
image_set = True
continue
if in_app:
if indent == 2 and re.match(r"^[A-Za-z0-9_-]+:\s*$", stripped):
in_app = False
in_build = False
if in_app:
if in_build:
if indent > 4:
continue
in_build = False
if re.match(r"^\s{4}build:\s*$", line):
in_build = True
continue
if re.match(r"^\s{4}image:\s*", line):
if image_set:
continue
out.append(f" image: {target_image}\n")
image_set = True
continue
out.append(line)
with open(compose_file, "w", encoding="utf-8") as f:
f.writelines(out)
PY
}
install_docker_if_missing() {
if command -v docker >/dev/null 2>&1; then
return 0
@@ -258,10 +347,10 @@ main() {
need_cmd python3
need_cmd curl
local tmp_dir meta_file tag bundle_url image_url
tmp_dir="$(mktemp -d)"
meta_file="$tmp_dir/release.json"
trap 'rm -rf "$tmp_dir"' EXIT
local meta_file tag bundle_url image_url
TMP_DIR="$(mktemp -d)"
meta_file="$TMP_DIR/release.json"
trap cleanup_tmp_dir EXIT
mapfile -t release_info < <(latest_tag_and_bundle_url "$meta_file")
tag="${release_info[0]:-}"
@@ -277,16 +366,20 @@ main() {
echo "Installing Inventarsystem release $tag into $PROJECT_DIR"
sudo mkdir -p "$PROJECT_DIR"
curl -fL "$bundle_url" -o "$tmp_dir/$BUNDLE_ASSET"
sudo tar -xzf "$tmp_dir/$BUNDLE_ASSET" -C "$PROJECT_DIR"
curl -fL "$bundle_url" -o "$TMP_DIR/$BUNDLE_ASSET"
sudo tar -xzf "$TMP_DIR/$BUNDLE_ASSET" -C "$PROJECT_DIR"
pin_compose_app_image "$tag"
if [ -z "$image_url" ]; then
echo "Error: release image asset is missing"
exit 1
fi
curl -fL "$image_url" -o "$tmp_dir/inventarsystem-image-$tag.tar.gz"
sudo docker load -i "$tmp_dir/inventarsystem-image-$tag.tar.gz" >/dev/null
curl -fL "$image_url" -o "$TMP_DIR/inventarsystem-image-$tag.tar.gz"
sudo docker load -i "$TMP_DIR/inventarsystem-image-$tag.tar.gz" >/dev/null
# Compatibility alias: some legacy compose bundles may still reference :latest.
sudo docker tag "ghcr.io/aiirondev/legendary-octo-garbanzo:$tag" "ghcr.io/aiirondev/legendary-octo-garbanzo:latest" >/dev/null 2>&1 || true
if [ ! -f "$PROJECT_DIR/start.sh" ]; then
echo "Error: release bundle is missing start.sh"
@@ -297,16 +390,18 @@ main() {
exit 1
fi
if [ ! -f "$PROJECT_DIR/restart.sh" ]; then
cat > "$tmp_dir/restart.sh" <<'EOF'
cat > "$TMP_DIR/restart.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
"$SCRIPT_DIR/stop.sh"
"$SCRIPT_DIR/start.sh"
EOF
sudo install -m 755 "$tmp_dir/restart.sh" "$PROJECT_DIR/restart.sh"
sudo install -m 755 "$TMP_DIR/restart.sh" "$PROJECT_DIR/restart.sh"
fi
refresh_start_script_from_main
if [ ! -f "$PROJECT_DIR/cleanup-old.sh" ] && [ -f "$INSTALLER_DIR/cleanup-old.sh" ]; then
sudo install -m 755 "$INSTALLER_DIR/cleanup-old.sh" "$PROJECT_DIR/cleanup-old.sh"
fi
@@ -317,23 +412,23 @@ EOF
echo "$tag" | sudo tee "$PROJECT_DIR/.release-version" >/dev/null
if [ ! -f "$PROJECT_DIR/.docker-build.env" ]; then
cat > "$tmp_dir/.docker-build.env" <<EOF
cat > "$TMP_DIR/.docker-build.env" <<EOF
NUITKA_BUILD=0
INVENTAR_HTTP_PORT=80
INVENTAR_HTTPS_PORT=443
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/inventarsystem:$tag
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:$tag
EOF
sudo install -m 644 "$tmp_dir/.docker-build.env" "$PROJECT_DIR/.docker-build.env"
sudo install -m 644 "$TMP_DIR/.docker-build.env" "$PROJECT_DIR/.docker-build.env"
elif sudo grep -q '^INVENTAR_APP_IMAGE=' "$PROJECT_DIR/.docker-build.env"; then
sudo sed -i "s|^INVENTAR_APP_IMAGE=.*|INVENTAR_APP_IMAGE=ghcr.io/aiirondev/inventarsystem:$tag|" "$PROJECT_DIR/.docker-build.env"
sudo sed -i "s|^INVENTAR_APP_IMAGE=.*|INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:$tag|" "$PROJECT_DIR/.docker-build.env"
else
echo "INVENTAR_APP_IMAGE=ghcr.io/aiirondev/inventarsystem:$tag" | sudo tee -a "$PROJECT_DIR/.docker-build.env" >/dev/null
echo "INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:$tag" | sudo tee -a "$PROJECT_DIR/.docker-build.env" >/dev/null
fi
backup_legacy_database
echo "Starting stack..."
sudo bash "$PROJECT_DIR/start.sh"
sudo env INVENTAR_APP_IMAGE="ghcr.io/aiirondev/legendary-octo-garbanzo:$tag" bash "$PROJECT_DIR/start.sh"
restore_legacy_backup_into_docker
cleanup_old_services
+6 -5
View File
@@ -5,7 +5,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
ENV_FILE="$SCRIPT_DIR/.docker-build.env"
APP_IMAGE_REPO="ghcr.io/aiirondev/inventarsystem"
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
DIST_DIR="$SCRIPT_DIR/dist"
SUDO=""
@@ -17,7 +17,7 @@ NUITKA_BUILD_VALUE="0"
HTTP_PORT_VALUE="80"
HTTPS_PORT_VALUE="443"
CRON_SETUP_VALUE="${INVENTAR_SETUP_CRON:-1}"
APP_IMAGE_VALUE="${INVENTAR_APP_IMAGE:-ghcr.io/aiirondev/inventarsystem:latest}"
APP_IMAGE_VALUE="${INVENTAR_APP_IMAGE:-$APP_IMAGE_REPO:latest}"
usage() {
cat <<EOF
@@ -364,11 +364,12 @@ configure_nuitka_mode() {
}
resolve_app_image() {
local env_image="" release_tag=""
local env_image="" release_tag="" default_latest
default_latest="$APP_IMAGE_REPO:latest"
if [ -f "$ENV_FILE" ]; then
env_image="$(awk -F= '/^INVENTAR_APP_IMAGE=/{print $2}' "$ENV_FILE" | tail -n1 | tr -d ' ' || true)"
if [ -n "$env_image" ] && [ "$env_image" != "ghcr.io/aiirondev/inventarsystem:latest" ]; then
if [ -n "$env_image" ] && [ "$env_image" != "$default_latest" ]; then
APP_IMAGE_VALUE="$env_image"
return 0
fi
@@ -379,7 +380,7 @@ resolve_app_image() {
fi
if [ -n "$release_tag" ]; then
APP_IMAGE_VALUE="ghcr.io/aiirondev/inventarsystem:$release_tag"
APP_IMAGE_VALUE="$APP_IMAGE_REPO:$release_tag"
return 0
fi
+21 -2
View File
@@ -8,12 +8,12 @@ PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_DIR="$PROJECT_DIR/logs"
LOG_FILE="$LOG_DIR/update.log"
STATE_FILE="$PROJECT_DIR/.release-version"
REPO_SLUG="AIIrondev/Inventarsystem"
REPO_SLUG="AIIrondev/legendary-octo-garbanzo"
API_URL="https://api.github.com/repos/$REPO_SLUG/releases/latest"
BUNDLE_ASSET="inventarsystem-docker-bundle.tar.gz"
APP_IMAGE_ASSET_PREFIX="inventarsystem-image-"
ENV_FILE="$PROJECT_DIR/.docker-build.env"
APP_IMAGE_REPO="ghcr.io/aiirondev/inventarsystem"
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
DIST_DIR="$PROJECT_DIR/dist"
mkdir -p "$LOG_DIR"
@@ -234,10 +234,26 @@ load_release_image() {
log_message "Loading app image from release asset $image_asset"
curl -fL "$image_url" -o "$archive"
docker load -i "$archive" >> "$LOG_FILE" 2>&1
docker tag "$APP_IMAGE_REPO:$tag" "$APP_IMAGE_REPO:latest" >> "$LOG_FILE" 2>&1 || true
trap - RETURN
}
refresh_runtime_scripts_from_main() {
local start_url stop_url restart_url update_url
start_url="https://raw.githubusercontent.com/$REPO_SLUG/main/start.sh"
stop_url="https://raw.githubusercontent.com/$REPO_SLUG/main/stop.sh"
restart_url="https://raw.githubusercontent.com/$REPO_SLUG/main/restart.sh"
update_url="https://raw.githubusercontent.com/$REPO_SLUG/main/update.sh"
curl -fsSL "$start_url" -o "$PROJECT_DIR/start.sh" || log_message "WARNING: Could not refresh start.sh from main"
curl -fsSL "$stop_url" -o "$PROJECT_DIR/stop.sh" || log_message "WARNING: Could not refresh stop.sh from main"
curl -fsSL "$restart_url" -o "$PROJECT_DIR/restart.sh" || log_message "WARNING: Could not refresh restart.sh from main"
curl -fsSL "$update_url" -o "$PROJECT_DIR/update.sh" || log_message "WARNING: Could not refresh update.sh from main"
chmod +x "$PROJECT_DIR/start.sh" "$PROJECT_DIR/stop.sh" "$PROJECT_DIR/restart.sh" "$PROJECT_DIR/update.sh"
}
find_local_dist_image_archive() {
local tag="$1"
local archive
@@ -277,6 +293,7 @@ load_local_dist_image() {
log_message "Loading app image from local dist artifact: $archive"
if docker load -i "$archive" >> "$LOG_FILE" 2>&1; then
docker tag "$APP_IMAGE_REPO:$tag" "$APP_IMAGE_REPO:latest" >> "$LOG_FILE" 2>&1 || true
return 0
fi
@@ -342,6 +359,7 @@ EOF
docker compose --env-file "$ENV_FILE" pull nginx mongodb >> "$LOG_FILE" 2>&1
docker compose --env-file "$ENV_FILE" up -d --remove-orphans >> "$LOG_FILE" 2>&1
docker tag "$app_image" "$APP_IMAGE_REPO:latest" >> "$LOG_FILE" 2>&1 || true
}
verify_stack_health() {
@@ -460,6 +478,7 @@ main() {
log_message "Updating from release $latest_tag"
download_and_extract_bundle "$bundle_url" "$tmp_dir"
refresh_runtime_scripts_from_main
deploy "$latest_tag" "$meta_file"
if ! verify_stack_health; then
log_message "ERROR: Updated stack failed health check"