237 Commits
v1.3.0 ... main

Author SHA1 Message Date
2ed50b9538 Merge pull request #1258 from mokibit/add-env-var-interpolation-to-keys
Implement environment variable interpolation to YAML dictionary keys
2025-07-01 00:15:05 +03:00
e97d446a04 Implement environment variable interpolation to YAML dictionary keys
`podman-compose` currently does not support interpolating environment
variables in dictionary keys, despite the compose file specification
indicating this capability.
See the relevant compose-spec documentation:
https://github.com/compose-spec/compose-spec/blob/main/12-interpolation.md

This feature is useful in `labels` or `environment` sections, where keys
can be user-defined strings. To enable interpolation, an alternate equal
sign syntax must be used, e.g.:
services:
  foo:
    labels:
      - "$VAR_NAME=label_value"

After this PR `podman-compose` will align more closely with the compose
file specification, allowing for the interpolation of environment
variables in dictionary keys.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-30 23:54:27 +03:00
9fe6e7f284 Merge pull request #1253 from whym/yaml-parse-error
Hide stack trace shown on YAML parse error by default
2025-06-30 16:06:11 +03:00
764efd360c Hide stack trace shown on YAML parse error by default
Fixes https://github.com/containers/podman-compose/issues/1139

Signed-off-by: Yusuke Matsubara <whym@whym.org>
2025-06-30 15:33:25 +03:00
b06224389e Merge pull request #1257 from astrojuanlu/migrate-pep-621
Migrate to PEP 621
2025-06-30 15:31:10 +03:00
0e37b31e45 Adapt release script
Signed-off-by: Juan Luis Cano Rodríguez <hello@juanlu.space>
2025-06-29 20:57:28 +02:00
3918f7e5f8 Add requires-python lower boundary
Signed-off-by: Juan Luis Cano Rodríguez <hello@juanlu.space>
2025-06-29 20:57:28 +02:00
d7cd02e3e9 Migrate to SPDX identifier for the license
Signed-off-by: Juan Luis Cano Rodríguez <hello@juanlu.space>
2025-06-29 20:57:28 +02:00
05f341b3c5 Python 2 is EOL
Signed-off-by: Juan Luis Cano Rodríguez <hello@juanlu.space>
2025-06-29 20:57:28 +02:00
f8d05babd7 Migrate to PEP 621
Signed-off-by: Juan Luis Cano Rodríguez <hello@juanlu.space>
2025-06-29 20:57:28 +02:00
8eb55735e9 Merge pull request #1250 from mokibit/fix-formatting-systemd-cmd-help
Fix formatting of description and help of `systemd` command
2025-06-27 11:22:02 +03:00
1c0c63aaf2 Fix formatting of description of systemd command
When running "podman-compose", the list of commands gets displayed.
The "systemd" command is an outlier, showing multiple lines, unintended
at this location.

This change moves the longer command description to its proper place,
that is, it gets shown when "podman-compose systemd --help" is
executed.

Signed-off-by: Cleber Rosa <crosa@redhat.com
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-27 11:15:34 +03:00
2f8dbdcd09 Remove assignment to variable that gets overriden and never used
Signed-off-by: Cleber Rosa <crosa@redhat.com>
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-26 20:54:54 +03:00
e789d98bf0 Merge pull request #1249 from p12tic/update-contributing
Update CONTRIBUTING.md
2025-06-26 14:59:42 +03:00
0de04b32bb CONTRIBUTING: Suggest contributors to split their commits
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-26 14:37:43 +03:00
d864e195ce CONTRIBUTING: Update instructions on commit message
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-26 14:37:41 +03:00
96ec9617f1 CONTRIBUTING: Update instructions for creating virtualenv
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-26 14:37:35 +03:00
b48317c22b Merge pull request #1248 from mokibit/add-short-syntax-for-env-variables
Implement short syntax for env variables in compose.yml "environment:"
2025-06-26 14:21:52 +03:00
0cbf70a4e9 Implement short syntax for env variables in compose.yml "environment:"
This commit allows compose file to directly use environment variable
values in "environment:" section when variables were set in `.env` file.
This functionality was missing, as docker-compose supports both: short
and variable interpolation syntax forms:
environment:
	- FOO
and
environment:
	- FOO=${FOO}
Relevant docker-compose documentation:
https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/
podman-compose is more compatible with docker-compose after this change.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-26 12:40:39 +03:00
7105198ae1 Merge pull request #1247 from whym/log-formatter-bug
Fixes #1237: Remove unnecessary 'or "text"'
2025-06-25 22:45:13 +03:00
8f9f6d0657 Remove unnecessary 'or "text"'
Fixes #1237

Signed-off-by: Yusuke Matsubara <whym@whym.org>
2025-06-25 21:53:34 +09:00
61392e9cba Merge pull request #1243 from mokibit/fix-dockerfile-definition
Fix dockerfile definition if directory name ends with ".git"
2025-06-17 19:53:15 +03:00
dd471c8918 Fix dockerfile definition if directory name ends with ".git"
After changes in 92f0a8583a, the
dockerfile parameter is igored if the (local) work directory's name ends
in `.git`.
This commit fixes the regression and adds more tests.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-17 19:43:29 +03:00
1113c833da Merge pull request #1242 from uosis/docker-compat
Add docker_compose_compat setting
2025-06-16 12:04:47 +03:00
4177bae807 Add docker_compose_compat setting
Signed-off-by: Uosis <uosisl+github@gmail.com>
2025-06-15 18:31:06 -06:00
fa2252801a Merge pull request #1241 from uosis/name-separator
Add support for using hyphens for name separation
2025-06-15 21:04:19 +03:00
6635b8b570 cleanup bool parsing
Signed-off-by: Uosis <uosisl+github@gmail.com>
2025-06-13 19:20:09 -06:00
8f55227167 add name_separator_compat
Signed-off-by: Uosis <uosisl+github@gmail.com>
2025-06-13 19:20:09 -06:00
9cde3993f2 Merge pull request #1238 from uosis/env-var-override
Add support for providing x-podman settings using environment variables
2025-06-11 22:38:25 +03:00
04155d0d09 Add documentation for env variables
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-11 22:31:56 +03:00
605495233e allow overriding x-podman using env vars 2025-06-11 22:27:45 +03:00
3e579f65f0 Merge pull request #1235 from p12tic/readme
Update README
2025-06-05 18:34:40 +03:00
034b86ea73 README: Remove basic usage section
There are plenty of resources on compose format, no need to repeat
anything. Beginners won't be helped by the examples and experienced
users will look into better places anyway.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 18:24:19 +03:00
bbdb63604e README: Update section on tests
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 18:24:18 +03:00
93371b0f4e README: Merge all repositories under single section
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 18:24:17 +03:00
27d1fc67a0 README: Add installation instructions on Debian
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 18:24:16 +03:00
77bc9c5602 Merge pull request #1234 from p12tic/release-notes
Release notes for 1.4.1
2025-06-05 17:20:19 +03:00
82dd0acab2 Release notes for 1.4.1
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-06-05 17:12:49 +03:00
0e4f686f4b Merge pull request #1231 from mokibit/fix-volume-bind-source
Fix relative host path resolution for volume bind mount source
2025-06-05 16:56:18 +03:00
0491269f53 Fix relative host path resolution for volume bind mount source
e03d675b9b broke relative host path
resolution by deleting os.chdir(). After this commit current working
directory is not relevant anymore.

Fixes e03d675b9b.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-06-05 16:46:07 +03:00
ee90712843 Merge pull request #1210 from jarovo/main
Add relabel option to secrets
2025-06-05 13:02:18 +03:00
82d7622c45 Add relabel option to secrets
On selinux enabled system, the secrets cannot be read without proper
relabeling or correct policy being set.

This patch enables user to instruc podman-copose to use :z or :Z podman
volume options to make podman relabel the file under bind-mount.

More info here:
https://unix.stackexchange.com/questions/728801/host-wide-consequences-of-setting-selinux-z-z-option-on-container-bind-mounts?rq=1

Signed-off-by: Jaroslav Henner <1187265+jarovo@users.noreply.github.com>
2025-06-05 00:13:58 +02:00
4c6df85efa Merge pull request #1224 from p12tic/podman-label
Expose io.podman.compose.service label
2025-05-29 22:18:42 +03:00
7b3276e5d7 Expose io.podman.compose.service label
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-29 22:01:35 +03:00
fc6bfc9931 Merge pull request #1223 from p12tic/github-mypy
.github: Run mypy as part of checks
2025-05-29 21:38:59 +03:00
949af2a50c .github: Run mypy as part of checks
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-29 21:23:21 +03:00
b650efbb33 Merge pull request #1222 from mokibit/print-full-dockerfile-path
Print full Dockerfile path instead of context on error
2025-05-28 17:34:45 +03:00
0b8b483cb7 Print full dockerfile path instead of context on error
Current error message does not provide the exact path where the
Dockerfile is being searched.

