89 Commits
v1.4.1 ... main

Author SHA1 Message Date
406596e1db Merge pull request #1259 from mokibit/push-non-zero-exit-code
Properly surface errors from `push` command
2025-07-03 15:10:37 +03:00
b3fd55047b tests/integration: Rename dir build_fail_multi
Renamed directory `build_fail_multi` to more appropriate
`commands_fail_exit_code` as more tests were added to other
commands:`push` and `run`. Names of tests were changed accordingly.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-07-03 14:37:58 +03:00
c1ca9166c6 tests/integration: Add test for run command failure exit code
Test is added to confirm that `run` command forwards non-zero failure
exit code.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-07-02 23:34:25 +03:00
256b51c8ee Properly surface errors from push command
Failure exit code for `push` command is not currently forwarded as exit
code for podman-compose.
With this PR, podman-compose stops pushing when the underlying podman
command fails and forwards its exit code.

Signed-off-by: Monika Kairaityte <monika@kibit.lt>
2025-07-02 23:34:24 +03:00
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
143 changed files with 2246 additions and 866 deletions

View File

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

View File

@ -19,11 +19,12 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
$ cd podman-compose $ cd podman-compose
``` ```
2. (OPTIONAL) Create a Python virtual environment. Example using 2. (OPTIONAL) Create a Python virtual environment. Example using python builtin
[virtualenv wrapper](https://virtualenvwrapper.readthedocs.io/en/latest/): `venv` module:
```shell ```shell
$ mkvirtualenv podman-compose $ python3 -m venv .venv
$ . .venv/bin/activate
``` ```
3. Install the project runtime and development requirements: 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. - 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) Read [this guide](https://github.com/containers/common/blob/main/CONTRIBUTING.md#sign-your-prs)
to learn how to sign your commits. to learn how to sign your commits.
- In the commit message, reference the Issue ID that your code fixes and a brief description of - In the commit message body, reference the Issue ID that your code fixes and a brief description of the changes.
the changes. Example:
Example: `Fixes #516: Allow empty network` ```
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. 9. Open a pull request to `containers/podman-compose` and wait for a maintainer to review your work.
## Adding new commands ## 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 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 ```bash
brew install podman-compose 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 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 ## Tests
Inside `tests/` directory we have many useless docker-compose stacks podman-compose is tested via unit and integration tests.
that are meant to test as many cases as we can to make sure we are compatible
### Unit tests with unittest Unit tests can be run via the following:
run a unittest with following command
```shell ```shell
python3 -m unittest discover tests/unit python3 -m unittest discover tests/unit
``` ```
Integration tests can be run via the following:
```shell
python3 -m unittest discover tests/integration
```
# Contributing guide # Contributing guide
If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section

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,22 @@ services:
For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/). 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 ## Network management
The following extension keys are available under network configuration: The following extension keys are available under network configuration:
@ -123,6 +139,44 @@ The options to the network modes are passed to the `--network` option of the `po
as-is. 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 ## Compatibility of default network names between docker-compose and podman-compose
Current versions of podman-compose may produce different default external network names than Current versions of podman-compose may produce different default external network names than
@ -140,6 +194,9 @@ x-podman:
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
setting will be removed. 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 ## Compatibility of default network behavior between docker-compose and podman-compose
When there is no network defined (neither network-mode nor networks) in service, When there is no network defined (neither network-mode nor networks) in service,
@ -160,6 +217,9 @@ x-podman:
default_net_behavior_compat: true default_net_behavior_compat: true
``` ```
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_BEHAVIOR_COMPAT` environment
variable.
## Custom pods management ## Custom pods management
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod. Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
@ -179,6 +239,9 @@ x-podman:
in_pod: false 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 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: used when --pod-args is not passed on the command line:
```yml ```yml
@ -192,3 +255,6 @@ x-podman:
``` ```
When not set in docker-compose.yml or on the command line, the pod args default When not set in docker-compose.yml or on the command line, the pod args default
to `["--infra=false", "--share="]`. to `["--infra=false", "--share="]`.
This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment
variable.

