Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7e1a44c
fix: quiet routine dockerload reconnect warnings (#133)
mstrhakr Sep 4, 2026
838964f
feat: add option to not close editor modal on outside click (#126)
mstrhakr Sep 4, 2026
9b98f66
fix: support docker-compose stacks that resolve COMPOSE_FILE from .en…
mstrhakr Sep 4, 2026
2d0e9e1
Fix: Pass stack directory to resolveProjectEnvFilePath for indirect s…
mstrhakr Sep 6, 2026
32db329
Fix: Support relative envpath values in getExplicitEnvFilePath
mstrhakr Sep 6, 2026
9e190d7
Fix #3: Add tests for indirect stack envpath metadata discovery
mstrhakr Sep 6, 2026
1be1c0e
chore: update changelog for v2026.09.05.2104 [skip ci]
github-actions[bot] Sep 6, 2026
ab4b71c
fix: enforce string type for path parameter in getComposeFilePath method
mstrhakr Sep 6, 2026
c2f1c16
chore: update changelog for v2026.09.06.1706 [skip ci]
github-actions[bot] Sep 6, 2026
026da45
fix: dynamically resolve latest infozip package from Slackware reposi…
mstrhakr Sep 7, 2026
2a672e8
fix: enhance environment variable handling in build scripts and workf…
mstrhakr Sep 7, 2026
fef5e81
chore: update changelog for v2026.09.06.2116 [skip ci]
github-actions[bot] Sep 7, 2026
c475d9d
Release v2026.09.06.2116 [skip ci]
github-actions[bot] Sep 7, 2026
21d02be
Merge branch 'main' into dev
mstrhakr Sep 8, 2026
be17bf6
chore: sync pluginURL+README for dev branch [skip ci]
github-actions[bot] Sep 8, 2026
1e3fc5b
chore: update changelog for v2026.09.07.2056 [skip ci]
github-actions[bot] Sep 8, 2026
8681080
Release v2026.09.07.2056 [skip ci]
github-actions[bot] Sep 8, 2026
7c76f36
fix: enhance logging and background processing in docker_started script
mstrhakr Sep 8, 2026
77e2482
chore: update changelog for v2026.09.07.2121 [skip ci]
github-actions[bot] Sep 8, 2026
f800f17
Release v2026.09.07.2121 [skip ci]
github-actions[bot] Sep 8, 2026
dcf7353
fix: adjust css so effective command is visible in all themes
mstrhakr Sep 8, 2026
3c14e08
fix: stop forced rebuilds on compose update
mstrhakr Sep 9, 2026
028a122
fix: set remove-orphans checkbox checked state at render time instead…
mstrhakr Sep 13, 2026
3240231
chore: update changelog for v2026.09.13.1636 [skip ci]
github-actions[bot] Sep 13, 2026
3d5ec4c
Release v2026.09.13.1636 [skip ci]
github-actions[bot] Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ concurrency:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
PLUGIN_NAME: compose.manager
HOST_WORKSPACE_ROOT: ${{ github.workspace }}
HOST_SOURCE_PATH: ${{ github.workspace }}/source
HOST_ARCHIVE_PATH: ${{ github.workspace }}/archive
HOST_CACHE_PATH: ${{ github.workspace }}/archive/.build-cache

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ Thumbs.db

# Runtime config files (created at runtime, not source)
autoupdate.json
.env
103 changes: 75 additions & 28 deletions build.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTPUT_PATH="$SCRIPT_DIR/archive"
PLG_FILE="$SCRIPT_DIR/compose.manager.plg"
VERSIONS_FILE="$SCRIPT_DIR/versions.env"
BUILD_ENV_FILE="${BUILD_ENV_FILE:-$SCRIPT_DIR/.env}"

load_env_file() {
local env_file="$1"
if [[ -n "$env_file" && -f "$env_file" ]]; then
# shellcheck disable=SC1090
set -a
source "$env_file"
set +a
fi
}

load_env_file "$VERSIONS_FILE"
load_env_file "$BUILD_ENV_FILE"

# Environment override knobs for nested Docker / Unraid host setups.
HOST_WORKSPACE_ROOT="${HOST_WORKSPACE_ROOT:-}"
HOST_SOURCE_PATH="${HOST_SOURCE_PATH:-}"
HOST_ARCHIVE_PATH_OVERRIDE="${HOST_ARCHIVE_PATH:-}"
HOST_CACHE_PATH_OVERRIDE="${HOST_CACHE_PATH:-}"

# Argument parsing
while [[ $# -gt 0 ]]; do
Expand Down Expand Up @@ -44,7 +64,7 @@ if [[ -f "$VERSIONS_FILE" ]]; then
[[ "$line" =~ ^RESVG_SHA256=(.+)$ ]] && [[ -z "$RESVG_SHA256" ]] && RESVG_SHA256="${BASH_REMATCH[1]}"
done < "$VERSIONS_FILE"
fi
: "${COMPOSE_VERSION:=5.1.2}"
: "${COMPOSE_VERSION:=5.5.0}"
: "${RESVG_VERSION:=0.48.1}"

# Generate dev version with timestamp if requested
Expand Down Expand Up @@ -114,7 +134,13 @@ mkdir -p "$ARCHIVE_PATH"

# Host path for docker socket operations should be the actual unRAID path.
HOST_ARCHIVE_PATH="$ARCHIVE_PATH"
if [[ "$in_container" == true && -d "/code" ]]; then
if [[ -n "$HOST_ARCHIVE_PATH_OVERRIDE" ]]; then
HOST_ARCHIVE_PATH="$HOST_ARCHIVE_PATH_OVERRIDE"
elif [[ -n "$HOST_WORKSPACE_ROOT" ]]; then
HOST_ARCHIVE_PATH="${HOST_WORKSPACE_ROOT%/}/compose_plugin/archive"
elif [[ "$in_container" == true && -d "/mnt/user/code" ]]; then
HOST_ARCHIVE_PATH="/mnt/user/code/compose_plugin/archive"
elif [[ "$in_container" == true && -d "/code" ]]; then
# Map /code inside container to host path for Docker bind mounts (normally /mnt/user/code).
read -r host_root host_source < <(awk '$5=="/code" {for(i=1;i<=NF;i++){if($i=="-"){print $4, $(i+2); exit}}}' /proc/self/mountinfo 2>/dev/null || true)
if [[ -n "$host_root" && -n "$host_source" ]]; then
Expand Down Expand Up @@ -158,8 +184,18 @@ mkdir -p "$HOST_ARCHIVE_PATH" 2>/dev/null || true

CACHE_PATH="$ARCHIVE_PATH/.build-cache"
HOST_CACHE_PATH="$HOST_ARCHIVE_PATH/.build-cache"
if [[ -n "$HOST_CACHE_PATH_OVERRIDE" ]]; then
HOST_CACHE_PATH="$HOST_CACHE_PATH_OVERRIDE"
fi

SOURCE_PATH="$SCRIPT_DIR/source"
if [[ -n "$HOST_SOURCE_PATH" ]]; then
SOURCE_PATH="$HOST_SOURCE_PATH"
elif [[ -n "$HOST_WORKSPACE_ROOT" ]]; then
SOURCE_PATH="${HOST_WORKSPACE_ROOT%/}/compose_plugin/source"
elif [[ "$in_container" == true && -d "/mnt/user/code/compose_plugin/source" ]]; then
SOURCE_PATH="/mnt/user/code/compose_plugin/source"
fi

mkdir -p "$ARCHIVE_PATH"
mkdir -p "$HOST_ARCHIVE_PATH"
Expand Down Expand Up @@ -248,28 +284,15 @@ SOURCE_PATH="$TMP_SOURCE_PATH"
echo "Docker will mount SOURCE_PATH=$SOURCE_PATH"

# Determine a strategy to provide SOURCE_PATH to the container.
# First attempt direct bind mount; if that fails we fallback to tar stream.

build_cmd_direct=(docker run --rm --tmpfs /tmp \
-v "$HOST_ARCHIVE_PATH:/mnt/output:rw" \
-v "$HOST_CACHE_PATH:/mnt/cache:rw" \
-v "$SOURCE_PATH:/mnt/source:ro" \
-v "$HOST_CA_CERT:$CONTAINER_CA_CERT:ro" \
-e TZ=America/New_York \
-e COMPOSE_VERSION="$COMPOSE_VERSION" \
-e RESVG_VERSION="$RESVG_VERSION" \
-e RESVG_SHA256="$RESVG_SHA256" \
-e OUTPUT_FOLDER=/mnt/output \
-e DOWNLOAD_CACHE_DIR=/mnt/cache \
-e PKG_VERSION="$VERSION" \
-e PKG_BUILD="$BUILD_NUM" \
-e CA_CERT="$CONTAINER_CA_CERT" \
vbatts/slackware:latest \
sh -c 'test -f /mnt/source/pkg_build.sh')

if "${build_cmd_direct[@]}"; then
echo "Direct source mount works. Running build via direct mount..."
if ! docker run --rm --tmpfs /tmp \
# In nested Docker and CI, direct bind mounts are usually not visible to the daemon,
# so prefer the tar-stream path unless we are on a native host with a visible workspace.
USE_DIRECT_BIND=false
if [[ "$in_container" != true && -z "${CI:-}" && -d "$SOURCE_PATH" ]]; then
USE_DIRECT_BIND=true
fi

if [[ "$USE_DIRECT_BIND" == true ]]; then
build_cmd_direct=(docker run --rm --tmpfs /tmp \
-v "$HOST_ARCHIVE_PATH:/mnt/output:rw" \
-v "$HOST_CACHE_PATH:/mnt/cache:rw" \
-v "$SOURCE_PATH:/mnt/source:ro" \
Expand All @@ -284,11 +307,35 @@ if "${build_cmd_direct[@]}"; then
-e PKG_BUILD="$BUILD_NUM" \
-e CA_CERT="$CONTAINER_CA_CERT" \
vbatts/slackware:latest \
/mnt/source/pkg_build.sh; then
echo "Docker build failed."; exit 1
sh -c 'test -f /mnt/source/pkg_build.sh')

if "${build_cmd_direct[@]}"; then
echo "Direct source mount works. Running build via direct mount..."
if ! docker run --rm --tmpfs /tmp \
-v "$HOST_ARCHIVE_PATH:/mnt/output:rw" \
-v "$HOST_CACHE_PATH:/mnt/cache:rw" \
-v "$SOURCE_PATH:/mnt/source:ro" \
-v "$HOST_CA_CERT:$CONTAINER_CA_CERT:ro" \
-e TZ=America/New_York \
-e COMPOSE_VERSION="$COMPOSE_VERSION" \
-e RESVG_VERSION="$RESVG_VERSION" \
-e RESVG_SHA256="$RESVG_SHA256" \
-e OUTPUT_FOLDER=/mnt/output \
-e DOWNLOAD_CACHE_DIR=/mnt/cache \
-e PKG_VERSION="$VERSION" \
-e PKG_BUILD="$BUILD_NUM" \
-e CA_CERT="$CONTAINER_CA_CERT" \
vbatts/slackware:latest \
/mnt/source/pkg_build.sh; then
echo "Docker build failed."; exit 1
fi
else
echo "Direct bind-mount probe failed. Docker is remote or nested; falling back to tar-stream upload."
fi
else
echo "Direct mount failed, using tar stream fallback."
fi

if [[ "$USE_DIRECT_BIND" != true || ! "${build_cmd_direct[@]}" ]]; then
echo "Using tar-stream upload for Docker build (safe for nested Docker and CI)."
if ! tar -C "$SOURCE_PATH" -cf - . | docker run --rm --tmpfs /tmp -i \
-v "$HOST_ARCHIVE_PATH:/mnt/output:rw" \
-v "$HOST_CACHE_PATH:/mnt/cache:rw" \
Expand Down
2 changes: 1 addition & 1 deletion build_in_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# shellcheck disable=SC1091
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
[ -f "${SCRIPT_DIR}/versions.env" ] && source "${SCRIPT_DIR}/versions.env"
[ -z "$COMPOSE_VERSION" ] && COMPOSE_VERSION=5.1.2
[ -z "$COMPOSE_VERSION" ] && COMPOSE_VERSION=5.5.0
[ -z "$PKG_VERSION" ] && PKG_VERSION="$(date +%Y.%m.%d)"
[ -z "$PKG_BUILD" ] && PKG_BUILD="$(date +%H%M)"
mkdir -p "$PWD/archive/.build-cache"
Expand Down
42 changes: 10 additions & 32 deletions compose.manager.plg
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<!DOCTYPE PLUGIN [
<!ENTITY name "compose.manager">
<!ENTITY author "mstrhakr">
<!ENTITY version "2026.09.03">
<!ENTITY version "2026.09.13.1636">
<!ENTITY launch "Settings/&name;.settings">
<!ENTITY packageVER "&version;">
<!ENTITY packageMD5 "177e9a4a29681e70c3d706f48073f4c6">
<!ENTITY pkgBUILD "2117">
<!ENTITY packageMD5 "16931fab8f5ddbf3f3fa46a173ba9663">
<!ENTITY pkgBUILD "1636">
<!ENTITY packageName "&name;-&packageVER;-noarch-&pkgBUILD;">
<!ENTITY packagefile "&packageName;.txz">
<!ENTITY github "mstrhakr/compose_plugin">
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/main/&name;.plg">
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/dev/&name;.plg">
<!ENTITY packageURL "https://github.com/&github;/releases/download/v&version;/&packagefile;">
<!ENTITY pluginsPATH "/boot/config/plugins">
<!ENTITY pluginLOC "&pluginsPATH;/&name;">
Expand All @@ -36,34 +36,12 @@
>

<CHANGES>
###2026.09.03
- Features (compose): add wait-for-healthy and wait-timeout settings for stack management
- Features (compose): add follow-logs functionality for live log streaming during compose up by omitting the detach option
- Features (icon): enhance icon caching and management for Docker containers
- Bug Fixes (test): update follow-logs test to check for correct option syntax
- Bug Fixes (dashboard): improve handling of Docker container visibility during loading
- Bug Fixes (icon): harden cache writes and reuse docker ps snapshot
- Bug Fixes (ui): escape identity chooser attributes and restore main channel
- Bug Fixes (ui): show plain warning for multi-stack identity errors
- Bug Fixes (identity): allow logs when identity unresolved
- Bug Fixes (identity): block mutating actions until project identity is proven
- Bug Fixes (identity): add fail-closed legacy project identity resolver
- Bug Fixes (icon): pass data URIs straight to the browser instead of proxying
- Bug Fixes (dashboard): load icon helpers on Dashboard tile (#143)
- Bug Fixes (icon): write icon cache and Docker Manager seeds atomically
- Refactoring (dashboard): extract dashboard JS and hide Docker flash
- Tests (icon): cover icon cache regression cases
- Tests (identity): add regression suite for legacy migration and fail-closed behavior
- Tests (icon): remove both Docker Manager icon copies after seeding tests
- Chores: update changelog for v2026.09.03.2109 [skip ci]
- Chores: update changelog for v2026.09.01.2251 [skip ci]
- Chores: sync pluginURL+README for dev branch [skip ci]
- Chores: sync pluginURL+README for dev branch [skip ci]
- Chores (changelog): split concatenated refactoring entry
- Harden follow-session suspension and add regression checks
- Escape dashboard stack folder attributes
- Fix follow-logs CLI parsing and cleanup trap
- [View all changes](https://github.com/mstrhakr/compose_plugin/compare/v2026.08.31...v2026.09.03)
###2026.09.13.1636
- Bug Fixes: set remove-orphans checkbox checked state at render time instead of via setTimeout
- Bug Fixes: stop forced rebuilds on compose update
- Bug Fixes: adjust css so effective command is visible in all themes
- [PR #150](https://github.com/mstrhakr/compose_plugin/pull/150)
- [beta release diff](https://github.com/mstrhakr/compose_plugin/compare/v2026.09.03...v2026.09.13.1636)
</CHANGES>

<!-- The 'pre-install' script. -->
Expand Down
29 changes: 26 additions & 3 deletions deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,38 @@ trap 'echo "ERROR: command failed on line $LINENO" >&2' ERR
VERSION=""
DEV=false
REMOTE_HOSTS=()
USER_NAME="root"
REMOTE_DIR="/tmp"
USER_NAME="${USER_NAME:-root}"
REMOTE_DIR="${REMOTE_DIR:-/tmp}"
PACKAGE_PATH=""
SKIP_BUILD=false
COMPOSE_VERSION="5.1.2"
COMPOSE_VERSION=""
QUICK=false

if [[ -n "${REMOTE_HOSTS:-}" ]]; then
IFS=',' read -r -a REMOTE_HOSTS <<< "${REMOTE_HOSTS}"
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ARCHIVE_DIR="$SCRIPT_DIR/archive"
ENV_FILE="$SCRIPT_DIR/.env"

if [[ -f "$SCRIPT_DIR/versions.env" ]]; then
# shellcheck disable=SC1091
set -a
source "$SCRIPT_DIR/versions.env"
set +a
fi

if [[ -f "$ENV_FILE" ]]; then
# shellcheck disable=SC1090
set -a
source "$ENV_FILE"
set +a
fi

if [[ -z "${COMPOSE_VERSION:-}" ]]; then
COMPOSE_VERSION="5.1.2"
fi

in_container=false
if [[ -f "/.dockerenv" ]] || grep -qE '/docker|/lxc|/kubepods' /proc/1/cgroup 2>/dev/null; then
Expand Down
2 changes: 1 addition & 1 deletion source/compose.manager/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
**Compose Manager Plus**
**Compose Manager Plus (Beta)**

A plugin for unRAID that installs Docker Compose and adds a management interface to the web UI.
41 changes: 40 additions & 1 deletion source/compose.manager/compose.manager.settings.page
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,24 @@ $acePath = file_exists('/usr/local/emhttp/plugins/dynamix/javascript/ace/ace.js'
}

.compose-status-info {
color: var(--dynamix-sb-title-text-color);
color: var(--text-color, var(--dynamix-sb-title-text-color, #f2f2f2));
background: var(--dynamix-sb-body-bg-color, var(--background-color, #111));
}

#settings-discovery-mode-badge,
#compose-stack-discovery-mode-badge {
display: inline-block;
color: var(--text-color, var(--dynamix-sb-title-text-color, #f2f2f2));
background: var(--dynamix-sb-body-bg-color, var(--background-color, #111));
border: 1px solid var(--border-color, var(--dynamix-box-inner-div-border-color, #3b3b3b));
}

#settings-discovery-mode-toggle,
#compose-stack-discovery-mode-toggle {
color: var(--black, #111);
background: var(--brand-orange, #f15a24);
border: 1px solid var(--brand-orange, #f15a24);
box-shadow: none;
}

#aggressive-mode-wrapper {
Expand Down Expand Up @@ -2746,6 +2763,18 @@ $acePath = file_exists('/usr/local/emhttp/plugins/dynamix/javascript/ace/ace.js'
</dd>
</dl>

<dl>
<dt style="cursor: help;" onclick="toggleHelp(this)">_(Rebuild Images on Update by Default)_:</dt>
<dd>
<input type="checkbox" name="BUILD_ON_UPDATE_DEFAULT" id="BUILD_ON_UPDATE_DEFAULT" class="compose-toggle" <?= ($cfg['BUILD_ON_UPDATE_DEFAULT'] ?? 'false') == 'true' ? 'checked' : '' ?>>
<blockquote class="inline_help">
Default behavior for stack <em>Update</em> actions: when enabled, <code>--build</code> is added so services with a <code>build:</code> section are rebuilt from source.
Leave disabled for stacks that publish an image alongside a <code>build:</code> section &mdash; those should be pulled, not rebuilt.
This is a global default and can still be overridden per stack.
</blockquote>
</dd>
</dl>

<div class="title"><span class="left"><i class="fa fa-plus-square icon"></i>_(New Stack Configuration)_</span></div>
<p style="margin:0 0 15px 0;color:var(--dynamix-sb-title-text-color);font-size:0.95em;">Default settings applied automatically when creating new compose stacks.</p>

Expand Down Expand Up @@ -2905,6 +2934,16 @@ $acePath = file_exists('/usr/local/emhttp/plugins/dynamix/javascript/ace/ace.js'
<div class="title"><span class="left"><i class="fa fa-sliders icon"></i>_(Advanced Options)_</span></div>
<p style="margin:0 0 15px 0;color:var(--dynamix-sb-title-text-color);font-size:0.95em;">Performance tuning and troubleshooting options for advanced users.</p>

<dl>
<dt style="cursor: help;" onclick="toggleHelp(this)">_(Don't close editor modal on outside click)_:</dt>
<dd>
<input type="checkbox" name="DONT_CLOSE_EDITOR_MODAL_ON_OUTSIDE_CLICK" id="DONT_CLOSE_EDITOR_MODAL_ON_OUTSIDE_CLICK" class="compose-toggle" <?= ($cfg['DONT_CLOSE_EDITOR_MODAL_ON_OUTSIDE_CLICK'] ?? 'false') == 'true' ? 'checked' : '' ?>>
<blockquote class="inline_help">
When enabled, the Compose editor stays open when you click or drag on the backdrop outside the modal. This keeps editing from being interrupted while selecting or moving large blocks of text.
</blockquote>
</dd>
</dl>

<dl>
<dt style="cursor: help;" onclick="toggleHelp(this)">_(Debug Logging)_:</dt>
<dd>
Expand Down
2 changes: 2 additions & 0 deletions source/compose.manager/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ RUN_IN_BACKGROUND_DEFAULT="false"
REMOVE_ORPHANS_DEFAULT="false"
WAIT_FOR_HEALTHY_DEFAULT="false"
WAIT_FOR_HEALTHY_TIMEOUT_DEFAULT="300"
BUILD_ON_UPDATE_DEFAULT="false"
DISABLE_ACTION_WARNINGS="false"
NEW_STACK_USE_DEFAULT_COMPOSE_FILES="false"
NEW_STACK_OVERRIDE_MANAGEMENT_AUTOMATIC="true"
Expand All @@ -30,3 +31,4 @@ STACKS_DEFAULT_EXPANDED="false"
ONLY_EXPAND_RUNNING_STACKS="false"
COMPOSE_STATS_RATE_MODE="live"
COMPOSE_STATS_CUSTOM_INTERVAL_MS="1000"
DONT_CLOSE_EDITOR_MODAL_ON_OUTSIDE_CLICK="false"
Loading