This commit distinguishes two types of errors when Dockerfile is not
found in build context:
- when the context does not have provided custom-named Dockerfile, the
path in the error message is absolute: "OSError: Dockerfile not found in
.../podman-compose/tests/integration/build_fail/context_no_file/custom-named-Dockerfile"
- when the context does not have any Dockerfile, the path in the error
message is: "OSError: Dockerfile not found in
.../podman-compose/tests/integration/build_fail/context_no_file"
Only this error message was used before the fix.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
Co-authored-by: Siteshwar Vashisht <svashisht@redhat.com>
2025-05-28 16:19:38 +03:00
0dcc864fdd Merge pull request #1205 from mokibit/add-missing-init-py-files
tests/integration: Add missing __init__.py files to actually run tests and fix the broken ones
2025-05-26 22:27:48 +03:00
56238b10e3 tests/integration: Fix service_scale tests
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-26 18:19:11 +03:00
d4ebf62e0e tests/integration: Fix lifetime tests
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-26 18:19:11 +03:00
83c7e9462e tests/integration: Add missing __init__.py files to actually run tests
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-24 22:09:30 +03:00
835e3abe95 Merge pull request #1220 from p12tic/types
Enforce types using mypy
2025-05-24 17:35:52 +03:00
248a63ebb0 test-requirements: Upgrade ruff
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:26:42 +03:00
efea0ee652 Address unused argument warnings
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:26:31 +03:00
3c2978c9ca examples: Add type annotations
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:19:29 +03:00
5765e5306b Use correct logging methods
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:19:29 +03:00
0be50ffdfb Fix return value from compose_systemd()
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:19:29 +03:00
1eae76ddca Add return type annotations to test_utils.py
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:19:29 +03:00
6c46678082 Fix mypy warnings
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:19:29 +03:00
a3f48f830d tests/integration: Add type annotations
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:11:38 +03:00
dedb081550 tests/unit: Add type annotations
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:11:36 +03:00
ea22227625 Add mypy configuration
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 17:11:33 +03:00
6b2665683c Merge pull request #1211 from p12tic/tests-importable-directories
Move tests to directories that can be imported
2025-05-24 17:09:03 +03:00
58df8497aa Move tests to directories that can be imported
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 16:47:49 +03:00
741cb008c8 Merge pull request #1213 from p12tic/fixes
Miscellaneous code quality fixes
2025-05-24 16:05:18 +03:00
39e21d8c11 Remove extraneous await on non-async function
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 15:29:53 +03:00
02166f584a Use more standard call to list.append
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 15:29:53 +03:00
8aeeafb98c Rename redefined variables
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 15:29:53 +03:00
9162fe6438 Remove unused code
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-24 15:29:49 +03:00
cc10a61017 Merge pull request #1218 from mokibit/fix-build-ssh-path
Fix build ssh path to be relative to directory of compose file
2025-05-24 15:25:31 +03:00
08d06df0f2 Fix build ssh path to be relative to directory of compose file
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-24 12:58:59 +03:00
c26e188991 Merge pull request #1214 from mokibit/fix-cmd-healthcheck
Fix CMD healthchecks running with `/bin/sh`
2025-05-21 15:52:43 +03:00
a983129e88 tests/unit: Add unit tests for fixing CMD healthcheck
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-20 16:54:25 +03:00
76b3055934 Fix CMD healthchecks running with /bin/sh
Signed-off-by: Ben Krieger <ben.krieger@intel.com>
2025-05-20 16:54:25 +03:00
f5e3162e91 Merge pull request #1212 from p12tic/normalize-depends-unittest
tests: Rewrite test_normalize_depends_on to unittest
2025-05-19 18:26:45 +03:00
225999eab1 tests: Rewrite test_normalize_depends_on to unittest
This test was forgotten about during initial migration.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-19 17:56:28 +03:00
b86f8b1d61 Merge pull request #1201 from Norbiros/feat/custom-pod-name
Allow specifying custom pod name in `--in-pod`
2025-05-18 18:59:58 +03:00
3d47849d28 Allow specifying custom pod name in --in-pod
Fixes #958: missing or incorrect use of --in-pod and pod-args
Fixes #693: --in-pod 'name' no function

Signed-off-by: norbiros <norbiros@protonmail.com>
Signed-off-by: Norbiros <norbiros@protonmail.com>
2025-05-18 18:46:15 +03:00
bfaf77a506 Merge pull request #1208 from mokibit/reset-depends-on
Fix reset tag attribute to also reset `depends_on` parameter
2025-05-18 18:42:52 +03:00
0c1c4ffea9 Fix reset tag attribute to also reset depends_on parameter
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-16 22:33:00 +03:00
98f065b3e2 Merge pull request #1203 from mokibit/fix-test-paths-for-reset-override-tags
tests/integration: Fix paths to compose.yaml files for testing override and reset tags
2025-05-16 22:23:14 +03:00
6e30673260 tests/integration: Fix paths for testing override and reset tags
Tests were not run due to missing __init__.py files.
This commit adds missing files and fixes paths to compose.yaml files.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-05-16 21:51:11 +03:00
9c09789948 Merge pull request #1193 from marat2509/main
feat(systemd): add unregister command to remove systemd service registration
2025-05-13 02:22:37 +03:00
01214fa013 Add unregister command to remove systemd service registration
Signed-off-by: marat2509 <marat2509@users.noreply.github.com>
2025-05-12 22:53:09 +03:00
bd29caa797 Release 1.4.0
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-10 15:24:32 +03:00
f0928dd399 Merge pull request #1197 from p12tic/release
Release notes for 1.4.0
2025-05-10 15:23:07 +03:00
6c9c09197a Release notes for 1.4.0
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-10 15:03:54 +03:00
cda84f439f Merge pull request #1181 from zeyugao/main
Return non-zero exit_code on failure when doing `up -d`
2025-05-10 14:44:41 +03:00
67616bdaac Handle exit code when compose up -d
Signed-off-by: Elsa <zeyugao@outlook.com>
2025-05-10 14:38:53 +03:00
7497692b19 Merge pull request #1184 from schnell18/main
Fix service_healthy condition enforcing
2025-05-10 14:20:06 +03:00
782c44d4c3 tests: Style cleanup
Signed-off-by: Justin Zhang <schnell18@gmail.com>
2025-05-10 14:12:28 +03:00
d7762a54f0 Fix service_healthy condition enforcing
Skip dependency health check to avoid compose-up hang for podman prior
to 4.6.0, which doesn't support --condition healthy.

Signed-off-by: Justin Zhang <schnell18@gmail.com>
2025-05-10 14:12:27 +03:00
eba2ca2695 Skip running compose-down during up when there are no active containers
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-05-10 14:12:18 +03:00
abe5965c9a tests: Improve reliability of network tests
The test did fail on my laptop with podman 5.4.1.

Signed-off-by: Justin Zhang <schnell18@gmail.com>
2025-05-10 14:10:22 +03:00
9e0da82726 Change compose-up to create then start container to avoid double exec
Signed-off-by: Justin Zhang <schnell18@gmail.com>
2025-05-10 13:58:23 +03:00
6acdafd5b1 Merge pull request #1190 from gtebbutt/abort-on-failure
Add `--abort-on-container-failure` option
2025-05-10 13:51:23 +03:00
8638eb9b6d tests: Test selected env variables to improve robustness
Signed-off-by: Justin Zhang <schnell18@gmail.com>
2025-05-10 13:46:26 +03:00
e1d938ffa6 Add --abort-on-container-failure
Signed-off-by: gtebbutt <5956226+gtebbutt@users.noreply.github.com>
2025-05-10 13:41:29 +03:00
d532e09d7d Merge pull request #1189 from mokibit/add-merge-reset-override
Implement `override` and `reset` analog to docker-compose
2025-05-08 01:16:15 +03:00
1dab256cdd tests/integration: Add override tag attribute test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
2a33ef5c79 tests/integration: Add override tag service test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
5ab734026c tests/integration: Add reset tag attribute test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
35dc395483 tests/integration: Add reset tag service test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
38a9263424 integration/tests: Move 'volumes_merge' tests to 'merge' directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
cbe9587973 Implement override and reset analog to docker-compose
Corresponding Docker compose file documentation:
https://docs.docker.com/reference/compose-file/merge/

Signed-off-by: Sebastian Sellmeier <mail@sebastian-sellmeier.de>
Co-authored-by: Monika Kairaityte <monika@kibit.lt>
2025-04-30 23:37:05 +03:00
8bb43100b1 Merge pull request #1182 from zeyugao/pids_limit
Implement pids_limit
2025-04-21 23:50:31 +03:00
98f166d2e4 Implement pids_limit
Signed-off-by: Elsa <zeyugao@outlook.com>
2025-04-21 22:51:37 +03:00
150ab02446 Merge pull request #1187 from rgasquet/feature/add-cpuset-option
Feature: add cpuset option
2025-04-21 22:49:08 +03:00
ff58a0bff0 Add newsfragment
Signed-off-by: Romain Gasquet <romain.gasquet@neutron.fr>
2025-04-19 14:33:15 +02:00
8d899ebb65 Feature: add cpuset option
Signed-off-by: Romain Gasquet <romain.gasquet@neutron.fr>
2025-04-19 14:10:30 +02:00
342a39dcfe Merge pull request #1179 from knarfS/fix_port_cmd
Fix port command
2025-04-14 18:05:53 +03:00
d6b8476573 Merge pull request #1180 from knarfS/add_rmi_arg
Add rmi argument for down command
2025-04-14 18:04:09 +03:00
ae41ef08c3 tests/integration: Improve tests for port command
Refs #778 and #1039

Signed-off-by: Frank Stettner <frank-stettner@gmx.net>
2025-04-10 07:51:39 +02:00
da46ee3910 Fix port command for dynamic host ports
Use `podman inspect` to get the actual host ports rather echoing the
defined ports from the compose yml.

Fixes #778 and #1039

Signed-off-by: Frank Stettner <frank-stettner@gmx.net>
2025-04-08 13:57:19 +02:00
d80c31f578 tests/integration: Add tests for up and down command
Refs #387

Signed-off-by: Frank Stettner <frank-stettner@gmx.net>
2025-04-08 13:53:27 +02:00
cefa68dc75 Implement rmi argument for down command
Fixes #387

Signed-off-by: Frank Stettner <frank-stettner@gmx.net>
2025-04-08 13:53:27 +02:00
2e46ff0db2 Merge pull request #1159 from me-coder/container_scaling_update
Updates handling of scale/replicas parameter in CLI and compose file
2025-04-08 02:54:32 +03:00
fbc4c7da80 Integration tests for container scaling changes
Signed-off-by: Yashodhan Pise <technoy@gmail.com>
2025-04-08 01:42:03 +03:00
11879d3e94 Updates handling of scale/replicas through CLI & compose file
Signed-off-by: Yashodhan Pise <technoy@gmail.com>
2025-04-08 01:37:15 +03:00
27cf8da06f Addition of relevant newsfragments file
Signed-off-by: Yashodhan Pise <technoy@gmail.com>
2025-04-05 20:32:58 +05:30
10a30ba24a Merge pull request #1173 from mokibit/automate-ulimit-test
tests/integration: Automate manual `ulimit` test
2025-04-04 17:12:42 +03:00
a1be62fd31 tests/integration: Automate manual ulimit test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-04 16:31:26 +03:00
15bf02a004 Merge pull request #1175 from mokibit/automate-volumes-merge-test
tests/integration: Automate manual `volumes_merge` test
2025-04-04 16:31:03 +03:00
e45b5d5063 tests/integration: Automate manual volumes_merge test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-04-04 15:22:45 +03:00
c46ecb226b Merge pull request #1171 from mokibit/fix-git-build-url-context
Fix using git URL as build context
2025-03-31 00:26:56 +03:00
e04b8f3a60 tests/integration: Add integration test for buid git URL as context
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-30 21:56:55 +03:00
815450aba9 tests/unit: Add test for buid git URL as context
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-30 21:56:55 +03:00
92f0a8583a Fix using git URL as build context
Podman-compose actually did not work with git URL as build context.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-30 21:56:55 +03:00
5f4fc4618c Add os.path.normpath to normalize dockerfile pathname
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-28 22:28:30 +02:00
4d899edeb3 Merge pull request #1166 from piotr-kubiak/megre-args
Allow merging of args in both list and dict syntax
2025-03-24 13:35:31 +02:00
f9489afaf5 Allow merging of args in both list and dict syntax
Signed-off-by: Piotr Kubiak <piotr-kubiak@users.noreply.github.com>
2025-03-24 13:31:19 +02:00
7d7533772b Merge pull request #1165 from drachenfels-de/fix-project-name-interpolation
Fix `COMPOSE_PROJECT_NAME` interpolation
2025-03-20 19:26:03 +02:00
65b455f081 Fix project name evaluation order
The COMPOSE_PROJECT_NAME environment variable must override the
top-level name: attribute in the Compose file.