View File

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

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] [tool.ruff]
line-length = 100 line-length = 100
target-version = "py38" target-version = "py38"
@ -53,3 +109,21 @@ quote-style = "preserve"
directory = "misc" directory = "misc"
name = "Misc" name = "Misc"
showcontent = true 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 #!/usr/bin/env bash
./scripts/uninstall.sh ./scripts/uninstall.sh
./scripts/clean_up.sh ./scripts/clean_up.sh
python3 setup.py register pyproject-build
python3 setup.py sdist bdist_wheel
twine upload dist/* twine upload dist/*

View File

@ -1,11 +1,5 @@
[bdist_wheel]
universal = 1
[metadata]
version = attr: podman_compose.__version__
[flake8] [flake8]
# The GitHub editor is 127 chars wide # The GitHub editor is 127 chars wide
max-line-length=127 max-line-length=127
# These are not being followed yet # These are not being followed yet
ignore=E222,E231,E272,E713,W503 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 . -e .
coverage==7.4.3 coverage==7.4.3
cryptography==44.0.3
parameterized==0.9.0 parameterized==0.9.0
pytest==8.0.2 pytest==8.0.2
tox==4.13.0 tox==4.13.0
ruff==0.3.1 mypy==1.15.0
ruff==0.11.11
pylint==3.1.0 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 # The packages below are transitive dependencies of the packages above and are included here
# to make testing reproducible. # to make testing reproducible.
@ -23,6 +28,7 @@ filelock==3.13.1
iniconfig==2.0.0 iniconfig==2.0.0
isort==5.13.2 isort==5.13.2
mccabe==0.7.0 mccabe==0.7.0
mypy_extensions==1.1.0
packaging==23.2 packaging==23.2
platformdirs==4.2.0 platformdirs==4.2.0
pluggy==1.4.0 pluggy==1.4.0
@ -31,4 +37,5 @@ python-dotenv==1.0.1
PyYAML==6.0.1 PyYAML==6.0.1
requests requests
tomlkit==0.12.4 tomlkit==0.12.4
typing_extensions==4.13.2
virtualenv==20.26.6 virtualenv==20.26.6

View File

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

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path from tests.integration.test_utils import test_path
def compose_yaml_path(failure_order): def compose_yaml_path(failure_order: str) -> str:
return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml") return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml")
@ -25,7 +25,7 @@ class TestComposeAbort(unittest.TestCase, RunSubprocessMixin):
("exit", "none", 0), ("exit", "none", 0),
("failure", "none", 0), ("failure", "none", 0),
]) ])
def test_abort(self, abort_type, failure_order, expected_exit_code): def test_abort(self, abort_type: str, failure_order: str, expected_exit_code: int) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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""" """ "Returns the path to the compose file used for this test module"""
return os.path.join(test_path(), "additional_contexts", "project") return os.path.join(test_path(), "additional_contexts", "project")
class TestComposeBuildAdditionalContexts(unittest.TestCase): 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 """podman build should receive additional contexts as --build-context
See additional_context/project/docker-compose.yaml for context paths See additional_context/project/docker-compose.yaml for context paths

View File

@ -0,0 +1 @@
test

View File

@ -3,3 +3,12 @@ services:
test: test:
build: ./context build: ./context
image: build-fail-img 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

@ -22,9 +22,48 @@ class TestComposeBuildFail(unittest.TestCase, RunSubprocessMixin):
"-f", "-f",
compose_yaml_path(), compose_yaml_path(),
"build", "build",
"test",
], ],
expected_returncode=127, expected_returncode=127,
) )
self.assertIn("RUN this_command_does_not_exist", str(output)) self.assertIn("RUN this_command_does_not_exist", str(output))
self.assertIn("this_command_does_not_exist: not found", str(error)) self.assertIn("this_command_does_not_exist: not found", str(error))
self.assertIn("while running runtime: exit status 127", 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

@ -1,31 +0,0 @@
# 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

@ -0,0 +1,76 @@
# 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:
""" "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "commands_fail_exit_code")
return os.path.join(base_path, "docker-compose.yml")
class TestComposeCommandsFailExitCodes(unittest.TestCase, RunSubprocessMixin):
def test_build_command_fail(self) -> None:
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))
def test_push_command_fail(self) -> None:
# test that push command is able to return other than "0" return code
# "push" command fails due to several steps missing before running it (logging, tagging)
try:
output, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"push",
"good",
],
expected_returncode=125,
)
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
def test_run_command_fail(self) -> None:
# test that run command is able to return other than "0" return code
try:
output, error = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"run",
"bad",
],
expected_returncode=125,
)
self.assertIn("RUN false", str(output))
self.assertIn("while running runtime: exit status 1", str(error))
finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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( return os.path.join(
os.path.join(test_path(), "default_net_behavior"), f"docker-compose_{scenario}.yaml" 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'), ('two_nets_compat', 'default_net_behavior_default'),
('with_default_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: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(scenario), "up", "-d"], [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(), podman_compose_path(),
"-f", "-f",
@ -43,7 +43,7 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
'{{.ID}}', '{{.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( output, _ = self.run_subprocess_assert_returncode(
[ [
"podman", "podman",

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path from tests.integration.test_utils import test_path
def compose_yaml_path(suffix=""): def compose_yaml_path(suffix: str = "") -> str:
return os.path.join(os.path.join(test_path(), "deps"), f"docker-compose{suffix}.yaml") return os.path.join(os.path.join(test_path(), "deps"), f"docker-compose{suffix}.yaml")
class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin): class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps(self): def test_deps(self) -> None:
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -37,7 +37,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_run_nodeps(self): def test_run_nodeps(self) -> None:
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -62,7 +62,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_up_nodeps(self): def test_up_nodeps(self) -> None:
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -89,7 +89,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_podman_compose_run(self): def test_podman_compose_run(self) -> None:
""" """
This will test depends_on as well This will test depends_on as well
""" """
@ -143,7 +143,7 @@ class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin): class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
def test_deps_succeeds(self): def test_deps_succeeds(self) -> None:
suffix = "-conditional-succeeds" suffix = "-conditional-succeeds"
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
@ -167,7 +167,7 @@ class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_deps_fails(self): def test_deps_fails(self) -> None:
suffix = "-conditional-fails" suffix = "-conditional-fails"
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
@ -188,10 +188,10 @@ class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubprocessMixin): class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubprocessMixin):
def setUp(self): def setUp(self) -> None:
self.podman_version = self.retrieve_podman_version() self.podman_version = self.retrieve_podman_version()
def test_up_deps_healthy(self): def test_up_deps_healthy(self) -> None:
suffix = "-conditional-healthy" suffix = "-conditional-healthy"
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
@ -261,6 +261,6 @@ class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubproc
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
"-f", "-f",
compose_yaml_path(), compose_yaml_path(suffix),
"down", "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

@ -1,2 +1,3 @@
ZZVAR1='This value is loaded but should be overwritten' ZZVAR1='This value is loaded but should be overwritten'
ZZVAR2='This value is loaded from .env in project/ directory' 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

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path from tests.integration.test_utils import test_path
def compose_base_path(): def compose_base_path() -> str:
return os.path.join(test_path(), "env-file-tests") return os.path.join(test_path(), "env_file_tests")
class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin): 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 # Test taking env variable value directly from env-file when its path is inline path
base_path = compose_base_path() base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml") path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -42,7 +42,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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 # Test taking env variable value from env-file/project-1.env which was declared in
# compose file's env_file # compose file's env_file
base_path = compose_base_path() base_path = compose_base_path()
@ -74,7 +74,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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 # take variable value from env-file project-1.env which was declared in compose
# file's env_file by -path: ... # file's env_file by -path: ...
base_path = compose_base_path() base_path = compose_base_path()
@ -106,7 +106,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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 # test taking env variable values from several env-files when one of them is optional
# and exists # and exists
base_path = compose_base_path() base_path = compose_base_path()
@ -139,7 +139,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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 # test taking env variable values from several env-files when one of them is optional and
# is missing (silently skip it) # is missing (silently skip it)
base_path = compose_base_path() base_path = compose_base_path()
@ -173,7 +173,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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 # Test overriding env value when value is declared in inline command
base_path = compose_base_path() base_path = compose_base_path()
path_compose_file = os.path.join(base_path, "project/container-compose.yaml") path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
@ -204,7 +204,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
"down", "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: # 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 # 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 # 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', 'ZZVAR1=This value is loaded but should be overwritten\r',
'ZZVAR2=This value is loaded from .env in project/ directory\r', 'ZZVAR2=This value is loaded from .env in project/ directory\r',
'ZZVAR3=\r', 'ZZVAR3=TEST\r',
'', '',
], ],
) )
@ -244,3 +244,36 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
path_compose_file, path_compose_file,
"down", "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

@ -8,14 +8,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "env-tests"), "container-compose.yml") return os.path.join(os.path.join(test_path(), "env_tests"), "container-compose.yml")
class TestComposeEnv(unittest.TestCase, RunSubprocessMixin): class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
"""Test that inline environment variable overrides environment variable from compose file.""" """Test that inline environment variable overrides environment variable from compose file."""
def test_env(self): def test_env(self) -> None:
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -50,7 +50,7 @@ class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
- https://github.com/compose-spec/compose-spec/blob/main/04-version-and-name.md - https://github.com/compose-spec/compose-spec/blob/main/04-version-and-name.md
""" """
def test_project_name(self): def test_project_name(self) -> None:
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -68,7 +68,7 @@ class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_project_name_override(self): def test_project_name_override(self) -> None:
try: try:
output, _ = self.run_subprocess_assert_returncode([ output, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),

View File

@ -0,0 +1 @@

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "exit-from"), "docker-compose.yaml") return os.path.join(os.path.join(test_path(), "exit_from"), "docker-compose.yaml")
class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin): class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
def test_exit_code_sh1(self): def test_exit_code_sh1(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [
@ -33,7 +33,7 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_exit_code_sh2(self): def test_exit_code_sh2(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [
@ -53,13 +53,13 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_podman_compose_exit_from(self): def test_podman_compose_exit_from(self) -> None:
up_cmd = [ up_cmd = [
"coverage", "coverage",
"run", "run",
podman_compose_path(), podman_compose_path(),
"-f", "-f",
os.path.join(test_path(), "exit-from", "docker-compose.yaml"), compose_yaml_path(),
"up", "up",
] ]

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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") return os.path.join(os.path.join(test_path(), "extends"), "docker-compose.yaml")
class TestComposeExteds(unittest.TestCase, RunSubprocessMixin): class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
def test_extends_service_launch_echo(self): def test_extends_service_launch_echo(self) -> None:
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -38,7 +38,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_extends_service_launch_echo1(self): def test_extends_service_launch_echo1(self) -> None:
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -63,7 +63,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_extends_service_launch_env1(self): def test_extends_service_launch_env1(self) -> None:
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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") return os.path.join(os.path.join(test_path(), "extends_w_empty_service"), "docker-compose.yml")
class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin): class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_empty_service(self): def test_extends_w_empty_service(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [
@ -39,7 +39,7 @@ class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_podman_compose_extends_w_empty_service(self): 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 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 includes an empty service. (e.g. if the file is used as placeholder for more complex

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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") return os.path.join(os.path.join(test_path(), "extends_w_file"), "docker-compose.yml")
class TestComposeExtendsWithFile(unittest.TestCase, RunSubprocessMixin): 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: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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_subdir"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "extends_w_file_subdir"), "docker-compose.yml")
class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin): class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
def test_extends_w_file_subdir(self): # when file is Dockerfile for building the image def test_extends_w_file_subdir(self) -> None: # when file is Dockerfile for building the image
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [
@ -39,7 +39,7 @@ class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
"down", "down",
]) ])
def test_podman_compose_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 Test that podman-compose can execute podman-compose -f <file> up with extended File which
includes a build context includes a build context

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import test_path
class TestFilesystem(unittest.TestCase, RunSubprocessMixin): 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 """The context of podman-compose.yml should come from the same directory as the file even
if it is a symlink if it is a symlink
""" """

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,26 +6,26 @@ import unittest
from tests.integration.test_utils import RunSubprocessMixin from tests.integration.test_utils import RunSubprocessMixin
def base_path(): def base_path() -> str:
"""Returns the base path for the project""" """Returns the base path for the project"""
return os.path.dirname(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""" """Returns the path to the tests directory"""
return os.path.join(base_path(), "tests/integration") 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""" """Returns the path to the podman compose script"""
return os.path.join(base_path(), "podman_compose.py") return os.path.join(base_path(), "podman_compose.py")
def is_root(): def is_root() -> bool:
return os.geteuid() == 0 return os.geteuid() == 0
def failure_exitcode_when_rootful(): def failure_exitcode_when_rootful() -> int:
if is_root(): if is_root():
return 125 return 125
return 0 return 0
@ -37,7 +37,7 @@ def failure_exitcode_when_rootful():
# Test all combinations of command line argument in_pod and compose file argument in_pod. # Test all combinations of command line argument in_pod and compose file argument in_pod.
class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin): class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# compose file provides x-podman in_pod=false # 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 Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
does not provide this option does not provide this option
@ -82,7 +82,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# throws an error, can not actually find this pod because it was not created # 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) 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 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 when --userns and --pod are set together: throws an error
@ -115,7 +115,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above) # been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod) 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 Test that podman-compose will not create a pod as command line sets in_pod=False
""" """
@ -160,7 +160,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created # can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1) 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 Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
command line in_pod="" command line in_pod=""
@ -207,7 +207,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod, 1) self.run_subprocess_assert_returncode(command_rm_pod, 1)
# compose file provides x-podman in_pod=true # 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 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 together even when x-podman in_pod=true: throws an error
@ -240,7 +240,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above) # created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod) 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 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 together even when x-podman in_pod=true and and command line in_pod=True: throws an error
@ -274,7 +274,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above) # been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod) 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 Test that podman-compose will not create a pod as command line sets in_pod=False
""" """
@ -319,7 +319,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created # can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1) 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 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 together even when x-podman in_pod=true and command line in_pod="": throws an error
@ -354,7 +354,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
self.run_subprocess_assert_returncode(command_rm_pod) self.run_subprocess_assert_returncode(command_rm_pod)
# compose file does not provide x-podman in_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 Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error together: throws an error
@ -387,7 +387,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# created) and have expected_returncode=1 (see FIXME above) # created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod) 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 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 together even when x-podman in_pod=true: throws an error
@ -421,7 +421,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# been created) and have expected_returncode=1 (see FIXME above) # been created) and have expected_returncode=1 (see FIXME above)
self.run_subprocess_assert_returncode(command_rm_pod) 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 Test that podman-compose will not create a pod as command line sets in_pod=False
""" """
@ -467,7 +467,136 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
# can not actually find this pod because it was not created # can not actually find this pod because it was not created
self.run_subprocess_assert_returncode(command_rm_pod, 1) 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 Test that podman-compose does not allow pod creating when --userns and --pod are set
together: throws an error together: throws an error

View File

@ -7,7 +7,7 @@ from tests.integration.test_utils import RunSubprocessMixin
class TestPodmanComposeInclude(unittest.TestCase, RunSubprocessMixin): class TestPodmanComposeInclude(unittest.TestCase, RunSubprocessMixin):
def test_podman_compose_include(self): def test_podman_compose_include(self) -> None:
""" """
Test that podman-compose can execute podman-compose -f <file> up with include Test that podman-compose can execute podman-compose -f <file> up with include
:return: :return:

View File

@ -1 +1,2 @@
DOT_ENV_VARIABLE=This value is from the .env file DOT_ENV_VARIABLE=This value is from the .env file
TEST_LABELS=TEST

View File

@ -11,4 +11,10 @@ services:
EXAMPLE_DOT_ENV: $DOT_ENV_VARIABLE EXAMPLE_DOT_ENV: $DOT_ENV_VARIABLE
EXAMPLE_LITERAL: This is a $$literal EXAMPLE_LITERAL: This is a $$literal
EXAMPLE_EMPTY: $NOT_A_VARIABLE EXAMPLE_EMPTY: $NOT_A_VARIABLE
labels_test:
image: busybox
labels:
- "$TEST_LABELS=test_labels"
- test.${TEST_LABELS}=${TEST_LABELS}
- "${TEST_LABELS}.test2=test2(`${TEST_LABELS}`)"

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
import json
import os import os
import unittest import unittest
@ -8,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "interpolation"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "interpolation"), "docker-compose.yml")
class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin): class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin):
def test_interpolation(self): def test_interpolation(self) -> None:
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
"env", "env",
@ -36,6 +37,18 @@ class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin):
self.assertIn("EXAMPLE_DOT_ENV='This value is from the .env file'", str(output)) self.assertIn("EXAMPLE_DOT_ENV='This value is from the .env file'", str(output))
self.assertIn("EXAMPLE_EMPTY=''", str(output)) self.assertIn("EXAMPLE_EMPTY=''", str(output))
self.assertIn("EXAMPLE_LITERAL='This is a $literal'", str(output)) self.assertIn("EXAMPLE_LITERAL='This is a $literal'", str(output))
output, _ = self.run_subprocess_assert_returncode([
"podman",
"inspect",
"interpolation_labels_test_1",
])
inspect_output = json.loads(output)
labels_dict = inspect_output[0].get("Config", {}).get("Labels", {})
self.assertIn(('TEST', 'test_labels'), labels_dict.items())
self.assertIn(('TEST.test2', 'test2(`TEST`)'), labels_dict.items())
self.assertIn(('test.TEST', 'TEST'), labels_dict.items())
finally: finally:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),

View File

@ -9,12 +9,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "ipam_default"), "docker-compose.yaml") return os.path.join(os.path.join(test_path(), "ipam_default"), "docker-compose.yaml")
class TestComposeIpamDefault(unittest.TestCase, RunSubprocessMixin): class TestComposeIpamDefault(unittest.TestCase, RunSubprocessMixin):
def test_ipam_default(self): def test_ipam_default(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"], [podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"],

View File

View File

@ -2,6 +2,7 @@
import os import os
import time
import unittest import unittest
from parameterized import parameterized from parameterized import parameterized
@ -12,7 +13,7 @@ from tests.integration.test_utils import test_path
class TestLifetime(unittest.TestCase, RunSubprocessMixin): class TestLifetime(unittest.TestCase, RunSubprocessMixin):
def test_up_single_container(self): def test_up_single_container(self) -> None:
"""Podman compose up should be able to start containers one after another""" """Podman compose up should be able to start containers one after another"""
compose_path = os.path.join(test_path(), "lifetime/up_single_container/docker-compose.yml") compose_path = os.path.join(test_path(), "lifetime/up_single_container/docker-compose.yml")
@ -68,7 +69,7 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
("no_ports", "up_single_container_many_times"), ("no_ports", "up_single_container_many_times"),
("with_ports", "up_single_container_many_times_with_ports"), ("with_ports", "up_single_container_many_times_with_ports"),
]) ])
def test_up_single_container_many_times(self, name, subdir): def test_up_single_container_many_times(self, name: str, subdir: str) -> None:
"""Podman compose up should be able to start a container many times after it finishes """Podman compose up should be able to start a container many times after it finishes
running. running.
""" """
@ -85,15 +86,14 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
"container1", "container1",
]) ])
for _ in range(0, 3): self.run_subprocess_assert_returncode([
self.run_subprocess_assert_returncode([ podman_compose_path(),
podman_compose_path(), "-f",
"-f", compose_path,
compose_path, "up",
"up", "-d",
"-d", "container2",
"container2", ])
])
out, _ = self.run_subprocess_assert_returncode([ out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
@ -105,6 +105,7 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
self.assertEqual(out, b"test1\n") self.assertEqual(out, b"test1\n")
# "restart: always" keeps restarting container until its removal
out, _ = self.run_subprocess_assert_returncode([ out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
"-f", "-f",
@ -113,13 +114,22 @@ class TestLifetime(unittest.TestCase, RunSubprocessMixin):
"container2", "container2",
]) ])
# BUG: container should be started 3 times, not 4. if not out.startswith(b"test2\ntest2"):
self.assertEqual(out, b"test2\n" * 4) time.sleep(1)
out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_path,
"logs",
"container2",
])
self.assertTrue(out.startswith(b"test2\ntest2"))
finally: finally:
out, _ = self.run_subprocess_assert_returncode([ out, _ = self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),
"-f", "-f",
compose_path, compose_path,
"down", "down",
"-t",
"0",
]) ])

View File

@ -5,5 +5,5 @@ services:
command: ["/bin/bash", "-c", "echo test1; sleep infinity"] command: ["/bin/bash", "-c", "echo test1; sleep infinity"]
container2: container2:
image: nopush/podman-compose-test image: nopush/podman-compose-test
restart: never restart: always
command: ["/bin/bash", "-c", "echo test2"] command: ["/bin/bash", "-c", "echo test2"]

View File

@ -6,6 +6,6 @@ services:
command: ["/bin/bash", "-c", "echo test1; sleep infinity"] command: ["/bin/bash", "-c", "echo test1; sleep infinity"]
container2: container2:
image: nopush/podman-compose-test image: nopush/podman-compose-test
restart: never restart: always
ports: "9002:9002" ports: "9002:9002"
command: ["/bin/bash", "-c", "echo test2"] command: ["/bin/bash", "-c", "echo test2"]

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -9,16 +9,19 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "override_tag_attribute"), "docker-compose.yaml") return os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_attribute/docker-compose.yaml",
)
class TestComposeOverrideTagAttribute(unittest.TestCase, RunSubprocessMixin): class TestComposeOverrideTagAttribute(unittest.TestCase, RunSubprocessMixin):
# test if a service attribute from docker-compose.yaml file is overridden # test if a service attribute from docker-compose.yaml file is overridden
def test_override_tag_attribute(self): def test_override_tag_attribute(self) -> None:
override_file = os.path.join( override_file = os.path.join(
os.path.join(test_path(), "override_tag_attribute"), test_path(),
"docker-compose.override_attribute.yaml", "merge/reset_and_override_tags/override_tag_attribute/docker-compose.override_attribute.yaml",
) )
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([

View File

@ -9,16 +9,19 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "override_tag_service"), "docker-compose.yaml") return os.path.join(
test_path(),
"merge/reset_and_override_tags/override_tag_service/docker-compose.yaml",
)
class TestComposeOverrideTagService(unittest.TestCase, RunSubprocessMixin): class TestComposeOverrideTagService(unittest.TestCase, RunSubprocessMixin):
# test if whole service from docker-compose.yaml file is overridden in another file # test if whole service from docker-compose.yaml file is overridden in another file
def test_override_tag_service(self): def test_override_tag_service(self) -> None:
override_file = os.path.join( override_file = os.path.join(
os.path.join(test_path(), "override_tag_service"), test_path(),
"docker-compose.override_service.yaml", "merge/reset_and_override_tags/override_tag_service/docker-compose.override_service.yaml",
) )
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([

View File

@ -3,3 +3,4 @@ services:
app: app:
image: busybox image: busybox
command: !reset {} command: !reset {}
depends_on: !reset null

View File

@ -3,3 +3,5 @@ services:
app: app:
image: busybox image: busybox
command: ["/bin/busybox", "echo", "Zero"] command: ["/bin/busybox", "echo", "Zero"]
depends_on:
- db

View File

@ -8,15 +8,19 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "reset_tag_attribute"), "docker-compose.yaml") return os.path.join(
test_path(),
"merge/reset_and_override_tags/reset_tag_attribute/docker-compose.yaml",
)
class TestComposeResetTagAttribute(unittest.TestCase, RunSubprocessMixin): class TestComposeResetTagAttribute(unittest.TestCase, RunSubprocessMixin):
# test if the attribute of the service is correctly reset # test if the attribute of the service is correctly reset
def test_reset_tag_attribute(self): def test_reset_tag_attribute(self) -> None:
reset_file = os.path.join( reset_file = os.path.join(
os.path.join(test_path(), "reset_tag_attribute"), "docker-compose.reset_attribute.yaml" test_path(),
"merge/reset_and_override_tags/reset_tag_attribute/docker-compose.reset_attribute.yaml",
) )
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
@ -49,6 +53,8 @@ class TestComposeResetTagAttribute(unittest.TestCase, RunSubprocessMixin):
"logs", "logs",
]) ])
self.assertEqual(output, b"") self.assertEqual(output, b"")
# depends_on: !reset null testing: if this test works, depends_on is correctly reset.
# Otherwise the test would break, since "db" dependency service is not provided
finally: finally:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
podman_compose_path(), podman_compose_path(),

View File

@ -8,15 +8,18 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "reset_tag_service"), "docker-compose.yaml") return os.path.join(
test_path(), "merge/reset_and_override_tags/reset_tag_service/docker-compose.yaml"
)
class TestComposeResetTagService(unittest.TestCase, RunSubprocessMixin): class TestComposeResetTagService(unittest.TestCase, RunSubprocessMixin):
# test if whole service from docker-compose.yaml file is reset # test if whole service from docker-compose.yaml file is reset
def test_reset_tag_service(self): def test_reset_tag_service(self) -> None:
reset_file = os.path.join( reset_file = os.path.join(
os.path.join(test_path(), "reset_tag_service"), "docker-compose.reset_service.yaml" test_path(),
"merge/reset_and_override_tags/reset_tag_service/docker-compose.reset_service.yaml",
) )
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([

View File

@ -9,14 +9,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path from tests.integration.test_utils import test_path
def compose_yaml_path(compose_name): def compose_yaml_path(compose_name: str) -> str:
""" "Returns the path to the compose file used for this test module""" """ "Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "volumes_merge/") base_path = os.path.join(test_path(), "merge/volumes_merge/")
return os.path.join(base_path, compose_name) return os.path.join(base_path, compose_name)
class TestComposeVolumesMerge(unittest.TestCase, RunSubprocessMixin): class TestComposeVolumesMerge(unittest.TestCase, RunSubprocessMixin):
def test_volumes_merge(self): def test_volumes_merge(self) -> None:
# test if additional compose file overrides host path and access mode of a volume # test if additional compose file overrides host path and access mode of a volume
try: try:
self.run_subprocess_assert_returncode([ self.run_subprocess_assert_returncode([
@ -55,7 +55,7 @@ class TestComposeVolumesMerge(unittest.TestCase, RunSubprocessMixin):
binds_info = volumes_info["HostConfig"]["Binds"] binds_info = volumes_info["HostConfig"]["Binds"]
binds_info.sort() binds_info.sort()
file_path = os.path.join(test_path(), "volumes_merge/override.txt") file_path = os.path.join(test_path(), "merge/volumes_merge/override.txt")
expected = [ expected = [
f'{file_path}:/var/www/html/index.html:ro,rprivate,rbind', f'{file_path}:/var/www/html/index.html:ro,rprivate,rbind',
f'{file_path}:/var/www/html/index2.html:rw,rprivate,rbind', f'{file_path}:/var/www/html/index2.html:rw,rprivate,rbind',

View File

@ -8,12 +8,12 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "multicompose"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "multicompose"), "docker-compose.yml")
class TestComposeMulticompose(unittest.TestCase, RunSubprocessMixin): class TestComposeMulticompose(unittest.TestCase, RunSubprocessMixin):
def test_multicompose(self): def test_multicompose(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,7 @@
services:
web:
image: busybox
command: httpd -f -p 8123 -h /tmp/
x-podman:
name_separator_compat: true

View File

@ -0,0 +1,4 @@
services:
web:
image: busybox
command: httpd -f -p 8123 -h /tmp/

View File

@ -0,0 +1,60 @@
# 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
class TestComposeNameSeparatorCompat(unittest.TestCase, RunSubprocessMixin):
@parameterized.expand([
('default', {}, '_'),
('default', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1'}, '-'),
('default', {'PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT': '1'}, '-'),
('compat', {}, '-'),
('compat', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1'}, '-'),
('compat', {'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '0'}, '_'),
])
def test_container_name(self, file: str, env: dict[str, str], expected_sep: str) -> None:
compose_yaml_path = os.path.join(
test_path(), "name_separator_compat", f"docker-compose_{file}.yaml"
)
try:
self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path, "up", "-d"],
env=env,
)
container_name_out, _ = self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path,
"ps",
"--format",
'{{.Names}}',
],
env=env,
)
container_name = container_name_out.decode('utf-8').strip()
expected_container_name = f'name_separator_compat{expected_sep}web{expected_sep}1'
self.assertEqual(container_name, expected_container_name)
finally:
self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path,
"down",
"-t",
"0",
],
env=env,
)

View File

@ -10,20 +10,20 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "nethost"), "docker-compose.yaml") return os.path.join(os.path.join(test_path(), "nethost"), "docker-compose.yaml")
class TestComposeNethost(unittest.TestCase, RunSubprocessMixin): class TestComposeNethost(unittest.TestCase, RunSubprocessMixin):
# check if container listens for http requests and sends response back # check if container listens for http requests and sends response back
# as network_mode: host allows to connect to container easily # as network_mode: host allows to connect to container easily
def test_nethost(self): def test_nethost(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"], [podman_compose_path(), "-f", compose_yaml_path(), "up", "-d"],
) )
container_id, _ = self.run_subprocess_assert_returncode( container_id_out, _ = self.run_subprocess_assert_returncode(
[ [
podman_compose_path(), podman_compose_path(),
"-f", "-f",
@ -33,7 +33,7 @@ class TestComposeNethost(unittest.TestCase, RunSubprocessMixin):
'{{.ID}}', '{{.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( output, _ = self.run_subprocess_assert_returncode(
[ [
"podman", "podman",

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "nets_test1"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "nets_test1"), "docker-compose.yml")
class TestComposeNetsTest1(unittest.TestCase, RunSubprocessMixin): class TestComposeNetsTest1(unittest.TestCase, RunSubprocessMixin):
# test if port mapping works as expected # test if port mapping works as expected
def test_nets_test1(self): def test_nets_test1(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

@ -11,13 +11,13 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "nets_test2"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "nets_test2"), "docker-compose.yml")
class TestComposeNetsTest2(unittest.TestCase, RunSubprocessMixin): class TestComposeNetsTest2(unittest.TestCase, RunSubprocessMixin):
# test if port mapping works as expected with networks top-level element # test if port mapping works as expected with networks top-level element
def test_nets_test2(self): def test_nets_test2(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

View File

@ -10,7 +10,7 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "nets_test3"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "nets_test3"), "docker-compose.yml")
@ -28,8 +28,12 @@ class TestComposeNetsTest3(unittest.TestCase, RunSubprocessMixin):
("nets_test3_web1_1", "alias21", b"", 1), ("nets_test3_web1_1", "alias21", b"", 1),
]) ])
def test_nets_test3( def test_nets_test3(
self, container_name, nework_alias_name, expected_text, expected_returncode self,
): container_name: str,
nework_alias_name: str,
expected_text: bytes,
expected_returncode: int,
) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

View File

@ -8,14 +8,14 @@ from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_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(), "nets_test_ip"), "docker-compose.yml") return os.path.join(os.path.join(test_path(), "nets_test_ip"), "docker-compose.yml")
class TestComposeNetsTestIp(unittest.TestCase, RunSubprocessMixin): class TestComposeNetsTestIp(unittest.TestCase, RunSubprocessMixin):
# test if services retain custom ipv4_address and mac_address matching the subnet provided # test if services retain custom ipv4_address and mac_address matching the subnet provided
# in networks top-level element # in networks top-level element
def test_nets_test_ip(self): def test_nets_test_ip(self) -> None:
try: try:
self.run_subprocess_assert_returncode( self.run_subprocess_assert_returncode(
[ [

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