Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0859113
feat(git): add a guard that keeps git stacks from writing to RAM or t…
grantemsley Oct 3, 2026
6943f43
feat(git): add a locked-down git runner for git stacks
grantemsley Oct 3, 2026
6e58e2d
feat(git): store and validate a git stack's settings
grantemsley Oct 3, 2026
f3daff9
feat(git): clone, fetch and check out a git stack's repository safely
grantemsley Oct 3, 2026
f50435d
feat(git): save a git stack's local changes as a patch before discard…
grantemsley Oct 4, 2026
35e661a
feat(git): keep a git stack's managed override and .env out of its clone
grantemsley Oct 3, 2026
5b71fe3
feat(git): check a git stack before a deploy touches any container
grantemsley Oct 3, 2026
a5bcd61
feat(git): record which commit a git stack has deployed
grantemsley Oct 4, 2026
c1d1583
feat(git): deploy a git stack with compose.sh gitdeploy
grantemsley Oct 4, 2026
45c8573
feat(git): recreate a git stack's containers when its folder changes
grantemsley Oct 3, 2026
95866b6
feat(git): add the compose-git command
grantemsley Oct 3, 2026
184732a
docs: add a guide to git stacks
grantemsley Oct 3, 2026
909c390
feat(git): create missing external networks in a git deploy when the …
grantemsley Oct 4, 2026
dd4bb31
feat(git): prune the override's orphan services before a git deploy's…
grantemsley Oct 6, 2026
e418a1d
test(git): run the gitdeploy Bats tests without root, as CI does
grantemsley Oct 6, 2026
0efe816
fix(git): stop the deploy when Docker cannot say which names and port…
grantemsley Oct 7, 2026
9cfcaf9
fix(git): catch two services of the stack publishing the same port
grantemsley Oct 7, 2026
80ed389
fix(git): keep the deployed commit when reclone finds the branch rewr…
grantemsley Oct 7, 2026
a26b48a
fix(git): notice a repository override that a checkout removed
grantemsley Oct 7, 2026
ae4aee4
docs(git): say what reclone leaves running on the old clone
grantemsley Oct 7, 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
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Documentation for the Compose Manager plugin for Unraid.
- [User Guide](user-guide.md) - How to use Compose Manager
- [Configuration](configuration.md) - Settings and options
- [Profiles](profiles.md) - Docker Compose profiles support
- [Git Stacks](git-stacks.md) - Deploy stacks from a git repository

## Screenshots

Expand Down
397 changes: 397 additions & 0 deletions docs/git-stacks.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions source/compose.manager/include/Defines.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ function locate_compose_root($name)
defined('COMPOSE_CREDENTIAL_KEY_FILE') || define('COMPOSE_CREDENTIAL_KEY_FILE', '/boot/config/plugins/compose.manager/credentials.key');
defined('COMPOSE_DOCKER_CONFIG_DIR') || define('COMPOSE_DOCKER_CONFIG_DIR', '/var/tmp/compose-manager-docker-config');
defined('COMPOSE_GITHUB_DEVICE_DIR') || define('COMPOSE_GITHUB_DEVICE_DIR', '/var/tmp/compose-manager-github-device');
// Git-backed stacks: where Unraid reports the array state and the live mounts,
// and the folder under which disks, pools and shares are mounted.
defined('COMPOSE_UNRAID_VAR_INI') || define('COMPOSE_UNRAID_VAR_INI', '/var/local/emhttp/var.ini');
defined('COMPOSE_MOUNTS_FILE') || define('COMPOSE_MOUNTS_FILE', '/proc/self/mounts');
defined('COMPOSE_GIT_MNT_DIR') || define('COMPOSE_GIT_MNT_DIR', '/mnt');
defined('COMPOSE_GIT_HOME_DIR') || define('COMPOSE_GIT_HOME_DIR', '/var/tmp/compose-manager-git-home');
defined('COMPOSE_GIT_DEFAULT_CLONES_ROOT') || define('COMPOSE_GIT_DEFAULT_CLONES_ROOT', '/mnt/user/appdata/compose.manager/git');
// The docker CLI (the git deploy checks run it; tests point this at a scripted stand-in).
defined('COMPOSE_DOCKER_BIN') || define('COMPOSE_DOCKER_BIN', 'docker');
// compose.sh's per-stack lock files (its LOCK_DIR), which compose-git takes too.
defined('COMPOSE_LOCK_DIR') || define('COMPOSE_LOCK_DIR', '/var/run/compose.manager');

/**
* Reserved filename at the compose root level used by the plugin installer
Expand Down
38 changes: 38 additions & 0 deletions source/compose.manager/include/DockerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

require_once '/usr/local/emhttp/plugins/compose.manager/include/Defines.php';
require_once '/usr/local/emhttp/plugins/compose.manager/include/ProcessRunner.php';

/**
* Runs the docker CLI without a shell, with a time limit.
*/
final class DockerCommand
{
public const DEFAULT_TIMEOUT_SECONDS = 120;

/**
* @param string[] $args Arguments after "docker"
*/
public static function run(array $args, ?string $workingDirectory = null, int $timeoutSeconds = self::DEFAULT_TIMEOUT_SECONDS): ProcessResult
{
$environment = [
'PATH' => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
'HOME' => getenv('HOME') ?: '/root',
'LC_ALL' => 'C',
];
// Keep the registry credential compose.sh selected for this run, if any.
$dockerConfig = getenv('DOCKER_CONFIG');
if (is_string($dockerConfig) && $dockerConfig !== '') {
$environment['DOCKER_CONFIG'] = $dockerConfig;
}

return ProcessRunner::run(
array_merge([COMPOSE_DOCKER_BIN], $args),
$workingDirectory ?? '/',
$environment,
$timeoutSeconds
);
}
}
Loading
Loading