The precedence order is defined in the docker compose documentation
https://docs.docker.com/compose/how-tos/project-name/#set-a-project-name

Signed-off-by: Ruben Jenster <r.jenster@drachenfels.de>
2025-03-20 12:07:07 +01:00
1aa750bacf integration/tests: Test project name override with COMPOSE_PROJECT_NAME env variable
Signed-off-by: Ruben Jenster <r.jenster@drachenfels.de>
2025-03-20 12:07:07 +01:00
98b9bb9f8e Fix interpolation for COMPOSE_PROJECT_NAME
Fixes #1073

Signed-off-by: Ruben Jenster <r.jenster@drachenfels.de>
2025-03-20 12:07:07 +01:00
170411de8b test/integration: Test COMPOSE_PROJECT_NAME interpolation
Refs #1073

Signed-off-by: Ruben Jenster <r.jenster@drachenfels.de>
2025-03-20 12:07:01 +01:00
0cf1378cb5 Merge pull request #1148 from mokazemi/fix/sigint-down
Handle SIGINT when running "up" command to shutdown gracefully
2025-03-20 00:14:11 +02:00
f5a6df6dc4 added changes to release notes
Signed-off-by: Mohammad Kazemi <mokazemi@disroot.org>
2025-03-19 16:02:34 +03:30
f106ea0c01 modifications to pass pylint test
Signed-off-by: Mohammad Kazemi <mokazemi@disroot.org>
2025-03-19 15:55:55 +03:30
b748c2666c add try-except block to handle error in case of shutdown error
Signed-off-by: Mohammad Kazemi <mokazemi@disroot.org>
2025-03-19 15:55:50 +03:30
3973c476c4 catch SIGINT signal properly in 'up' function and call compose 'down' function for a graceful shutdown
Signed-off-by: Mohammad Kazemi <mokazemi@disroot.org>
2025-03-19 15:55:38 +03:30
8b1bd0123c Merge pull request #1168 from underground-software/build_exit
Properly surface errors from build commands
2025-03-19 12:50:16 +02:00
2e7d83f7f0 Properly surface errors from build commands
the commit 38b13a3 ("Use asyncio for subprocess calls") broke the way
exit codes are reported from the podman compose build command.

The tasks are awaited as they finish which means that if a later build
finishes sucessfully after a failing build, it overwrites status.

Previously the `parse_return_code` function would skip updating the status
if the new return code was zero, but in removing it, this logic was not
carried forward.

Fixes: 38b13a3 ("Use asyncio for subprocess calls")
Signed-off-by: charliemirabile <46761267+charliemirabile@users.noreply.github.com>
2025-03-18 21:49:55 -04:00
52e2912e0b Merge pull request #1157 from mokibit/automate-selinux-test
test/integration: Automate manual `selinux` test
2025-03-11 18:15:55 +02:00
8ef537e247 test/integration: Automate manual selinux test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-06 13:04:53 +02:00
04fcc26a79 Merge pull request #1117 from rjeffman/no_exception_if_service_is_not_in_compose
Don't raise exception on inexistent services in 'down' command
2025-03-05 22:17:10 +02:00
d4760712b7 Don't raise exception on inexistent services in 'down' command
When running 'podman-compose down <service>', if service is not part of
the compose, a KeyError exception is raised in function 'get_excluded'.

By only allowing evaluation of services that exist in the compose
provides a cleaner and gentler exit for this case.

Signed-off-by: Rafael Guterres Jeffman <rjeffman@redhat.com>
2025-03-05 15:49:52 -03:00
7c61f24467 Merge pull request #1158 from mokibit/automate-uidmaps-test
test/integration: Automate manual `uidmaps` test
2025-03-04 23:41:55 +02:00
202c3771a9 test/integration: Automate manual uidmaps test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-03-04 22:28:50 +02:00
a54f0fa573 Merge pull request #1149 from AlexandreAANP/fix/windows-asyncio-loop
Fix event loop handling for Windows platform in compose_up function
2025-03-01 16:43:26 +02:00
3353697402 Merge pull request #1152 from IamTheFij/config-quiet
Add quiet flag to podman-compose config
2025-03-01 16:42:20 +02:00
ca1b59c449 Merge pull request #1153 from IamTheFij/dco-hook
Add hook to check for signoff in commit messages
2025-03-01 16:39:50 +02:00
b9f27795c0 Add hook to check for signoff in commit messages
Since this is checked on PR, it could also be checked at commit so users can avoid making commits to
the tree without expected documentation.

Signed-off-by: Ian Fijolek <ian@iamthefij.com>
2025-02-28 13:05:54 -08:00
4cd1642be0 Add quiet flag to podman-compose config
This skips printing and is useful for validating config files.

Signed-off-by: Ian Fijolek <ian@iamthefij.com>
2025-02-28 12:48:08 -08:00
fd401331e5 added release note to newsfragment directory
Signed-off-by: Alexandre Pita <alexandreanpita@gmail.com>
2025-02-27 11:45:38 +00:00
37b27fa233 Refactor event loop handling to simplify logic for Windows platforms
Signed-off-by: Alexandre Pita <alexandreanpita@gmail.com>
2025-02-26 17:28:59 +00:00
976847ef9b Merge pull request #1143 from italomaia/bug/use-ruff
Bug: replaced black with ruff on pre-commit
2025-02-26 18:21:31 +02:00
c6b3d497d6 Adds lint exclusions already ignored by the code
Added flake8 excludes to rules that are already ignored by the current
code to avoid validation issues with code that has already been
approved. Added pylint disable to line with lint offense already
accepted.

Signed-off-by: Italo Maia <italo.maia@gmail.com>
2025-02-26 17:57:34 +02:00
10ad739746 Replaces black with ruff on pre-commit-config
Current python files are already compatible with ruff, while very
incompatible with black standard therefore, this change just enforces
the reality of the codebase. Without it, pre-commit and the ci will
fight one-another with different formatting.

Signed-off-by: Italo Maia <italo.maia@gmail.com>
2025-02-26 17:57:20 +02:00
784d798dac Fix event loop handling for Windows platform in compose_up function
Signed-off-by: Alexandre Pita <alexandreanpita@gmail.com>
2025-02-26 14:38:46 +00:00
dd01d039bf Merge pull request #1140 from whym/rename-comment
Fix comment, add tests, improve coding style
2025-02-25 02:02:23 +02:00
81a0a5933e Add more logging tests
Signed-off-by: Yusuke Matsubara <whym@whym.org>
2025-02-25 01:52:45 +02:00
c289a3b827 Fix logging test coding style
Signed-off-by: Yusuke Matsubara <whym@whym.org>
2025-02-25 01:52:39 +02:00
baccce4f3f Fix comments related to logging
Signed-off-by: Yusuke Matsubara <whym@whym.org>
2025-02-25 01:38:41 +02:00
07af8488db Merge pull request #1147 from joern19/main
Allow configuration of interface_name
2025-02-24 01:26:38 +02:00
cbc5a8c8b3 Add newsfragment for interface_name option
Signed-off-by: Jörn Hirschfeld <joern@hirschfeld.tech>
2025-02-23 17:08:06 +01:00
aeaceed7ba integration test for x-podman.interface_name option
Signed-off-by: Jörn Hirschfeld <joern@hirschfeld.tech>
2025-02-23 17:08:00 +01:00
b1eb558b41 Document existence of x-podman.interface_name
Signed-off-by: Jörn Hirschfeld <joern@hirschfeld.tech>
2025-02-23 17:04:10 +01:00
1cdc9e6552 interface_name can be specified in net_config_
Signed-off-by: Jörn Hirschfeld <joern@hirschfeld.tech>
2025-02-23 17:04:10 +01:00
2f8ed2137c Merge pull request #1144 from mokibit/automate-secrets-tests
test/integration: Automate manual `secrets` test
2025-02-20 09:57:11 +02:00
838957b902 test/integration: Automate manual 'secrets' test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-19 21:42:52 +02:00
15380a809d Merge pull request #1135 from rpluem-vf/keep_fds_open
Do not close file descriptors when executing podman
2025-02-18 13:26:15 +02:00
d4e5859370 Do not close file descriptors when executing podman
Do not close file descriptors when executing podman. This allows
externally created file descriptors to be passed to containers.
These file descriptors might have been created through systemd
socket activation. See also
https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md#socket-activation-of-containers

Signed-off-by: Ruediger Pluem <ruediger.pluem@vodafone.com>
2025-02-12 11:35:51 +01:00
593d7c825e Merge pull request #1138 from mokibit/automate-seccomp-test
tests/integration: Automate manual `seccomp` test
2025-02-07 22:46:39 +02:00
bfba7ba32d tests/integration: Automate manual seccomp test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-07 22:38:58 +02:00
fe9be2d98f Merge pull request #1133 from neocturne/pod-args
Implement x-podman.pod_args to override --pod-args default
2025-02-07 20:59:36 +02:00
43a2f1d01f Implement x-podman.pod_args to override --pod-args default
Allow setting an argument list as x-podman.pod_args to override the
default value `--infra=false --share=`. `--pod-args` passed on the command
line takes precedence over the value set in docker-compose.yml; the values
are not merged.

Fixes #1057.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
2025-02-07 12:11:19 +01:00
aa47a373ca Merge pull request #1132 from mokibit/describe-test_pid
tests/integration: Describe `pid` test
2025-02-06 15:29:42 +02:00
eaec19336f tests/integration: Describe pid test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-06 15:16:44 +02:00
34bee28bb8 Merge pull request #1131 from mokibit/automate-test-no_services
tests/integration: Automate manual `no_services` test
2025-02-05 20:53:38 +02:00
bfea139362 tests/integration: Automate manual no_services test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-05 20:47:59 +02:00
4a81bce2a5 Merge pull request #1130 from mokibit/automate-nets_test_ip
tests/integration: Automate manual `nets_test_ip` test
2025-02-05 20:44:07 +02:00
e626f15eff tests/integration: Automate manual nets_test_ip test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-05 19:31:43 +02:00
974250caa5 Merge pull request #1128 from mokibit/automate-nets_test3
tests/integration: Automate manual `nets_test3` test
2025-02-03 22:59:45 +02:00
29404af723 tests/integration: Automate manual 'nets_test3' test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-02-03 19:04:15 +02:00
d1ba2f4c7d Merge pull request #1124 from notdian/file_not_found_error
remove incorrect os.chdir, handle relative extends/includes
2025-01-31 01:48:13 +02:00
e03d675b9b Remove incorrect os.chdir call to fix folder error
Signed-off-by: notdian <dian@fishekqi.com>
2025-01-31 01:24:24 +02:00
51d180d2d0 Merge pull request #1120 from mokibit/inform-user-to-use-newer-python
Throw a readable error on too old Python
2025-01-27 21:53:24 +02:00
9c905f9012 Merge pull request #1116 from Zeglius/dockerfile_inline
Add support for dockerfile_inline
2025-01-27 21:52:05 +02:00
bdb3e4e984 Throw a readable error on too old Python
podman-compose v1.0.6 is the last to support Python3.6. When newer
podman-compose version is used with too old Python, podman-compose gives
only a confusing error. This commit gives a clear message to use
upgraded Python version.
A descriptive error can not be thrown, as line "from __future__ imports"
must occur at the beginning of the file, but older Python (older than
Python3.7) does not recognize __future__ and throws an error
immediately.
Therefore, a comment is used to inform the user to update his Python
version.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-27 21:49:50 +02:00
105e390f6b Add support for dockerfile_inline
Fixes #864

