Skip to content

Commit efa310f

Browse files
authored
Scaffold an execution-environment project using init subcommand (#368)
* Scaffold an execution-environment project using init subcommand * Fix jinja2 error by adding raw block and add integration test * Remove launch.json changes and a minor change in endraw block to prevent adding extra lines in ci.yml workflow file * Add unit test and update README.md
1 parent 1c22085 commit efa310f

File tree

12 files changed

+255
-4
lines changed

12 files changed

+255
-4
lines changed

src/ansible_creator/arg_parser.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ def _init(self, subparser: SubParser[ArgumentParser]) -> None:
457457

458458
self._init_collection(subparser=subparser)
459459
self._init_playbook(subparser=subparser)
460+
self._init_ee_project(subparser=subparser)
460461

461462
def _init_collection(self, subparser: SubParser[ArgumentParser]) -> None:
462463
"""Initialize an Ansible collection.
@@ -518,6 +519,27 @@ def _init_playbook(self, subparser: SubParser[ArgumentParser]) -> None:
518519
self._add_args_common(parser)
519520
self._add_args_init_common(parser)
520521

522+
def _init_ee_project(self, subparser: SubParser[ArgumentParser]) -> None:
523+
"""Initialize an EE project.
524+
525+
Args:
526+
subparser: The subparser to add EE project to
527+
"""
528+
parser = subparser.add_parser(
529+
"execution_env",
530+
help="Create a new execution environment project.",
531+
formatter_class=CustomHelpFormatter,
532+
)
533+
parser.add_argument(
534+
"init_path",
535+
metavar="path",
536+
nargs="?",
537+
help="The destination directory for the EE project.",
538+
)
539+
540+
self._add_args_common(parser)
541+
self._add_args_init_common(parser)
542+
521543
def _valid_collection_name(self, collection: str) -> str:
522544
"""Validate the collection name.
523545
@@ -560,7 +582,7 @@ def handle_deprecations(self) -> bool: # noqa: C901
560582
parser.add_argument("--init-path", help="")
561583
args, extras = parser.parse_known_args()
562584

563-
if args.collection in ["playbook", "collection"]:
585+
if args.collection in ["playbook", "collection", "execution_env"]:
564586
return True
565587
if args.project:
566588
msg = "The `project` flag is no longer needed and will be removed."
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Combine workflow for pull-request, push-to-main and release events.
2+
3+
name: Execution environment build
4+
5+
on:
6+
pull_request_target:
7+
branches:
8+
- main
9+
types: [opened, reopened, synchronize]
10+
push:
11+
branches:
12+
- main
13+
release:
14+
types: [published]
15+
{% raw %}
16+
jobs:
17+
ee-build:
18+
uses: ansible/ansible-content-actions/.github/workflows/ee-build.yml@main
19+
with:
20+
registry: ghcr.io
21+
secrets:
22+
registry_username: ${{ github.actor }}
23+
registry_password: ${{ secrets.GITHUB_TOKEN }}
24+
# Only needed if base image of execution-environment.yml file is from Red Hat (ee-minimal)
25+
# registry_redhat_username: ${{ secrets.registry_redhat_username }}
26+
# registry_redhat_password: ${{ secrets.registry_redhat_password }}
27+
{%- endraw %}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
context/
2+
.DS_Store
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Execution Environment Project
2+
3+
### This is a sample execution environment project to build and publish your EE.
4+
5+
## Included content/ Directory Structure
6+
7+
The directory structure follows best practices recommended by the Ansible community. Feel free to customize this template according to your specific project requirements.
8+
9+
```
10+
├── .github
11+
│ └── workflows
12+
│ └── ci.yml
13+
├── .gitignore
14+
├── README.md
15+
└── execution-environment.yml
16+
```
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
version: 3
3+
4+
images:
5+
base_image:
6+
name: quay.io/fedora/fedora:41
7+
8+
dependencies:
9+
# Use python3
10+
python_interpreter:
11+
package_system: python3
12+
python_path: /usr/bin/python3
13+
14+
ansible_core:
15+
package_pip: ansible-core
16+
17+
ansible_runner:
18+
package_pip: ansible-runner
19+
20+
system:
21+
- openssh-clients
22+
- sshpass
23+
24+
python:
25+
- ansible-navigator
26+
- boto3
27+
- requests
28+
29+
galaxy:
30+
collections:
31+
- name: ansible.posix
32+
- name: ansible.utils
33+
34+
additional_build_steps:
35+
append_base:
36+
- RUN $PYCMD -m pip install -U pip
37+
38+
options:
39+
tags:
40+
- ansible_sample_ee

src/ansible_creator/subcommands/init.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(
5656
def run(self) -> None:
5757
"""Start scaffolding skeleton."""
5858
self._construct_init_path()
59-
self.output.debug(msg=f"final collection path set to {self._init_path}")
59+
self.output.debug(msg=f"final destination path set to {self._init_path}")
6060

6161
if self._init_path.exists():
6262
self.init_exists()
@@ -66,7 +66,7 @@ def run(self) -> None:
6666

6767
def _construct_init_path(self) -> None:
6868
"""Construct the init path based on project type."""
69-
if self._project == "playbook":
69+
if self._project in ("playbook", "execution_env"):
7070
return
7171

7272
if (
@@ -119,6 +119,7 @@ def _scaffold(self) -> None:
119119
CreatorError: When the destination directory contains files that will be overwritten and
120120
the user chooses not to proceed.
121121
"""
122+
resources: tuple[str, ...]
122123
self.output.debug(
123124
msg=f"started copying {self._project} skeleton to destination",
124125
)
@@ -129,8 +130,13 @@ def _scaffold(self) -> None:
129130
dev_file_name=self.unique_name_in_devfile(),
130131
)
131132

133+
if self._project == "execution_env":
134+
resources = (f"{self._project}_project",)
135+
else:
136+
resources = (f"{self._project}_project", *self.common_resources)
137+
132138
walker = Walker(
133-
resources=(f"{self._project}_project", *self.common_resources),
139+
resources=resources,
134140
resource_id=f"{self._project}_project",
135141
dest=self._init_path,
136142
output=self.output,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Combine workflow for pull-request, push-to-main and release events.
2+
3+
name: Execution environment build
4+
5+
on:
6+
pull_request_target:
7+
branches:
8+
- main
9+
types: [opened, reopened, synchronize]
10+
push:
11+
branches:
12+
- main
13+
release:
14+
types: [published]
15+
16+
jobs:
17+
ee-build:
18+
uses: ansible/ansible-content-actions/.github/workflows/ee-build.yml@main
19+
with:
20+
registry: ghcr.io
21+
secrets:
22+
registry_username: ${{ github.actor }}
23+
registry_password: ${{ secrets.GITHUB_TOKEN }}
24+
# Only needed if base image of execution-environment.yml file is from Red Hat (ee-minimal)
25+
# registry_redhat_username: ${{ secrets.registry_redhat_username }}
26+
# registry_redhat_password: ${{ secrets.registry_redhat_password }}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
context/
2+
.DS_Store
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Execution Environment Project
2+
3+
### This is a sample execution environment project to build and publish your EE.
4+
5+
## Included content/ Directory Structure
6+
7+
The directory structure follows best practices recommended by the Ansible community. Feel free to customize this template according to your specific project requirements.
8+
9+
```
10+
├── .github
11+
│ └── workflows
12+
│ └── ci.yml
13+
├── .gitignore
14+
├── README.md
15+
└── execution-environment.yml
16+
```
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
version: 3
3+
4+
images:
5+
base_image:
6+
name: quay.io/fedora/fedora:41
7+
8+
dependencies:
9+
# Use python3
10+
python_interpreter:
11+
package_system: python3
12+
python_path: /usr/bin/python3
13+
14+
ansible_core:
15+
package_pip: ansible-core
16+
17+
ansible_runner:
18+
package_pip: ansible-runner
19+
20+
system:
21+
- openssh-clients
22+
- sshpass
23+
24+
python:
25+
- ansible-navigator
26+
- boto3
27+
- requests
28+
29+
galaxy:
30+
collections:
31+
- name: ansible.posix
32+
- name: ansible.utils
33+
34+
additional_build_steps:
35+
append_base:
36+
- RUN $PYCMD -m pip install -U pip
37+
38+
options:
39+
tags:
40+
- ansible_sample_ee

tests/integration/test_init.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,22 @@ def test_run_init_basic(cli: CliRunCallable, tmp_path: Path) -> None:
141141
result = cli(f"{CREATOR_BIN} init testorg.testcol --init-path {tmp_path} --no-overwrite")
142142
assert result.returncode != 0
143143
assert re.search(r"The flag `--no-overwrite` restricts overwriting.", result.stderr) is not None
144+
145+
146+
def test_run_init_ee(cli: CliRunCallable, tmp_path: Path) -> None:
147+
"""Test running ansible-creator init for ee_project.
148+
149+
Args:
150+
cli: cli_run function.
151+
tmp_path: Temporary path.
152+
"""
153+
final_dest = f"{tmp_path}/ee_project"
154+
cli(f"mkdir -p {final_dest}")
155+
156+
result = cli(
157+
f"{CREATOR_BIN} init execution_env {final_dest}",
158+
)
159+
assert result.returncode == 0
160+
161+
# check stdout
162+
assert re.search(r"Note: execution_env project created at", result.stdout) is not None

tests/units/test_init.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,41 @@ def mock_unique_name_in_devfile(init: Init) -> str:
169169
assert re.search(r"Warning: re-initializing existing directory", result) is not None, result
170170

171171

172+
def test_run_success_ee_project(
173+
capsys: pytest.CaptureFixture[str],
174+
tmp_path: Path,
175+
cli_args: ConfigDict,
176+
) -> None:
177+
"""Test Init.run().
178+
179+
Successfully create new ee project
180+
181+
Args:
182+
capsys: Pytest fixture to capture stdout and stderr.
183+
tmp_path: Temporary directory path.
184+
cli_args: Dictionary, partial Init class object.
185+
"""
186+
cli_args["project"] = "execution_env"
187+
cli_args["init_path"] = str(tmp_path / "new_project")
188+
init = Init(
189+
Config(**cli_args),
190+
)
191+
192+
init.run()
193+
result = capsys.readouterr().out
194+
195+
# check stdout
196+
assert re.search(r"Note: execution_env project created", result) is not None
197+
198+
# recursively assert files created
199+
cmp = dircmp(
200+
str(tmp_path / "new_project"),
201+
str(FIXTURES_DIR / "project" / "ee_project"),
202+
)
203+
diff = has_differences(dcmp=cmp, errors=[])
204+
assert diff == [], diff
205+
206+
172207
def test_run_success_ansible_project(
173208
capsys: pytest.CaptureFixture[str],
174209
tmp_path: Path,

0 commit comments

Comments
 (0)