├── src └── ansible_creator │ ├── py.typed │ ├── _version.pyi │ ├── resources │ ├── collection_project │ │ ├── MAINTAINERS │ │ ├── docs │ │ │ ├── .keep │ │ │ └── docsite │ │ │ │ └── links.yml.j2 │ │ ├── tests │ │ │ ├── unit │ │ │ │ ├── .keep │ │ │ │ ├── __init__.py │ │ │ │ └── test_basic.py.j2 │ │ │ ├── .gitignore │ │ │ └── integration │ │ │ │ ├── __init__.py.j2 │ │ │ │ ├── targets │ │ │ │ └── hello_world │ │ │ │ │ └── tasks │ │ │ │ │ └── main.yml.j2 │ │ │ │ └── test_integration.py.j2 │ │ ├── plugins │ │ │ ├── action │ │ │ │ ├── __init__.py.j2 │ │ │ │ └── sample_action.py.j2 │ │ │ ├── cache │ │ │ │ └── __init__.py.j2 │ │ │ ├── filter │ │ │ │ ├── __init__.py.j2 │ │ │ │ └── sample_filter.py.j2 │ │ │ ├── lookup │ │ │ │ ├── __init__.py.j2 │ │ │ │ └── sample_lookup.py.j2 │ │ │ ├── test │ │ │ │ ├── __init__.py.j2 │ │ │ │ └── sample_test.py.j2 │ │ │ ├── inventory │ │ │ │ └── __init__.py.j2 │ │ │ ├── modules │ │ │ │ ├── __init__.py.j2 │ │ │ │ ├── sample_action.py.j2 │ │ │ │ └── sample_module.py.j2 │ │ │ ├── sub_plugins │ │ │ │ └── __init__.py.j2 │ │ │ ├── module_utils │ │ │ │ └── __init__.py.j2 │ │ │ └── plugin_utils │ │ │ │ └── __init__.py.j2 │ │ ├── meta │ │ │ └── runtime.yml │ │ ├── requirements.txt │ │ ├── CONTRIBUTING │ │ ├── test-requirements.txt │ │ ├── tox-ansible.ini.j2 │ │ ├── .isort.cfg.j2 │ │ ├── CODE_OF_CONDUCT.md │ │ ├── extensions │ │ │ ├── molecule │ │ │ │ ├── utils │ │ │ │ │ ├── playbooks │ │ │ │ │ │ ├── noop.yml.j2 │ │ │ │ │ │ └── converge.yml.j2 │ │ │ │ │ └── vars │ │ │ │ │ │ └── vars.yml │ │ │ │ └── integration_hello_world │ │ │ │ │ └── molecule.yml.j2 │ │ │ └── eda │ │ │ │ └── rulebooks │ │ │ │ └── rulebook.yml.j2 │ │ ├── pyproject.toml.j2 │ │ ├── .prettierignore.j2 │ │ ├── CHANGELOG.rst │ │ ├── .github │ │ │ └── workflows │ │ │ │ ├── release.yml.j2 │ │ │ │ └── tests.yml.j2 │ │ ├── changelogs │ │ │ └── config.yaml.j2 │ │ ├── .pre-commit-config.yaml.j2 │ │ ├── galaxy.yml.j2 │ │ └── README.md.j2 │ ├── common │ │ ├── role │ │ │ └── roles │ │ │ │ └── run │ │ │ │ ├── files │ │ │ │ └── .keep │ │ │ │ ├── templates │ │ │ │ └── .keep │ │ │ │ ├── tests │ │ │ │ └── inventory │ │ │ │ ├── vars │ │ │ │ └── main.yml.j2 │ │ │ │ ├── handlers │ │ │ │ └── main.yml.j2 │ │ │ │ ├── defaults │ │ │ │ └── main.yml.j2 │ │ │ │ ├── tasks │ │ │ │ └── main.yml.j2 │ │ │ │ ├── meta │ │ │ │ ├── argument_specs.yml.j2 │ │ │ │ └── main.yml.j2 │ │ │ │ └── README.md.j2 │ │ ├── vscode │ │ │ └── .vscode │ │ │ │ └── extensions.json.j2 │ │ ├── ai │ │ │ └── AGENTS.md │ │ ├── play-argspec │ │ │ ├── inventory │ │ │ │ └── argspec_validation_inventory.yml │ │ │ ├── argspec_validation_plays.yml │ │ │ └── argspec_validation_plays.meta.yml │ │ ├── devfile │ │ │ └── devfile.yaml.j2 │ │ ├── gitignore │ │ │ └── __meta__.yml │ │ ├── execution-environment │ │ │ └── execution-environment.yml.j2 │ │ └── devcontainer │ │ │ └── .devcontainer │ │ │ ├── devcontainer.json.j2 │ │ │ ├── docker │ │ │ └── devcontainer.json.j2 │ │ │ └── podman │ │ │ └── devcontainer.json.j2 │ ├── execution_env_project │ │ ├── .gitignore │ │ ├── README.md │ │ ├── execution-environment.yml.j2 │ │ └── .github │ │ │ └── workflows │ │ │ └── ci.yml.j2 │ └── playbook_project │ │ ├── collections │ │ ├── ansible_collections │ │ │ └── project_org │ │ │ │ └── project_repo │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── meta │ │ │ │ └── runtime.yml │ │ │ │ ├── roles │ │ │ │ └── run │ │ │ │ │ ├── tasks │ │ │ │ │ └── main.yml.j2 │ │ │ │ │ └── README.md.j2 │ │ │ │ ├── galaxy.yml.j2 │ │ │ │ └── README.md.j2 │ │ └── requirements.yml.j2 │ │ ├── inventory │ │ ├── host_vars │ │ │ ├── server1.yml.j2 │ │ │ ├── server2.yml.j2 │ │ │ ├── server3.yml.j2 │ │ │ ├── switch1.yml.j2 │ │ │ └── switch2.yml.j2 │ │ ├── group_vars │ │ │ ├── test.yml.j2 │ │ │ ├── db_servers.yml.j2 │ │ │ ├── production.yml.j2 │ │ │ ├── web_servers.yml.j2 │ │ │ └── all.yml.j2 │ │ ├── argspec_validation_inventory.yml │ │ └── hosts.yml.j2 │ │ ├── .github │ │ ├── ansible-code-bot.yml.j2 │ │ └── workflows │ │ │ └── tests.yml.j2 │ │ ├── site.yml.j2 │ │ ├── ansible-navigator.yml.j2 │ │ ├── ansible.cfg.j2 │ │ ├── linux_playbook.yml.j2 │ │ ├── network_playbook.yml.j2 │ │ ├── README.md.j2 │ │ ├── argspec_validation_plays.yml │ │ └── argspec_validation_plays.meta.yml │ ├── __init__.py │ ├── schemas │ └── __init__.py │ ├── subcommands │ └── __init__.py │ ├── __main__.py │ ├── compat.py │ ├── exceptions.py │ ├── constants.py │ ├── templar.py │ ├── types.py │ └── config.py ├── .config ├── pydoclint-baseline.txt └── dictionary.txt ├── .tool-versions ├── tombi.toml ├── .github ├── CODEOWNERS ├── release-drafter.yml ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── documentation_report.md │ ├── security_bug_report.md │ └── bug_report.md └── workflows │ ├── push.yml │ ├── ack.yml │ ├── tox.yml │ ├── finalize.yml │ └── release.yml ├── tests ├── fixtures │ ├── collection │ │ └── testorg │ │ │ └── testcol │ │ │ ├── MAINTAINERS │ │ │ ├── docs │ │ │ ├── .keep │ │ │ └── docsite │ │ │ │ └── links.yml │ │ │ ├── tests │ │ │ ├── unit │ │ │ │ ├── .keep │ │ │ │ ├── __init__.py │ │ │ │ └── test_basic.py │ │ │ ├── .gitignore │ │ │ └── integration │ │ │ │ ├── __init__.py │ │ │ │ ├── targets │ │ │ │ └── hello_world │ │ │ │ │ └── tasks │ │ │ │ │ └── main.yml │ │ │ │ └── test_integration.py │ │ │ ├── roles │ │ │ └── run │ │ │ │ ├── files │ │ │ │ └── .keep │ │ │ │ ├── templates │ │ │ │ └── .keep │ │ │ │ ├── tests │ │ │ │ └── inventory │ │ │ │ ├── vars │ │ │ │ └── main.yml │ │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ │ ├── meta │ │ │ │ ├── argument_specs.yml │ │ │ │ └── main.yml │ │ │ │ └── README.md │ │ │ ├── plugins │ │ │ ├── action │ │ │ │ ├── __init__.py │ │ │ │ └── sample_action.py │ │ │ ├── cache │ │ │ │ └── __init__.py │ │ │ ├── filter │ │ │ │ ├── __init__.py │ │ │ │ └── sample_filter.py │ │ │ ├── lookup │ │ │ │ ├── __init__.py │ │ │ │ └── sample_lookup.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ └── sample_test.py │ │ │ ├── inventory │ │ │ │ └── __init__.py │ │ │ ├── modules │ │ │ │ ├── __init__.py │ │ │ │ ├── sample_action.py │ │ │ │ └── sample_module.py │ │ │ ├── sub_plugins │ │ │ │ └── __init__.py │ │ │ ├── module_utils │ │ │ │ └── __init__.py │ │ │ └── plugin_utils │ │ │ │ └── __init__.py │ │ │ ├── meta │ │ │ └── runtime.yml │ │ │ ├── AGENTS.md │ │ │ ├── requirements.txt │ │ │ ├── .vscode │ │ │ └── extensions.json │ │ │ ├── CONTRIBUTING │ │ │ ├── test-requirements.txt │ │ │ ├── tox-ansible.ini │ │ │ ├── .isort.cfg │ │ │ ├── CODE_OF_CONDUCT.md │ │ │ ├── extensions │ │ │ ├── molecule │ │ │ │ ├── utils │ │ │ │ │ ├── playbooks │ │ │ │ │ │ ├── noop.yml │ │ │ │ │ │ └── converge.yml │ │ │ │ │ └── vars │ │ │ │ │ │ └── vars.yml │ │ │ │ └── integration_hello_world │ │ │ │ │ └── molecule.yml │ │ │ └── eda │ │ │ │ └── rulebooks │ │ │ │ └── rulebook.yml │ │ │ ├── pyproject.toml │ │ │ ├── .prettierignore │ │ │ ├── CHANGELOG.rst │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ ├── release.yml │ │ │ │ └── tests.yml │ │ │ ├── devfile.yaml │ │ │ ├── .devcontainer │ │ │ ├── devcontainer.json │ │ │ ├── docker │ │ │ │ └── devcontainer.json │ │ │ └── podman │ │ │ │ └── devcontainer.json │ │ │ ├── changelogs │ │ │ └── config.yaml │ │ │ ├── .pre-commit-config.yaml │ │ │ ├── galaxy.yml │ │ │ └── README.md │ ├── project │ │ ├── ee_project │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── execution-environment.yml │ │ │ └── .github │ │ │ │ └── workflows │ │ │ │ └── ci.yml │ │ └── playbook_project │ │ │ ├── collections │ │ │ ├── ansible_collections │ │ │ │ └── weather │ │ │ │ │ └── demo │ │ │ │ │ ├── CHANGELOG.md │ │ │ │ │ ├── meta │ │ │ │ │ └── runtime.yml │ │ │ │ │ ├── roles │ │ │ │ │ └── run │ │ │ │ │ │ ├── tasks │ │ │ │ │ │ └── main.yml │ │ │ │ │ │ └── README.md │ │ │ │ │ ├── galaxy.yml │ │ │ │ │ └── README.md │ │ │ └── requirements.yml │ │ │ ├── inventory │ │ │ ├── host_vars │ │ │ │ ├── server1.yml │ │ │ │ ├── server2.yml │ │ │ │ ├── server3.yml │ │ │ │ ├── switch1.yml │ │ │ │ └── switch2.yml │ │ │ ├── group_vars │ │ │ │ ├── test.yml │ │ │ │ ├── db_servers.yml │ │ │ │ ├── production.yml │ │ │ │ ├── web_servers.yml │ │ │ │ └── all.yml │ │ │ ├── argspec_validation_inventory.yml │ │ │ └── hosts.yml │ │ │ ├── AGENTS.md │ │ │ ├── .github │ │ │ ├── ansible-code-bot.yml │ │ │ └── workflows │ │ │ │ └── tests.yml │ │ │ ├── .vscode │ │ │ └── extensions.json │ │ │ ├── site.yml │ │ │ ├── ansible-navigator.yml │ │ │ ├── devfile.yaml │ │ │ ├── .devcontainer │ │ │ ├── devcontainer.json │ │ │ ├── docker │ │ │ │ └── devcontainer.json │ │ │ └── podman │ │ │ │ └── devcontainer.json │ │ │ ├── ansible.cfg │ │ │ ├── linux_playbook.yml │ │ │ ├── network_playbook.yml │ │ │ ├── README.md │ │ │ ├── argspec_validation_plays.yml │ │ │ └── argspec_validation_plays.meta.yml │ └── common │ │ └── execution-environment │ │ └── execution-environment.yml ├── __init__.py ├── integration │ ├── __init__.py │ ├── test_no_input.py │ └── test_lint.py ├── units │ ├── __init__.py │ ├── test_compat.py │ ├── test_templar.py │ ├── test_argparse_help.py │ └── test_output.py ├── defaults.py └── conftest.py ├── .yamllint ├── ansible.cfg ├── docs ├── media │ ├── refresh.gif │ ├── log-to-file.gif │ ├── open-folder.gif │ ├── open-log-file.gif │ └── open-collection.gif ├── index.md ├── content_creation.md └── contributing.md ├── package.json ├── .markdownlint.yaml ├── codecov.yml ├── mise.toml ├── .ansible-lint.yml ├── .sonarlint └── connectedMode.json ├── CHANGELOG.md ├── sonar-project.properties ├── .env ├── .claude └── settings.local.json ├── .markdownlint-cli2.yaml ├── AGENTS.md ├── tools └── report-coverage ├── biome.json ├── .vscode ├── extensions.json ├── tasks.json ├── launch.json └── settings.json ├── .readthedocs.yml ├── renovate.json ├── cspell.config.yaml ├── README.md └── mkdocs.yml /src/ansible_creator/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.config/pydoclint-baseline.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 24.11.1 2 | -------------------------------------------------------------------------------- /tombi.toml: -------------------------------------------------------------------------------- 1 | schema.strict = false 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ansible/devtools 2 | -------------------------------------------------------------------------------- /src/ansible_creator/_version.pyi: -------------------------------------------------------------------------------- 1 | version: str 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/MAINTAINERS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/docs/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests for ansible-creator.""" 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/unit/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- 1 | """Integration tests.""" 2 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/MAINTAINERS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/docs/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/files/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/files/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/unit/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/templates/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/action/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/cache/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/filter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/lookup/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/templates/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/units/__init__.py: -------------------------------------------------------------------------------- 1 | """Unit tests for ansible-creator.""" 2 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: | 3 | .tox 4 | .pre-commit-config.yaml 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/inventory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/modules/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/sub_plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/.gitignore: -------------------------------------------------------------------------------- 1 | output/ 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/integration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/project/ee_project/.gitignore: -------------------------------------------------------------------------------- 1 | context/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /src/ansible_creator/__init__.py: -------------------------------------------------------------------------------- 1 | """The ansible-creator application.""" 2 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/action/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/cache/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/filter/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/lookup/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/test/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/.gitignore: -------------------------------------------------------------------------------- 1 | output/ 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/module_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/plugin_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/inventory/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/modules/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/sub_plugins/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/integration/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/module_utils/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/plugin_utils/__init__.py.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | # User during testing to ensure local user config does not affect testing 2 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/execution_env_project/.gitignore: -------------------------------------------------------------------------------- 1 | context/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/media/refresh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/ansible-creator/HEAD/docs/media/refresh.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@devcontainers/cli": "^0.80.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | requires_ansible: ">=2.15.0" 3 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | requires_ansible: ">=2.15.0" 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/host_vars/server1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver1 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/host_vars/server2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver2 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/host_vars/server3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver3 3 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | MD013: false 3 | first-line-heading: false 4 | useGitignore: true 5 | fix: true 6 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | comment: false 3 | coverage: 4 | status: 5 | patch: false 6 | project: true 7 | -------------------------------------------------------------------------------- /docs/media/log-to-file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/ansible-creator/HEAD/docs/media/log-to-file.gif -------------------------------------------------------------------------------- /docs/media/open-folder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/ansible-creator/HEAD/docs/media/open-folder.gif -------------------------------------------------------------------------------- /src/ansible_creator/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | """A package containing all schemas required by ansible-creator.""" 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for testorg.testcol.run 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/AGENTS.md: -------------------------------------------------------------------------------- 1 | ../../../../src/ansible_creator/resources/common/ai/AGENTS.md -------------------------------------------------------------------------------- /docs/media/open-log-file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/ansible-creator/HEAD/docs/media/open-log-file.gif -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/host_vars/server1.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver1 3 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/host_vars/server2.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver2 3 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/host_vars/server3.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | server_name: webserver3 3 | -------------------------------------------------------------------------------- /src/ansible_creator/subcommands/__init__.py: -------------------------------------------------------------------------------- 1 | """A package containing all actions supported by ansible-creator.""" 2 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/AGENTS.md: -------------------------------------------------------------------------------- 1 | ../../../../../src/ansible_creator/resources/common/ai/AGENTS.md -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.github/ansible-code-bot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | schedule: 3 | interval: "daily" 4 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # see https://github.com/ansible/team-devtools 3 | _extends: ansible/team-devtools 4 | -------------------------------------------------------------------------------- /docs/media/open-collection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/ansible-creator/HEAD/docs/media/open-collection.gif -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for testorg.testcol.run 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/group_vars/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /mise.toml: -------------------------------------------------------------------------------- 1 | [settings] 2 | idiomatic_version_file_enable_tools = [] 3 | 4 | [tools] 5 | python = "latest" 6 | uv = "latest" 7 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/.github/ansible-code-bot.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | schedule: 3 | interval: "daily" 4 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/group_vars/db_servers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/group_vars/production.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/group_vars/web_servers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /.ansible-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - tests/fixtures/project/playbook_project/network_playbook.yml 4 | - mkdocs.yml 5 | -------------------------------------------------------------------------------- /.sonarlint/connectedMode.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectKey": "ansible_ansible-creator", 3 | "sonarCloudOrganization": "ansible" 4 | } 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/group_vars/test.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/requirements.txt: -------------------------------------------------------------------------------- 1 | # TO-DO: add python packages that are required for this collection 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Please see the 4 | [release notes](https://github.com/ansible-community/ansible-creator/releases). 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/requirements.txt: -------------------------------------------------------------------------------- 1 | # TO-DO: add python packages that are required for this collection 2 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/group_vars/db_servers.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/group_vars/production.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/group_vars/web_servers.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | http_port: 80 3 | app_version: "1.0.0" 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/vscode/.vscode/extensions.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": {{ recommended_extensions | json }} 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | requires_ansible: ">=2.17.0" 3 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/vars/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for {{ namespace }}.{{ collection_name }}.{{ role_name }} 3 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["redhat.ansible", "redhat.vscode-redhat-account"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["redhat.ansible", "redhat.vscode-redhat-account"] 3 | } 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/handlers/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for {{ namespace }}.{{ collection_name }}.{{ role_name }} 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Example playbook 3 | hosts: localhost 4 | roles: 5 | - role: weather.demo.run 6 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/meta/runtime.yml: -------------------------------------------------------------------------------- 1 | --- 2 | requires_ansible: ">=2.17.0" 3 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: your_username 3 | ansible_ssh_private_key_file: /path/to/your/private/key 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/group_vars/all.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: your_username 3 | ansible_ssh_private_key_file: /path/to/your/private/key 4 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/CONTRIBUTING: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Refer to the [Ansible community guide](https://docs.ansible.com/ansible/devel/community/index.html). 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/CONTRIBUTING: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Refer to the [Ansible community guide](https://docs.ansible.com/ansible/devel/community/index.html). 4 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/site.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Example playbook 3 | hosts: localhost 4 | roles: 5 | - role: {{ namespace }}.{{ collection_name }}.run 6 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/test-requirements.txt: -------------------------------------------------------------------------------- 1 | # TO-DO: add python packages that are required for testing this collection 2 | pytest-ansible 3 | pytest-xdist 4 | molecule 5 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tox-ansible.ini: -------------------------------------------------------------------------------- 1 | [ansible] 2 | 3 | skip = 4 | py3.7 5 | py3.8 6 | 2.9 7 | 2.10 8 | 2.11 9 | 2.12 10 | 2.13 11 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/test-requirements.txt: -------------------------------------------------------------------------------- 1 | # TO-DO: add python packages that are required for testing this collection 2 | pytest-ansible 3 | pytest-xdist 4 | molecule 5 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/host_vars/switch1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: cisco.ios.ios 3 | ansible_connection: ansible.netcommon.network_cli 4 | ansible_become: true 5 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/host_vars/switch2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: cisco.nxos.nxos 3 | ansible_connection: ansible.netcommon.httpapi 4 | ansible_httpapi_port: 80 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tox-ansible.ini.j2: -------------------------------------------------------------------------------- 1 | [ansible] 2 | 3 | skip = 4 | py3.7 5 | py3.8 6 | 2.9 7 | 2.10 8 | 2.11 9 | 2.12 10 | 2.13 11 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | Please see the official 4 | [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/host_vars/switch1.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: cisco.ios.ios 3 | ansible_connection: ansible.netcommon.network_cli 4 | ansible_become: true 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/host_vars/switch2.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: cisco.nxos.nxos 3 | ansible_connection: ansible.netcommon.httpapi 4 | ansible_httpapi_port: 80 5 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | known_first_party=ansible_collections.testorg.testcol 3 | line_length=100 4 | lines_after_imports=2 5 | lines_between_types=1 6 | profile=black 7 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.organization=ansible 2 | sonar.projectKey=ansible_ansible-creator 3 | sonar.python.coverage.reportPaths=**/coverage.xml 4 | sonar.python.version=3.10, 3.11, 3.12, 3.13 5 | sonar.sources=src/ 6 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/unit/test_basic.py: -------------------------------------------------------------------------------- 1 | """Unit tests for testorg.testcol.""" 2 | 3 | 4 | def test_basic() -> None: 5 | """Dummy unit test that always passes.""" 6 | assert bool(1) is True 7 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | Please see the official 4 | [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). 5 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # PWD is supposed to be the directory container the .envrc file based on the 3 | # specs. This trick should isolate our testing from user environment. 4 | ANSIBLE_HOME=$PWD/.ansible 5 | ANSIBLE_CONFIG=$PWD/ansible.cfg 6 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/.isort.cfg.j2: -------------------------------------------------------------------------------- 1 | [settings] 2 | known_first_party=ansible_collections.{{ namespace }}.{{ collection_name }} 3 | line_length=100 4 | lines_after_imports=2 5 | lines_between_types=1 6 | profile=black 7 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | Please see the official 4 | [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). 5 | -------------------------------------------------------------------------------- /.claude/settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "allow": [ 4 | "Bash(ansible-lint:*)", 5 | "Bash(python -m pytest -v)", 6 | "Bash(pre-commit run:*)" 7 | ], 8 | "ask": [], 9 | "deny": [] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.markdownlint-cli2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # only show filenames, at the top level 3 | outputFormatters: 4 | - - markdownlint-cli2-formatter-pretty 5 | - appendLink: true 6 | - - markdownlint-cli2-formatter-summarize 7 | - byFile: true 8 | gitignore: true 9 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/unit/test_basic.py.j2: -------------------------------------------------------------------------------- 1 | """Unit tests for {{ namespace }}.{{ collection_name }}.""" 2 | 3 | 4 | def test_basic() -> None: 5 | """Dummy unit test that always passes.""" 6 | assert bool(1) is True 7 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for testorg.testcol.run 3 | 4 | - name: Display the value of run_my_variable 5 | ansible.builtin.debug: 6 | msg: "The value of run_my_variable is {{ run_my_variable }}" 7 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/extensions/molecule/utils/playbooks/noop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: No-op 3 | hosts: localhost 4 | gather_facts: false 5 | tasks: 6 | - name: Run a noop 7 | ansible.builtin.debug: 8 | msg: "This does nothing!" 9 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/argspec_validation_inventory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | vars: 4 | ping_data: Pong 5 | stat: 6 | description: Custom stat data 7 | returned: always 8 | type: raw 9 | sample: Hello, World! 10 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/extensions/molecule/utils/playbooks/noop.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | - name: No-op 3 | hosts: localhost 4 | gather_facts: false 5 | tasks: 6 | - name: Run a noop 7 | ansible.builtin.debug: 8 | msg: "This does nothing!" 9 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/ai/AGENTS.md: -------------------------------------------------------------------------------- 1 | 2 | # AGENTS.md 3 | 4 | Ensure that all practices and instructions described by 5 | https://raw.githubusercontent.com/ansible/ansible-creator/refs/heads/main/docs/agents.md 6 | are followed. 7 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/play-argspec/inventory/argspec_validation_inventory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | vars: 4 | ping_data: Pong 5 | stat: 6 | description: Custom stat data 7 | returned: always 8 | type: raw 9 | sample: Hello, World! 10 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/argspec_validation_inventory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | vars: 4 | ping_data: Pong 5 | stat: 6 | description: Custom stat data 7 | returned: always 8 | type: raw 9 | sample: Hello, World! 10 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for testorg.testcol.run 3 | 4 | # Variable that will be displayed in debug output 5 | # This demonstrates proper role variable naming with the 'run_' prefix 6 | run_my_variable: "default_value" 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "✨ Feature request" 3 | about: Suggest an idea for this project 4 | labels: enhancement, new 5 | --- 6 | 7 | ##### ISSUE TYPE 8 | 9 | - Feature Idea 10 | 11 | ##### SUMMARY 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 100 3 | 4 | [tool.pytest.ini_options] 5 | addopts = ["-vvv", "-n", "2", "--log-level", "WARNING", "--color", "yes"] 6 | filterwarnings = ["ignore:AnsibleCollectionFinder has already been configured"] 7 | testpaths = ["tests"] 8 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/extensions/molecule/utils/vars/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collection_root: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/.." 3 | integration_tests_path: "{{ collection_root }}/tests/integration/targets/" 4 | molecule_scenario_name: "{{ molecule_scenario_directory | basename }}" 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/extensions/molecule/utils/vars/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collection_root: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/.." 3 | integration_tests_path: "{{ collection_root }}/tests/integration/targets/" 4 | molecule_scenario_name: "{{ molecule_scenario_directory | basename }}" 5 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/pyproject.toml.j2: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 100 3 | 4 | [tool.pytest.ini_options] 5 | addopts = ["-vvv", "-n", "2", "--log-level", "WARNING", "--color", "yes"] 6 | filterwarnings = ["ignore:AnsibleCollectionFinder has already been configured"] 7 | testpaths = ["tests"] 8 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/ansible-navigator.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible-navigator: 3 | logging: 4 | level: debug 5 | append: false 6 | file: $PWD/.logs/ansible-navigator.log 7 | 8 | playbook-artifact: 9 | enable: true 10 | save-as: "$PWD/.logs/{playbook_name}-artifact-{time_stamp}.json" 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "📝 Documentation Report" 3 | about: Ask us about docs 4 | labels: documentation, new 5 | --- 6 | 7 | ##### ISSUE TYPE 8 | 9 | - Doc issue 10 | 11 | ##### SUMMARY 12 | 13 | 14 | -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | # Interacting with the project 2 | 3 | Always use `uv run` to run different commands, like pre-commit, tox, pytest, 4 | or the project itself. This will ensure that the dependencies are installed 5 | automatically. 6 | 7 | # Testing instructions 8 | 9 | - Ensure `tox` passes successfully. Fix any reported issues. 10 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/defaults/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for {{ namespace }}.{{ collection_name }}.{{ role_name }} 3 | 4 | # Variable that will be displayed in debug output 5 | # This demonstrates proper role variable naming with the 'run_' prefix 6 | {{ role_name }}_my_variable: "default_value" 7 | -------------------------------------------------------------------------------- /src/ansible_creator/__main__.py: -------------------------------------------------------------------------------- 1 | """A runpy entry point for ansible-creator. 2 | 3 | This makes it possible to invoke CLI 4 | via :command:`python3 -m ansible_creator`. 5 | """ 6 | 7 | from __future__ import annotations 8 | 9 | from .cli import main 10 | 11 | 12 | if __name__ == "__main__": # pragma: no cover 13 | main() 14 | -------------------------------------------------------------------------------- /tests/defaults.py: -------------------------------------------------------------------------------- 1 | """Constants with default values used throughout the tests.""" 2 | 3 | from __future__ import annotations 4 | 5 | import sys 6 | 7 | from pathlib import Path 8 | 9 | 10 | FIXTURES_DIR = (Path(__file__).parent / "fixtures").resolve() 11 | CREATOR_BIN = Path(sys.executable).parent / "ansible-creator" 12 | 13 | UUID_LENGTH = 8 14 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/extensions/eda/rulebooks/rulebook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Hello Events 3 | hosts: localhost 4 | sources: 5 | - ansible.eda.range: 6 | limit: 5 7 | rules: 8 | - name: Say Hello 9 | condition: event.i == 1 10 | action: 11 | run_playbook: 12 | name: ansible.eda.hello 13 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # See https://github.com/ansible/team-devtools/blob/main/.github/workflows/push.yml 3 | name: push 4 | on: 5 | push: 6 | branches: 7 | - main 8 | - "releases/**" 9 | - "stable/**" 10 | workflow_dispatch: 11 | jobs: 12 | ack: 13 | uses: ansible/team-devtools/.github/workflows/push.yml@main 14 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/ansible-navigator.yml.j2: -------------------------------------------------------------------------------- 1 | {% raw %}--- 2 | ansible-navigator: 3 | logging: 4 | level: debug 5 | append: false 6 | file: $PWD/.logs/ansible-navigator.log 7 | 8 | playbook-artifact: 9 | enable: true 10 | save-as: "$PWD/.logs/{playbook_name}-artifact-{time_stamp}.json" 11 | {%- endraw %} 12 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/extensions/eda/rulebooks/rulebook.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Hello Events 3 | hosts: localhost 4 | sources: 5 | - ansible.eda.range: 6 | limit: 5 7 | rules: 8 | - name: Say Hello 9 | condition: event.i == 1 10 | action: 11 | run_playbook: 12 | name: ansible.eda.hello 13 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/tasks/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for {{ namespace }}.{{ collection_name }}.{{ role_name }} 3 | 4 | - name: Display the value of {{ role_name }}_my_variable 5 | ansible.builtin.debug: 6 | msg: "The value of {{ role_name }}_my_variable is {% raw %}{{ {% endraw %}{{ role_name }}_my_variable{% raw %} }}{% endraw %}" 7 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.prettierignore: -------------------------------------------------------------------------------- 1 | # files we don't want prettier to ever to look into 2 | .*/ 3 | coverage/ 4 | 5 | # Environments 6 | .env 7 | .venv 8 | env/ 9 | venv/ 10 | ENV/ 11 | env.bak/ 12 | venv.bak/ 13 | 14 | # A linked collection directory created by pytest-ansible-units 15 | collections/ 16 | 17 | tests/output/ 18 | 19 | README.md 20 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/.prettierignore.j2: -------------------------------------------------------------------------------- 1 | # files we don't want prettier to ever to look into 2 | .*/ 3 | coverage/ 4 | 5 | # Environments 6 | .env 7 | .venv 8 | env/ 9 | venv/ 10 | ENV/ 11 | env.bak/ 12 | venv.bak/ 13 | 14 | # A linked collection directory created by pytest-ansible-units 15 | collections/ 16 | 17 | tests/output/ 18 | 19 | README.md 20 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/meta/argument_specs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # argument spec file for testorg.testcol.run 3 | 4 | argument_specs: 5 | main: 6 | short_description: Role description. 7 | options: 8 | run_my_variable: 9 | type: str 10 | description: A simple string argument for demonstration. 11 | default: "default_value" 12 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/integration/targets/hello_world/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test the Hello World filter plugin 3 | ansible.builtin.set_fact: 4 | msg: "{{ 'ansible-creator' | testorg.testcol.sample_filter }}" 5 | 6 | - name: Assert that the filter worked 7 | ansible.builtin.assert: 8 | that: 9 | - msg == 'Hello, ansible-creator' 10 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/roles/run/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Debug print task-1 3 | ansible.builtin.debug: 4 | msg: "This is task-1" 5 | 6 | - name: Debug print task-2 7 | ansible.builtin.debug: 8 | msg: "This is task-2" 9 | 10 | - name: Debug print task-3 11 | ansible.builtin.debug: 12 | msg: "This is task-3" 13 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | This should be updated by antsibull-changelog. Do not edit this manually! 2 | 3 | See https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelogs.rst for 4 | information on how to use antsibull-changelog. 5 | 6 | Check out ``changelogs/config.yaml`` for its configuration. You need to change at least the ``title`` field in there. 7 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | This should be updated by antsibull-changelog. Do not edit this manually! 2 | 3 | See https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelogs.rst for 4 | information on how to use antsibull-changelog. 5 | 6 | Check out ``changelogs/config.yaml`` for its configuration. You need to change at least the ``title`` field in there. 7 | -------------------------------------------------------------------------------- /tools/report-coverage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | coverage combine -q "--data-file=${TOX_ENV_DIR}/.coverage" "${TOX_ENV_DIR}"/.coverage.* 4 | coverage xml "--data-file=${TOX_ENV_DIR}/.coverage" -o "${TOX_ENV_DIR}/coverage.xml" --ignore-errors --fail-under=0 5 | COVERAGE_FILE="${TOX_ENV_DIR}/.coverage" coverage lcov --fail-under=0 --ignore-errors -q 6 | COVERAGE_FILE="${TOX_ENV_DIR}/.coverage" coverage report --ignore-errors 7 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/meta/argument_specs.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # argument spec file for {{ namespace }}.{{ collection_name }}.{{ role_name }} 3 | 4 | argument_specs: 5 | main: 6 | short_description: Role description. 7 | options: 8 | {{ role_name }}_my_variable: 9 | type: str 10 | description: A simple string argument for demonstration. 11 | default: "default_value" 12 | -------------------------------------------------------------------------------- /tests/units/test_compat.py: -------------------------------------------------------------------------------- 1 | """Tests for compat module.""" 2 | 3 | from __future__ import annotations 4 | 5 | from ansible_creator.compat import Traversable 6 | 7 | 8 | def test_import() -> None: 9 | """Test the import of traversable. 10 | 11 | This is a simple test to ensure that the import of Traversable is working. 12 | Since it is only imported for type checking. 13 | 14 | """ 15 | assert Traversable is not None 16 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/roles/run/tasks/main.yml.j2: -------------------------------------------------------------------------------- 1 | {% raw %}--- 2 | - name: Debug print task-1 3 | ansible.builtin.debug: 4 | msg: "This is task-1" 5 | 6 | - name: Debug print task-2 7 | ansible.builtin.debug: 8 | msg: "This is task-2" 9 | 10 | - name: Debug print task-3 11 | ansible.builtin.debug: 12 | msg: "This is task-3" 13 | {%- endraw %} 14 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/integration/targets/hello_world/tasks/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test the Hello World filter plugin 3 | ansible.builtin.set_fact: 4 | msg: {% raw %}"{{ 'ansible-creator' | {% endraw %}{{ namespace }}.{{ collection_name }}.{% raw %}sample_filter }}"{% endraw %} 5 | 6 | - name: Assert that the filter worked 7 | ansible.builtin.assert: 8 | that: 9 | - msg == 'Hello, ansible-creator' 10 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release testorg.testcol 3 | 4 | on: # yamllint disable-line rule:truthy 5 | release: 6 | types: [published] 7 | jobs: 8 | release_automation_hub: 9 | uses: ansible/ansible-content-actions/.github/workflows/release_galaxy.yaml@main 10 | with: 11 | environment: release 12 | secrets: 13 | ansible_galaxy_api_key: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/security_bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F525 Security bug report" 3 | about: How to report security vulnerabilities 4 | labels: new 5 | --- 6 | 7 | For all security related bugs, email `security@ansible.com` instead of using this 8 | issue tracker and you will receive a prompt response. 9 | 10 | For more information on the Ansible community's practices regarding responsible 11 | disclosure, see [security](https://www.ansible.com/security) 12 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/devfile/devfile.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | schemaVersion: 2.2.2 3 | metadata: 4 | name: {{ dev_file_name }} 5 | components: 6 | - name: tooling-container 7 | container: 8 | image: {{ dev_file_image }} 9 | memoryRequest: 256M 10 | memoryLimit: 6Gi 11 | cpuRequest: 250m 12 | cpuLimit: 2000m 13 | args: ["tail", "-f", "/dev/null"] 14 | env: 15 | - name: KUBEDOCK_ENABLED 16 | value: "true" 17 | -------------------------------------------------------------------------------- /.github/workflows/ack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # See https://github.com/ansible/team-devtools/blob/main/.github/workflows/ack.yml 3 | name: ack 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 7 | cancel-in-progress: true 8 | 9 | on: 10 | pull_request_target: 11 | types: [opened, labeled, unlabeled, synchronize] 12 | jobs: 13 | ack: 14 | uses: ansible/team-devtools/.github/workflows/ack.yml@main 15 | secrets: inherit 16 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/devfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schemaVersion: 2.2.2 3 | metadata: 4 | name: weather.demo 5 | components: 6 | - name: tooling-container 7 | container: 8 | image: ghcr.io/ansible/ansible-devspaces:latest 9 | memoryRequest: 256M 10 | memoryLimit: 6Gi 11 | cpuRequest: 250m 12 | cpuLimit: 2000m 13 | args: ["tail", "-f", "/dev/null"] 14 | env: 15 | - name: KUBEDOCK_ENABLED 16 | value: "true" 17 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/devfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schemaVersion: 2.2.2 3 | metadata: 4 | name: testorg.testcol 5 | components: 6 | - name: tooling-container 7 | container: 8 | image: ghcr.io/ansible/ansible-devspaces:latest 9 | memoryRequest: 256M 10 | memoryLimit: 6Gi 11 | cpuRequest: 250m 12 | cpuLimit: 2000m 13 | args: ["tail", "-f", "/dev/null"] 14 | env: 15 | - name: KUBEDOCK_ENABLED 16 | value: "true" 17 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/.github/workflows/release.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release {{ namespace }}.{{ collection_name }} 3 | {% raw %} 4 | on: # yamllint disable-line rule:truthy 5 | release: 6 | types: [published] 7 | jobs: 8 | release_automation_hub: 9 | uses: ansible/ansible-content-actions/.github/workflows/release_galaxy.yaml@main 10 | with: 11 | environment: release 12 | secrets: 13 | ansible_galaxy_api_key: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} 14 | {%- endraw %} 15 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Minimal galaxy.yml for a playbook project for tools to recognize this as a collection 3 | 4 | namespace: "weather" 5 | name: "demo" 6 | readme: README.md 7 | version: 0.0.1 8 | authors: 9 | - your name 10 | 11 | description: Collection for weather.demo playbook project 12 | license: ["GPL-3.0-or-later"] 13 | # TO-DO: update the tags based on your content type 14 | tags: ["tools"] 15 | repository: NA 16 | -------------------------------------------------------------------------------- /.config/dictionary.txt: -------------------------------------------------------------------------------- 1 | Chakarborty 2 | FQCN 3 | FQCNs 4 | KUBEDOCK 5 | Nilashish 6 | PYCMD 7 | Testcol 8 | Testorg 9 | addopts 10 | antsibull 11 | argnames 12 | argspec 13 | argvalues 14 | capsys 15 | delenv 16 | devfile 17 | devspaces 18 | docsite 19 | endraw 20 | fileh 21 | flatmap 22 | fqcn 23 | hostvars 24 | httpapi 25 | myorg 26 | myproject 27 | myuser 28 | netcommon 29 | notesdir 30 | pydoclint 31 | rulebook 32 | rulebooks 33 | sshpass 34 | sysargs 35 | testcol 36 | testname 37 | testns 38 | testorg 39 | testpaths 40 | webservers 41 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/tests/integration/test_integration.py: -------------------------------------------------------------------------------- 1 | """Tests for molecule scenarios.""" 2 | 3 | from __future__ import absolute_import, division, print_function 4 | 5 | from pytest_ansible.molecule import MoleculeScenario 6 | 7 | 8 | def test_integration(molecule_scenario: MoleculeScenario) -> None: 9 | """Run molecule for each scenario. 10 | 11 | Args: 12 | molecule_scenario: The molecule scenario object 13 | """ 14 | proc = molecule_scenario.test() 15 | assert proc.returncode == 0 16 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/tests/integration/test_integration.py.j2: -------------------------------------------------------------------------------- 1 | """Tests for molecule scenarios.""" 2 | 3 | from __future__ import absolute_import, division, print_function 4 | 5 | from pytest_ansible.molecule import MoleculeScenario 6 | 7 | 8 | def test_integration(molecule_scenario: MoleculeScenario) -> None: 9 | """Run molecule for each scenario. 10 | 11 | Args: 12 | molecule_scenario: The molecule scenario object 13 | """ 14 | proc = molecule_scenario.test() 15 | assert proc.returncode == 0 16 | -------------------------------------------------------------------------------- /tests/fixtures/project/ee_project/README.md: -------------------------------------------------------------------------------- 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 8 | community. Feel free to customize this template according to your specific 9 | project requirements. 10 | 11 | ```shell 12 | ├── .github 13 | │ └── workflows 14 | │ └── ci.yml 15 | ├── .gitignore 16 | ├── README.md 17 | └── execution-environment.yml 18 | ``` 19 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/execution_env_project/README.md: -------------------------------------------------------------------------------- 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 8 | community. Feel free to customize this template according to your specific 9 | project requirements. 10 | 11 | ```shell 12 | ├── .github 13 | │ └── workflows 14 | │ └── ci.yml 15 | ├── .gitignore 16 | ├── README.md 17 | └── execution-environment.yml 18 | ``` 19 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CI" 3 | 4 | concurrency: 5 | group: ${{ github.head_ref || github.run_id }} 6 | cancel-in-progress: true 7 | 8 | on: # yamllint disable-line rule:truthy 9 | pull_request: 10 | branches: [main] 11 | workflow_dispatch: 12 | # TO-DO: Below is an example cron scheduler. Uncomment and tweak it as per your requirement 13 | # schedule: 14 | # - cron: '0 0 * * *' 15 | 16 | jobs: 17 | ansible-lint: 18 | uses: ansible/ansible-content-actions/.github/workflows/ansible_lint.yaml@main 19 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/extensions/molecule/integration_hello_world/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | platforms: 3 | - name: na 4 | 5 | provisioner: 6 | name: ansible 7 | playbooks: 8 | cleanup: ../utils/playbooks/noop.yml 9 | converge: ../utils/playbooks/converge.yml 10 | destroy: ../utils/playbooks/noop.yml 11 | prepare: ../utils/playbooks/noop.yml 12 | config_options: 13 | defaults: 14 | collections_path: ${ANSIBLE_COLLECTIONS_PATH} 15 | scenario: 16 | test_sequence: 17 | - prepare 18 | - converge 19 | destroy_sequence: 20 | - destroy 21 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: ansible.posix 4 | version: 1.4.0 5 | 6 | - name: ansible.scm 7 | version: 2.0.0 8 | 9 | - name: ansible.utils 10 | version: 4.0.0 11 | 12 | - name: cisco.ios 13 | 14 | - name: https://github.com/redhat-cop/network.backup 15 | type: git 16 | 17 | # TO-DO: User's own collections can also be specified as mention below. 18 | # - name: my_organization.my_collection 19 | # version: 1.2.3 20 | # source: https://github.com/my_organization/my_collection.git 21 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/galaxy.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # Minimal galaxy.yml for a playbook project for tools to recognize this as a collection 3 | 4 | namespace: "{{ namespace }}" 5 | name: "{{ collection_name }}" 6 | readme: README.md 7 | version: 0.0.1 8 | authors: 9 | - your name 10 | 11 | description: Collection for {{ namespace }}.{{ collection_name }} playbook project 12 | license: ["GPL-3.0-or-later"] 13 | # TO-DO: update the tags based on your content type 14 | tags: ["tools"] 15 | repository: NA 16 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/requirements.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: ansible.posix 4 | version: 1.4.0 5 | 6 | - name: ansible.scm 7 | version: 2.0.0 8 | 9 | - name: ansible.utils 10 | version: 4.0.0 11 | 12 | - name: cisco.ios 13 | 14 | - name: https://github.com/redhat-cop/network.backup 15 | type: git 16 | 17 | # TO-DO: User's own collections can also be specified as mention below. 18 | # - name: my_organization.my_collection 19 | # version: 1.2.3 20 | # source: https://github.com/my_organization/my_collection.git 21 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/latest/schema.json", 3 | "assist": { 4 | "actions": { 5 | "source": { 6 | "useSortedKeys": "on" 7 | } 8 | } 9 | }, 10 | "files": { 11 | "includes": ["**", "!**/devcontainer.json"] 12 | }, 13 | "formatter": { 14 | "enabled": true, 15 | "indentStyle": "space" 16 | }, 17 | "json": { 18 | "formatter": { 19 | "enabled": true, 20 | "indentStyle": "space" 21 | } 22 | }, 23 | "vcs": { 24 | "clientKind": "git", 25 | "enabled": true, 26 | "useIgnoreFile": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/.github/workflows/tests.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CI" 3 | {% raw %} 4 | concurrency: 5 | group: ${{ github.head_ref || github.run_id }} 6 | cancel-in-progress: true 7 | 8 | on: # yamllint disable-line rule:truthy 9 | pull_request: 10 | branches: [main] 11 | workflow_dispatch: 12 | # TO-DO: Below is an example cron scheduler. Uncomment and tweak it as per your requirement 13 | # schedule: 14 | # - cron: '0 0 * * *' 15 | 16 | jobs: 17 | ansible-lint: 18 | uses: ansible/ansible-content-actions/.github/workflows/ansible_lint.yaml@main 19 | {%- endraw %} 20 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/extensions/molecule/utils/playbooks/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Shared integration test runner 3 | hosts: localhost 4 | gather_facts: false 5 | 6 | tasks: 7 | - name: Load the vars 8 | ansible.builtin.include_vars: 9 | file: ../../utils/vars/vars.yml 10 | 11 | - name: "Integration test: {{ test_name }}" 12 | ansible.builtin.include_role: 13 | name: "{{ test_path }}" 14 | vars: 15 | test_path: "{{ integration_tests_path }}{{ test_name }}" 16 | test_name: "{{ molecule_scenario_name.replace('integration_', '') }}" 17 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/extensions/molecule/integration_hello_world/molecule.yml.j2: -------------------------------------------------------------------------------- 1 | {% raw %}--- 2 | platforms: 3 | - name: na 4 | 5 | provisioner: 6 | name: ansible 7 | playbooks: 8 | cleanup: ../utils/playbooks/noop.yml 9 | converge: ../utils/playbooks/converge.yml 10 | destroy: ../utils/playbooks/noop.yml 11 | prepare: ../utils/playbooks/noop.yml 12 | config_options: 13 | defaults: 14 | collections_path: ${ANSIBLE_COLLECTIONS_PATH} 15 | scenario: 16 | test_sequence: 17 | - prepare 18 | - converge 19 | destroy_sequence: 20 | - destroy 21 | {%- endraw %} 22 | -------------------------------------------------------------------------------- /src/ansible_creator/compat.py: -------------------------------------------------------------------------------- 1 | """Compat library for ansible-creator. 2 | 3 | This contains compatibility definitions for older python 4 | When we need to import a module differently depending on python versions, we do it 5 | here. 6 | """ 7 | 8 | from __future__ import annotations 9 | 10 | import sys 11 | 12 | 13 | if sys.version_info >= (3, 11): # pragma: no cover 14 | from importlib.resources.abc import Traversable as _Traversable 15 | else: 16 | from importlib.abc import ( # pylint: disable = deprecated-class 17 | Traversable as _Traversable, # pragma: no cover 18 | ) 19 | 20 | Traversable = _Traversable 21 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "biomejs.biome", 4 | "charliermarsh.ruff", 5 | "github.vscode-github-actions", 6 | "gruntfuggly.triggertaskonsave", 7 | "markis.code-coverage", 8 | "ms-python.debugpy", 9 | "ms-python.mypy-type-checker", 10 | "ms-python.pylint", 11 | "ms-python.python", 12 | "redhat.ansible", 13 | "redhat.vscode-yaml", 14 | "streetsidesoftware.code-spell-checker", 15 | "timonwong.shellcheck", 16 | "tombi-toml.tombi" 17 | ], 18 | "unwantedRecommendations": [ 19 | "esbenp.prettier-vscode", 20 | "tamasfe.even-better-toml" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/gitignore/__meta__.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collection_project: 3 | additions: 4 | template: false 5 | value: "" 6 | 7 | playbook_project: 8 | additions: 9 | template: true 10 | value: | 11 | .logs/* 12 | *.retry 13 | *.vault 14 | collections/* 15 | !collections/ansible_collections 16 | !collections/requirements.yml 17 | collections/ansible_collections/* 18 | !collections/ansible_collections/{{ namespace }} 19 | collections/ansible_collections/{{ namespace }}/* 20 | !collections/ansible_collections/{{ namespace }}/{{ collection_name }} 21 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/extensions/molecule/utils/playbooks/converge.yml.j2: -------------------------------------------------------------------------------- 1 | {% raw %}--- 2 | - name: Shared integration test runner 3 | hosts: localhost 4 | gather_facts: false 5 | 6 | tasks: 7 | - name: Load the vars 8 | ansible.builtin.include_vars: 9 | file: ../../utils/vars/vars.yml 10 | 11 | - name: "Integration test: {{ test_name }}" 12 | ansible.builtin.include_role: 13 | name: "{{ test_path }}" 14 | vars: 15 | test_path: "{{ integration_tests_path }}{{ test_name }}" 16 | test_name: "{{ molecule_scenario_name.replace('integration_', '') }}" 17 | {%- endraw %} 18 | -------------------------------------------------------------------------------- /tests/fixtures/common/execution-environment/execution-environment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 3 3 | 4 | images: 5 | base_image: 6 | name: quay.io/fedora/fedora:41 7 | 8 | dependencies: 9 | ansible_core: 10 | package_pip: ansible-core 11 | 12 | ansible_runner: 13 | package_pip: ansible-runner 14 | 15 | system: 16 | - openssh-clients 17 | - sshpass 18 | 19 | python: 20 | - requests 21 | - boto3 22 | 23 | galaxy: 24 | collections: 25 | - name: ansible.posix 26 | - name: ansible.utils 27 | 28 | additional_build_steps: 29 | append_base: 30 | - RUN $PYCMD -m pip install -U pip 31 | 32 | options: 33 | tags: 34 | - ansible_sample_ee 35 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | # sadly no color output due to https://github.com/readthedocs/readthedocs.org/issues/8733 4 | mkdocs: 5 | fail_on_warning: true 6 | configuration: mkdocs.yml 7 | 8 | build: 9 | os: ubuntu-24.04 10 | tools: 11 | python: "3.13" 12 | commands: 13 | - curl https://mise.run | sh 14 | - ~/.local/bin/mise settings experimental=true 15 | - ~/.local/bin/mise settings python.compile=false 16 | - ~/.local/bin/mise settings python.uv_venv_auto=true 17 | - ~/.local/bin/mise trust 18 | - ~/.local/bin/mise install 19 | - ~/.local/bin/mise exec --command "uv run tox run -e docs" 20 | submodules: 21 | include: all 22 | recursive: true 23 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/execution-environment/execution-environment.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | version: 3 3 | 4 | images: 5 | base_image: 6 | name: {{ execution_environment_image }} 7 | 8 | dependencies: 9 | ansible_core: 10 | package_pip: ansible-core 11 | 12 | ansible_runner: 13 | package_pip: ansible-runner 14 | 15 | system: 16 | - openssh-clients 17 | - sshpass 18 | 19 | python: 20 | - requests 21 | - boto3 22 | 23 | galaxy: 24 | collections: 25 | - name: ansible.posix 26 | - name: ansible.utils 27 | 28 | additional_build_steps: 29 | append_base: 30 | - RUN $PYCMD -m pip install -U pip 31 | 32 | options: 33 | tags: 34 | - ansible_sample_ee 35 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/devcontainer/.devcontainer/devcontainer.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-codespaces", 3 | "image": "{{ dev_container_image }}", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": {{ recommended_extensions | json }} 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/devcontainer/.devcontainer/docker/devcontainer.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-docker", 3 | "image": "{{ dev_container_image }}", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": {{ recommended_extensions | json }} 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-codespaces", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-codespaces", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.devcontainer/docker/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-docker", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.devcontainer/docker/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-docker", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--security-opt", 7 | "seccomp=unconfined", 8 | "--security-opt", 9 | "label=disable", 10 | "--cap-add=SYS_ADMIN", 11 | "--cap-add=SYS_RESOURCE", 12 | "--device", 13 | "/dev/fuse", 14 | "--security-opt", 15 | "apparmor=unconfined", 16 | "--hostname=ansible-dev-container" 17 | ], 18 | "updateRemoteUserUID": true, 19 | "customizations": { 20 | "vscode": { 21 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/tox.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # cspell:ignore anthropics 3 | name: tox 4 | 5 | on: 6 | merge_group: 7 | branches: 8 | - "main" 9 | push: 10 | branches: 11 | - "main" 12 | pull_request: 13 | branches: 14 | - "main" 15 | schedule: 16 | - cron: "0 0 * * *" 17 | workflow_call: 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | tox: 24 | uses: ansible/team-devtools/.github/workflows/tox.yml@main 25 | secrets: inherit 26 | with: 27 | min_python: "3.10" 28 | default_python: "3.13" 29 | max_python: "3.13" 30 | other_names: | 31 | pkg 32 | lint 33 | docs 34 | py314-devel 35 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | # Specify the inventory file 3 | inventory = inventory/hosts.yml 4 | 5 | # Define the directory for host and group variables 6 | host_vars_inventory = inventory/host_vars 7 | group_vars_inventory = inventory/group_vars 8 | 9 | # Set the logging verbosity level 10 | verbosity = 2 11 | 12 | # Set the default user for SSH connections 13 | remote_user = myuser 14 | 15 | # Define the default become method 16 | become_method = sudo 17 | 18 | [persistent_connection] 19 | # Controls how long the persistent connection will remain idle before it is destroyed 20 | connect_timeout=30 21 | 22 | # Controls the amount of time to wait for response from remote device before timing out persistent connection 23 | command_timeout=30 24 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/ansible.cfg.j2: -------------------------------------------------------------------------------- 1 | [defaults] 2 | # Specify the inventory file 3 | inventory = inventory/hosts.yml 4 | 5 | # Define the directory for host and group variables 6 | host_vars_inventory = inventory/host_vars 7 | group_vars_inventory = inventory/group_vars 8 | 9 | # Set the logging verbosity level 10 | verbosity = 2 11 | 12 | # Set the default user for SSH connections 13 | remote_user = myuser 14 | 15 | # Define the default become method 16 | become_method = sudo 17 | 18 | [persistent_connection] 19 | # Controls how long the persistent connection will remain idle before it is destroyed 20 | connect_timeout=30 21 | 22 | # Controls the amount of time to wait for response from remote device before timing out persistent connection 23 | command_timeout=30 24 | -------------------------------------------------------------------------------- /tests/fixtures/project/ee_project/execution-environment.yml: -------------------------------------------------------------------------------- 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 41 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/devcontainer/.devcontainer/podman/devcontainer.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-podman", 3 | "image": "{{ dev_container_image }}", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--cap-add=CAP_MKNOD", 7 | "--cap-add=NET_ADMIN", 8 | "--cap-add=SYS_ADMIN", 9 | "--cap-add=SYS_RESOURCE", 10 | "--device", 11 | "/dev/fuse", 12 | "--security-opt", 13 | "seccomp=unconfined", 14 | "--security-opt", 15 | "label=disable", 16 | "--security-opt", 17 | "apparmor=unconfined", 18 | "--security-opt", 19 | "unmask=/sys/fs/cgroup", 20 | "--userns=host", 21 | "--hostname=ansible-dev-container" 22 | ], 23 | "customizations": { 24 | "vscode": { 25 | "extensions": {{ recommended_extensions | json }} 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "args": ["."], 5 | "command": "pydoclint", 6 | "group": { 7 | "isDefault": true, 8 | "kind": "none" 9 | }, 10 | "label": "pydoclint", 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "problemMatcher": { 15 | "fileLocation": ["relative", "${workspaceFolder}"], 16 | "owner": "pydoclint", 17 | "pattern": { 18 | "code": 3, 19 | "file": 1, 20 | "line": 2, 21 | "message": 4, 22 | "regexp": "^(.*?):(\\d+):\\s(.*?):\\s(.*)$" 23 | } 24 | }, 25 | "type": "shell" 26 | } 27 | ], 28 | // See https://go.microsoft.com/fwlink/?LinkId=733558 29 | // for the documentation about the tasks.json format 30 | "version": "2.0.0" 31 | } 32 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/inventory/hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | server1: 5 | ansible_host: 192.168.1.101 6 | server2: 7 | ansible_host: 192.168.1.102 8 | switch1: 9 | ansible_host: 192.168.1.106 10 | switch2: 11 | ansible_host: 192.168.1.107 12 | children: 13 | web_servers: 14 | hosts: 15 | server1: 16 | server2: 17 | db_servers: 18 | hosts: 19 | server3: 20 | ansible_host: 192.168.1.103 21 | switches: 22 | hosts: 23 | switch1: 24 | switch2: 25 | production: 26 | hosts: 27 | server1: 28 | ansible_host: 192.168.1.101 29 | server2: 30 | ansible_host: 192.168.1.102 31 | test: 32 | hosts: 33 | server3: 34 | ansible_host: 192.168.1.103 35 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/execution_env_project/execution-environment.yml.j2: -------------------------------------------------------------------------------- 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 41 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/inventory/hosts.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | server1: 5 | ansible_host: 192.168.1.101 6 | server2: 7 | ansible_host: 192.168.1.102 8 | switch1: 9 | ansible_host: 192.168.1.106 10 | switch2: 11 | ansible_host: 192.168.1.107 12 | children: 13 | web_servers: 14 | hosts: 15 | server1: 16 | server2: 17 | db_servers: 18 | hosts: 19 | server3: 20 | ansible_host: 192.168.1.103 21 | switches: 22 | hosts: 23 | switch1: 24 | switch2: 25 | production: 26 | hosts: 27 | server1: 28 | ansible_host: 192.168.1.101 29 | server2: 30 | ansible_host: 192.168.1.102 31 | test: 32 | hosts: 33 | server3: 34 | ansible_host: 192.168.1.103 35 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.devcontainer/podman/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-podman", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--cap-add=CAP_MKNOD", 7 | "--cap-add=NET_ADMIN", 8 | "--cap-add=SYS_ADMIN", 9 | "--cap-add=SYS_RESOURCE", 10 | "--device", 11 | "/dev/fuse", 12 | "--security-opt", 13 | "seccomp=unconfined", 14 | "--security-opt", 15 | "label=disable", 16 | "--security-opt", 17 | "apparmor=unconfined", 18 | "--security-opt", 19 | "unmask=/sys/fs/cgroup", 20 | "--userns=host", 21 | "--hostname=ansible-dev-container" 22 | ], 23 | "customizations": { 24 | "vscode": { 25 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/.devcontainer/podman/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansible-dev-container-podman", 3 | "image": "ghcr.io/ansible/community-ansible-dev-tools:latest", 4 | "containerUser": "root", 5 | "runArgs": [ 6 | "--cap-add=CAP_MKNOD", 7 | "--cap-add=NET_ADMIN", 8 | "--cap-add=SYS_ADMIN", 9 | "--cap-add=SYS_RESOURCE", 10 | "--device", 11 | "/dev/fuse", 12 | "--security-opt", 13 | "seccomp=unconfined", 14 | "--security-opt", 15 | "label=disable", 16 | "--security-opt", 17 | "apparmor=unconfined", 18 | "--security-opt", 19 | "unmask=/sys/fs/cgroup", 20 | "--userns=host", 21 | "--hostname=ansible-dev-container" 22 | ], 23 | "customizations": { 24 | "vscode": { 25 | "extensions": ["redhat.ansible", "redhat.vscode-redhat-account"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/linux_playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update web servers 3 | hosts: webservers 4 | become: true 5 | 6 | tasks: 7 | - name: Ensure apache is at the present version 8 | ansible.builtin.dnf: 9 | name: httpd 10 | state: present 11 | 12 | - name: Write the apache config file 13 | ansible.builtin.template: 14 | src: /srv/httpd.j2 15 | dest: /etc/httpd.conf 16 | mode: "0644" 17 | 18 | - name: Update db servers 19 | hosts: databases 20 | become: true 21 | 22 | tasks: 23 | - name: Ensure postgresql is at the present version 24 | ansible.builtin.dnf: 25 | name: postgresql 26 | state: present 27 | 28 | - name: Ensure that postgresql is started 29 | ansible.builtin.service: 30 | name: postgresql 31 | state: started 32 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/linux_playbook.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update web servers 3 | hosts: webservers 4 | become: true 5 | 6 | tasks: 7 | - name: Ensure apache is at the present version 8 | ansible.builtin.dnf: 9 | name: httpd 10 | state: present 11 | 12 | - name: Write the apache config file 13 | ansible.builtin.template: 14 | src: /srv/httpd.j2 15 | dest: /etc/httpd.conf 16 | mode: "0644" 17 | 18 | - name: Update db servers 19 | hosts: databases 20 | become: true 21 | 22 | tasks: 23 | - name: Ensure postgresql is at the present version 24 | ansible.builtin.dnf: 25 | name: postgresql 26 | state: present 27 | 28 | - name: Ensure that postgresql is started 29 | ansible.builtin.service: 30 | name: postgresql 31 | state: started 32 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/network_playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Network Getting Started First Playbook Extended 3 | gather_facts: false 4 | hosts: switch1 5 | tasks: 6 | - name: Get config for IOS devices 7 | cisco.ios.ios_facts: 8 | gather_subset: all 9 | 10 | - name: Display the config 11 | ansible.builtin.debug: 12 | msg: "The hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}" 13 | 14 | - name: Update the hostname 15 | cisco.ios.ios_config: 16 | lines: 17 | - hostname ios-changed 18 | 19 | - name: Get changed config for IOS devices 20 | cisco.ios.ios_facts: 21 | gather_subset: all 22 | 23 | - name: Display the changed config 24 | ansible.builtin.debug: 25 | msg: "The new hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}" 26 | -------------------------------------------------------------------------------- /.github/workflows/finalize.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: finalize 3 | on: 4 | workflow_run: 5 | workflows: 6 | - tox 7 | types: 8 | - completed 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | finalize: 14 | if: | 15 | github.event.workflow_run.conclusion == 'success' && 16 | (github.event.workflow_run.event == 'pull_request' || 17 | (github.event.workflow_run.event == 'push' && github.event.workflow_run.head_branch == 'main')) 18 | uses: ansible/team-devtools/.github/workflows/finalize.yml@main 19 | with: 20 | run-id: ${{ github.event.workflow_run.id }} 21 | workflow-event: ${{ github.event.workflow_run.event }} 22 | head-sha: ${{ github.event.workflow_run.head_sha }} 23 | head-branch: ${{ github.event.workflow_run.head_branch }} 24 | head-repository: ${{ github.event.workflow_run.head_repository.full_name }} 25 | secrets: inherit 26 | -------------------------------------------------------------------------------- /tests/fixtures/project/ee_project/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Combine workflow for pull-request, push-to-main and release events. 3 | 4 | name: Execution environment build 5 | 6 | on: 7 | pull_request_target: 8 | branches: 9 | - main 10 | types: [opened, reopened, synchronize] 11 | push: 12 | branches: 13 | - main 14 | release: 15 | types: [published] 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 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide: 3 | - navigation 4 | - toc 5 | --- 6 | 7 | # Welcome to Ansible-Creator Documentation 8 | 9 | The `ansible-creator` is a Command-Line Interface (CLI) tool designed for 10 | effortlessly scaffolding all your Ansible content. Whether you are initializing 11 | an Ansible Collection or creating the framework for specific plugins, this tool 12 | streamlines the process with efficiency and precision based on your 13 | requirements. 14 | 15 | This documentation serves as a detailed guide for using ansible-creator, 16 | emphasizing the 'init' and 'add' functionalities. The 'init' functionality 17 | initializes a new Ansible project whereas 'add' enables you to add resources to 18 | an existing ansible project. 19 | 20 | ## Licensing 21 | 22 | **ansible-creator** is licensed under the Apache License version 2. Refer to the 23 | [LICENSE](http://www.apache.org/licenses/LICENSE-2.0) file for the full text. 24 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/network_playbook.yml.j2: -------------------------------------------------------------------------------- 1 | {% raw %}--- 2 | - name: Network Getting Started First Playbook Extended 3 | gather_facts: false 4 | hosts: switch1 5 | tasks: 6 | - name: Get config for IOS devices 7 | cisco.ios.ios_facts: 8 | gather_subset: all 9 | 10 | - name: Display the config 11 | ansible.builtin.debug: 12 | msg: "The hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}" 13 | 14 | - name: Update the hostname 15 | cisco.ios.ios_config: 16 | lines: 17 | - hostname ios-changed 18 | 19 | - name: Get changed config for IOS devices 20 | cisco.ios.ios_facts: 21 | gather_subset: all 22 | 23 | - name: Display the changed config 24 | ansible.builtin.debug: 25 | msg: "The new hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}" 26 | {%- endraw %} 27 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/execution_env_project/.github/workflows/ci.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # Combine workflow for pull-request, push-to-main and release events. 3 | 4 | name: Execution environment build 5 | 6 | on: 7 | pull_request_target: 8 | branches: 9 | - main 10 | types: [opened, reopened, synchronize] 11 | push: 12 | branches: 13 | - main 14 | release: 15 | types: [published] 16 | {% raw -%} 17 | jobs: 18 | ee-build: 19 | uses: ansible/ansible-content-actions/.github/workflows/ee-build.yml@main 20 | with: 21 | registry: ghcr.io 22 | secrets: 23 | registry_username: ${{ github.actor }} 24 | registry_password: ${{ secrets.GITHUB_TOKEN }} 25 | # Only needed if base image of execution-environment.yml file is from Red Hat (ee-minimal) 26 | # registry_redhat_username: ${{ secrets.registry_redhat_username }} 27 | # registry_redhat_password: ${{ secrets.registry_redhat_password }} 28 | {%- endraw %} 29 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/changelogs/config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | changelog_filename_template: ../CHANGELOG.rst 3 | changelog_filename_version_depth: 0 4 | changes_file: changelog.yaml 5 | changes_format: combined 6 | keep_fragments: false 7 | mention_ancestor: true 8 | new_plugins_after_name: removed_features 9 | notesdir: fragments 10 | prelude_section_name: release_summary 11 | prelude_section_title: Release Summary 12 | flatmap: true 13 | sections: 14 | - - major_changes 15 | - Major Changes 16 | - - minor_changes 17 | - Minor Changes 18 | - - breaking_changes 19 | - Breaking Changes / Porting Guide 20 | - - deprecated_features 21 | - Deprecated Features 22 | - - removed_features 23 | - Removed Features (previously deprecated) 24 | - - security_fixes 25 | - Security Fixes 26 | - - bugfixes 27 | - Bugfixes 28 | - - known_issues 29 | - Known Issues 30 | - - doc_changes 31 | - Documentation Changes 32 | title: "Testorg Testcol Collection" 33 | trivial_section_name: trivial 34 | -------------------------------------------------------------------------------- /docs/content_creation.md: -------------------------------------------------------------------------------- 1 | # Creating ansible content using ansible-creator and VS Code Ansible extension 2 | 3 | - For users who prefer a graphical interface, ansible-creator seamlessly 4 | integrates with the 5 | [Visual Studio Code (VS Code)](https://code.visualstudio.com/docs) and the 6 | [Ansible extension](https://marketplace.visualstudio.com/items?itemName=redhat.ansible) 7 | for it, offering an intuitive GUI experience. 8 | 9 | - By navigating to the Ansible section in the VS Code activity bar and selecting 10 | "Ansible Development Tools," users can access a menu-driven interface. 11 | 12 | - This GUI provides interactive forms for straightforward input. So you can 13 | effortlessly manage your Ansible content without delving into the intricacies 14 | of command-line operations. 15 | 16 | - Here is a detailed 17 | [guide](https://ansible.readthedocs.io/projects/vscode-ansible/) on creating 18 | an ansible content using the ansible-creator and VS Code Ansible extension. 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/changelogs/config.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | changelog_filename_template: ../CHANGELOG.rst 3 | changelog_filename_version_depth: 0 4 | changes_file: changelog.yaml 5 | changes_format: combined 6 | keep_fragments: false 7 | mention_ancestor: true 8 | new_plugins_after_name: removed_features 9 | notesdir: fragments 10 | prelude_section_name: release_summary 11 | prelude_section_title: Release Summary 12 | flatmap: true 13 | sections: 14 | - - major_changes 15 | - Major Changes 16 | - - minor_changes 17 | - Minor Changes 18 | - - breaking_changes 19 | - Breaking Changes / Porting Guide 20 | - - deprecated_features 21 | - Deprecated Features 22 | - - removed_features 23 | - Removed Features (previously deprecated) 24 | - - security_fixes 25 | - Security Fixes 26 | - - bugfixes 27 | - Bugfixes 28 | - - known_issues 29 | - Known Issues 30 | - - doc_changes 31 | - Documentation Changes 32 | title: "{{ namespace|capitalize }} {{ collection_name|capitalize }} Collection" 33 | trivial_section_name: trivial 34 | -------------------------------------------------------------------------------- /tests/units/test_templar.py: -------------------------------------------------------------------------------- 1 | """Tests for templar.""" 2 | 3 | from __future__ import annotations 4 | 5 | from ansible_creator.templar import Templar 6 | from ansible_creator.types import TemplateData 7 | 8 | 9 | def test_templar() -> None: 10 | """Test templar.""" 11 | templar = Templar() 12 | data = TemplateData(collection_name="test") 13 | template = "{{ collection_name }}" 14 | assert templar.render_from_content(template, data) == "test" 15 | 16 | 17 | def test_templar_json_simple() -> None: 18 | """Test templar json with a simple structure.""" 19 | templar = Templar() 20 | data = TemplateData(recommended_extensions=["value"]) 21 | template = "{{ recommended_extensions | json }}" 22 | assert templar.render_from_content(template, data) == '["value"]' 23 | 24 | 25 | def test_templar_json_complex() -> None: 26 | """Test templar json with a complex structure.""" 27 | templar = Templar() 28 | data = TemplateData(additions={"key": {"key": {"key": True}}}) 29 | template = "{{ additions | json }}" 30 | assert templar.render_from_content(template, data) == '{"key": {"key": {"key": true}}}' 31 | -------------------------------------------------------------------------------- /src/ansible_creator/exceptions.py: -------------------------------------------------------------------------------- 1 | """Custom exception classes for ansible-creator.""" 2 | 3 | from __future__ import annotations 4 | 5 | 6 | class CreatorError(Exception): 7 | """Class representing exceptions raised from creator code.""" 8 | 9 | def __init__(self, message: str) -> None: 10 | """Instantiate an object of this class. 11 | 12 | Args: 13 | message: The exception message. 14 | """ 15 | super().__init__(message) 16 | self._message = message 17 | 18 | @property 19 | def message(self) -> str: 20 | """Craft and return the CreatorError message. 21 | 22 | Includes the 'cause' when raised from another exception. 23 | 24 | Returns: 25 | An exception message. 26 | """ 27 | msg = self._message 28 | if getattr(self, "__cause__", ""): 29 | msg += f"\n{self.__cause__!s}" 30 | return msg 31 | 32 | def __str__(self) -> str: 33 | """Return a string representation of the exception. 34 | 35 | Returns: 36 | The exception message as a string. 37 | """ 38 | return self.message 39 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/modules/sample_action.py: -------------------------------------------------------------------------------- 1 | # sample_action.py 2 | # GNU General Public License v3.0+ 3 | 4 | DOCUMENTATION = """ 5 | module: sample_action 6 | author: Your Name (@username) 7 | version_added: "1.0.0" 8 | short_description: A custom action plugin for Ansible. 9 | description: 10 | - This is a custom action plugin to provide action functionality. 11 | options: 12 | prefix: 13 | description: 14 | - A string that is added as a prefix to the message passed to the module. 15 | type: str 16 | msg: 17 | description: The message to display in the output. 18 | type: str 19 | with_prefix: 20 | description: 21 | - A boolean flag indicating whether to include the prefix in the message. 22 | type: bool 23 | notes: 24 | - This is a scaffold template. Customize the plugin to fit your needs. 25 | """ 26 | 27 | EXAMPLES = """ 28 | - name: Example Action Plugin 29 | hosts: localhost 30 | tasks: 31 | - name: Example sample_action plugin 32 | with_prefix: 33 | prefix: "Hello, World" 34 | msg: "Ansible!" 35 | """ 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help us improve 4 | labels: bug, new 5 | --- 6 | 7 | ##### ISSUE TYPE 8 | 9 | - Bug Report 10 | 11 | ##### SUMMARY 12 | 13 | 14 | 15 | ##### ANSIBLE-CREATOR VERSION 16 | 17 | 18 | 19 | ```shell 20 | 21 | ``` 22 | 23 | ##### PYTHON VERSION 24 | 25 | 26 | 27 | ##### LOG FILE 28 | 29 | 33 | 34 | ##### STEPS TO REPRODUCE 35 | 36 | 37 | 38 | ##### EXPECTED RESULTS 39 | 40 | 41 | 42 | ##### ACTUAL RESULTS 43 | 44 | 45 | 46 | ##### ADDITIONAL INFORMATION 47 | 48 | 50 | -------------------------------------------------------------------------------- /src/ansible_creator/constants.py: -------------------------------------------------------------------------------- 1 | """Definition of constants for this package.""" 2 | 3 | from __future__ import annotations 4 | 5 | 6 | GLOBAL_TEMPLATE_VARS = { 7 | # DEV_CONTAINER_IMAGE gets updated with the downstream image when the package 8 | # is installed using rpm 9 | # See: https://gitlab.cee.redhat.com/aap-cpaas/config/ansible-creator/-/blob/ansible-automation-platform-2.5/distgit/rpms/ansible-creator/ansible-creator.spec.in?ref_type=heads#L34 10 | "DEV_CONTAINER_IMAGE": "ghcr.io/ansible/community-ansible-dev-tools:latest", 11 | "DEV_CONTAINER_UPSTREAM_IMAGE": "ghcr.io/ansible/community-ansible-dev-tools:latest", 12 | "DEV_CONTAINER_DOWNSTREAM_IMAGE": ( 13 | "registry.redhat.io/ansible-automation-platform-25/ansible-dev-tools-rhel8:latest" 14 | ), 15 | "DEV_FILE_IMAGE": "ghcr.io/ansible/ansible-devspaces:latest", 16 | "RECOMMENDED_EXTENSIONS": ["redhat.ansible", "redhat.vscode-redhat-account"], 17 | "EXECUTION_ENVIRONMENT_DEFAULT_IMAGE": "quay.io/fedora/fedora:41", 18 | } 19 | 20 | MIN_COLLECTION_NAME_LEN = 2 21 | 22 | # directory names that will be skipped in any resource 23 | SKIP_DIRS = ("__pycache__",) 24 | # file types that will be skipped in any resource 25 | SKIP_FILES_TYPES = (".pyc",) 26 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | // Run testing debugging in the terminal so the workspace venv is used 4 | { 5 | "console": "integratedTerminal", 6 | "name": "Debug tests", 7 | "purpose": ["debug-test"], 8 | "request": "launch", 9 | "type": "debugpy" 10 | }, 11 | // Configuration for pure debugging (use args and cwd attributes accordingly) 12 | { 13 | "args": [ 14 | "init", 15 | "playbook", 16 | "testns.testname", 17 | "/home/user/..path/to/your/new_playbook_project" 18 | ], 19 | "cwd": "${workspaceFolder}/src", 20 | "justMyCode": false, 21 | "module": "ansible_creator", 22 | "name": "Debug subcommand: init", 23 | "request": "launch", 24 | "type": "debugpy" 25 | }, 26 | { 27 | "args": [ 28 | "add", 29 | "resource", 30 | "devcontainer", 31 | "/home/user/..path/to/your/existing_project" 32 | ], 33 | "cwd": "${workspaceFolder}/src", 34 | "justMyCode": false, 35 | "module": "ansible_creator", 36 | "name": "Debug subcommand: add", 37 | "request": "launch", 38 | "type": "debugpy" 39 | } 40 | ], 41 | "version": "0.2.0" 42 | } 43 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/modules/sample_action.py.j2: -------------------------------------------------------------------------------- 1 | {%- set module_name = plugin_name | default("sample_action",true) -%} 2 | {%- set author = author | default("Your Name (@username)") -%} 3 | # {{ module_name }}.py 4 | # GNU General Public License v3.0+ 5 | 6 | DOCUMENTATION = """ 7 | module: {{ module_name }} 8 | author: {{ author }} 9 | version_added: "1.0.0" 10 | short_description: A custom action plugin for Ansible. 11 | description: 12 | - This is a custom action plugin to provide action functionality. 13 | options: 14 | prefix: 15 | description: 16 | - A string that is added as a prefix to the message passed to the module. 17 | type: str 18 | msg: 19 | description: The message to display in the output. 20 | type: str 21 | with_prefix: 22 | description: 23 | - A boolean flag indicating whether to include the prefix in the message. 24 | type: bool 25 | notes: 26 | - This is a scaffold template. Customize the plugin to fit your needs. 27 | """ 28 | 29 | EXAMPLES = """ 30 | - name: Example Action Plugin 31 | hosts: localhost 32 | tasks: 33 | - name: Example {{ module_name }} plugin 34 | with_prefix: 35 | prefix: "Hello, World" 36 | msg: "Ansible!" 37 | """ 38 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[json]": { 3 | "editor.defaultFormatter": "biomejs.biome" 4 | }, 5 | "[markdown]": { 6 | "editor.defaultFormatter": "biomejs.biome" 7 | }, 8 | "[python]": { 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll": "explicit", 11 | "source.organizeImports": "explicit" 12 | }, 13 | "editor.defaultFormatter": "charliermarsh.ruff", 14 | "editor.formatOnSave": true 15 | }, 16 | "[toml]": { 17 | "editor.defaultFormatter": "tombi-toml.tombi" 18 | }, 19 | "editor.codeActionsOnSave": { 20 | "source.action.useSortedKeys.biome": "explicit", 21 | "source.fixAll.biome": "always", 22 | "source.organizeImports.biome": "explicit" 23 | }, 24 | "files.associations": { 25 | "*.j2": "yaml" 26 | }, 27 | "markiscodecoverage.searchCriteria": ".cache/.coverage/lcov.info", 28 | "mypy-type-checker.args": ["--config-file=${workspaceFolder}/pyproject.toml"], 29 | "mypy-type-checker.importStrategy": "fromEnvironment", 30 | "mypy-type-checker.reportingScope": "workspace", 31 | "pylint.importStrategy": "fromEnvironment", 32 | "python.testing.pytestArgs": ["tests"], 33 | "python.testing.pytestEnabled": true, 34 | "python.testing.unittestEnabled": false, 35 | "sonarlint.connectedMode.project": { 36 | "connectionId": "ansible", 37 | "projectKey": "ansible_ansible-creator" 38 | }, 39 | "triggerTaskOnSave.tasks": { 40 | "pydoclint": ["*.py"] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release 3 | 4 | on: 5 | release: 6 | types: [published] 7 | jobs: 8 | release: 9 | environment: release 10 | runs-on: ubuntu-latest 11 | permissions: 12 | id-token: write 13 | 14 | env: 15 | FORCE_COLOR: 1 16 | PY_COLORS: 1 17 | 18 | steps: 19 | - name: Switch to using Python 3.12 by default 20 | uses: actions/setup-python@v6 21 | with: 22 | python-version: "3.14" 23 | 24 | - name: Install tox 25 | run: python3 -m pip install --user "tox>=4.0.0" 26 | 27 | - name: Check out src from Git 28 | uses: actions/checkout@v6 29 | with: 30 | fetch-depth: 0 # needed by setuptools-scm 31 | 32 | - name: Build dists 33 | run: python3 -m tox -e pkg 34 | 35 | - name: Publish to pypi.org 36 | uses: pypa/gh-action-pypi-publish@release/v1 37 | 38 | forum_post: 39 | needs: release 40 | runs-on: ubuntu-latest 41 | 42 | steps: 43 | - name: Retrieve the forum post script from team-devtools 44 | run: curl -O https://raw.githubusercontent.com/ansible/team-devtools/main/.github/workflows/forum_post.py 45 | 46 | - name: Run the forum post script 47 | run: >- 48 | python3 forum_post.py ${{ github.event.repository.full_name }} 49 | ${{ github.event.release.tag_name }} ${{ secrets.FORUM_KEY }} 50 | ${{ secrets.FORUM_USER }} 51 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/README.md: -------------------------------------------------------------------------------- 1 | # Weather Demo Ansible Project 2 | 3 | ## Included content/ Directory Structure 4 | 5 | The directory structure follows best practices recommended by the Ansible 6 | community. Feel free to customize this template according to your specific 7 | project requirements. 8 | 9 | ```shell 10 | ansible-project/ 11 | |── .devcontainer/ 12 | | └── docker/ 13 | | └── devcontainer.json 14 | | └── podman/ 15 | | └── devcontainer.json 16 | | └── devcontainer.json 17 | |── .github/ 18 | | └── workflows/ 19 | | └── tests.yml 20 | | └── ansible-code-bot.yml 21 | |── .vscode/ 22 | | └── extensions.json 23 | |── collections/ 24 | | └── requirements.yml 25 | | └── ansible_collections/ 26 | | └── project_org/ 27 | | └── project_repo/ 28 | | └── README.md 29 | | └── roles/sample_role/ 30 | | └── README.md 31 | | └── tasks/main.yml 32 | |── inventory/ 33 | | |── hosts.yml 34 | | |── argspec_validation_inventory.yml 35 | | └── groups_vars/ 36 | | └── host_vars/ 37 | |── ansible-navigator.yml 38 | |── ansible.cfg 39 | |── devfile.yaml 40 | |── linux_playbook.yml 41 | |── network_playbook.yml 42 | |── README.md 43 | |── site.yml 44 | ``` 45 | 46 | ## Compatible with Ansible-lint 47 | 48 | Tested with ansible-lint >=24.2.0 releases and the current development version 49 | of ansible-core. 50 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/ansible-network/collection_prep 4 | rev: 1.1.1 5 | hooks: 6 | - id: update-docs 7 | 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v4.4.0 10 | hooks: 11 | - id: check-merge-conflict 12 | - id: check-symlinks 13 | - id: debug-statements 14 | - id: end-of-file-fixer 15 | - id: no-commit-to-branch 16 | args: [--branch, main] 17 | - id: trailing-whitespace 18 | 19 | - repo: https://github.com/asottile/add-trailing-comma 20 | rev: v3.0.0 21 | hooks: 22 | - id: add-trailing-comma 23 | 24 | - repo: https://github.com/pre-commit/mirrors-prettier 25 | rev: "v3.0.0" 26 | hooks: 27 | - id: prettier 28 | entry: env CI=1 bash -c "prettier --list-different . || ec=$? && prettier --loglevel=error --write . && exit $ec" 29 | pass_filenames: false 30 | args: [] 31 | additional_dependencies: 32 | - prettier 33 | - prettier-plugin-toml 34 | 35 | - repo: https://github.com/PyCQA/isort 36 | rev: 5.12.0 37 | hooks: 38 | - id: isort 39 | name: Sort import statements using isort 40 | args: ["--filter-files"] 41 | 42 | - repo: https://github.com/psf/black 43 | rev: 23.7.0 44 | hooks: 45 | - id: black 46 | 47 | - repo: https://github.com/pycqa/flake8 48 | rev: 7.0.0 49 | hooks: 50 | - id: flake8 51 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/.pre-commit-config.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/ansible-network/collection_prep 4 | rev: 1.1.1 5 | hooks: 6 | - id: update-docs 7 | 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v4.4.0 10 | hooks: 11 | - id: check-merge-conflict 12 | - id: check-symlinks 13 | - id: debug-statements 14 | - id: end-of-file-fixer 15 | - id: no-commit-to-branch 16 | args: [--branch, main] 17 | - id: trailing-whitespace 18 | 19 | - repo: https://github.com/asottile/add-trailing-comma 20 | rev: v3.0.0 21 | hooks: 22 | - id: add-trailing-comma 23 | 24 | - repo: https://github.com/pre-commit/mirrors-prettier 25 | rev: "v3.0.0" 26 | hooks: 27 | - id: prettier 28 | entry: env CI=1 bash -c "prettier --list-different . || ec=$? && prettier --loglevel=error --write . && exit $ec" 29 | pass_filenames: false 30 | args: [] 31 | additional_dependencies: 32 | - prettier 33 | - prettier-plugin-toml 34 | 35 | - repo: https://github.com/PyCQA/isort 36 | rev: 5.12.0 37 | hooks: 38 | - id: isort 39 | name: Sort import statements using isort 40 | args: ["--filter-files"] 41 | 42 | - repo: https://github.com/psf/black 43 | rev: 23.7.0 44 | hooks: 45 | - id: black 46 | 47 | - repo: https://github.com/pycqa/flake8 48 | rev: 7.0.0 49 | hooks: 50 | - id: flake8 51 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/test/sample_test.py: -------------------------------------------------------------------------------- 1 | # sample_test.py - A custom test plugin for Ansible. 2 | # Author: Your Name 3 | # License: GPL-3.0-or-later 4 | 5 | from __future__ import absolute_import, annotations, division, print_function 6 | 7 | 8 | __metaclass__ = type # pylint: disable=C0103 9 | 10 | from typing import TYPE_CHECKING 11 | 12 | 13 | if TYPE_CHECKING: 14 | from typing import Callable 15 | 16 | 17 | DOCUMENTATION = """ 18 | name: sample_test 19 | author: Your Name 20 | version_added: "1.0.0" 21 | short_description: A custom test plugin for Ansible. 22 | description: 23 | - This is a demo test plugin designed to return a bool. 24 | options: 25 | name: 26 | type: bool 27 | description: This is a sample option. 28 | """ 29 | 30 | EXAMPLES = """ 31 | # sample_test test example 32 | 33 | - name: Display a bool 34 | ansible.builtin.debug: 35 | msg: "{{ 50 | sample_test }}" 36 | """ 37 | 38 | 39 | def _sample_test(val: int) -> bool: 40 | """Returns a bool. 41 | 42 | Args: 43 | val: The value to test. 44 | 45 | Returns: 46 | bool: The result. 47 | """ 48 | return val > 42 49 | 50 | 51 | class TestModule: 52 | """test plugin.""" 53 | 54 | def tests(self) -> dict[str, Callable[[int], bool]]: 55 | """Map test plugin names to their functions. 56 | 57 | Returns: 58 | dict: The test plugin functions. 59 | """ 60 | return {"sample_test": _sample_test} 61 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/README.md.j2: -------------------------------------------------------------------------------- 1 | # {{ namespace|capitalize }} {{ collection_name|capitalize }} Ansible Project 2 | 3 | ## Included content/ Directory Structure 4 | 5 | The directory structure follows best practices recommended by the Ansible 6 | community. Feel free to customize this template according to your specific 7 | project requirements. 8 | 9 | ```shell 10 | ansible-project/ 11 | |── .devcontainer/ 12 | | └── docker/ 13 | | └── devcontainer.json 14 | | └── podman/ 15 | | └── devcontainer.json 16 | | └── devcontainer.json 17 | |── .github/ 18 | | └── workflows/ 19 | | └── tests.yml 20 | | └── ansible-code-bot.yml 21 | |── .vscode/ 22 | | └── extensions.json 23 | |── collections/ 24 | | └── requirements.yml 25 | | └── ansible_collections/ 26 | | └── project_org/ 27 | | └── project_repo/ 28 | | └── README.md 29 | | └── roles/sample_role/ 30 | | └── README.md 31 | | └── tasks/main.yml 32 | |── inventory/ 33 | | |── hosts.yml 34 | | |── argspec_validation_inventory.yml 35 | | └── groups_vars/ 36 | | └── host_vars/ 37 | |── ansible-navigator.yml 38 | |── ansible.cfg 39 | |── devfile.yaml 40 | |── linux_playbook.yml 41 | |── network_playbook.yml 42 | |── README.md 43 | |── site.yml 44 | ``` 45 | 46 | ## Compatible with Ansible-lint 47 | 48 | Tested with ansible-lint >=24.2.0 releases and the current development version 49 | of ansible-core. 50 | -------------------------------------------------------------------------------- /tests/units/test_argparse_help.py: -------------------------------------------------------------------------------- 1 | """Test the custom help formatter.""" 2 | 3 | from __future__ import annotations 4 | 5 | import sys 6 | 7 | import pytest 8 | 9 | from ansible_creator.arg_parser import CustomArgumentParser 10 | 11 | 12 | @pytest.mark.skipif( 13 | sys.version_info >= (3, 14), reason="Custom help formatter is not supported in Python 3.14+" 14 | ) 15 | def test_custom_help_single() -> None: 16 | """Test the custom help formatter with single.""" 17 | parser = CustomArgumentParser() 18 | parser.add_argument("--foo", help="foo help") 19 | help_text = parser.format_help() 20 | line = " --foo foo help" 21 | assert line in help_text.splitlines() 22 | 23 | 24 | @pytest.mark.skipif( 25 | sys.version_info >= (3, 14), reason="Custom help formatter is not supported in Python 3.14+" 26 | ) 27 | def test_custom_help_double() -> None: 28 | """Test the custom help formatter with double.""" 29 | parser = CustomArgumentParser() 30 | parser.add_argument("-f", "--foo", help="foo help") 31 | help_text = parser.format_help() 32 | line = " -f --foo foo help" 33 | assert line in help_text.splitlines() 34 | 35 | 36 | @pytest.mark.skipif( 37 | sys.version_info >= (3, 14), reason="Custom help formatter is not supported in Python 3.14+" 38 | ) 39 | def test_custom_help_triple() -> None: 40 | """Test the custom help formatter with triple.""" 41 | parser = CustomArgumentParser() 42 | parser.add_argument("-f", "--foo", "--foolish", help="foo help") 43 | 44 | with pytest.raises(ValueError, match="Too many option strings"): 45 | parser.format_help() 46 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/filter/sample_filter.py: -------------------------------------------------------------------------------- 1 | # sample_filter.py - A custom filter plugin for Ansible. 2 | # Author: Your Name 3 | # License: GPL-3.0-or-later 4 | 5 | from __future__ import absolute_import, annotations, division, print_function 6 | 7 | 8 | __metaclass__ = type # pylint: disable=C0103 9 | 10 | from typing import TYPE_CHECKING 11 | 12 | 13 | if TYPE_CHECKING: 14 | from typing import Callable 15 | 16 | 17 | DOCUMENTATION = """ 18 | name: sample_filter 19 | author: Your Name 20 | version_added: "1.0.0" 21 | short_description: A custom filter plugin for Ansible. 22 | description: 23 | - This is a demo filter plugin designed to return Hello message. 24 | options: 25 | name: 26 | description: Value specified here is appended to the Hello message. 27 | type: str 28 | """ 29 | 30 | EXAMPLES = """ 31 | # sample_filter filter example 32 | 33 | - name: Display a hello message 34 | ansible.builtin.debug: 35 | msg: "{{ 'ansible-creator' | sample_filter }}" 36 | """ 37 | 38 | 39 | def _sample_filter(name: str) -> str: 40 | """Returns Hello message. 41 | 42 | Args: 43 | name: The name to greet. 44 | 45 | Returns: 46 | str: The greeting message. 47 | """ 48 | return "Hello, " + name 49 | 50 | 51 | class FilterModule: 52 | """filter plugin.""" 53 | 54 | def filters(self) -> dict[str, Callable[[str], str]]: 55 | """Map filter plugin names to their functions. 56 | 57 | Returns: 58 | dict: The filter plugin functions. 59 | """ 60 | return {"sample_filter": _sample_filter} 61 | -------------------------------------------------------------------------------- /src/ansible_creator/templar.py: -------------------------------------------------------------------------------- 1 | """A Jinja2 template engine.""" 2 | 3 | from __future__ import annotations 4 | 5 | import json 6 | 7 | from dataclasses import asdict 8 | from typing import TYPE_CHECKING 9 | 10 | 11 | if TYPE_CHECKING: 12 | from ansible_creator.types import TemplateData 13 | 14 | 15 | try: 16 | from jinja2 import Environment, StrictUndefined 17 | 18 | HAS_JINJA2 = True 19 | except ImportError: 20 | HAS_JINJA2 = False 21 | 22 | 23 | class Templar: 24 | """Class representing a Jinja2 template engine.""" 25 | 26 | def __init__(self) -> None: 27 | """Instantiate the template engine. 28 | 29 | Raises: 30 | ImportError: when jinja2 is not installed. 31 | """ 32 | if not HAS_JINJA2: 33 | msg = ( 34 | "jinja2 is required but does not appear to be installed." 35 | "It can be installed using `pip install jinja2`" 36 | ) 37 | raise ImportError( 38 | msg, 39 | ) 40 | self.env: Environment = Environment( # noqa: S701 41 | undefined=StrictUndefined, 42 | keep_trailing_newline=True, 43 | ) 44 | self.env.filters["json"] = json.dumps 45 | 46 | def render_from_content(self, template: str, data: TemplateData) -> str: 47 | """Render a template with provided data. 48 | 49 | Args: 50 | template: The template to load and render. 51 | data: Data to render template with. 52 | 53 | Returns: 54 | Templated content. 55 | """ 56 | return self.env.from_string(template).render(asdict(data)) 57 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>ansible/actions//config/renovate.json"], 4 | "packageRules": [ 5 | { 6 | "allowedVersions": "<2.17", 7 | "description": "Platform compatibility constraint", 8 | "matchPackageNames": ["ansible-core"] 9 | }, 10 | { 11 | "allowedVersions": "<1.16", 12 | "description": "Platform compatibility constraint", 13 | "matchPackageNames": ["cffi"] 14 | }, 15 | { 16 | "allowedVersions": "<4.3", 17 | "description": "Platform compatibility constraint", 18 | "matchPackageNames": ["django"] 19 | }, 20 | { 21 | "allowedVersions": "<6.1", 22 | "description": "Platform compatibility constraint", 23 | "matchPackageNames": ["importlib-metadata"] 24 | }, 25 | { 26 | "allowedVersions": "<4.22", 27 | "description": "Platform compatibility constraint", 28 | "matchPackageNames": ["jsonschema"] 29 | }, 30 | { 31 | "allowedVersions": "<25.0", 32 | "description": "Platform compatibility constraint", 33 | "matchPackageNames": ["packaging"] 34 | }, 35 | { 36 | "allowedVersions": "<6.0.2", 37 | "description": "Platform compatibility constraint", 38 | "matchPackageNames": ["pyyaml"] 39 | }, 40 | { 41 | "allowedVersions": "<0.5.3", 42 | "description": "Platform compatibility constraint", 43 | "matchPackageNames": ["python-gnupg"] 44 | }, 45 | { 46 | "allowedVersions": "<65.6", 47 | "description": "Platform compatibility constraint", 48 | "matchPackageNames": ["setuptools"] 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /tests/integration/test_no_input.py: -------------------------------------------------------------------------------- 1 | """Test running ansible-creator commands without input or --help.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | import pytest 8 | 9 | from tests.defaults import CREATOR_BIN 10 | 11 | 12 | if TYPE_CHECKING: 13 | from tests.conftest import CliRunCallable 14 | 15 | 16 | @pytest.mark.parametrize( 17 | argnames=("args", "error_msg"), 18 | argvalues=( 19 | pytest.param("add", "Missing required argument 'content-type'.", id="add"), 20 | pytest.param("add --help", "", id="add-help"), 21 | pytest.param( 22 | "add resource", "Missing required argument 'resource-type'.", id="add-resource" 23 | ), 24 | pytest.param("add resource --help", "", id="add-resource-help"), 25 | pytest.param("add plugin", "Missing required argument 'plugin-type'.", id="add-plugin"), 26 | pytest.param("add plugin --help", "", id="add-plugin-help"), 27 | pytest.param("init", "Missing required argument 'project-type'.", id="init"), 28 | pytest.param("init --help", "", id="init-help"), 29 | ), 30 | ) 31 | def test_run_no_input(cli: CliRunCallable, args: str, error_msg: str) -> None: 32 | """Test running ansible-creator commands without input or --help. 33 | 34 | Args: 35 | cli: cli_run function. 36 | args: args to pass to the CLI. 37 | error_msg: Expected error message. 38 | """ 39 | result = cli(f"{CREATOR_BIN} {args}", env={"NO_COLOR": "1"}) 40 | if not error_msg: 41 | assert result.returncode == 0 42 | else: 43 | assert result.returncode != 0 44 | assert error_msg in result.stderr 45 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This collection is initialized by https://github.com/ansible/ansible-creator 0.0.1 3 | 4 | # See https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html 5 | 6 | namespace: "testorg" 7 | name: "testcol" 8 | version: 1.0.0 9 | readme: README.md 10 | authors: 11 | - your name 12 | 13 | description: your collection description 14 | license_file: LICENSE 15 | 16 | # TO-DO: update the tags based on your content type 17 | tags: ["linux", "tools"] 18 | # TO-DO: maintain this list to reflect the collection's dependencies 19 | dependencies: 20 | "ansible.utils": "*" # note: "*" selects the latest version available 21 | 22 | repository: http://example.com/repository 23 | documentation: http://docs.example.com 24 | homepage: http://example.com 25 | issues: http://example.com/issue/tracker 26 | 27 | # A list of file glob-like patterns used to filter any files or directories that should not be included in the build 28 | # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This 29 | # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', 30 | # and '.git' are always filtered. Mutually exclusive with 'manifest' 31 | build_ignore: 32 | - .gitignore 33 | - changelogs/.plugin-cache.yaml 34 | # A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a 35 | # list of MANIFEST.in style 36 | # L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key 37 | # 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive 38 | # with 'build_ignore' 39 | # manifest: null 40 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CI" 3 | 4 | concurrency: 5 | group: ${{ github.head_ref || github.run_id }} 6 | cancel-in-progress: true 7 | 8 | on: # yamllint disable-line rule:truthy 9 | pull_request: 10 | branches: [main] 11 | workflow_dispatch: 12 | # TO-DO: Below is an example cron scheduler. Uncomment and tweak it as per your requirement 13 | # schedule: 14 | # - cron: '0 0 * * *' 15 | 16 | jobs: 17 | changelog: 18 | uses: ansible/ansible-content-actions/.github/workflows/changelog.yaml@main 19 | if: github.event_name == 'pull_request' 20 | build-import: 21 | uses: ansible/ansible-content-actions/.github/workflows/build_import.yaml@main 22 | ansible-lint: 23 | uses: ansible/ansible-content-actions/.github/workflows/ansible_lint.yaml@main 24 | sanity: 25 | uses: ansible/ansible-content-actions/.github/workflows/sanity.yaml@main 26 | unit-galaxy: 27 | uses: ansible/ansible-content-actions/.github/workflows/unit.yaml@main 28 | unit-source: 29 | uses: ansible-network/github_actions/.github/workflows/unit_source.yml@main 30 | with: 31 | collection_pre_install: >- 32 | git+https://github.com/ansible-collections/ansible.utils.git 33 | all_green: 34 | if: ${{ always() }} 35 | needs: 36 | - changelog 37 | - build-import 38 | - sanity 39 | - unit-galaxy 40 | - unit-source 41 | - ansible-lint 42 | runs-on: ubuntu-latest 43 | steps: 44 | - run: >- 45 | python -c "assert 'failure' not in 46 | set([ 47 | '${{ needs.changelog.result }}', 48 | '${{ needs.sanity.result }}', 49 | '${{ needs.unit-galaxy.result }}' 50 | '${{ needs.ansible-lint.result }}' 51 | '${{ needs.unit-source.result }}' 52 | ])" 53 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/galaxy.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # This collection is initialized by https://github.com/ansible/ansible-creator {{ creator_version }} 3 | 4 | # See https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html 5 | 6 | namespace: "{{ namespace }}" 7 | name: "{{ collection_name }}" 8 | version: 1.0.0 9 | readme: README.md 10 | authors: 11 | - your name 12 | 13 | description: your collection description 14 | license_file: LICENSE 15 | 16 | # TO-DO: update the tags based on your content type 17 | tags: ["linux", "tools"] 18 | # TO-DO: maintain this list to reflect the collection's dependencies 19 | dependencies: 20 | "ansible.utils": "*" # note: "*" selects the latest version available 21 | 22 | repository: http://example.com/repository 23 | documentation: http://docs.example.com 24 | homepage: http://example.com 25 | issues: http://example.com/issue/tracker 26 | 27 | # A list of file glob-like patterns used to filter any files or directories that should not be included in the build 28 | # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This 29 | # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', 30 | # and '.git' are always filtered. Mutually exclusive with 'manifest' 31 | build_ignore: 32 | - .gitignore 33 | - changelogs/.plugin-cache.yaml 34 | # A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a 35 | # list of MANIFEST.in style 36 | # L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key 37 | # 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive 38 | # with 'build_ignore' 39 | # manifest: null 40 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/test/sample_test.py.j2: -------------------------------------------------------------------------------- 1 | {# test_plugin_template.j2 #} 2 | {%- set test_name = plugin_name | default("sample_test",true) -%} 3 | {%- set author = author | default("Your Name") -%} 4 | {%- set description = description | default("A custom test plugin for Ansible.") -%} 5 | {%- set license = license | default("GPL-3.0-or-later") -%} 6 | # {{ test_name }}.py - {{ description }} 7 | # Author: {{ author }} 8 | # License: {{ license }} 9 | 10 | from __future__ import absolute_import, annotations, division, print_function 11 | 12 | 13 | __metaclass__ = type # pylint: disable=C0103 14 | 15 | from typing import TYPE_CHECKING 16 | 17 | 18 | if TYPE_CHECKING: 19 | from typing import Callable 20 | 21 | 22 | DOCUMENTATION = """ 23 | name: {{ test_name }} 24 | author: {{ author }} 25 | version_added: "1.0.0" 26 | short_description: {{ description }} 27 | description: 28 | - This is a demo test plugin designed to return a bool. 29 | options: 30 | name: 31 | type: bool 32 | description: This is a sample option. 33 | """ 34 | 35 | EXAMPLES = """ 36 | # {{ test_name }} test example 37 | {% raw %} 38 | - name: Display a bool 39 | ansible.builtin.debug: 40 | msg: "{{ 50 {%- endraw %} | {{ test_name }} }}" 41 | """ 42 | 43 | 44 | def _sample_test(val: int) -> bool: 45 | """Returns a bool. 46 | 47 | Args: 48 | val: The value to test. 49 | 50 | Returns: 51 | bool: The result. 52 | """ 53 | return val > 42 54 | 55 | 56 | class TestModule: 57 | """test plugin.""" 58 | 59 | def tests(self) -> dict[str, Callable[[int], bool]]: 60 | """Map test plugin names to their functions. 61 | 62 | Returns: 63 | dict: The test plugin functions. 64 | """ 65 | return {"{{ test_name }}": _sample_test} 66 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: foo 4 | description: testorg.testcol run Role 5 | company: testorg 6 | 7 | # If the issue tracker for your role is not on github, uncomment the 8 | # next line and provide a value 9 | # issue_tracker_url: http://example.com/issue/tracker 10 | 11 | # Choose a valid license ID from https://spdx.org - some suggested licenses: 12 | # - BSD-3-Clause (default) 13 | # - MIT 14 | # - GPL-2.0-or-later 15 | # - GPL-3.0-only 16 | # - Apache-2.0 17 | # - CC-BY-4.0 18 | license: GPL-2.0-or-later 19 | 20 | min_ansible_version: "2.14" 21 | 22 | # If this a Container Enabled role, provide the minimum Ansible Container version. 23 | # min_ansible_container_version: 24 | 25 | # 26 | # Provide a list of supported platforms, and for each platform a list of versions. 27 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 28 | # To view available platforms and versions (or releases), visit: 29 | # https://galaxy.ansible.com/api/v1/platforms/ 30 | # 31 | # platforms: 32 | # - name: Fedora 33 | # versions: 34 | # - all 35 | # - 25 36 | # - name: SomePlatform 37 | # versions: 38 | # - all 39 | # - 1.0 40 | # - 7 41 | # - 99.99 42 | 43 | galaxy_tags: [] 44 | # List tags for your role here, one per line. A tag is a keyword that describes 45 | # and categorizes the role. Users find roles by searching for tags. Be sure to 46 | # remove the '[]' above, if you add tags to this list. 47 | # 48 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters. 49 | # Maximum 20 tags per role. 50 | 51 | dependencies: [] 52 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 53 | # if you add dependencies to this list. 54 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/.github/workflows/tests.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CI" 3 | {% raw %} 4 | concurrency: 5 | group: ${{ github.head_ref || github.run_id }} 6 | cancel-in-progress: true 7 | 8 | on: # yamllint disable-line rule:truthy 9 | pull_request: 10 | branches: [main] 11 | workflow_dispatch: 12 | # TO-DO: Below is an example cron scheduler. Uncomment and tweak it as per your requirement 13 | # schedule: 14 | # - cron: '0 0 * * *' 15 | 16 | jobs: 17 | changelog: 18 | uses: ansible/ansible-content-actions/.github/workflows/changelog.yaml@main 19 | if: github.event_name == 'pull_request' 20 | build-import: 21 | uses: ansible/ansible-content-actions/.github/workflows/build_import.yaml@main 22 | ansible-lint: 23 | uses: ansible/ansible-content-actions/.github/workflows/ansible_lint.yaml@main 24 | sanity: 25 | uses: ansible/ansible-content-actions/.github/workflows/sanity.yaml@main 26 | unit-galaxy: 27 | uses: ansible/ansible-content-actions/.github/workflows/unit.yaml@main 28 | unit-source: 29 | uses: ansible-network/github_actions/.github/workflows/unit_source.yml@main 30 | with: 31 | collection_pre_install: >- 32 | git+https://github.com/ansible-collections/ansible.utils.git 33 | all_green: 34 | if: ${{ always() }} 35 | needs: 36 | - changelog 37 | - build-import 38 | - sanity 39 | - unit-galaxy 40 | - unit-source 41 | - ansible-lint 42 | runs-on: ubuntu-latest 43 | steps: 44 | - run: >- 45 | python -c "assert 'failure' not in 46 | set([ 47 | '${{ needs.changelog.result }}', 48 | '${{ needs.sanity.result }}', 49 | '${{ needs.unit-galaxy.result }}' 50 | '${{ needs.ansible-lint.result }}' 51 | '${{ needs.unit-source.result }}' 52 | ])" 53 | {%- endraw %} 54 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/meta/main.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: foo 4 | description: {{ namespace }}.{{ collection_name }} {{ role_name }} Role 5 | company: {{ namespace }} 6 | 7 | # If the issue tracker for your role is not on github, uncomment the 8 | # next line and provide a value 9 | # issue_tracker_url: http://example.com/issue/tracker 10 | 11 | # Choose a valid license ID from https://spdx.org - some suggested licenses: 12 | # - BSD-3-Clause (default) 13 | # - MIT 14 | # - GPL-2.0-or-later 15 | # - GPL-3.0-only 16 | # - Apache-2.0 17 | # - CC-BY-4.0 18 | license: GPL-2.0-or-later 19 | 20 | min_ansible_version: "2.14" 21 | 22 | # If this a Container Enabled role, provide the minimum Ansible Container version. 23 | # min_ansible_container_version: 24 | 25 | # 26 | # Provide a list of supported platforms, and for each platform a list of versions. 27 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 28 | # To view available platforms and versions (or releases), visit: 29 | # https://galaxy.ansible.com/api/v1/platforms/ 30 | # 31 | # platforms: 32 | # - name: Fedora 33 | # versions: 34 | # - all 35 | # - 25 36 | # - name: SomePlatform 37 | # versions: 38 | # - all 39 | # - 1.0 40 | # - 7 41 | # - 99.99 42 | 43 | galaxy_tags: [] 44 | # List tags for your role here, one per line. A tag is a keyword that describes 45 | # and categorizes the role. Users find roles by searching for tags. Be sure to 46 | # remove the '[]' above, if you add tags to this list. 47 | # 48 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters. 49 | # Maximum 20 tags per role. 50 | 51 | dependencies: [] 52 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 53 | # if you add dependencies to this list. 54 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/argspec_validation_plays.yml: -------------------------------------------------------------------------------- 1 | # Example playbook using play argspec validation 2 | # Run with: 3 | # ansible-playbook argspec_validation_plays.yml -e message=hello -i inventory/argspec_validation_inventory.yml 4 | --- 5 | - name: Debug_localhost 6 | hosts: localhost 7 | gather_facts: false 8 | tasks: 9 | - name: Verify with argspec 10 | ansible.builtin.validate_argument_spec: 11 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 12 | vars: 13 | lowercase_play_name: "{{ ansible_play_name | lower }}" 14 | filename: "argspec_validation_plays.meta.yml" 15 | - name: Print debug message 16 | ansible.builtin.debug: 17 | msg: "{{ message }}" 18 | 19 | - name: Ping_localhost 20 | hosts: localhost 21 | gather_facts: false 22 | tasks: 23 | - name: Verify with argspec 24 | ansible.builtin.validate_argument_spec: 25 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 26 | vars: 27 | lowercase_play_name: "{{ ansible_play_name | lower }}" 28 | filename: "argspec_validation_plays.meta.yml" 29 | - name: Print debug message 30 | ansible.builtin.ping: 31 | data: "{{ ping_data }}" 32 | 33 | - name: Set_stats 34 | hosts: localhost 35 | gather_facts: false 36 | tasks: 37 | - name: Verify with argspec 38 | ansible.builtin.validate_argument_spec: 39 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 40 | vars: 41 | lowercase_play_name: "{{ ansible_play_name | lower }}" 42 | filename: "argspec_validation_plays.meta.yml" 43 | - name: Set custom stats 44 | ansible.builtin.set_stats: 45 | data: "{{ stat }}" 46 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/play-argspec/argspec_validation_plays.yml: -------------------------------------------------------------------------------- 1 | # Example playbook using play argspec validation 2 | # Run with: 3 | # ansible-playbook argspec_validation_plays.yml -e message=hello -i inventory/argspec_validation_inventory.yml 4 | --- 5 | - name: Debug_localhost 6 | hosts: localhost 7 | gather_facts: false 8 | tasks: 9 | - name: Verify with argspec 10 | ansible.builtin.validate_argument_spec: 11 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 12 | vars: 13 | lowercase_play_name: "{{ ansible_play_name | lower }}" 14 | filename: "argspec_validation_plays.meta.yml" 15 | - name: Print debug message 16 | ansible.builtin.debug: 17 | msg: "{{ message }}" 18 | 19 | - name: Ping_localhost 20 | hosts: localhost 21 | gather_facts: false 22 | tasks: 23 | - name: Verify with argspec 24 | ansible.builtin.validate_argument_spec: 25 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 26 | vars: 27 | lowercase_play_name: "{{ ansible_play_name | lower }}" 28 | filename: "argspec_validation_plays.meta.yml" 29 | - name: Print debug message 30 | ansible.builtin.ping: 31 | data: "{{ ping_data }}" 32 | 33 | - name: Set_stats 34 | hosts: localhost 35 | gather_facts: false 36 | tasks: 37 | - name: Verify with argspec 38 | ansible.builtin.validate_argument_spec: 39 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 40 | vars: 41 | lowercase_play_name: "{{ ansible_play_name | lower }}" 42 | filename: "argspec_validation_plays.meta.yml" 43 | - name: Set custom stats 44 | ansible.builtin.set_stats: 45 | data: "{{ stat }}" 46 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/argspec_validation_plays.yml: -------------------------------------------------------------------------------- 1 | # Example playbook using play argspec validation 2 | # Run with: 3 | # ansible-playbook argspec_validation_plays.yml -e message=hello -i inventory/argspec_validation_inventory.yml 4 | --- 5 | - name: Debug_localhost 6 | hosts: localhost 7 | gather_facts: false 8 | tasks: 9 | - name: Verify with argspec 10 | ansible.builtin.validate_argument_spec: 11 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 12 | vars: 13 | lowercase_play_name: "{{ ansible_play_name | lower }}" 14 | filename: "argspec_validation_plays.meta.yml" 15 | - name: Print debug message 16 | ansible.builtin.debug: 17 | msg: "{{ message }}" 18 | 19 | - name: Ping_localhost 20 | hosts: localhost 21 | gather_facts: false 22 | tasks: 23 | - name: Verify with argspec 24 | ansible.builtin.validate_argument_spec: 25 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 26 | vars: 27 | lowercase_play_name: "{{ ansible_play_name | lower }}" 28 | filename: "argspec_validation_plays.meta.yml" 29 | - name: Print debug message 30 | ansible.builtin.ping: 31 | data: "{{ ping_data }}" 32 | 33 | - name: Set_stats 34 | hosts: localhost 35 | gather_facts: false 36 | tasks: 37 | - name: Verify with argspec 38 | ansible.builtin.validate_argument_spec: 39 | argument_spec: "{{ (lookup('ansible.builtin.file', filename) | from_yaml)['argument_specs'][lowercase_play_name]['options'] }}" 40 | vars: 41 | lowercase_play_name: "{{ ansible_play_name | lower }}" 42 | filename: "argspec_validation_plays.meta.yml" 43 | - name: Set custom stats 44 | ansible.builtin.set_stats: 45 | data: "{{ stat }}" 46 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/filter/sample_filter.py.j2: -------------------------------------------------------------------------------- 1 | {# filter_plugin_template.j2 #} 2 | {%- set filter_name = plugin_name | default("sample_filter",true) -%} 3 | {%- set author = author | default("Your Name") -%} 4 | {%- set description = description | default("A custom filter plugin for Ansible.") -%} 5 | {%- set license = license | default("GPL-3.0-or-later") -%} 6 | # {{ filter_name }}.py - {{ description }} 7 | # Author: {{ author }} 8 | # License: {{ license }} 9 | 10 | from __future__ import absolute_import, annotations, division, print_function 11 | 12 | 13 | __metaclass__ = type # pylint: disable=C0103 14 | 15 | from typing import TYPE_CHECKING 16 | 17 | 18 | if TYPE_CHECKING: 19 | from typing import Callable 20 | 21 | 22 | DOCUMENTATION = """ 23 | name: {{ filter_name }} 24 | author: {{ author }} 25 | version_added: "1.0.0" 26 | short_description: {{ description }} 27 | description: 28 | - This is a demo filter plugin designed to return Hello message. 29 | options: 30 | name: 31 | description: Value specified here is appended to the Hello message. 32 | type: str 33 | """ 34 | 35 | EXAMPLES = """ 36 | # {{ filter_name }} filter example 37 | {% raw %} 38 | - name: Display a hello message 39 | ansible.builtin.debug: 40 | msg: "{{ 'ansible-creator' {%- endraw %} | {{ filter_name }} }}" 41 | """ 42 | 43 | 44 | def _sample_filter(name: str) -> str: 45 | """Returns Hello message. 46 | 47 | Args: 48 | name: The name to greet. 49 | 50 | Returns: 51 | str: The greeting message. 52 | """ 53 | return "Hello, " + name 54 | 55 | 56 | class FilterModule: 57 | """filter plugin.""" 58 | 59 | def filters(self) -> dict[str, Callable[[str], str]]: 60 | """Map filter plugin names to their functions. 61 | 62 | Returns: 63 | dict: The filter plugin functions. 64 | """ 65 | return {"{{ filter_name }}": _sample_filter} 66 | -------------------------------------------------------------------------------- /src/ansible_creator/types.py: -------------------------------------------------------------------------------- 1 | """A home for shared types.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | from typing import TYPE_CHECKING 7 | 8 | from ansible_creator.constants import GLOBAL_TEMPLATE_VARS 9 | 10 | 11 | if TYPE_CHECKING: 12 | from collections.abc import Sequence 13 | 14 | 15 | @dataclass 16 | class TemplateData: 17 | """Dataclass representing the template data. 18 | 19 | Attributes: 20 | resource_type: The type of resource to be scaffolded. 21 | plugin_type: The type of plugin to be scaffolded. 22 | plugin_name: The name of the plugin to be scaffolded. 23 | role_name: The name of the role to be scaffolded. 24 | additions: A dictionary containing additional data to add to the gitignore. 25 | collection_name: The name of the collection. 26 | creator_version: The version of the creator. 27 | dev_container_image: The devcontainer image. 28 | dev_file_image: The devfile image. 29 | dev_file_name: The unique name entry in devfile. 30 | namespace: The namespace of the collection. 31 | execution_environment_image: The execution environment image. 32 | recommended_extensions: A list of recommended VsCode extensions. 33 | """ 34 | 35 | resource_type: str = "" 36 | plugin_type: str = "" 37 | plugin_name: str = "" 38 | role_name: str = "" 39 | additions: dict[str, dict[str, dict[str, str | bool]]] = field(default_factory=dict) 40 | collection_name: str = "" 41 | creator_version: str = "" 42 | dev_container_image: Sequence[str] = GLOBAL_TEMPLATE_VARS["DEV_CONTAINER_IMAGE"] 43 | dev_file_image: Sequence[str] = GLOBAL_TEMPLATE_VARS["DEV_FILE_IMAGE"] 44 | dev_file_name: str = "" 45 | namespace: str = "" 46 | execution_environment_image: Sequence[str] = GLOBAL_TEMPLATE_VARS[ 47 | "EXECUTION_ENVIRONMENT_DEFAULT_IMAGE" 48 | ] 49 | recommended_extensions: Sequence[str] = field( 50 | default_factory=lambda: GLOBAL_TEMPLATE_VARS["RECOMMENDED_EXTENSIONS"], 51 | ) 52 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/docs/docsite/links.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This will make sure that plugin and module documentation gets Edit on GitHub links 3 | # that allow users to directly create a PR for this plugin or module in GitHub's UI. 4 | # Remove this section if the collection repository is not on GitHub, or if you do not 5 | # want this functionality for your collection. 6 | edit_on_github: 7 | # TO-DO: Update this if your collection lives in a different GitHub organization. 8 | repository: ansible-collections/testorg.testcol 9 | branch: main 10 | # If your collection root (the directory containing galaxy.yml) does not coincide with your 11 | # repository's root, you have to specify the path to the collection root here. For example, 12 | # if the collection root is in a subdirectory ansible_collections/community/REPO_NAME 13 | # in your repository, you have to set path_prefix to 'ansible_collections/community/REPO_NAME'. 14 | path_prefix: "" 15 | 16 | # Here you can add arbitrary extra links. Please keep the number of links down to a 17 | # minimum! Also please keep the description short, since this will be the text put on 18 | # a button. 19 | # 20 | # Also note that some links are automatically added from information in galaxy.yml. 21 | # The following are automatically added: 22 | # 1. A link to the issue tracker (if `issues` is specified); 23 | # 2. A link to the homepage (if `homepage` is specified and does not equal the 24 | # `documentation` or `repository` link); 25 | # 3. A link to the collection's repository (if `repository` is specified). 26 | 27 | extra_links: 28 | - description: Report an issue 29 | # TO-DO: Update this if your collection lives in a different GitHub organization. 30 | url: https://github.com/ansible-collections/testorg.testcol/issues/new/choose 31 | 32 | # Specify communication channels for your collection. We suggest to not specify more 33 | # than one place for communication per communication tool to avoid confusion. 34 | communication: 35 | forum: 36 | - topic: Ansible Forum 37 | url: https://forum.ansible.com/ 38 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/roles/run/README.md: -------------------------------------------------------------------------------- 1 | Weather.Demo Run Role 2 | ======================== 3 | 4 | A brief description of the role is here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any prerequisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. host vars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | ```yaml 27 | - name: Execute tasks on servers 28 | hosts: servers 29 | roles: 30 | - role: weather.demo.run 31 | run_x: 42 32 | ``` 33 | 34 | Another way to consume this role would be: 35 | 36 | ```yaml 37 | - name: Initialize the run role from weather.demo 38 | hosts: servers 39 | gather_facts: false 40 | tasks: 41 | - name: Trigger invocation of run role 42 | ansible.builtin.include_role: 43 | name: weather.demo.run 44 | vars: 45 | run_x: 42 46 | ``` 47 | 48 | License 49 | ------- 50 | 51 | 52 | BSD 53 | 54 | Author Information 55 | ------------------ 56 | 57 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 58 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/docs/docsite/links.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # This will make sure that plugin and module documentation gets Edit on GitHub links 3 | # that allow users to directly create a PR for this plugin or module in GitHub's UI. 4 | # Remove this section if the collection repository is not on GitHub, or if you do not 5 | # want this functionality for your collection. 6 | edit_on_github: 7 | # TO-DO: Update this if your collection lives in a different GitHub organization. 8 | repository: ansible-collections/{{ namespace }}.{{ collection_name }} 9 | branch: main 10 | # If your collection root (the directory containing galaxy.yml) does not coincide with your 11 | # repository's root, you have to specify the path to the collection root here. For example, 12 | # if the collection root is in a subdirectory ansible_collections/community/REPO_NAME 13 | # in your repository, you have to set path_prefix to 'ansible_collections/community/REPO_NAME'. 14 | path_prefix: "" 15 | 16 | # Here you can add arbitrary extra links. Please keep the number of links down to a 17 | # minimum! Also please keep the description short, since this will be the text put on 18 | # a button. 19 | # 20 | # Also note that some links are automatically added from information in galaxy.yml. 21 | # The following are automatically added: 22 | # 1. A link to the issue tracker (if `issues` is specified); 23 | # 2. A link to the homepage (if `homepage` is specified and does not equal the 24 | # `documentation` or `repository` link); 25 | # 3. A link to the collection's repository (if `repository` is specified). 26 | 27 | extra_links: 28 | - description: Report an issue 29 | # TO-DO: Update this if your collection lives in a different GitHub organization. 30 | url: https://github.com/ansible-collections/{{ namespace }}.{{ collection_name }}/issues/new/choose 31 | 32 | # Specify communication channels for your collection. We suggest to not specify more 33 | # than one place for communication per communication tool to avoid confusion. 34 | communication: 35 | forum: 36 | - topic: Ansible Forum 37 | url: https://forum.ansible.com/ 38 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/argspec_validation_plays.meta.yml: -------------------------------------------------------------------------------- 1 | # Example play argspec file 2 | --- 3 | short_description: A shorter summary of `description` below 4 | description: This is a description of a playbook, that may contain multiple plays with multiple play argument specs 5 | argument_specs: 6 | debug_localhost: 7 | short_description: Play for printing a debug message 8 | description: 9 | - Example play within a collection containing an argspec for printing a debug message 10 | author: 11 | - developer (@developer) 12 | options: 13 | message: 14 | description: Debug message to print 15 | type: str 16 | required: true 17 | examples: | 18 | - import_playbook: argspec_validation_plays.yml 19 | vars: 20 | message: 'Custom debug message' 21 | return: 22 | ping_localhost: 23 | short_description: Play for pinging localhost with custom data 24 | description: 25 | - Example play within a collection containing an argspec for pinging localhost with custom data 26 | author: 27 | - developer (@developer) 28 | options: 29 | ping_data: 30 | description: Ping data 31 | type: str 32 | required: true 33 | examples: | 34 | - import_playbook: argspec_validation_plays.yml 35 | vars: 36 | data: Pong 37 | return: 38 | set_stats: 39 | short_description: Play for setting a custom stat 40 | description: 41 | - Example play within a collection containing an argspec for setting a custom stat 42 | author: 43 | - developer (@developer) 44 | options: 45 | stat: 46 | description: Stat data 47 | type: raw 48 | required: true 49 | notes: 50 | - This play has some notes 51 | - They specify additional information 52 | examples: | 53 | - import_playbook: argspec_validation_plays.yml 54 | vars: 55 | stat: This is some custom stat 56 | return: 57 | stat: 58 | description: Custom stat data 59 | returned: always 60 | type: raw 61 | sample: Hello, World! 62 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/argspec_validation_plays.meta.yml: -------------------------------------------------------------------------------- 1 | # Example play argspec file 2 | --- 3 | short_description: A shorter summary of `description` below 4 | description: This is a description of a playbook, that may contain multiple plays with multiple play argument specs 5 | argument_specs: 6 | debug_localhost: 7 | short_description: Play for printing a debug message 8 | description: 9 | - Example play within a collection containing an argspec for printing a debug message 10 | author: 11 | - developer (@developer) 12 | options: 13 | message: 14 | description: Debug message to print 15 | type: str 16 | required: true 17 | examples: | 18 | - import_playbook: argspec_validation_plays.yml 19 | vars: 20 | message: 'Custom debug message' 21 | return: 22 | ping_localhost: 23 | short_description: Play for pinging localhost with custom data 24 | description: 25 | - Example play within a collection containing an argspec for pinging localhost with custom data 26 | author: 27 | - developer (@developer) 28 | options: 29 | ping_data: 30 | description: Ping data 31 | type: str 32 | required: true 33 | examples: | 34 | - import_playbook: argspec_validation_plays.yml 35 | vars: 36 | data: Pong 37 | return: 38 | set_stats: 39 | short_description: Play for setting a custom stat 40 | description: 41 | - Example play within a collection containing an argspec for setting a custom stat 42 | author: 43 | - developer (@developer) 44 | options: 45 | stat: 46 | description: Stat data 47 | type: raw 48 | required: true 49 | notes: 50 | - This play has some notes 51 | - They specify additional information 52 | examples: | 53 | - import_playbook: argspec_validation_plays.yml 54 | vars: 55 | stat: This is some custom stat 56 | return: 57 | stat: 58 | description: Custom stat data 59 | returned: always 60 | type: raw 61 | sample: Hello, World! 62 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/play-argspec/argspec_validation_plays.meta.yml: -------------------------------------------------------------------------------- 1 | # Example play argspec file 2 | --- 3 | short_description: A shorter summary of `description` below 4 | description: This is a description of a playbook, that may contain multiple plays with multiple play argument specs 5 | argument_specs: 6 | debug_localhost: 7 | short_description: Play for printing a debug message 8 | description: 9 | - Example play within a collection containing an argspec for printing a debug message 10 | author: 11 | - developer (@developer) 12 | options: 13 | message: 14 | description: Debug message to print 15 | type: str 16 | required: true 17 | examples: | 18 | - import_playbook: argspec_validation_plays.yml 19 | vars: 20 | message: 'Custom debug message' 21 | return: 22 | ping_localhost: 23 | short_description: Play for pinging localhost with custom data 24 | description: 25 | - Example play within a collection containing an argspec for pinging localhost with custom data 26 | author: 27 | - developer (@developer) 28 | options: 29 | ping_data: 30 | description: Ping data 31 | type: str 32 | required: true 33 | examples: | 34 | - import_playbook: argspec_validation_plays.yml 35 | vars: 36 | data: Pong 37 | return: 38 | set_stats: 39 | short_description: Play for setting a custom stat 40 | description: 41 | - Example play within a collection containing an argspec for setting a custom stat 42 | author: 43 | - developer (@developer) 44 | options: 45 | stat: 46 | description: Stat data 47 | type: raw 48 | required: true 49 | notes: 50 | - This play has some notes 51 | - They specify additional information 52 | examples: | 53 | - import_playbook: argspec_validation_plays.yml 54 | vars: 55 | stat: This is some custom stat 56 | return: 57 | stat: 58 | description: Custom stat data 59 | returned: always 60 | type: raw 61 | sample: Hello, World! 62 | -------------------------------------------------------------------------------- /cspell.config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | dictionaryDefinitions: 3 | - name: words 4 | path: .config/dictionary.txt 5 | addWords: true 6 | dictionaries: 7 | - bash 8 | - networking-terms 9 | - python 10 | - words 11 | - "!aws" 12 | - "!backwards-compatibility" 13 | - "!cryptocurrencies" 14 | - "!cpp" 15 | useGitignore: true 16 | ignorePaths: 17 | - "**/.gitignore*" 18 | - .vscode/extensions.json 19 | - .vscode/settings.json 20 | - _readthedocs 21 | - build 22 | - coverage.lcov 23 | - cspell.config.yaml 24 | - junit.xml 25 | - site 26 | # - mkdocs.yml 27 | ignoreWords: 28 | - adoc 29 | - CAP_MKNOD 30 | - CMDB 31 | - equalto 32 | - lineinfile 33 | - SSOT 34 | - SSOTs 35 | - autorefs 36 | - commitlint 37 | - dists 38 | - docstrings 39 | - envrc 40 | - facelessuser 41 | - fontawesome 42 | - htmlproofer 43 | - inlinehilite 44 | - junitxml 45 | - linenums 46 | - loglevel 47 | - magiclink 48 | - pkgs 49 | - posargs 50 | - pymdownx 51 | - pypa 52 | - seccomp 53 | - sonarlint 54 | - superfences 55 | - triggertaskonsave 56 | - userns 57 | suggestWords: 58 | - alwayscopy->always_copy 59 | - basepython->base_python 60 | - changedir->change_dir 61 | - env_log_dir->env_log_dir 62 | - envbindir->env_bin_dir 63 | - envdir->env_dir 64 | - envlist->env_list 65 | - envname->env_name 66 | - envpython->env_python 67 | - envsitepackagesdir->env_site_packages_dir 68 | - envtmpdir->env_tmp_dir 69 | - ignore_basepython_conflict->ignore_base_python_conflict 70 | - isolated_build_env->package_env 71 | - min_version->deprecated-use-requires 72 | - minversion ->deprecated-use-requires 73 | - passenv->pass_env 74 | - setenv->set_env 75 | - setupdir->package_root 76 | - sitepackages->system_site_packages 77 | - skipsdist->no_package 78 | - toxinidir->tox_root 79 | - "toxworkdir->work_dir" 80 | - usedevelop->use_develop 81 | languageSettings: 82 | - languageId: python 83 | allowCompoundWords: false 84 | - languageId: toml 85 | allowCompoundWords: false 86 | ignoreWords: 87 | - showlocals 88 | - xunit 89 | - norecursedirs 90 | - tomlsort 91 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/roles/run/README.md.j2: -------------------------------------------------------------------------------- 1 | {{ namespace|capitalize }}.{{ collection_name|capitalize }} Run Role 2 | ======================== 3 | 4 | A brief description of the role is here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any prerequisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. host vars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | ```yaml 27 | - name: Execute tasks on servers 28 | hosts: servers 29 | roles: 30 | - role: {{ namespace }}.{{ collection_name }}.run 31 | run_x: 42 32 | ``` 33 | 34 | Another way to consume this role would be: 35 | 36 | ```yaml 37 | - name: Initialize the run role from {{ namespace }}.{{ collection_name }} 38 | hosts: servers 39 | gather_facts: false 40 | tasks: 41 | - name: Trigger invocation of run role 42 | ansible.builtin.include_role: 43 | name: {{ namespace }}.{{ collection_name }}.run 44 | vars: 45 | run_x: 42 46 | ``` 47 | 48 | License 49 | ------- 50 | 51 | 52 | BSD 53 | 54 | Author Information 55 | ------------------ 56 | 57 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 58 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/modules/sample_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # pylint: disable=E0401 3 | # sample_module.py - A custom module plugin for Ansible. 4 | # Author: Your Name (@username) 5 | # License: GPL-3.0-or-later 6 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 7 | 8 | from __future__ import absolute_import, annotations, division, print_function 9 | 10 | 11 | DOCUMENTATION = """ 12 | module: sample_module 13 | author: Your Name (@username) 14 | version_added: "1.0.0" 15 | short_description: A custom module plugin for Ansible. 16 | description: 17 | - This is a demo module plugin designed to return Hello message. 18 | options: 19 | name: 20 | description: Value specified here is appended to the Hello message. 21 | type: str 22 | required: true 23 | """ 24 | 25 | EXAMPLES = """ 26 | - name: Run the module 27 | register: result 28 | sample_module: 29 | name: "ansible-creator" 30 | 31 | - name: Display the message 32 | ansible.builtin.debug: 33 | msg: result.message 34 | """ 35 | 36 | RETURN = """ 37 | message: 38 | description: 39 | - A demo message. 40 | type: str 41 | returned: always 42 | sample: "Hello, ansible-creator" 43 | """ 44 | 45 | 46 | __metaclass__ = type # pylint: disable=C0103 47 | 48 | from typing import TYPE_CHECKING 49 | 50 | from ansible.module_utils.basic import AnsibleModule # type: ignore 51 | 52 | 53 | if TYPE_CHECKING: 54 | from typing import Callable 55 | 56 | 57 | def _sample_module(name: str) -> str: 58 | """Returns Hello message. 59 | 60 | Args: 61 | name: The name to greet. 62 | 63 | Returns: 64 | str: The greeting message. 65 | """ 66 | return "Hello, " + name 67 | 68 | 69 | def main() -> None: 70 | """Entry point for module execution""" 71 | argument_spec = dict( 72 | name=dict(type="str", required=True), 73 | ) 74 | module = AnsibleModule( 75 | argument_spec=argument_spec, 76 | ) 77 | 78 | message = _sample_module(module.params["name"]) 79 | 80 | result = { 81 | "changed": False, 82 | "message": message, 83 | } 84 | module.exit_json(**result) 85 | 86 | 87 | if __name__ == "__main__": 88 | main() 89 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/modules/sample_module.py.j2: -------------------------------------------------------------------------------- 1 | {# module_plugin_template.j2 #} 2 | {%- set module_name = plugin_name | default("sample_module",true) -%} 3 | {%- set author = author | default("Your Name (@username)") -%} 4 | {%- set description = description | default("A custom module plugin for Ansible.") -%} 5 | {%- set license = license | default("GPL-3.0-or-later") -%} 6 | #!/usr/bin/python 7 | # pylint: disable=E0401 8 | # {{ module_name }}.py - {{ description }} 9 | # Author: {{ author }} 10 | # License: {{ license }} 11 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 12 | 13 | from __future__ import absolute_import, annotations, division, print_function 14 | 15 | 16 | DOCUMENTATION = """ 17 | module: {{ module_name }} 18 | author: {{ author }} 19 | version_added: "1.0.0" 20 | short_description: {{ description }} 21 | description: 22 | - This is a demo module plugin designed to return Hello message. 23 | options: 24 | name: 25 | description: Value specified here is appended to the Hello message. 26 | type: str 27 | required: true 28 | """ 29 | 30 | EXAMPLES = """ 31 | - name: Run the module 32 | register: result 33 | {{ module_name }}: 34 | name: "ansible-creator" 35 | 36 | - name: Display the message 37 | ansible.builtin.debug: 38 | msg: result.message 39 | """ 40 | 41 | RETURN = """ 42 | message: 43 | description: 44 | - A demo message. 45 | type: str 46 | returned: always 47 | sample: "Hello, ansible-creator" 48 | """ 49 | 50 | 51 | __metaclass__ = type # pylint: disable=C0103 52 | 53 | from typing import TYPE_CHECKING 54 | 55 | from ansible.module_utils.basic import AnsibleModule # type: ignore 56 | 57 | 58 | if TYPE_CHECKING: 59 | from typing import Callable 60 | 61 | 62 | def _sample_module(name: str) -> str: 63 | """Returns Hello message. 64 | 65 | Args: 66 | name: The name to greet. 67 | 68 | Returns: 69 | str: The greeting message. 70 | """ 71 | return "Hello, " + name 72 | 73 | 74 | def main() -> None: 75 | """Entry point for module execution""" 76 | argument_spec = dict( 77 | name=dict(type="str", required=True), 78 | ) 79 | module = AnsibleModule( 80 | argument_spec=argument_spec, 81 | ) 82 | 83 | message = _sample_module(module.params["name"]) 84 | 85 | result = { 86 | "changed": False, 87 | "message": message, 88 | } 89 | module.exit_json(**result) 90 | 91 | 92 | if __name__ == "__main__": 93 | main() 94 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to ansible-creator 2 | 3 | To actively contribute to the development and enhancement of ansible-creator, 4 | your participation is valued. Please use pull requests on a branch of your own 5 | fork. After 6 | [creating your fork on GitHub](https://docs.github.com/en/get-started/quickstart/contributing-to-projects), 7 | you can do: 8 | 9 | ```console 10 | $ git clone --recursive git@github.com:your-name/ansible-creator 11 | $ cd ansible-creator 12 | $ git checkout -b your-branch-name 13 | 14 | # DO SOME CODING HERE 15 | 16 | $ git add your new files 17 | $ git commit -v 18 | $ git push origin your-branch-name 19 | ``` 20 | 21 | You will then be able to create a pull request from your commit. This will 22 | initiate the process of reviewing and merging your contributions. 23 | 24 | For contributions affecting core functionality (i.e., anything except docs or 25 | examples), ensure to include corresponding tests that validate the changes. Even 26 | if you're not providing a code fix, your input is valuable—feel free to raise 27 | [issues](https://github.com/ansible/ansible-creator/issues) in the repository. 28 | 29 | ## Standards 30 | 31 | All pull requests undergo automated tests. To ensure that your changes align 32 | with project standards, run checks locally before pushing commits using 33 | [tox](https://tox.wiki/en/latest/). 34 | 35 | ## Get in touch 36 | 37 | Connect with the ansible-creator community! 38 | 39 | Join the Ansible forum to ask questions, get help, and interact with us. 40 | 41 | - [Get Help](https://forum.ansible.com/c/help/6): get help or help others. 42 | Please add appropriate tags if you start new discussions, for example the 43 | `ansible-creator` or `devtools` tags. 44 | - [Social Spaces](https://forum.ansible.com/c/chat/4): meet and interact with 45 | fellow enthusiasts. 46 | - [News & Announcements](https://forum.ansible.com/c/news/5): track project-wide 47 | announcements including social events. 48 | 49 | To get release announcements and important changes from the community, see the 50 | [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn). 51 | 52 | If you encounter security-related concerns, report them via email to 53 | [security@ansible.com](mailto:security@ansible.com). 54 | 55 | ## Code of Conduct 56 | 57 | As with all Ansible projects, adhere to the 58 | [Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) 59 | to foster a respectful and inclusive collaborative environment. Your 60 | contributions, feedback, and engagement are essential to the success of 61 | ansible-creator. 62 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/roles/run/README.md: -------------------------------------------------------------------------------- 1 | # testorg.testcol run Role 2 | 3 | A brief description of the role goes here. 4 | 5 | ## Requirements 6 | 7 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 8 | 9 | ## Role Variables 10 | 11 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 12 | 13 | ## Dependencies 14 | 15 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 16 | 17 | ## Example Playbook 18 | 19 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 20 | 21 | ```yaml 22 | - name: Execute tasks on servers 23 | hosts: servers 24 | roles: 25 | - role: testorg.testcol.run 26 | run_x: 42 27 | ``` 28 | 29 | Another way to consume this role would be: 30 | 31 | ```yaml 32 | - name: Initialize the run role from testorg.testcol 33 | hosts: servers 34 | gather_facts: false 35 | tasks: 36 | - name: Trigger invocation of run role 37 | ansible.builtin.include_role: 38 | name: testorg.testcol.run 39 | vars: 40 | run_x: 42 41 | ``` 42 | 43 | ## Role Idempotency 44 | 45 | Designation of the role as idempotent (True/False) 46 | 47 | ## Role Atomicity 48 | 49 | Designation of the role as atomic if applicable (True/False) 50 | 51 | ## Roll-back capabilities 52 | 53 | Define the roll-back capabilities of the role 54 | 55 | ## Argument Specification 56 | 57 | Including an example of how to add an argument Specification file that validates the arguments provided to the role. 58 | 59 | ```yaml 60 | argument_specs: 61 | main: 62 | short_description: Role description. 63 | options: 64 | string_arg1: 65 | description: string argument description. 66 | type: "str" 67 | default: "x" 68 | choices: ["x", "y"] 69 | ``` 70 | 71 | ## License 72 | 73 | 74 | BSD 75 | 76 | ## Author Information 77 | 78 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 79 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/common/role/roles/run/README.md.j2: -------------------------------------------------------------------------------- 1 | # {{ namespace }}.{{ collection_name }} {{ role_name }} Role 2 | 3 | A brief description of the role goes here. 4 | 5 | ## Requirements 6 | 7 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 8 | 9 | ## Role Variables 10 | 11 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 12 | 13 | ## Dependencies 14 | 15 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 16 | 17 | ## Example Playbook 18 | 19 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 20 | 21 | ```yaml 22 | - name: Execute tasks on servers 23 | hosts: servers 24 | roles: 25 | - role: {{ namespace }}.{{ collection_name }}.run 26 | run_x: 42 27 | ``` 28 | 29 | Another way to consume this role would be: 30 | 31 | ```yaml 32 | - name: Initialize the run role from {{ namespace }}.{{ collection_name }} 33 | hosts: servers 34 | gather_facts: false 35 | tasks: 36 | - name: Trigger invocation of run role 37 | ansible.builtin.include_role: 38 | name: {{ namespace }}.{{ collection_name }}.run 39 | vars: 40 | run_x: 42 41 | ``` 42 | 43 | ## Role Idempotency 44 | 45 | Designation of the role as idempotent (True/False) 46 | 47 | ## Role Atomicity 48 | 49 | Designation of the role as atomic if applicable (True/False) 50 | 51 | ## Roll-back capabilities 52 | 53 | Define the roll-back capabilities of the role 54 | 55 | ## Argument Specification 56 | 57 | Including an example of how to add an argument Specification file that validates the arguments provided to the role. 58 | 59 | ```yaml 60 | argument_specs: 61 | main: 62 | short_description: Role description. 63 | options: 64 | string_arg1: 65 | description: string argument description. 66 | type: "str" 67 | default: "x" 68 | choices: ["x", "y"] 69 | ``` 70 | 71 | ## License 72 | 73 | 74 | BSD 75 | 76 | ## Author Information 77 | 78 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 79 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/lookup/sample_lookup.py: -------------------------------------------------------------------------------- 1 | # sample_lookup.py - A custom lookup plugin for Ansible. 2 | 3 | # pylint: disable=E0401 4 | # sample_lookup.py - A custom lookup plugin for Ansible. 5 | # Author: Your Name (@username) 6 | # Copyright 2020 Red Hat 7 | # GNU General Public License v3.0+ 8 | # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 9 | 10 | DOCUMENTATION = """ 11 | name: sample_lookup 12 | author: Your Name (@username) 13 | version_added: "1.0.0" 14 | short_description: A custom lookup plugin for Ansible. 15 | description: 16 | - This is a custom lookup plugin to provide lookup functionality. 17 | options: 18 | _terms: 19 | description: Terms to lookup 20 | required: True 21 | notes: 22 | - This is a scaffold template. Customize the plugin to fit your needs. 23 | """ 24 | 25 | EXAMPLES = """ 26 | - name: Example usage of sample_lookup 27 | ansible.builtin.debug: 28 | msg: "{{ lookup('sample_lookup', 'example_term') }}" 29 | """ 30 | 31 | RETURN = """ 32 | _list: 33 | description: The list of values found by the lookup 34 | type: list 35 | """ 36 | 37 | from typing import Any, Dict, List, Optional 38 | 39 | from ansible.errors import AnsibleError # type: ignore 40 | from ansible.plugins.lookup import LookupBase # type: ignore 41 | from ansible.utils.display import Display # type: ignore 42 | 43 | display = Display() 44 | 45 | 46 | class LookupModule(LookupBase): # type: ignore[misc] 47 | """ 48 | Custom Ansible lookup plugin: sample_lookup 49 | A custom lookup plugin for Ansible. 50 | """ 51 | 52 | def run( 53 | self, 54 | terms: List[str], 55 | variables: Optional[Dict[str, Any]] = None, 56 | **kwargs: Dict[str, Any], 57 | ) -> list[str]: 58 | """ 59 | Run the lookup with the specified terms. 60 | 61 | Args: 62 | terms: A list of terms to lookup. 63 | variables: Additional variables. 64 | **kwargs: Additional keyword arguments. 65 | 66 | Returns: 67 | list: A list of processed results. 68 | 69 | Raises: 70 | AnsibleError: If the 'terms' parameter is not a list. 71 | """ 72 | if not isinstance(terms, list): 73 | raise AnsibleError("The 'terms' parameter must be a list.") 74 | 75 | display.vvv(f"Running sample_lookup lookup plugin with terms: {terms}") 76 | 77 | try: 78 | # Example processing logic - Replace this with actual lookup code 79 | result = [term.upper() for term in terms] 80 | 81 | display.vvv(f"Result from sample_lookup lookup: {result}") 82 | return result 83 | 84 | except Exception as e: 85 | raise AnsibleError(f"Error in sample_lookup plugin: {e}") from e 86 | -------------------------------------------------------------------------------- /src/ansible_creator/config.py: -------------------------------------------------------------------------------- 1 | """Application configuration class for ansible-creator.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass 6 | from typing import TYPE_CHECKING 7 | 8 | from ansible_creator.utils import expand_path 9 | 10 | 11 | if TYPE_CHECKING: 12 | from pathlib import Path 13 | 14 | from ansible_creator.output import Output 15 | 16 | 17 | @dataclass(frozen=True) 18 | class Config: 19 | """The application configuration for ansible-creator. 20 | 21 | Attributes: 22 | creator_version: The version of ansible-creator. 23 | output: The output object to use for logging. 24 | subcommand: The subcommand to execute. 25 | collection: The collection name to scaffold. 26 | force: Whether to overwrite existing files. 27 | overwrite: To overwrite files in an existing directory. 28 | no_overwrite: To not overwrite files in an existing directory. 29 | init_path: The path to initialize the project. 30 | project: The type of project to scaffold. 31 | collection_name: The name of the collection. 32 | namespace: The namespace for the collection. 33 | resource_type: The type of resource to be scaffolded. 34 | plugin_name: The name of plugin to be scaffolded. 35 | plugin_type: The type of plugin to be scaffolded. 36 | type: The type of the project for which the resource is being scaffolded. 37 | path: The file path where the resource should be added. 38 | image: The image to be used while scaffolding devcontainer. 39 | role_name: The role to be scaffolded. 40 | """ 41 | 42 | creator_version: str 43 | output: Output 44 | subcommand: str 45 | collection: str = "" 46 | force: bool = False 47 | overwrite: bool = False 48 | no_overwrite: bool = False 49 | init_path: str | Path = "./" 50 | project: str = "" 51 | collection_name: str | None = None 52 | namespace: str = "" 53 | resource_type: str = "" 54 | plugin_name: str = "" 55 | plugin_type: str = "" 56 | type: str = "" 57 | path: str | Path = "./" 58 | image: str = "" 59 | role_name: str = "run" 60 | 61 | def __post_init__(self) -> None: 62 | """Post process config values.""" 63 | if self.project == "ansible-project": 64 | object.__setattr__(self, "project", "playbook") 65 | 66 | if self.collection: 67 | fqcn = self.collection.split(".", maxsplit=1) 68 | object.__setattr__(self, "namespace", fqcn[0]) 69 | object.__setattr__(self, "collection_name", fqcn[-1]) 70 | 71 | if isinstance(self.init_path, str): 72 | object.__setattr__(self, "init_path", expand_path(self.init_path)) 73 | 74 | if self.plugin_type == "module": 75 | object.__setattr__(self, "plugin_type", "modules") 76 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/plugins/action/sample_action.py: -------------------------------------------------------------------------------- 1 | # sample_action.py - A custom action plugin for Ansible. 2 | # Author: Your Name 3 | # License: GPL-3.0-or-later 4 | # pylint: disable=E0401 5 | 6 | from __future__ import absolute_import, annotations, division, print_function 7 | 8 | __metaclass__ = type # pylint: disable=C0103 9 | 10 | from typing import TYPE_CHECKING 11 | from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( # type: ignore 12 | AnsibleArgSpecValidator, 13 | ) 14 | from ansible_collections.ansible.utils.plugins.modules.fact_diff import DOCUMENTATION # type: ignore 15 | from ansible.plugins.action import ActionBase # type: ignore 16 | 17 | 18 | if TYPE_CHECKING: 19 | from typing import Optional, Dict, Any 20 | 21 | 22 | class ActionModule(ActionBase): # type: ignore[misc] 23 | """ 24 | Custom Ansible action plugin: sample_action 25 | A custom action plugin for Ansible. 26 | """ 27 | 28 | def _check_argspec(self, result: dict[str, Any]) -> None: 29 | aav = AnsibleArgSpecValidator( 30 | data=self._task.args, 31 | schema=DOCUMENTATION, 32 | schema_format="doc", 33 | name=self._task.action, 34 | ) 35 | valid, errors, self._task.args = aav.validate() 36 | if not valid: 37 | result["failed"] = True 38 | result["msg"] = errors 39 | 40 | def run( 41 | self, 42 | tmp: Optional[str] = None, 43 | task_vars: Optional[Dict[str, Any]] = None, 44 | ) -> Dict[str, Any]: 45 | """ 46 | Executes the action plugin. 47 | 48 | Args: 49 | tmp: Temporary path provided by Ansible for the module execution. Defaults to None. 50 | task_vars: Dictionary of task variables available to the plugin. Defaults to None. 51 | 52 | Returns: 53 | dict: Result of the action plugin execution. 54 | """ 55 | # Get the task arguments 56 | if task_vars is None: 57 | task_vars = {} 58 | result: Dict[str, Any] = {} 59 | warnings: list[str] = [] 60 | 61 | # Example processing logic - Replace this with actual action code 62 | result = super(ActionModule, self).run(tmp, task_vars) 63 | self._check_argspec(result) 64 | 65 | # Copy the task arguments 66 | module_args = self._task.args.copy() 67 | 68 | prefix = module_args.get("prefix", "DefaultPrefix") 69 | message = module_args.get("msg", "No message provided") 70 | module_args["msg"] = f"{prefix}: {message}" 71 | 72 | result.update( 73 | self._execute_module( 74 | module_name="debug", 75 | module_args=module_args, 76 | task_vars=task_vars, 77 | tmp=tmp, 78 | ), 79 | ) 80 | 81 | if warnings: 82 | if "warnings" in result: 83 | result["warnings"].extend(warnings) 84 | else: 85 | result["warnings"] = warnings 86 | return result 87 | -------------------------------------------------------------------------------- /tests/fixtures/collection/testorg/testcol/README.md: -------------------------------------------------------------------------------- 1 | # Testorg Testcol Collection 2 | 3 | This repository contains the `testorg.testcol` Ansible Collection. 4 | 5 | 6 | 7 | 8 | ## External requirements 9 | 10 | Some modules and plugins require external libraries. Please check the 11 | requirements for each plugin or module you use in the documentation to find out 12 | which requirements are needed. 13 | 14 | ## Included content 15 | 16 | 17 | 18 | 19 | ## Using this collection 20 | 21 | ```bash 22 | ansible-galaxy collection install testorg.testcol 23 | ``` 24 | 25 | You can also include it in a `requirements.yml` file and install it via 26 | `ansible-galaxy collection install -r requirements.yml` using the format: 27 | 28 | ```yaml 29 | collections: 30 | - name: testorg.testcol 31 | ``` 32 | 33 | To upgrade the collection to the latest available version, run the following 34 | command: 35 | 36 | ```bash 37 | ansible-galaxy collection install testorg.testcol --upgrade 38 | ``` 39 | 40 | You can also install a specific version of the collection, for example, if you 41 | need to downgrade when something is broken in the latest version (please report 42 | an issue in this repository). Use the following syntax where `X.Y.Z` can be any 43 | [available version](https://galaxy.ansible.com/testorg/testcol): 44 | 45 | ```bash 46 | ansible-galaxy collection install testorg.testcol:==X.Y.Z 47 | ``` 48 | 49 | See 50 | [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) 51 | for more details. 52 | 53 | ## Release notes 54 | 55 | See the 56 | [changelog](https://github.com/ansible-collections/testorg.testcol/tree/main/CHANGELOG.rst). 57 | 58 | ## Roadmap 59 | 60 | 61 | 62 | ## More information 63 | 64 | 65 | 66 | - [Ansible collection development forum](https://forum.ansible.com/c/project/collection-development/27) 67 | - [Ansible User guide](https://docs.ansible.com/ansible/devel/user_guide/index.html) 68 | - [Ansible Developer guide](https://docs.ansible.com/ansible/devel/dev_guide/index.html) 69 | - [Ansible Collections Checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_requirements.html) 70 | - [Ansible Community code of conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) 71 | - [The Bullhorn (the Ansible Contributor newsletter)](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn) 72 | - [News for Maintainers](https://forum.ansible.com/tag/news-for-maintainers) 73 | 74 | ## Licensing 75 | 76 | GNU General Public License v3.0 or later. 77 | 78 | See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text. 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![codecov](https://codecov.io/github/ansible/ansible-creator/graph/badge.svg?token=QZKqxsNNsL)](https://codecov.io/github/ansible/ansible-creator) 2 | [![PyPI - Status](https://img.shields.io/pypi/status/ansible-creator)](https://pypi.org/project/ansible-creator/) 3 | [![PyPI - Version](https://img.shields.io/pypi/v/ansible-creator)](https://pypi.org/project/ansible-creator/) 4 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ansible-creator) 5 | ![License](https://img.shields.io/github/license/ansible/ansible-creator) 6 | [![Ansible Code of Conduct](https://img.shields.io/badge/Code%20of%20Conduct-Ansible-silver.svg)](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) 7 | [![GitHub issues](https://img.shields.io/github/issues/ansible/ansible-creator)](https://github.com/ansible/ansible-creator/issues) 8 | 9 | # ansible-creator 10 | 11 | A CLI tool for scaffolding all your Ansible Content. 12 | 13 | ## Installation 14 | 15 | ```shell 16 | pip install ansible-creator 17 | ``` 18 | 19 | ```shell 20 | $ ansible-creator --help 21 | usage: ansible-creator [-h] command ... 22 | 23 | The fastest way to generate all your ansible content. 24 | 25 | Positional arguments: 26 | command 27 | add Add resources to an existing Ansible project. 28 | init Initialize a new Ansible project. 29 | 30 | Options: 31 | --version Print ansible-creator version and exit. 32 | -h --help Show this help message and exit 33 | ``` 34 | 35 | ## Usage 36 | 37 | Full documentation on how to use `ansible-creator`, including integration with 38 | the VS Code Ansible Extension, is available in 39 | [ansible-creator documentation](https://ansible.readthedocs.io/projects/creator/). 40 | 41 | ## Command line completion 42 | 43 | `ansible-creator` has experimental command line completion for common shells. 44 | Please ensure you have the `argcomplete` package installed and configured. 45 | 46 | ```shell 47 | pip install argcomplete --user 48 | activate-global-python-argcomplete --user 49 | ``` 50 | 51 | ## Upcoming features 52 | 53 | - Scaffold Ansible plugins of your choice with the `create` action. Switch to 54 | the [create](https://github.com/ansible-community/ansible-creator/tree/create) 55 | branch and try it out! 56 | 57 | ## Communication 58 | 59 | Refer to the 60 | [Get in Touch](https://ansible.readthedocs.io/projects/creator/contributing/#get-in-touch) 61 | section of the Contributor Guide to find out how to communicate with us. 62 | 63 | You can also find more information in the 64 | [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html). 65 | 66 | ## Contributing 67 | 68 | See 69 | [Contributing to ansible-creator](https://ansible.readthedocs.io/projects/creator/contributing/). 70 | 71 | ## Code of Conduct 72 | 73 | Please see the 74 | [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). 75 | 76 | ## Licensing 77 | 78 | ansible-creator is released under the Apache License version 2. 79 | 80 | See the [LICENSE](https://github.com/ansible/ansible-creator/blob/main/LICENSE) 81 | file for more details. 82 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | """conftest.""" 2 | 3 | from __future__ import annotations 4 | 5 | import os 6 | import subprocess 7 | 8 | from pathlib import Path 9 | from subprocess import CalledProcessError, CompletedProcess 10 | from typing import Protocol 11 | 12 | import pytest 13 | 14 | from ansible_creator.output import Output 15 | from ansible_creator.utils import TermFeatures 16 | 17 | 18 | os.environ["HOME"] = str(Path.home()) 19 | os.environ["DEV_WORKSPACE"] = "collections/ansible_collections" 20 | 21 | 22 | @pytest.fixture 23 | def cli() -> CliRunCallable: 24 | """Fixture to run CLI commands. 25 | 26 | Returns: 27 | function: cli_run function. 28 | """ 29 | return cli_run 30 | 31 | 32 | @pytest.fixture 33 | def output(tmp_path: Path) -> Output: 34 | """Create an Output class object as fixture. 35 | 36 | Args: 37 | tmp_path: Temporary path. 38 | 39 | Returns: 40 | Output: Output class object. 41 | """ 42 | return Output( 43 | display="text", 44 | log_file=str(tmp_path) + "ansible-creator.log", 45 | log_level="notset", 46 | log_append="false", 47 | term_features=TermFeatures(color=False, links=False), 48 | verbosity=0, 49 | ) 50 | 51 | 52 | @pytest.fixture 53 | def home_path() -> Path: 54 | """Create the home directory as a fixture. 55 | 56 | Returns: 57 | Path: Home directory. 58 | """ 59 | return Path.home() 60 | 61 | 62 | class CliRunCallable(Protocol): 63 | """Callable protocol for cli_run function.""" 64 | 65 | def __call__( 66 | self, 67 | args: str, 68 | env: dict[str, str] | None = None, 69 | ) -> CompletedProcess[str] | CalledProcessError: 70 | """Run a command using subprocess. 71 | 72 | Args: 73 | args: Command to run. 74 | env: Supplemental environment variables. 75 | 76 | Returns: 77 | CompletedProcess: CompletedProcess object. 78 | CalledProcessError: CalledProcessError object. 79 | """ 80 | 81 | 82 | def cli_run( 83 | args: str, 84 | env: dict[str, str] | None = None, 85 | ) -> CompletedProcess[str] | CalledProcessError: 86 | """Run a command using subprocess. 87 | 88 | Args: 89 | args: Command to run. 90 | env: Supplemental environment variables. 91 | 92 | Returns: 93 | CompletedProcess: CompletedProcess object. 94 | CalledProcessError: CalledProcessError object. 95 | """ 96 | updated_env = os.environ.copy() 97 | # this helps asserting stdout/stderr 98 | updated_env.update({"LINES": "40", "COLUMNS": "300", "TERM": "xterm-256color"}) 99 | if env: 100 | updated_env.update(env) 101 | try: 102 | result = subprocess.run( 103 | args, 104 | shell=True, 105 | capture_output=True, 106 | check=True, 107 | text=True, 108 | env=updated_env, 109 | ) 110 | except subprocess.CalledProcessError as err: 111 | return err 112 | return result 113 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/lookup/sample_lookup.py.j2: -------------------------------------------------------------------------------- 1 | {# lookup_plugin_template.j2 #} 2 | {%- set lookup_name = plugin_name | default("sample_lookup",true) -%} 3 | {%- set author = author | default("Your Name (@username)") -%} 4 | {%- set description = description | default("A custom lookup plugin for Ansible.") -%} 5 | {%- set license = license | default("GPL-3.0-or-later") -%} 6 | # {{ lookup_name }}.py - {{ description }} 7 | 8 | # pylint: disable=E0401 9 | # {{ lookup_name }}.py - {{ description }} 10 | # Author: {{ author }} 11 | # Copyright 2020 Red Hat 12 | # GNU General Public License v3.0+ 13 | # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 14 | 15 | DOCUMENTATION = """ 16 | name: {{ lookup_name }} 17 | author: {{ author }} 18 | version_added: "1.0.0" 19 | short_description: {{ description }} 20 | description: 21 | - This is a custom lookup plugin to provide lookup functionality. 22 | options: 23 | _terms: 24 | description: Terms to lookup 25 | required: True 26 | notes: 27 | - This is a scaffold template. Customize the plugin to fit your needs. 28 | """ 29 | 30 | EXAMPLES = """ 31 | - name: Example usage of {{ lookup_name }} 32 | {%- raw %} 33 | ansible.builtin.debug: 34 | msg: "{{ lookup('{%- endraw %}{{ lookup_name }}', 'example_term') }}" 35 | """ 36 | 37 | RETURN = """ 38 | _list: 39 | description: The list of values found by the lookup 40 | type: list 41 | """ 42 | 43 | from typing import Any, Dict, List, Optional 44 | 45 | from ansible.errors import AnsibleError # type: ignore 46 | from ansible.plugins.lookup import LookupBase # type: ignore 47 | from ansible.utils.display import Display # type: ignore 48 | 49 | display = Display() 50 | 51 | 52 | class LookupModule(LookupBase): # type: ignore[misc] 53 | """ 54 | Custom Ansible lookup plugin: {{ lookup_name }} 55 | A custom lookup plugin for Ansible. 56 | """ 57 | 58 | def run( 59 | self, 60 | terms: List[str], 61 | variables: Optional[Dict[str, Any]] = None, 62 | **kwargs: Dict[str, Any], 63 | ) -> list[str]: 64 | """ 65 | Run the lookup with the specified terms. 66 | 67 | Args: 68 | terms: A list of terms to lookup. 69 | variables: Additional variables. 70 | **kwargs: Additional keyword arguments. 71 | 72 | Returns: 73 | list: A list of processed results. 74 | 75 | Raises: 76 | AnsibleError: If the 'terms' parameter is not a list. 77 | """ 78 | if not isinstance(terms, list): 79 | raise AnsibleError("The 'terms' parameter must be a list.") 80 | 81 | display.vvv(f"Running {{ lookup_name }} lookup plugin with terms: {terms}") 82 | 83 | try: 84 | # Example processing logic - Replace this with actual lookup code 85 | result = [term.upper() for term in terms] 86 | 87 | display.vvv(f"Result from {{ lookup_name }} lookup: {result}") 88 | return result 89 | 90 | except Exception as e: 91 | raise AnsibleError(f"Error in {{ lookup_name }} plugin: {e}") from e 92 | -------------------------------------------------------------------------------- /tests/units/test_output.py: -------------------------------------------------------------------------------- 1 | """Test the output module.""" 2 | 3 | from __future__ import annotations 4 | 5 | import os 6 | 7 | from typing import TYPE_CHECKING 8 | 9 | import pytest 10 | 11 | from ansible_creator.output import Color, Level, Msg, Output, console_width 12 | from ansible_creator.utils import TermFeatures 13 | 14 | 15 | if TYPE_CHECKING: 16 | from pathlib import Path 17 | 18 | 19 | @pytest.mark.parametrize( 20 | argnames=("width", "expected"), 21 | argvalues=((79, 79), (131, 81), (133, 132)), 22 | ) 23 | def test_console_width(width: int, expected: int, monkeypatch: pytest.MonkeyPatch) -> None: 24 | """Test the console width function.""" 25 | 26 | def mock_get_terminal_size( 27 | fallback: tuple[int, int] = (80, 24), # noqa: ARG001 28 | ) -> tuple[int, int]: 29 | """Mock the get_terminal_size function. 30 | 31 | Args: 32 | fallback: Default terminal size. 33 | 34 | Returns: 35 | Mocked terminal size. 36 | """ 37 | return os.terminal_size((width, 24)) 38 | 39 | monkeypatch.setattr("shutil.get_terminal_size", mock_get_terminal_size) 40 | 41 | monkeypatch.delenv("COLUMNS", raising=False) 42 | assert console_width() == expected 43 | 44 | 45 | @pytest.mark.parametrize( 46 | "params", 47 | ( 48 | (Level.CRITICAL, Color.BRIGHT_RED), 49 | (Level.DEBUG, Color.GREY), 50 | (Level.ERROR, Color.RED), 51 | (Level.HINT, Color.CYAN), 52 | (Level.INFO, Color.MAGENTA), 53 | (Level.NOTE, Color.GREEN), 54 | (Level.WARNING, Color.YELLOW), 55 | ), 56 | ids=("critical", "debug", "error", "hint", "info", "note", "warning"), 57 | ) 58 | def test_color_mapping(params: tuple[Level, Color]) -> None: 59 | """Test the color mapping for Msg in the output module. 60 | 61 | Args: 62 | params: Tuple of Level and Color. 63 | """ 64 | assert Msg(message="", prefix=params[0]).color == str(params[1]) 65 | 66 | 67 | @pytest.mark.parametrize("level", ("info", "warning", "error", "debug", "critical", "hint", "note")) 68 | def test_console_output(level: str, capsys: pytest.CaptureFixture[str], tmp_path: Path) -> None: 69 | """Test the console output function. 70 | 71 | Args: 72 | level: Log level. 73 | capsys: Pytest fixture. 74 | tmp_path: Pytest fixture 75 | """ 76 | output = Output( 77 | log_file=str(tmp_path / "test.log"), 78 | log_level="debug", 79 | log_append="false", 80 | term_features=TermFeatures(color=True, links=True), 81 | verbosity=3, 82 | ) 83 | message = f"{level} message" 84 | msg = Msg(message=message, prefix=getattr(Level, level.upper())) 85 | if level == "critical": 86 | with pytest.raises(SystemExit): 87 | getattr(output, level)(message) 88 | else: 89 | getattr(output, level)(message) 90 | captured = capsys.readouterr() 91 | standard_x = captured.err if level in ("critical", "error") else captured.out 92 | assert standard_x.startswith(msg.color) 93 | assert standard_x.endswith(Color.END + "\n") 94 | assert level.capitalize() in standard_x 95 | assert message in standard_x 96 | -------------------------------------------------------------------------------- /tests/fixtures/project/playbook_project/collections/ansible_collections/weather/demo/README.md: -------------------------------------------------------------------------------- 1 | # Weather Demo Collection 2 | 3 | This repository contains the `weather.demo` Ansible Collection. 4 | 5 | ## Tested with Ansible 6 | 7 | Tested with ansible-core >=2.14 releases and the current development version of 8 | ansible-core. 9 | 10 | ## External requirements 11 | 12 | Some modules and plugins require external libraries. Please check the 13 | requirements for each plugin or module you use in the documentation to find out 14 | which requirements are needed. 15 | 16 | ## Included content 17 | 18 | Please check the included content on the 19 | [Ansible Galaxy page for this collection](https://galaxy.ansible.com/weather/demo). 20 | 21 | ## Using this collection 22 | 23 | ```shell 24 | ansible-galaxy collection install weather.demo 25 | ``` 26 | 27 | You can also include it in a `requirements.yml` file and install it via 28 | `ansible-galaxy collection install -r requirements.yml` using the format: 29 | 30 | ```yaml 31 | collections: 32 | - name: weather.demo 33 | ``` 34 | 35 | To upgrade the collection to the latest available version, run the following 36 | command: 37 | 38 | ```bash 39 | ansible-galaxy collection install weather.demo --upgrade 40 | ``` 41 | 42 | You can also install a specific version of the collection, for example, if you 43 | need to downgrade when something is broken in the latest version (please report 44 | an issue in this repository). Use the following syntax where `X.Y.Z` can be any 45 | [available version](https://galaxy.ansible.com/weather/demo): 46 | 47 | ```bash 48 | ansible-galaxy collection install weather.demo:==X.Y.Z 49 | ``` 50 | 51 | See 52 | [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) 53 | for more details. 54 | 55 | ## Release notes 56 | 57 | See the 58 | [changelog](https://github.com/ansible-collections/weather.demo/tree/main/CHANGELOG.rst). 59 | 60 | ## Roadmap 61 | 62 | 63 | 64 | ## More information 65 | 66 | 67 | 68 | - [Ansible collection development forum](https://forum.ansible.com/c/project/collection-development/27) 69 | - [Ansible User guide](https://docs.ansible.com/ansible/devel/user_guide/index.html) 70 | - [Ansible Developer guide](https://docs.ansible.com/ansible/devel/dev_guide/index.html) 71 | - [Ansible Collections Checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_requirements.html) 72 | - [Ansible Community code of conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) 73 | - [The Bullhorn (the Ansible Contributor newsletter)](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn) 74 | - [News for Maintainers](https://forum.ansible.com/tag/news-for-maintainers) 75 | 76 | ## Licensing 77 | 78 | GNU General Public License v3.0 or later. 79 | 80 | See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text. 81 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/README.md.j2: -------------------------------------------------------------------------------- 1 | # {{ namespace|capitalize }} {{ collection_name|capitalize }} Collection 2 | 3 | This repository contains the `{{ namespace }}.{{ collection_name }}` Ansible Collection. 4 | 5 | 6 | 7 | 8 | ## External requirements 9 | 10 | Some modules and plugins require external libraries. Please check the 11 | requirements for each plugin or module you use in the documentation to find out 12 | which requirements are needed. 13 | 14 | ## Included content 15 | 16 | 17 | 18 | 19 | ## Using this collection 20 | 21 | ```bash 22 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }} 23 | ``` 24 | 25 | You can also include it in a `requirements.yml` file and install it via 26 | `ansible-galaxy collection install -r requirements.yml` using the format: 27 | 28 | ```yaml 29 | collections: 30 | - name: {{ namespace }}.{{ collection_name }} 31 | ``` 32 | 33 | To upgrade the collection to the latest available version, run the following 34 | command: 35 | 36 | ```bash 37 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }} --upgrade 38 | ``` 39 | 40 | You can also install a specific version of the collection, for example, if you 41 | need to downgrade when something is broken in the latest version (please report 42 | an issue in this repository). Use the following syntax where `X.Y.Z` can be any 43 | [available version](https://galaxy.ansible.com/{{ namespace }}/{{ collection_name }}): 44 | 45 | ```bash 46 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }}:==X.Y.Z 47 | ``` 48 | 49 | See 50 | [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) 51 | for more details. 52 | 53 | ## Release notes 54 | 55 | See the 56 | [changelog](https://github.com/ansible-collections/{{ namespace }}.{{ collection_name }}/tree/main/CHANGELOG.rst). 57 | 58 | ## Roadmap 59 | 60 | 61 | 62 | ## More information 63 | 64 | 65 | 66 | - [Ansible collection development forum](https://forum.ansible.com/c/project/collection-development/27) 67 | - [Ansible User guide](https://docs.ansible.com/ansible/devel/user_guide/index.html) 68 | - [Ansible Developer guide](https://docs.ansible.com/ansible/devel/dev_guide/index.html) 69 | - [Ansible Collections Checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_requirements.html) 70 | - [Ansible Community code of conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) 71 | - [The Bullhorn (the Ansible Contributor newsletter)](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn) 72 | - [News for Maintainers](https://forum.ansible.com/tag/news-for-maintainers) 73 | 74 | ## Licensing 75 | 76 | GNU General Public License v3.0 or later. 77 | 78 | See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text. 79 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/collection_project/plugins/action/sample_action.py.j2: -------------------------------------------------------------------------------- 1 | {# action_plugin_template.j2 #} 2 | {%- set action_name = plugin_name | default("sample_action",true) -%} 3 | {%- set author = author | default("Your Name") -%} 4 | {%- set description = description | default("A custom action plugin for Ansible.") -%} 5 | {%- set license = license | default("GPL-3.0-or-later") -%} 6 | # {{ action_name }}.py - {{ description }} 7 | # Author: {{ author }} 8 | # License: {{ license }} 9 | # pylint: disable=E0401 10 | 11 | from __future__ import absolute_import, annotations, division, print_function 12 | 13 | __metaclass__ = type # pylint: disable=C0103 14 | 15 | from typing import TYPE_CHECKING 16 | from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( # type: ignore 17 | AnsibleArgSpecValidator, 18 | ) 19 | from ansible_collections.ansible.utils.plugins.modules.fact_diff import DOCUMENTATION # type: ignore 20 | from ansible.plugins.action import ActionBase # type: ignore 21 | 22 | 23 | if TYPE_CHECKING: 24 | from typing import Optional, Dict, Any 25 | 26 | 27 | class ActionModule(ActionBase): # type: ignore[misc] 28 | """ 29 | Custom Ansible action plugin: {{ action_name }} 30 | A custom action plugin for Ansible. 31 | """ 32 | 33 | def _check_argspec(self, result: dict[str, Any]) -> None: 34 | aav = AnsibleArgSpecValidator( 35 | data=self._task.args, 36 | schema=DOCUMENTATION, 37 | schema_format="doc", 38 | name=self._task.action, 39 | ) 40 | valid, errors, self._task.args = aav.validate() 41 | if not valid: 42 | result["failed"] = True 43 | result["msg"] = errors 44 | 45 | def run( 46 | self, 47 | tmp: Optional[str] = None, 48 | task_vars: Optional[Dict[str, Any]] = None, 49 | ) -> Dict[str, Any]: 50 | """ 51 | Executes the action plugin. 52 | 53 | Args: 54 | tmp: Temporary path provided by Ansible for the module execution. Defaults to None. 55 | task_vars: Dictionary of task variables available to the plugin. Defaults to None. 56 | 57 | Returns: 58 | dict: Result of the action plugin execution. 59 | """ 60 | # Get the task arguments 61 | if task_vars is None: 62 | task_vars = {} 63 | result: Dict[str, Any] = {} 64 | warnings: list[str] = [] 65 | 66 | # Example processing logic - Replace this with actual action code 67 | result = super(ActionModule, self).run(tmp, task_vars) 68 | self._check_argspec(result) 69 | 70 | # Copy the task arguments 71 | module_args = self._task.args.copy() 72 | 73 | prefix = module_args.get("prefix", "DefaultPrefix") 74 | message = module_args.get("msg", "No message provided") 75 | module_args["msg"] = f"{prefix}: {message}" 76 | 77 | result.update( 78 | self._execute_module( 79 | module_name="debug", 80 | module_args=module_args, 81 | task_vars=task_vars, 82 | tmp=tmp, 83 | ), 84 | ) 85 | 86 | if warnings: 87 | if "warnings" in result: 88 | result["warnings"].extend(warnings) 89 | else: 90 | result["warnings"] = warnings 91 | return result 92 | -------------------------------------------------------------------------------- /src/ansible_creator/resources/playbook_project/collections/ansible_collections/project_org/project_repo/README.md.j2: -------------------------------------------------------------------------------- 1 | # {{ namespace|capitalize }} {{ collection_name|capitalize }} Collection 2 | 3 | This repository contains the `{{ namespace }}.{{ collection_name }}` Ansible Collection. 4 | 5 | ## Tested with Ansible 6 | 7 | Tested with ansible-core >=2.14 releases and the current development version of 8 | ansible-core. 9 | 10 | ## External requirements 11 | 12 | Some modules and plugins require external libraries. Please check the 13 | requirements for each plugin or module you use in the documentation to find out 14 | which requirements are needed. 15 | 16 | ## Included content 17 | 18 | Please check the included content on the 19 | [Ansible Galaxy page for this collection](https://galaxy.ansible.com/{{ namespace }}/{{ collection_name }}). 20 | 21 | ## Using this collection 22 | 23 | ```shell 24 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }} 25 | ``` 26 | 27 | You can also include it in a `requirements.yml` file and install it via 28 | `ansible-galaxy collection install -r requirements.yml` using the format: 29 | 30 | ```yaml 31 | collections: 32 | - name: {{ namespace }}.{{ collection_name }} 33 | ``` 34 | 35 | To upgrade the collection to the latest available version, run the following 36 | command: 37 | 38 | ```bash 39 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }} --upgrade 40 | ``` 41 | 42 | You can also install a specific version of the collection, for example, if you 43 | need to downgrade when something is broken in the latest version (please report 44 | an issue in this repository). Use the following syntax where `X.Y.Z` can be any 45 | [available version](https://galaxy.ansible.com/{{ namespace }}/{{ collection_name }}): 46 | 47 | ```bash 48 | ansible-galaxy collection install {{ namespace }}.{{ collection_name }}:==X.Y.Z 49 | ``` 50 | 51 | See 52 | [Ansible Using Collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) 53 | for more details. 54 | 55 | ## Release notes 56 | 57 | See the 58 | [changelog](https://github.com/ansible-collections/{{ namespace }}.{{ collection_name }}/tree/main/CHANGELOG.rst). 59 | 60 | ## Roadmap 61 | 62 | 63 | 64 | ## More information 65 | 66 | 67 | 68 | - [Ansible collection development forum](https://forum.ansible.com/c/project/collection-development/27) 69 | - [Ansible User guide](https://docs.ansible.com/ansible/devel/user_guide/index.html) 70 | - [Ansible Developer guide](https://docs.ansible.com/ansible/devel/dev_guide/index.html) 71 | - [Ansible Collections Checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_requirements.html) 72 | - [Ansible Community code of conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) 73 | - [The Bullhorn (the Ansible Contributor newsletter)](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn) 74 | - [News for Maintainers](https://forum.ansible.com/tag/news-for-maintainers) 75 | 76 | ## Licensing 77 | 78 | GNU General Public License v3.0 or later. 79 | 80 | See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text. 81 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # cspell:ignore autohide, autofix 3 | site_name: Ansible Creator Documentation 4 | site_url: https://ansible.readthedocs.io/projects/creator/ 5 | repo_url: https://github.com/ansible/ansible-creator 6 | edit_uri: blob/main/docs/ 7 | copyright: Copyright © Red Hat, Inc. 8 | docs_dir: docs 9 | strict: true 10 | 11 | # extra_css: 12 | # - stylesheets/extra.css 13 | 14 | theme: 15 | name: ansible 16 | features: 17 | - announce.dismiss 18 | - content.action.edit 19 | - content.action.view 20 | - content.code.annotate 21 | - content.code.copy 22 | - content.tabs.link 23 | - content.tooltips 24 | - header.autohide 25 | - navigation.expand 26 | - navigation.footer 27 | - navigation.indexes 28 | - navigation.instant 29 | - navigation.path 30 | - navigation.prune 31 | - navigation.sections 32 | - navigation.tabs 33 | - navigation.tabs.sticky 34 | - navigation.top 35 | - navigation.tracking 36 | - search.highlight 37 | - search.share 38 | - search.suggest 39 | - toc.integrate 40 | - tox.follow 41 | extra: 42 | generator: false 43 | social: 44 | - icon: fontawesome/brands/python 45 | link: https://pypi.org/project/ansible-creator/ 46 | name: PyPI 47 | - icon: fontawesome/solid/scroll 48 | link: https://github.com/ansible/ansible-creator/releases 49 | name: Releases 50 | - icon: simple/mastodon 51 | link: https://fosstodon.org/@ansible 52 | name: Mastodon 53 | - icon: fontawesome/brands/twitter 54 | link: https://twitter.com/ansible 55 | name: Twitter 56 | - icon: simple/matrix 57 | link: https://matrix.to/#/#devtools:ansible.com 58 | name: Matrix 59 | - icon: fontawesome/brands/discourse 60 | link: https://forum.ansible.com/c/project/7 61 | name: Ansible forum 62 | - icon: fontawesome/brands/github-alt 63 | link: https://github.com/ansible/ansible-creator 64 | name: GitHub 65 | 66 | nav: 67 | - Home: 68 | - home: index.md 69 | - Setup: 70 | - installing.md 71 | - content_creation.md 72 | - Contributing: contributing.md 73 | 74 | exclude_docs: | 75 | _autofix_rules.md 76 | 77 | plugins: 78 | - autorefs 79 | - macros: 80 | modules: [mkdocs-ansible:mkdocs_ansible] 81 | - markdown-exec 82 | - material/search: 83 | separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])' 84 | - material/social 85 | - material/tags 86 | # https://github.com/manuzhang/mkdocs-htmlproofer-plugin 87 | # - htmlproofer 88 | 89 | markdown_extensions: 90 | - markdown_include.include: 91 | base_path: docs 92 | - admonition 93 | - def_list 94 | - footnotes 95 | - pymdownx.highlight: 96 | anchor_linenums: true 97 | - pymdownx.inlinehilite 98 | - pymdownx.superfences 99 | - pymdownx.magiclink: 100 | repo_url_shortener: true 101 | repo_url_shorthand: true 102 | social_url_shorthand: true 103 | social_url_shortener: true 104 | user: facelessuser 105 | repo: pymdown-extensions 106 | normalize_issue_symbols: true 107 | - pymdownx.tabbed: 108 | alternate_style: true 109 | - toc: 110 | toc_depth: 3 111 | permalink: true 112 | - pymdownx.superfences: 113 | custom_fences: 114 | - name: mermaid 115 | class: mermaid 116 | format: !!python/name:pymdownx.superfences.fence_code_format 117 | - name: python 118 | class: python 119 | validator: !!python/name:markdown_exec.validator 120 | format: !!python/name:markdown_exec.formatter 121 | -------------------------------------------------------------------------------- /tests/integration/test_lint.py: -------------------------------------------------------------------------------- 1 | """Check fixture content integration with ansible-lint. 2 | 3 | The fixture content is compared to the output of ansible-creator in the 4 | test_run_success_for_collection and test_run_success_ansible_project 5 | tests. 6 | """ 7 | 8 | from __future__ import annotations 9 | 10 | import re 11 | import sys 12 | 13 | from pathlib import Path 14 | from typing import TYPE_CHECKING 15 | 16 | from tests.defaults import FIXTURES_DIR 17 | 18 | 19 | if TYPE_CHECKING: 20 | import pytest 21 | 22 | from tests.conftest import CliRunCallable 23 | 24 | GALAXY_BIN = Path(sys.executable).parent / "ansible-galaxy" 25 | LINT_BIN = Path(sys.executable).parent / "ansible-lint" 26 | 27 | LINT_RE = re.compile( 28 | r"Passed: (?P\d+) failure\(s\), " 29 | r"(?P\d+) warning\(s\) (on|in) (?P\d+) files" 30 | ) 31 | LINT_PROFILE_RE = re.compile( 32 | r"Last profile that met the validation criteria was '(?P\w+)'.", 33 | ) 34 | 35 | 36 | def test_lint_collection( 37 | cli: CliRunCallable, 38 | monkeypatch: pytest.MonkeyPatch, 39 | ) -> None: 40 | """Lint the scaffolded collection with ansible-lint. 41 | 42 | Args: 43 | cli: CLI callable. 44 | monkeypatch: Monkeypatch fixture. 45 | 46 | """ 47 | project_path = FIXTURES_DIR / "collection" 48 | monkeypatch.chdir(project_path) 49 | 50 | args = str(LINT_BIN) 51 | env = {"NO_COLOR": "1"} 52 | result = cli(args=args, env=env) 53 | 54 | print("STDOUT:", result.stdout) 55 | print("STDERR:", result.stderr) 56 | 57 | assert result.returncode == 0 58 | 59 | combined = (result.stdout or "") + (result.stderr or "") 60 | match = LINT_RE.search(combined) 61 | assert match is not None 62 | assert int(match.group("failures")) == 0 63 | assert int(match.group("warnings")) == 0 64 | assert int(match.group("files")) > 0 65 | 66 | match = LINT_PROFILE_RE.search(result.stderr) 67 | assert match is not None 68 | assert match.group("profile") == "production" 69 | 70 | 71 | def test_lint_playbook_project( 72 | tmp_path: Path, 73 | cli: CliRunCallable, 74 | monkeypatch: pytest.MonkeyPatch, 75 | ) -> None: 76 | """Lint the scaffolded playbook project with ansible-lint. 77 | 78 | This is an expensive test as it installs collections from the requirements.yml file. 79 | If it becomes necessary again, consider using a session fixture to install the collections. 80 | 81 | Args: 82 | tmp_path: Temporary path. 83 | cli: CLI callable. 84 | monkeypatch: Monkeypatch fixture. 85 | 86 | """ 87 | req_path = str( 88 | FIXTURES_DIR / "project" / "playbook_project" / "collections" / "requirements.yml", 89 | ) 90 | dest_path = tmp_path / "collections" 91 | galaxy_cmd = f"{GALAXY_BIN} collection install -r {req_path} -p {dest_path}" 92 | result = cli(args=galaxy_cmd) 93 | assert result.returncode == 0, result.stderr 94 | 95 | project_path = FIXTURES_DIR / "project" / "playbook_project" 96 | monkeypatch.chdir(project_path) 97 | args = str(LINT_BIN) 98 | env = {"NO_COLOR": "1", "ANSIBLE_COLLECTIONS_PATH": str(dest_path)} 99 | result = cli(args=args, env=env) 100 | 101 | assert result.returncode == 0, result.stderr 102 | 103 | combined = (result.stdout or "") + (result.stderr or "") 104 | match = LINT_RE.search(combined) 105 | assert match is not None 106 | assert int(match.group("failures")) == 0 107 | assert int(match.group("warnings")) == 0 108 | assert int(match.group("files")) > 0 109 | 110 | match = LINT_PROFILE_RE.search(result.stderr) 111 | assert match is not None 112 | assert match.group("profile") == "production" 113 | --------------------------------------------------------------------------------