Signed-off-by: Zeglius <33781398+Zeglius@users.noreply.github.com>
2025-01-27 21:45:42 +02:00
d79ff01e77 Merge pull request #1113 from mokibit/categorize-integration-tests
tests/integration: Categorize integration tests
2025-01-23 02:17:08 +02:00
d9ef3d2cc6 tests/integration: Add missing __init__.py for network_scoped_aliases
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
d23ef4f481 tests/integration: Add missing __init__.py for build_labels test
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
b685bce400 tests/integration: Move test utils to one test_utils file
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
7d5bf645f6 tests/integration: Move test "vol" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
9f7ae38bac tests/integration: Move test "ports" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
3cee4e015c tests/integration: Move test "config" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
498a1994ce tests/integration: Move test "env" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
488908f809 tests/integration: Move test "env_file" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
f7bcc4221e tests/integration: Move test "up_down" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
a73df712cc tests/integration: Move test "build_ulimits" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
50dc19f5f8 tests/integration: Move test "network" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
9029dce0f6 tests/integration: Move test "nets_test2" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
a8282c77d6 tests/integration: Move test "nets_test1" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
f4b775c7e4 tests/integration: Move test "nethost" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
adf30e0475 tests/integration: Move test "multicompose" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
41675c3916 tests/integration: Move test "ipam_default" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
6caf2eae42 tests/integration: Move test "interpolation" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
3093b00326 tests/integration: Move test "include" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
1c21d655ba tests/integration: Move test "in_pod" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
18e5fd64f3 tests/integration: Move test "filesystem" to corresponding dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
24bdfd1e17 tests/integration: Move test "extends_w_file_subdir" to corresp. dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
c2d3e156c2 tests/integration: Move test "extends_w_file" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
ba95100cff tests/integration: Move test "extends_w_empty_service" to corresp. dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:11:46 +02:00
6022669991 tests/integration: Move test "extends" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:01:44 +02:00
e29df71d42 tests/integration: Move test "exit_from" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 02:01:44 +02:00
21b9d385b2 tests/integration: Move test "deps" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
4c17ce2434 tests/integration: Move test "default_net_behavior" to corresponding dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
09d54e9dcc tests/integration: Move test "build_secrets" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
f1dd9b374e tests/integration: Move test "build_fail" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
87af67fe94 tests/integration: Move test "network_scoped_aliases" to corresp. dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
f1d663874e tests/integration: Move test "build" to corresponding directory
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
69ffff33f6 tests/integration: Move test "additional_contexts" to corresp. dir
Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-01-23 01:48:47 +02:00
f376700972 Merge pull request #1104 from rjeffman/disable_dns
Add support for disable_dns, dns and ignore on network creation
2025-01-19 19:41:30 +02:00
9be3ec985f Add network "dns" support
This patch add 'x-podman.dns' option to the 'network' configuration,
allowing users to set the DNS resolvers for a defined network.

Signed-off-by: Rafael Guterres Jeffman <rjeffman@redhat.com>
2025-01-17 13:58:13 -03:00
6e642dca1f Add network "disable-dns" support
Podman allows to create a network disabling the DNS plugin with
'--disable-dns', but this option is not available in the compose spec.

This patch add 'x-podman.disable-dns' to the podman-compose options,
allowing the creation of a network with the DNS plugin disabled.

Signed-off-by: Rafael Guterres Jeffman <rjeffman@redhat.com>
2025-01-17 12:14:15 -03:00
0f2c717655 Merge pull request #1110 from indrat/1105-service-env-vars
expand service environment_variables before adding to subs_dict
2025-01-16 20:13:39 +02:00
2aa042b9c7 expand service environment_variables before adding to subs_dict
Also modifies an existing integration test to expect an empty string as `docker-compose` warns that
`ZZVAR3` is not set and defaults it to an empty string per the acutal output here.

```yaml
$ docker-compose -f container-compose.load-.env-in-project.yaml config
WARN[0000] The "ZZVAR3" variable is not set. Defaulting to a blank string.
name: project
services:
  app:
    command:
      - /bin/busybox
      - sh
      - -c
      - env | grep ZZ
    environment:
      ZZVAR1: This value is loaded but should be overwritten
      ZZVAR2: This value is loaded from .env in project/ directory
      ZZVAR3: ""
...
```

Signed-off-by: indra <indra.talip@gmail.com>
2025-01-16 21:00:49 +11:00
a177603661 Merge pull request #1108 from bailsman/fix-398
Fixes #398: exclude deps on up if --no-deps
2025-01-15 23:51:37 +02:00
bc4177fbdc Exclude dependent containers on up if --no-deps.
Fixes #398.

Signed-off-by: Emanuel Rietveld <e.j.rietveld@gmail.com>
2025-01-15 22:32:28 +01:00
8206cc3ea2 Run should not add --requires if --no-deps.
Fixes #717.

Signed-off-by: Emanuel Rietveld <e.j.rietveld@gmail.com>
2025-01-15 22:29:51 +01:00
60ac5e43b3 Merge pull request #1107 from containers/dependabot/pip/virtualenv-20.26.6
build(deps): bump virtualenv from 20.25.1 to 20.26.6
2025-01-13 22:17:09 +02:00
48c6c38fcd build(deps): bump virtualenv from 20.25.1 to 20.26.6
Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.25.1 to 20.26.6.
- [Release notes](https://github.com/pypa/virtualenv/releases)
- [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pypa/virtualenv/compare/20.25.1...20.26.6)

---
updated-dependencies:
- dependency-name: virtualenv
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 18:24:07 +00:00
84f1fbd622 Merge pull request #1101 from p12tic/post-release-fixes
RELEASING: Fix release command
2025-01-07 21:24:36 +02:00
ac5291e10b RELEASING: Fix release command
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2025-01-07 21:18:35 +02:00
235 changed files with 5741 additions and 1419 deletions

View File

@ -14,12 +14,19 @@ jobs:
options: --privileged --cgroupns=host
steps:
- uses: actions/checkout@v4
- name: Analysing the code with ruff
- name: Install dependencies
run: |
set -e
pip install -r test-requirements.txt
- name: Analysing the code using ruff
run: |
set -e
ruff format --check
ruff check
- name: Analysing the code using mypy
run: |
set -e
mypy .
- name: Analysing the code with pylint
run: |
pylint podman_compose.py

View File

@ -1,17 +1,10 @@
default_install_hook_types: [pre-commit, commit-msg]
repos:
- repo: https://github.com/psf/black
rev: 23.3.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.6
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.10
- id: ruff
types: [python]
args: [
"--check", # Don't apply changes automatically
]
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
@ -34,3 +27,8 @@ repos:
rev: v2.2.5
hooks:
- id: codespell
- repo: https://github.com/gklein/check_signoff
rev: v1.0.5
hooks:
- id: check-signoff

View File

@ -1,7 +1,7 @@
[MESSAGES CONTROL]
# C0111 missing-docstring: missing-class-docstring, missing-function-docstring, missing-method-docstring, missing-module-docstrin
# consider-using-with: we need it for color formatter pipe
disable=too-many-lines,too-many-branches,too-many-locals,too-many-statements,too-many-arguments,too-many-instance-attributes,fixme,multiple-statements,missing-docstring,line-too-long,consider-using-f-string,consider-using-with,unnecessary-lambda-assignment
disable=too-many-lines,too-many-branches,too-many-locals,too-many-statements,too-many-arguments,too-many-instance-attributes,fixme,multiple-statements,missing-docstring,line-too-long,consider-using-f-string,consider-using-with,unnecessary-lambda-assignment,broad-exception-caught
# allow _ for ignored variables
# allow generic names like a,b,c and i,j,k,l,m,n and x,y,z
# allow k,v for key/value

View File

@ -19,11 +19,12 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
$ cd podman-compose
```
2. (OPTIONAL) Create a Python virtual environment. Example using
[virtualenv wrapper](https://virtualenvwrapper.readthedocs.io/en/latest/):
2. (OPTIONAL) Create a Python virtual environment. Example using python builtin
`venv` module:
```shell
$ mkvirtualenv podman-compose
$ python3 -m venv .venv
$ . .venv/bin/activate
```
3. Install the project runtime and development requirements:
@ -60,9 +61,25 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
- Make sure you include a `Signed-off-by` message in your commits.
Read [this guide](https://github.com/containers/common/blob/main/CONTRIBUTING.md#sign-your-prs)
to learn how to sign your commits.
- In the commit message, reference the Issue ID that your code fixes and a brief description of
the changes.
Example: `Fixes #516: Allow empty network`
- In the commit message body, reference the Issue ID that your code fixes and a brief description of the changes.
Example:
```
Allow empty network
<description, such as links to the compose spec and so on>
Fixes https://github.com/containers/podman-compose/issues/516
```
- If your commit requires a refactoring, first do the refactoring and
commit it separately before starting feature work. This makes the
pull request easier to review. Additionally, pull request will be
less risky, because if it breaks something, it's way easier to
isolate the offending code, understand what's broken and fix it.
Due to the latter reason it's best to commit in as many independent
commits as reasonable.
This will result in pull requests being merged much faster.
9. Open a pull request to `containers/podman-compose` and wait for a maintainer to review your work.
## Adding new commands

View File

@ -68,7 +68,23 @@ Or latest development version from GitHub:
pip3 install https://github.com/containers/podman-compose/archive/main.tar.gz
```
### Homebrew
### Package repositories
podman-compose is available from the following package repositories:
Debian:
```bash
sudo apt install podman-compose
```
Fedora (starting from f31) repositories:
```bash
sudo dnf install podman-compose
```
Homebrew:
```bash
brew install podman-compose
@ -94,51 +110,22 @@ curl -o ~/.local/bin/podman-compose https://raw.githubusercontent.com/containers
chmod +x ~/.local/bin/podman-compose
```
or install from Fedora (starting from f31) repositories:
```bash
sudo dnf install podman-compose
```
## Basic Usage
We have included fully functional sample stacks inside `examples/` directory.
You can get more examples from [awesome-compose](https://github.com/docker/awesome-compose).
A quick example would be
```bash
cd examples/busybox
podman-compose --help
podman-compose up --help
podman-compose up
```
A more rich example can be found in [examples/awx3](examples/awx3)
which have
- A Postgres Database
- RabbitMQ server
- MemCached server
- a django web server
- a django tasks
When testing the `AWX3` example, if you got errors, just wait for db migrations to end.
There is also AWX 17.1.0
## Tests
Inside `tests/` directory we have many useless docker-compose stacks
that are meant to test as many cases as we can to make sure we are compatible
podman-compose is tested via unit and integration tests.
### Unit tests with unittest
run a unittest with following command
Unit tests can be run via the following:
```shell
python3 -m unittest discover tests/unit
```
Integration tests can be run via the following:
```shell
python3 -m unittest discover tests/integration
```
# Contributing guide
If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section

View File

@ -35,7 +35,7 @@ Pull the merge commit created on the `main` branch during the step 2.
Then run:
```
./scripts/make_release.sh
./scripts/make_release.sh $VERSION
```
This will create release commit, tag and push everything.

39
docs/Changelog-1.4.0.md Normal file
View File

@ -0,0 +1,39 @@
Version 1.4.0 (2025-05-10)
==========================
Bug fixes
---------
- Fixed handling of relative includes and extends in compose files
- Fixed error when merging arguments in list and dictionary syntax
- Fixed issue where short-lived containers could execute twice when using `up` in detached mode
- Fixed `up` command hanging on Podman versions earlier than 4.6.0
- Fixed issue where `service_healthy` conditions weren't enforced during `up` command
- Fixed support for the `--scale` flag
- Fixed bug causing dependent containers to start despite `--no-deps` flag
- Fixed port command behavior for dynamic host ports
- Fixed interpolation of `COMPOSE_PROJECT_NAME` when set from top-level `name` in compose file
- Fixed project name evaluation order to match compose spec
- Fixed build context when using git URLs
- Fixed `KeyError` when `down` is called with non-existent service
- Skip `down` during `up` when no active containers exist
- Fixed non-zero exit code on failure when using `up -d`
- Fixed SIGINT handling during `up` command for graceful shutdown
- Fixed `NotImplementedError` when interrupted on Windows
Features
--------
- Added `--quiet` flag to `config` command to suppress output
- Added support for `pids_limit` and `deploy.resources.limits.pids`
- Added `--abort-on-container-failure` option
- Added `--rmi` argument to `down` command for image removal
- Added support for `x-podman.disable-dns` to disable DNS plugin on defined networks
- Added support for `x-podman.dns` to set DNS nameservers for defined networks
- Improved file descriptor handling - no longer closes externally created descriptors.
This allows descriptors created e.g. via systemd socket activation to be passed to
containers.
- Added support for `cpuset` configuration
- Added support for `reset` and `override` tags when merging compose files
- Added support for `x-podman.interface_name` to set network interface names
- Added support for `x-podman.pod_args` to override default `--pod-args`

7
docs/Changelog-1.4.1.md Normal file
View File

@ -0,0 +1,7 @@
Version 1.4.1 (2025-06-05)
==========================
Bug fixes
---------
- Fixed relative host path resolution for volume bind mount source

View File

@ -27,6 +27,42 @@ services:
For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/).
## Secrets
The following extension keys are available under `secret` configuration:
x-podman.relabel - Configure SELinux relabeling
For example, the following configures custom-secret to use mount with private and unshared content.
Only the current container can use a private volume.
```yml
secrets:
custom-secret:
x-podman.relabel: Z
```
For explanations of these extensions, please refer to the [podman-run --volume documentation](https://docs.podman.io/en/latest/markdown/podman-run.1.html#volume-v-source-volume-host-dir-container-dir-options)).
## Network management
The following extension keys are available under network configuration:
* `x-podman.disable-dns` - Disable the DNS plugin for the network when set to 'true'.
* `x-podman.dns` - Set nameservers for the network using supplied addresses (cannot be used with x-podman.disable-dns`).
For example, the following docker-compose.yml allows all containers on the same network to use the
specified nameservers:
```yml
version: "3"
network:
my_network:
x-podman.dns:
- "10.1.2.3"
- "10.1.2.4"
```
For explanations of these extensions, please refer to the
[Podman network create command Documentation](https://docs.podman.io/en/latest/markdown/podman-network-create.1.html).
## Per-network MAC-addresses
@ -66,7 +102,7 @@ networks:
- subnet: "192.168.1.0/24"
services:
webserver
webserver:
image: "busybox"
command: ["/bin/busybox", "httpd", "-f", "-h", "/etc", "-p", "8001"]
networks:
@ -78,6 +114,10 @@ services:
mac_address: "02:bb:bb:bb:bb:bb" # mac_address is supported
```
## Per-network interface name
Using `x-podman.interface_name` within a containers network config you can specify the interface name inside the container.
## Podman-specific network modes
Generic docker-compose supports the following values for `network-mode` for a container:
@ -99,6 +139,44 @@ The options to the network modes are passed to the `--network` option of the `po
as-is.
## Docker Compose Compatibility
podman-compose aims to be compatible with docker-compose, but there are some differences in
behavior and features. The following sections describe how to enable compatibility with docker-compose
and how to handle some of the differences.
Compatibility settings can either be set explicitly as described below, or by setting the `docker_compose_compat` meta
settings to `true` under the global `x-podman` key:
```yaml
x-podman:
docker_compose_compat: true
```
This will enable all compatibility settings described below, and is equivalent to setting each of them to `true`.
This setting can also be changed by setting the `PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT` environment variable.
## Compatibility of name separators between docker-compose and podman-compose
Currently, podman-compose is using underscores (`_` character) as a separator in names of
containers, images, etc., while docker-compose has switched to hyphens (`-` character). This setting
allows to switch podman-compose to use hyphens as well.
To enable compatibility between docker-compose and podman-compose, specify
`name_separator_compat: true` under global `x-podman` key:
```
x-podman:
name_separator_compat: true
```
By default `name_separator_compat` is `false`. This will change to `true` at some point and the
setting will be removed.
This setting can also be changed by setting `PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT` environment
variable.
## Compatibility of default network names between docker-compose and podman-compose
Current versions of podman-compose may produce different default external network names than
@ -116,6 +194,9 @@ x-podman:
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
setting will be removed.
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_NAME_COMPAT` environment
variable.
## Compatibility of default network behavior between docker-compose and podman-compose
When there is no network defined (neither network-mode nor networks) in service,
@ -136,6 +217,9 @@ x-podman:
default_net_behavior_compat: true
```
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_BEHAVIOR_COMPAT` environment
variable.
## Custom pods management
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
@ -154,3 +238,23 @@ services:
x-podman:
in_pod: false
```
This setting can also be changed by setting `PODMAN_COMPOSE_IN_POD` environment
variable.
It is also possible to override the default arguments for pod creation that are
used when --pod-args is not passed on the command line:
```yml
version: "3"
services:
cont:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"]
x-podman:
pod_args: ["--infra=false", "--share=", "--cpus=1"]
```
When not set in docker-compose.yml or on the command line, the pod args default
to `["--infra=false", "--share="]`.
This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment
variable.

View File

@ -0,0 +1,9 @@
---
version: '3'
services:
dummy:
build:
context: .
dockerfile_inline: |
FROM alpine
RUN echo "hello world"

View File

@ -3,8 +3,8 @@
import asyncio # noqa: F401
import os
import aioredis
from aiohttp import web
import aioredis # type: ignore[import-not-found]
from aiohttp import web # type: ignore[import-not-found]
REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
@ -16,13 +16,13 @@ routes = web.RouteTableDef()
@routes.get("/")
async def hello(request): # pylint: disable=unused-argument
async def hello(request: web.Request) -> web.Response: # pylint: disable=unused-argument
counter = await redis.incr("mycounter")
return web.Response(text=f"counter={counter}")
@routes.get("/hello.json")
async def hello_json(request): # pylint: disable=unused-argument
async def hello_json(request: web.Request) -> web.Response: # pylint: disable=unused-argument
counter = await redis.incr("mycounter")
data = {"counter": counter}
return web.json_response(data)
@ -31,7 +31,7 @@ async def hello_json(request): # pylint: disable=unused-argument
app.add_routes(routes)
def main():
def main() -> None:
web.run_app(app, port=8080)

View File

@ -0,0 +1 @@
- Add unregister command to remove systemd service registration (`podman-compose systemd -a unregister`)

View File

@ -0,0 +1 @@
- Change behaviour of `--in-pod` to handle custom pod names instead of only disabling pod feature

View File

@ -0,0 +1 @@
- Add new docker_compose_compat x-podman meta setting to enable all Docker Compose compatibility settings

View File

@ -0,0 +1 @@
Add support for environment variable interpolation for YAML keys.

View File

@ -0,0 +1 @@
Fixed build ssh path to a local SSH key, to be relative to the directory of compose file.

View File

@ -0,0 +1 @@
Fixed support for CMD healthchecks to run using the given command directly and not using `/bin/sh -c`.

View File

@ -0,0 +1 @@
Fixed regression of dockerfile definition if working directory name ends with ".git".

View File

@ -0,0 +1 @@
Implemented short syntax for environment variables set in `.env` for compose.yml "environment:" section.

View File

@ -0,0 +1 @@
Fixed regression of log output including "text" in detached mode.

View File

@ -0,0 +1 @@
Hide the stack trace on a YAML parse error.

View File

@ -0,0 +1 @@
Added `io.podman.compose.service` label to created containers. It contains the same value as com.docker.compose.service.

View File

@ -0,0 +1 @@
- Add new name_separator_compat x-podman setting to change name separator to hyphen, same as Docker Compose

View File

@ -0,0 +1 @@
- Add relabel option to secret to make possible to read the secret file by the contained process.

View File

@ -0,0 +1 @@
- Add support for setting x-podman values using PODMAN_COMPOSE_* environment variables.

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,59 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools"]
[project]
name = "podman-compose"
authors = [
{ email = "alsadi@gmail.com", name = "Muayyad Alsadi" },
]
description = "A script to run docker-compose.yml using podman"
dependencies = [
"python-dotenv",
"pyyaml",
]
requires-python = ">=3.9"
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Build Tools",
]
keywords = [
"podman",
"podman-compose",
]
license = "GPL-2.0-only"
dynamic = ["version", "readme"]
[project.urls]
homepage = "https://github.com/containers/podman-compose"
[project.optional-dependencies]
devel = [
"coverage",
"parameterized",
"pre-commit",
"ruff",
]
[project.scripts]
podman-compose = "podman_compose:main"
[tool.setuptools]
py-modules = ["podman_compose"]
[tool.setuptools.dynamic]
readme = {file = ["README.md"], content-type = "text/markdown"}
version = {attr = "podman_compose.__version__"}
[tool.ruff]
line-length = 100
target-version = "py38"
@ -53,3 +109,21 @@ quote-style = "preserve"
directory = "misc"
name = "Misc"
showcontent = true
[tool.mypy]
python_version = "3.9"
namespace_packages = true
explicit_package_bases = true
pretty = true
warn_redundant_casts = true
disallow_untyped_calls = false
disallow_untyped_defs = true
no_implicit_optional = true
mypy_path = "$MYPY_CONFIG_FILE_DIR"
exclude = "build"
[[tool.mypy.overrides]]
module = [
"parameterized.*",
]
ignore_missing_imports = true

View File

@ -1,6 +1,5 @@
#!/usr/bin/env bash
./scripts/uninstall.sh
./scripts/clean_up.sh
python3 setup.py register
python3 setup.py sdist bdist_wheel
pyproject-build
twine upload dist/*

View File

@ -1,9 +1,5 @@
[bdist_wheel]
universal = 1
[metadata]
version = attr: podman_compose.__version__
[flake8]
# The GitHub editor is 127 chars wide
max-line-length=127
max-line-length=127
# These are not being followed yet
ignore=E222,E231,E272,E713,W503

View File

@ -1,49 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
import os
from setuptools import setup
try:
README = open(os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8").read()
except: # noqa: E722 # pylint: disable=bare-except
README = ""
setup(
name="podman-compose",
description="A script to run docker-compose.yml using podman",
long_description=README,
long_description_content_type="text/markdown",
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Development Status :: 3 - Alpha",
"Topic :: Software Development :: Build Tools",
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
],
keywords="podman, podman-compose",
author="Muayyad Alsadi",
author_email="alsadi@gmail.com",
url="https://github.com/containers/podman-compose",
py_modules=["podman_compose"],
entry_points={"console_scripts": ["podman-compose = podman_compose:main"]},
include_package_data=True,
license="GPL-2.0-only",
install_requires=[
"pyyaml",
"python-dotenv",
],
extras_require={"devel": ["ruff", "pre-commit", "coverage", "parameterized"]},
# test_suite='tests',
# tests_require=[
# 'coverage',
# 'tox',
# ]
)

View File

@ -1,10 +1,15 @@
-e .
coverage==7.4.3
cryptography==44.0.3
parameterized==0.9.0
pytest==8.0.2
tox==4.13.0
ruff==0.3.1
mypy==1.15.0
ruff==0.11.11
pylint==3.1.0
types-PyYAML==6.0.12.20250402
types-requests==2.32.0.20250328
types-setuptools==80.7.0.20250516
# The packages below are transitive dependencies of the packages above and are included here
# to make testing reproducible.
@ -23,6 +28,7 @@ filelock==3.13.1
iniconfig==2.0.0
isort==5.13.2
mccabe==0.7.0
mypy_extensions==1.1.0
packaging==23.2
platformdirs==4.2.0
pluggy==1.4.0
@ -31,4 +37,5 @@ python-dotenv==1.0.1
PyYAML==6.0.1
requests
tomlkit==0.12.4
virtualenv==20.25.1
typing_extensions==4.13.2
virtualenv==20.26.6

View File

@ -2,7 +2,7 @@ import os
import subprocess
def create_base_test_image():
def create_base_test_image() -> None:
subprocess.check_call(
['podman', 'build', '-t', 'nopush/podman-compose-test', '.'],
cwd=os.path.join(os.path.dirname(__file__), "base_image"),

View File

View File

@ -0,0 +1,11 @@
version: "3"
services:
sh1:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
sh2:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
sh3:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]

View File

@ -0,0 +1,11 @@
version: "3"
services:
sh1:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
sh2:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
sh3:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]

View File

@ -0,0 +1,11 @@
version: "3"
services:
sh1:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
sh2:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 1"]
sh3:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]

View File

@ -0,0 +1,11 @@
version: "3"
services:
sh1:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
sh2:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
sh3:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from parameterized import parameterized
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(failure_order: str) -> str:
return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml")
class TestComposeAbort(unittest.TestCase, RunSubprocessMixin):
@parameterized.expand([
("exit", "first", 0),
("failure", "first", 1),
("exit", "second", 0),
("failure", "second", 1),
("exit", "simultaneous", 0),
("failure", "simultaneous", 1),
("exit", "none", 0),
("failure", "none", 0),
])
def test_abort(self, abort_type: str, failure_order: str, expected_exit_code: int) -> None:
try:
self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(failure_order),
"up",
f"--abort-on-container-{abort_type}",
],
expected_exit_code,
)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(failure_order),
"down",
])

View File

@ -0,0 +1 @@

View File

@ -7,17 +7,17 @@ import os
import subprocess
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
def compose_yaml_path() -> str:
""" "Returns the path to the compose file used for this test module"""
return os.path.join(test_path(), "additional_contexts", "project")
class TestComposeBuildAdditionalContexts(unittest.TestCase):
def test_build_additional_context(self):
def test_build_additional_context(self) -> None:
"""podman build should receive additional contexts as --build-context
See additional_context/project/docker-compose.yaml for context paths

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,9 @@
version: "3"
services:
test_context:
build:
context: https://github.com/mokibit/test-git-url-as-context.git
image: test-git-url-as-context
test_context_inline:
build: https://github.com/mokibit/test-git-url-as-context.git
image: test-git-url-as-context-inline

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0
import os
from parameterized import parameterized
import unittest
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
from tests.integration.test_utils import RunSubprocessMixin
def compose_yaml_path():
""" "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "build/git_url_context")
return os.path.join(base_path, "docker-compose.yml")
class TestComposeBuildGitUrlAsContext(unittest.TestCase, RunSubprocessMixin):
@parameterized.expand([
("git_url_context_test_context_1", "data_1.txt", b'test1\r\n'),
("git_url_context_test_context_1", "data_2.txt", b'test2\r\n'),
("git_url_context_test_context_inline_1", "data_1.txt", b'test1\r\n'),
("git_url_context_test_context_inline_1", "data_2.txt", b'test2\r\n'),
])
def test_build_git_url_as_context(self, container_name, file_name, output):
# test if container can access specific files from git repository when git url is used as
# a build context
try:
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"up",
"-d",
])
out, _ = self.run_subprocess_assert_returncode([
"podman",
"exec",
"-ti",
f"{container_name}",
"sh",
"-c",
f"cat {file_name}",
])
self.assertEqual(out, output)
finally:
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
"-t",
"0",
])

View File

@ -5,8 +5,8 @@ import unittest
import requests
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
from tests.integration.test_utils import RunSubprocessMixin

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
test

View File

@ -3,3 +3,12 @@ services:
test:
build: ./context
image: build-fail-img
test_no_dockerfile:
build:
context: ./context_no_file
image: busybox
test_no_custom_dockerfile:
build:
context: ./context_no_file
dockerfile: Dockerfile-alt
image: busybox

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
""" "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "build_fail")
return os.path.join(base_path, "docker-compose.yml")
class TestComposeBuildFail(unittest.TestCase, RunSubprocessMixin):
def test_build_fail(self):
output, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"test",
],
expected_returncode=127,
)
self.assertIn("RUN this_command_does_not_exist", str(output))
self.assertIn("this_command_does_not_exist: not found", str(error))
self.assertIn("while running runtime: exit status 127", str(error))
def test_dockerfile_does_not_exist(self):
out, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"test_no_dockerfile",
],
expected_returncode=1,
)
error = error.decode('utf-8')
result = '\n'.join(error.splitlines()[-1:])
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file")
expected = f'OSError: Dockerfile not found in {expected_path}'
self.assertEqual(expected, result)
def test_custom_dockerfile_does_not_exist(self):
out, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"test_no_custom_dockerfile",
],
expected_returncode=1,
)
error = error.decode('utf-8')
result = '\n'.join(error.splitlines()[-1:])
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file/Dockerfile-alt")
expected = f'OSError: Dockerfile not found in {expected_path}'
self.assertEqual(expected, result)

View File

@ -0,0 +1,3 @@
FROM busybox
RUN false

View File

@ -0,0 +1,8 @@
version: "3"
services:
bad:
build:
context: bad
good:
build:
context: good

View File

@ -0,0 +1,3 @@
FROM busybox
#ensure that this build finishes second so that it has a chance to overwrite the return code
RUN sleep 0.5

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
""" "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "build_fail_multi")
return os.path.join(base_path, "docker-compose.yml")
class TestComposeBuildFailMulti(unittest.TestCase, RunSubprocessMixin):
def test_build_fail_multi(self):
output, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
# prevent the successful build from being cached to ensure it runs long enough
"--no-cache",
],
expected_returncode=1,
)
self.assertIn("RUN false", str(output))
self.assertIn("while running runtime: exit status 1", str(error))

View File

@ -5,9 +5,9 @@ import json
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
class TestBuildLabels(unittest.TestCase, RunSubprocessMixin):

View File

@ -0,0 +1 @@

View File

@ -7,8 +7,8 @@ import os
import subprocess
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():

View File

@ -0,0 +1 @@

View File

@ -9,9 +9,9 @@ import unittest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
expected_lines = [
"default: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFYQvN9a+toIB6jSs4zY7FMapZnHt80EKCUr/WhLwUum",

View File

@ -0,0 +1 @@

View File

@ -5,12 +5,12 @@ import unittest
from parameterized import parameterized
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(scenario):
def compose_yaml_path(scenario: str) -> str:
return os.path.join(
os.path.join(test_path(), "default_net_behavior"), f"docker-compose_{scenario}.yaml"
)
@ -27,13 +27,13 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
('two_nets_compat', 'default_net_behavior_default'),
('with_default_compat', 'default_net_behavior_default'),
])
def test_nethost(self, scenario, default_net):
def test_nethost(self, scenario: str, default_net: str) -> None:
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(scenario), "up", "-d"],
)
container_id, _ = self.run_subprocess_assert_returncode(
container_id_out, _ = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
@ -43,7 +43,7 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
'{{.ID}}',
],
)
container_id = container_id.decode('utf-8').split('\n')[0]
container_id = container_id_out.decode('utf-8').split('\n')[0]
output, _ = self.run_subprocess_assert_returncode(
[
"podman",

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,23 @@
version: "3.7"
services:
web:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-h", "/etc/", "-p", "8000"]
tmpfs:
- /run
- /tmp
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8000/hosts"]
start_period: 10s # initialization time for containers that need time to bootstrap
interval: 10s # Time between health checks
timeout: 5s # Time to wait for a response
retries: 3 # Number of consecutive failures before marking as unhealthy
sleep:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3600"]
depends_on:
web:
condition: service_healthy
tmpfs:
- /run
- /tmp

View File

@ -0,0 +1,266 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from tests.integration.test_utils import PodmanAwareRunSubprocessMixin
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import is_systemd_available
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path(suffix: str = "") -> str:
return os.path.join(os.path.join(test_path(), "deps"), f"docker-compose{suffix}.yaml")
class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps(self) -> None:
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"--rm",
"sleep",
"/bin/sh",
"-c",
"wget -O - http://web:8000/hosts",
])
self.assertIn(b"HTTP request sent, awaiting response... 200 OK", output)
self.assertIn(b"deps_web_1", output)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def test_run_nodeps(self) -> None:
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"--rm",
"--no-deps",
"sleep",
"/bin/sh",
"-c",
"wget -O - http://web:8000/hosts || echo Failed to connect",
])
self.assertNotIn(b"HTTP request sent, awaiting response... 200 OK", output)
self.assertNotIn(b"deps_web_1", output)
self.assertIn(b"Failed to connect", output)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def test_up_nodeps(self) -> None:
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"up",
"--no-deps",
"--detach",
"sleep",
])
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"ps",
])
self.assertNotIn(b"deps_web_1", output)
self.assertIn(b"deps_sleep_1", output)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def test_podman_compose_run(self) -> None:
"""
This will test depends_on as well
"""
run_cmd = [
"coverage",
"run",
podman_compose_path(),
"-f",
os.path.join(test_path(), "deps", "docker-compose.yaml"),
"run",
"--rm",
"sleep",
"/bin/sh",
"-c",
"wget -q -O - http://web:8000/hosts",
]
out, _ = self.run_subprocess_assert_returncode(run_cmd)
self.assertIn(b"127.0.0.1\tlocalhost", out)
# Run it again to make sure we can run it twice. I saw an issue where a second run, with
# the container left up, would fail
run_cmd = [
"coverage",
"run",
podman_compose_path(),
"-f",
os.path.join(test_path(), "deps", "docker-compose.yaml"),
"run",
"--rm",
"sleep",
"/bin/sh",
"-c",
"wget -q -O - http://web:8000/hosts",
]
out, _ = self.run_subprocess_assert_returncode(run_cmd)
self.assertIn(b"127.0.0.1\tlocalhost", out)
# This leaves a container running. Not sure it's intended, but it matches docker-compose
down_cmd = [
"coverage",
"run",
podman_compose_path(),
"-f",
os.path.join(test_path(), "deps", "docker-compose.yaml"),
"down",
]
self.run_subprocess_assert_returncode(down_cmd)
class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps_succeeds(self) -> None:
suffix = "-conditional-succeeds"
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"run",
"--rm",
"sleep",
"/bin/sh",
"-c",
"wget -O - http://web:8000/hosts",
])
self.assertIn(b"HTTP request sent, awaiting response... 200 OK", output)
self.assertIn(b"deps_web_1", output)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"down",
])
def test_deps_fails(self) -> None:
suffix = "-conditional-fails"
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"ps",
])
self.assertNotIn(b"HTTP request sent, awaiting response... 200 OK", output)
self.assertNotIn(b"deps_web_1", output)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"down",
])
class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubprocessMixin):
def setUp(self) -> None:
self.podman_version = self.retrieve_podman_version()
def test_up_deps_healthy(self) -> None:
suffix = "-conditional-healthy"
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"up",
"sleep",
"--detach",
])
# Since the command `podman wait --condition=healthy` is invalid prior to 4.6.0,
# we only validate healthy status for podman 4.6.0+, which won't be tested in the
# CI pipeline of the podman-compose project where podman 4.3.1 is employed.
podman_ver_major, podman_ver_minor, podman_ver_patch = self.podman_version
if podman_ver_major >= 4 and podman_ver_minor >= 6 and podman_ver_patch >= 0:
self.run_subprocess_assert_returncode([
"podman",
"wait",
"--condition=running",
"deps_web_1",
"deps_sleep_1",
])
# check both web and sleep are running
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"ps",
"--format",
"{{.ID}}\t{{.Names}}\t{{.Status}}\t{{.StartedAt}}",
])
# extract container id of web
decoded_out = output.decode('utf-8')
lines = decoded_out.split("\n")
web_lines = [line for line in lines if "web" in line]
self.assertTrue(web_lines)
self.assertEqual(1, len(web_lines))
web_cnt_id, web_cnt_name, web_cnt_status, web_cnt_started = web_lines[0].split("\t")
self.assertNotEqual("", web_cnt_id)
self.assertEqual("deps_web_1", web_cnt_name)
sleep_lines = [line for line in lines if "sleep" in line]
self.assertTrue(sleep_lines)
self.assertEqual(1, len(sleep_lines))
sleep_cnt_id, sleep_cnt_name, _, sleep_cnt_started = sleep_lines[0].split("\t")
self.assertNotEqual("", sleep_cnt_id)
self.assertEqual("deps_sleep_1", sleep_cnt_name)
# When test case is executed inside container like github actions, the absence of
# systemd prevents health check from working properly, resulting in failure to
# transit to healthy state. As a result, we only assert the `healthy` state where
# systemd is functioning.
if (
is_systemd_available()
and podman_ver_major >= 4
and podman_ver_minor >= 6
and podman_ver_patch >= 0
):
self.assertIn("healthy", web_cnt_status)
self.assertGreaterEqual(int(sleep_cnt_started), int(web_cnt_started))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(suffix),
"down",
])

View File

@ -1,2 +0,0 @@
ZZVAR1='This value is overwritten by env-file-tests/.env'
ZZVAR3='This value is loaded from env-file-tests/.env'

View File

@ -0,0 +1,2 @@
ZZVAR1='This value is overwritten by env_file_tests/.env'
ZZVAR3='This value is loaded from env_file_tests/.env'

View File

@ -0,0 +1 @@

View File

@ -1,2 +1,3 @@
ZZVAR1='This value is loaded but should be overwritten'
ZZVAR2='This value is loaded from .env in project/ directory'
ZZVAR3=TEST

View File

@ -0,0 +1,10 @@
services:
app:
image: nopush/podman-compose-test
command: ["/bin/busybox", "sh", "-c", "env | grep ZZVAR3"]
# 'env_file:' section is not used, so .env file is searched in the same directory as compose.yml
# file
environment:
# this is short syntax: podman-compose takes only this variable value from '.env' file and
# sends it to container environment
- ZZVAR3

View File

@ -3,17 +3,17 @@
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_base_path():
return os.path.join(test_path(), "env-file-tests")
def compose_base_path() -> str:
return os.path.join(test_path(), "env_file_tests")
class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
def test_path_env_file_inline(self):
def test_path_env_file_inline(self) -> None:
# Test taking env variable value directly from env-file when its path is inline path
base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -42,7 +42,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_path_env_file_flat_in_compose_file(self):
def test_path_env_file_flat_in_compose_file(self) -> None:
# Test taking env variable value from env-file/project-1.env which was declared in
# compose file's env_file
base_path = compose_base_path()
@ -74,7 +74,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_path_env_file_obj_in_compose_file(self):
def test_path_env_file_obj_in_compose_file(self) -> None:
# take variable value from env-file project-1.env which was declared in compose
# file's env_file by -path: ...
base_path = compose_base_path()
@ -106,7 +106,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_exists_optional_env_file_path_in_compose_file(self):
def test_exists_optional_env_file_path_in_compose_file(self) -> None:
# test taking env variable values from several env-files when one of them is optional
# and exists
base_path = compose_base_path()
@ -139,7 +139,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_missing_optional_env_file_path_in_compose_file(self):
def test_missing_optional_env_file_path_in_compose_file(self) -> None:
# test taking env variable values from several env-files when one of them is optional and
# is missing (silently skip it)
base_path = compose_base_path()
@ -173,7 +173,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_var_value_inline_overrides_env_file_path_inline(self):
def test_var_value_inline_overrides_env_file_path_inline(self) -> None:
# Test overriding env value when value is declared in inline command
base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -204,7 +204,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_taking_env_variables_from_env_files_from_different_directories(self):
def test_taking_env_variables_from_env_files_from_different_directories(self) -> None:
# FIXME: It is not clear what this test actually tests, but from README.md it looks like:
# Test overriding env values by directory env-files-tests/.env file values
# and only take value from project/.env, when it does not exist in env-files-tests/.env
@ -233,7 +233,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
[
'ZZVAR1=This value is loaded but should be overwritten\r',
'ZZVAR2=This value is loaded from .env in project/ directory\r',
'ZZVAR3=$ZZVAR3\r',
'ZZVAR3=TEST\r',
'',
],
)
@ -244,3 +244,36 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
path_compose_file,
"down",
])
def test_env_var_value_accessed_in_compose_file_short_syntax(self) -> None:
# Test that compose file can access the environment variable set in .env file using
# short syntax, that is: only the name of environment variable is used in "environment:" in
# compose.yml file and its value is picked up directly from .env file
# long syntax of environment variables interpolation is tested in
# tests/integration/interpolation
base_path = compose_base_path()
compose_file_path = os.path.join(base_path, "project/container-compose.short_syntax.yaml")
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"up",
"-d",
])
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"logs",
])
# ZZVAR3 was set in .env file
self.assertEqual(output, b"ZZVAR3=TEST\n")
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_file_path,
"down",
])

View File

@ -0,0 +1 @@

View File

@ -1,5 +1,7 @@
version: "3"
name: my-project-name
services:
env-test:
image: busybox
@ -8,3 +10,9 @@ services:
ZZVAR1: myval1
ZZVAR2: 2-$ZZVAR1
ZZVAR3: 3-$ZZVAR2
project-name-test:
image: busybox
command: sh -c "echo $$PNAME"
environment:
PNAME: ${COMPOSE_PROJECT_NAME}

View File

@ -0,0 +1,89 @@
# SPDX-License-Identifier: GPL-2.0
import os
import unittest
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "env_tests"), "container-compose.yml")
class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
"""Test that inline environment variable overrides environment variable from compose file."""
def test_env(self) -> None:
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"-l",
"monkey",
"-e",
"ZZVAR1=myval2",
"env-test",
])
self.assertIn("ZZVAR1='myval2'", str(output))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
"""
Tests interpolation of COMPOSE_PROJECT_NAME in the podman-compose config,
which is different from external environment variables because COMPOSE_PROJECT_NAME
is a predefined environment variable generated from the `name` value in the top-level
of the compose.yaml.
See also
- https://docs.docker.com/reference/compose-file/interpolation/
- https://docs.docker.com/reference/compose-file/version-and-name/#name-top-level-element
- https://docs.docker.com/compose/how-tos/environment-variables/envvars/
- https://github.com/compose-spec/compose-spec/blob/main/04-version-and-name.md
"""
def test_project_name(self) -> None:
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"project-name-test",
])
self.assertIn("my-project-name", str(output))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def test_project_name_override(self) -> None:
try:
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"-e",
"COMPOSE_PROJECT_NAME=project-name-override",
"project-name-test",
])
self.assertIn("project-name-override", str(output))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])

View File

@ -0,0 +1 @@

View File

@ -3,17 +3,17 @@
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
return os.path.join(os.path.join(test_path(), "exit-from"), "docker-compose.yaml")
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "exit_from"), "docker-compose.yaml")
class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
def test_exit_code_sh1(self):
def test_exit_code_sh1(self) -> None:
try:
self.run_subprocess_assert_returncode(
[
@ -33,7 +33,7 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_exit_code_sh2(self):
def test_exit_code_sh2(self) -> None:
try:
self.run_subprocess_assert_returncode(
[
@ -52,3 +52,16 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
compose_yaml_path(),
"down",
])
def test_podman_compose_exit_from(self) -> None:
up_cmd = [
"coverage",
"run",
podman_compose_path(),
"-f",
compose_yaml_path(),
"up",
]
self.run_subprocess_assert_returncode(up_cmd + ["--exit-code-from", "sh1"], 1)
self.run_subprocess_assert_returncode(up_cmd + ["--exit-code-from", "sh2"], 2)

View File

@ -0,0 +1 @@

View File

@ -3,17 +3,17 @@
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "extends"), "docker-compose.yaml")
class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
def test_extends_service_launch_echo(self):
def test_extends_service_launch_echo(self) -> None:
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -38,7 +38,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_extends_service_launch_echo1(self):
def test_extends_service_launch_echo1(self) -> None:
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -63,7 +63,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down",
])
def test_extends_service_launch_env1(self):
def test_extends_service_launch_env1(self) -> None:
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
@ -80,18 +80,25 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"env1",
])
lines = output.decode('utf-8').split('\n')
# HOSTNAME name is random string so is ignored in asserting
lines = sorted([line for line in lines if not line.startswith("HOSTNAME")])
# Test selected env variables to improve robustness
lines = sorted([
line
for line in lines
if line.startswith("BAR")
or line.startswith("BAZ")
or line.startswith("FOO")
or line.startswith("HOME")
or line.startswith("PATH")
or line.startswith("container")
])
self.assertEqual(
lines,
[
'',
'BAR=local',
'BAZ=local',
'FOO=original',
'HOME=/root',
'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
'TERM=xterm',
'container=podman',
],
)

View File

@ -0,0 +1 @@

View File

@ -2,18 +2,19 @@
import os
import unittest
from pathlib import Path
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "extends_w_empty_service"), "docker-compose.yml")
class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_empty_service(self):
def test_extends_w_empty_service(self) -> None:
try:
self.run_subprocess_assert_returncode(
[
@ -37,3 +38,26 @@ class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
compose_yaml_path(),
"down",
])
def test_podman_compose_extends_w_empty_service(self) -> None:
"""
Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes an empty service. (e.g. if the file is used as placeholder for more complex
configurations.)
"""
main_path = Path(__file__).parent.parent.parent.parent
command_up = [
"python3",
str(main_path.joinpath("podman_compose.py")),
"-f",
str(
main_path.joinpath(
"tests", "integration", "extends_w_empty_service", "docker-compose.yml"
)
),
"up",
"-d",
]
self.run_subprocess_assert_returncode(command_up)

View File

@ -0,0 +1 @@

View File

@ -3,17 +3,17 @@
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def compose_yaml_path():
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "extends_w_file"), "docker-compose.yml")
class TestComposeExtendsWithFile(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file(self): # when file is Dockerfile for building the image
def test_extends_w_file(self) -> None: # when file is Dockerfile for building the image
try:
self.run_subprocess_assert_returncode(
[

View File

@ -0,0 +1 @@

View File

@ -5,31 +5,47 @@ import unittest
from pathlib import Path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
def base_path():
"""Returns the base path for the project"""
return Path(__file__).parent.parent.parent
def compose_yaml_path() -> str:
return os.path.join(os.path.join(test_path(), "extends_w_file_subdir"), "docker-compose.yml")
def test_path():
"""Returns the path to the tests directory"""
return os.path.join(base_path(), "tests/integration")
class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file_subdir(self) -> None: # when file is Dockerfile for building the image
try:
self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"up",
],
)
output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"ps",
])
self.assertIn("extends_w_file_subdir_web_1", str(output))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def podman_compose_path():
"""Returns the path to the podman compose script"""
return os.path.join(base_path(), "podman_compose.py")
class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file_subdir(self):
def test_podman_compose_extends_w_file_subdir(self) -> None:
"""
Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes a build context
:return:
"""
main_path = Path(__file__).parent.parent.parent
main_path = Path(__file__).parent.parent.parent.parent
command_up = [
"coverage",
@ -86,26 +102,3 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin):
# check container did not exists anymore
out, _ = self.run_subprocess_assert_returncode(command_check_container)
self.assertEqual(out, b'')
def test_extends_w_empty_service(self):
"""
Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes an empty service. (e.g. if the file is used as placeholder for more complex
configurations.)
"""
main_path = Path(__file__).parent.parent.parent
command_up = [
"python3",
str(main_path.joinpath("podman_compose.py")),
"-f",
str(
main_path.joinpath(
"tests", "integration", "extends_w_empty_service", "docker-compose.yml"
)
),
"up",
"-d",
]
self.run_subprocess_assert_returncode(command_up)

View File

@ -0,0 +1 @@

View File

@ -4,13 +4,13 @@
import os
import unittest
from tests.integration.test_podman_compose import podman_compose_path
from tests.integration.test_podman_compose import test_path
from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path
class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
def test_compose_symlink(self):
def test_compose_symlink(self) -> None:
"""The context of podman-compose.yml should come from the same directory as the file even
if it is a symlink
"""
@ -35,8 +35,7 @@ class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
"container1",
])
# BUG: figure out why cat is called twice
self.assertEqual(out, b'data_compose_symlink\ndata_compose_symlink\n')
self.assertEqual(out, b'data_compose_symlink\n')
finally:
out, _ = self.run_subprocess_assert_returncode([

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,8 @@
version: "3"
services:
cont:
image: nopush/podman-compose-test
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"]
x-podman:
in_pod: custom_test_pod_name

View File

@ -6,28 +6,38 @@ import unittest
from tests.integration.test_utils import RunSubprocessMixin
def base_path():
def base_path() -> str:
"""Returns the base path for the project"""
return os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
return os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
def test_path():
def test_path() -> str:
"""Returns the path to the tests directory"""
return os.path.join(base_path(), "tests/integration")
def podman_compose_path():
def podman_compose_path() -> str:
"""Returns the path to the podman compose script"""
return os.path.join(base_path(), "podman_compose.py")
def is_root() -> bool:
return os.geteuid() == 0
def failure_exitcode_when_rootful() -> int:
if is_root():
return 125
return 0
# If a compose file has userns_mode set, setting in_pod to True, results in error.
# Default in_pod setting is True, unless compose file provides otherwise.
# Compose file provides custom in_pod option, which can be overridden by command line in_pod option.
# Test all combinations of command line argument in_pod and compose file argument in_pod.
class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# compose file provides x-podman in_pod=false
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self):
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self) -> None:
"""
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
does not provide this option
@ -64,7 +74,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
finally:
self.run_subprocess_assert_returncode(down_cmd)
@ -72,7 +82,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# throws an error, can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, expected_returncode=1)
def test_x_podman_in_pod_false_command_line_in_pod_true(self):
def test_x_podman_in_pod_false_command_line_in_pod_true(self) -> None:
"""
Test that podman-compose does not allow pod creating even with command line in_pod=True
when --userns and --pod are set together: throws an error
@ -96,7 +106,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -105,7 +115,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_false_command_line_in_pod_false(self):
def test_x_podman_in_pod_false_command_line_in_pod_false(self) -> None:
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -142,7 +152,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
finally:
self.run_subprocess_assert_returncode(down_cmd)
@ -150,7 +160,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self):
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self) -> None:
"""
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
command line in_pod=""
@ -188,7 +198,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
finally:
self.run_subprocess_assert_returncode(down_cmd)
@ -197,7 +207,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod, 1)
# compose file provides x-podman in_pod=true
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self):
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true: throws an error
@ -221,7 +231,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -230,7 +240,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_true_command_line_in_pod_true(self):
def test_x_podman_in_pod_true_command_line_in_pod_true(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true and and command line in_pod=True: throws an error
@ -255,7 +265,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -264,7 +274,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_true_command_line_in_pod_false(self):
def test_x_podman_in_pod_true_command_line_in_pod_false(self) -> None:
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -301,7 +311,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
finally:
self.run_subprocess_assert_returncode(down_cmd)
@ -309,7 +319,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self):
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true and command line in_pod="": throws an error
@ -334,7 +344,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -344,7 +354,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod)
# compose file does not provide x-podman in_pod
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self):
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error
@ -368,7 +378,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -377,7 +387,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self):
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together even when x-podman in_pod=true: throws an error
@ -402,7 +412,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:
@ -411,7 +421,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self):
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self) -> None:
"""
Test that podman-compose will not create a pod as command line sets in_pod=False
"""
@ -448,7 +458,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
self.run_subprocess_assert_returncode(command_up)
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
finally:
self.run_subprocess_assert_returncode(down_cmd)
@ -457,7 +467,136 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self):
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_docker_compat(self) -> None:
"""
Test that podman-compose will not create a pod when docker compat is requested.
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"up",
"-d",
]
down_cmd = [
"python3",
podman_compose_path(),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"down",
]
env = {
"PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT": "1",
}
try:
self.run_subprocess_assert_returncode(
command_up, failure_exitcode_when_rootful(), env=env
)
finally:
self.run_subprocess_assert_returncode(down_cmd, env=env)
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_env_var(self) -> None:
"""
Test that podman-compose will not create a pod when env var is set.
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"up",
"-d",
]
down_cmd = [
"python3",
podman_compose_path(),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_not_exists",
"docker-compose.yml",
),
"down",
]
env = {
"PODMAN_COMPOSE_IN_POD": "0",
}
try:
self.run_subprocess_assert_returncode(
command_up, failure_exitcode_when_rootful(), env=env
)
finally:
self.run_subprocess_assert_returncode(down_cmd, env=env)
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
# can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1)
def test_x_podman_in_pod_custom_name(self) -> None:
"""
Test that podman-compose will create a pod with a custom name
"""
command_up = [
"python3",
os.path.join(base_path(), "podman_compose.py"),
"-f",
os.path.join(
base_path(),
"tests",
"integration",
"in_pod",
"custom_x-podman_custom_name",
"docker-compose.yml",
),
"up",
"--no-start",
]
try:
self.run_subprocess_assert_returncode(command_up)
finally:
command_rm_pod = ["podman", "pod", "rm", "custom_test_pod_name"]
self.run_subprocess_assert_returncode(command_rm_pod)
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self) -> None:
"""
Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error
@ -482,7 +621,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
]
try:
out, err = self.run_subprocess_assert_returncode(command_up)
out, err = self.run_subprocess_assert_returncode(command_up, 125)
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
finally:

View File

@ -0,0 +1 @@

Some files were not shown because too many files have changed in this diff Show More