diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..c34b751 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,20 @@ +--- +# .ansible-lint +exclude_paths: + - "*.yml.swp" + - .ansible/ + - .cache/ # implicit unless exclude_paths is defined in config +# Ansible-lint does not automatically load rules that have the 'opt-in' tag. +# You must enable opt-in rules by listing each rule 'id' below. +enable_list: + - args + - empty-string-compare # opt-in + - no-log-password # opt-in + - no-same-owner # opt-in + # - name[prefix] # opt-in + # add yaml here if you want to avoid ignoring yaml checks when yamllint + # library is missing. Normally its absence just skips using that rule. + - yaml +mock_roles: + - community.docker.docker_image +verbosity: 0 diff --git a/.ansible.cfg b/.ansible.cfg index fc4e2ab..65b6c22 100644 --- a/.ansible.cfg +++ b/.ansible.cfg @@ -6,7 +6,8 @@ bin_ansible_callbacks = True # Leave the 'cows' alone! nocows = 1 # Use the YAML callback plugin. -stdout_callback = yaml +stdout_callback = default +callback_result_format = yaml [diff] # Always print diff when running (same as always running with -D/--diff). diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..05608f2 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,50 @@ +--- +# CodeRabbit configuration +chat: + auto_reply: true +early_access: true +reviews: + auto_review: + base_branches: + - "dev*" + - "main" + - "master" + drafts: false + enabled: true + ignore_title_keywords: + - "WIP" + - "DO NOT MERGE" + high_level_summary: true + path_filters: + - "**/*.j2" + - "**/*.md" + - "**/*.py" + - "**/*.yaml" + - "**/*.yml" + - "defaults/**" + - "meta/**" + - "molecule/**" + - "tasks/**" + - "vars/**" + path_instructions: + - path: "**/*.yml" + instructions: | + - For Ansible files, review the YAML code against the Ansible best practices and point out any mismatches. + - Ensure keys are in lexicographical order when possible. + poem: true + request_changes_workflow: false + review_status: true + tools: + actionlint: + enabled: true + gitleaks: + enabled: true + hadolint: + enabled: true + markdownlint: + enabled: true + shellcheck: + enabled: true + yamllint: + enabled: true +version: 1 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a16b75d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,57 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + + // "build": { + // "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + // "args": { "VARIANT": "ubuntu-22.04" } + // }, + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "GitHub.copilot", + "GitHub.copilot-chat", + "elagil.pre-commit-helper", + "formulahendry.code-runner", + "formulahendry.code-runner-copilot", + "github.vscode-github-actions", + "ms-python.python", + "vscodevim.vim" + ], + } + }, + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + // "ghcr.io/maks1ms/devcontainers-features/wine:0": {}, + "ghcr.io/devcontainers-contrib/features/actionlint:1": {}, + "ghcr.io/devcontainers-contrib/features/node-asdf:0": {}, + "ghcr.io/devcontainers-extra/features/pipx-package:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/python:1": {}, + "ghcr.io/guiyomh/features/vim:0": {}, + "ghcr.io/jungaretti/features/make:1": {}, + "ghcr.io/prulloac/devcontainer-features/pre-commit:1": {}, + "ghcr.io/jungaretti/features/ripgrep:1": {} + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "name": "ansible-role-mt-runner", + // Install dependencies and pre-commit hooks. + "postCreateCommand": "pip install -r .devcontainer/requirements.txt && pre-commit install", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "onCreateCommand": "sudo apt update && sudo apt install -y gh pipx && pipx install --include-deps ansible" +} diff --git a/.devcontainer/requirements.txt b/.devcontainer/requirements.txt new file mode 100644 index 0000000..5cffc4c --- /dev/null +++ b/.devcontainer/requirements.txt @@ -0,0 +1,11 @@ +# Python's requirements +# Usage: pip install -r requirements.txt +ansible +ansible-lint +docker>=7.1 +jinja2-cli +molecule +molecule-docker +pipenv +pre-commit +requests==2.31.0 diff --git a/.github/actionlint-matcher.json b/.github/actionlint-matcher.json new file mode 100644 index 0000000..4613e16 --- /dev/null +++ b/.github/actionlint-matcher.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "actionlint", + "pattern": [ + { + "regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$", + "file": 1, + "line": 2, + "column": 3, + "message": 4, + "code": 5 + } + ] + } + ] +} diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..10f7359 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,85 @@ +# Copilot Instructions for ansible-role-mt-runner + +You are expected to be an expert in: + +- Ansible +- Python +- Jinja2 +- Molecule +- Linux (Alpine, Debian/Ubuntu, Nix) +- YAML + +## Code Standards + +- Avoid writing trailing whitespace +- Follow PEP 8 for Python. +- Include docstrings and type hints where applicable +- Maintain consistent YAML indentation +- Optimize for readability first, performance second +- Prefer modular, DRY approaches and list comprehensions when appropriate +- Use environment variables for configuration, never hardcode sensitive info +- Write clean, documented, error-handling code with appropriate logging + +## General Approach + +- Be accurate, thorough and terse +- Cite sources at the end, not inline +- Provide immediate answers with clear explanations +- Skip repetitive code in responses; use brief snippets showing only changes +- Suggest alternative solutions beyond conventional approaches +- Treat the user as an expert + +## Ansible Guidelines + +- Ensure idempotency in all tasks +- Ensure indentation is correct, especially for YAML files +- Follow standard role structure: tasks/, handlers/, templates/, defaults/, meta/ +- Use ansible-lint and write Molecule tests for verification +- Use descriptive task names and include helpful comments + +## Ansible Linting + +Ensure enforcing the following rules: + +- fqcn[keyword]: Avoid `collections` keyword by using FQCN for all plugins, modules, roles and playbooks + +## YAML Guidelines + +Ensure the following rules are strictly followed: + +- yaml[empty-lines]: Avoid too many blank lines +- yaml[indentation]: Avoid wrong indentation +- yaml[line-length]: No long lines (max. 120 characters) +- yaml[new-line-at-end-of-file]: Enforce new line character at the end of file +- yaml[truthy]: Truthy value should be one of [false, true] +- Ensure items are in lexicographical order when possible. +- When writing inline code, add a new line at the end to maintain proper indentation + +## Project Specifics + +This role installs and runs trading platform with distribution-specific approaches: + +- **Alpine Linux**: Uses apk package manager +- **Debian/Ubuntu**: Uses apt package manager +- **Nix**: Uses nix-env in lightweight Nix environments + +Notes: + +- Project utilizes Codespaces with config file at .devcontainer/devcontainer.json + and requirements at .devcontainer/requirements.txt +- GitHub Actions are used to validate the code by running + pre-commit checks (see .pre-commit-config.yaml file) and Molecule (molecule/). +- Service management uses supervisord across platforms. +- Formatting rules are defined in .yamllint (YAML) and .markdownlint.yaml (Markdown) files. + +### Key Variables + +Variables are defined in defaults/main.yml and vars/main.yml files. + +Notes: + +- On variable changes, update main.yml and README.md files accordingly. + +### Testing Approach + +- Use Molecule with Docker driver diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7cbc379 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot +--- +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/.github/prompts/code-review.prompt.md b/.github/prompts/code-review.prompt.md new file mode 100644 index 0000000..98cb6bd --- /dev/null +++ b/.github/prompts/code-review.prompt.md @@ -0,0 +1,72 @@ +# Ansible Role Code Review Guidelines + +Your goal is to review Ansible role code +to ensure it meets high-quality standards and follows best practices. + +## Ensure Code Quality + +- Follow PEP 8 for Python. +- Maintain consistent YAML indentation. +- Optimize for readability first, performance second. +- Ensure idempotency in all Ansible tasks. +- Use environment variables for configuration, never hardcode sensitive info. +- Write clean, documented, error-handling code with appropriate logging. + +## Check for Linting and Formatting + +- Ensure YAML files adhere to [.yamllint](../../.yamllint) rules. +- Ensure Markdown files adhere to [.markdownlint.yaml](../../.markdownlint.yaml) rules. +- Ensure Ansible playbooks and roles pass `ansible-lint`. + +## Review Ansible Role Structure + +- Follow standard role structure: + + - [tasks/](../../tasks/) + - [handlers/](../../handlers/) + - [templates/](../../templates/) + - [defaults/](../../defaults/) + - [meta/](../../meta/) + +- Use descriptive task names and include helpful comments. +- Ensure indentation is correct, especially for arguments used for Ansible modules. + +## Verify Variables and Defaults + +- Ensure variables are defined in + [defaults/main.yml](../../defaults/main.yml) and [vars/main.yml](../../vars/main.yml). +- Update [README.md](../../README.md) with any changes to variables. +- Ensure variables are used consistently across tasks and playbooks. + +## Check for Idempotency + +- Ensure all tasks are idempotent and do not cause unnecessary changes on repeated runs. + +## Review Molecule Tests + +- Ensure Molecule scenarios are defined and cover all supported platforms. +- Verify that Molecule tests are comprehensive and validate the role's functionality. +- Check [molecule/](../../molecule/) directory for test configurations. + +## Ensure Proper Error Handling + +- Write error-handling code with appropriate logging. +- Ensure tasks fail gracefully and provide meaningful error messages. + +## Check for Dependencies + +- Ensure all dependencies are listed in + [.devcontainer/requirements.txt](../../.devcontainer/requirements.txt) and [requirements.yml](../../requirements.yml). +- Verify that the role does not have any missing dependencies. + +## Review GitHub Actions + +- Ensure GitHub Actions workflows are correctly configured to run pre-commit checks and Molecule tests. +- Verify that the workflows cover all necessary validation steps. +- Check [.github/workflows/](../) directory for workflow configurations. + +## Documentation + +- Ensure the [README.md](../../README.md) file is up-to-date + and provides clear instructions for installation, usage, and variables. +- Include any additional documentation as needed for clarity. diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 48a7daf..88a7d01 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -7,7 +7,18 @@ on: push: jobs: - Pre-commit: + actionlint: + name: actionlint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-actionlint@v1 + - name: Add Problem Matcher for actionlint + run: | + echo "::add-matcher::.github/actionlint-matcher.json" + shell: bash + pre-commit: + name: Pre-commit runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -16,4 +27,4 @@ jobs: path: ~/.cache/pre-commit key: pre-commit|${{ hashFiles('.pre-commit-config.yaml') }} - uses: actions/setup-python@v5 - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml index 7cc6a43..8ea0849 100644 --- a/.github/workflows/molecule.yml +++ b/.github/workflows/molecule.yml @@ -4,10 +4,25 @@ name: Molecule # yamllint disable-line rule:truthy on: pull_request: + paths-ignore: + - '!.github/workflows/**' + - '**.cfg' + - '**.md' + - '.*' + - LICENSE + - Pipfile* push: + paths-ignore: + - '!.github/workflows/**' + - '**.cfg' + - '**.md' + - '.*' + - LICENSE + - Pipfile* jobs: - Test: + test: + name: Test runs-on: ubuntu-latest strategy: fail-fast: false @@ -19,20 +34,32 @@ jobs: steps: - uses: actions/checkout@v4 with: - path: "${{ github.repository }}" + path: ${{ github.repository }} - uses: gofrolist/molecule-action@v2 env: ANSIBLE_FORCE_COLOR: '1' - ANSIBLE_STDOUT_CALLBACK: yaml - MT_RUNNER_MT4_LOGIN: ${{ secrets.MT_RUNNER_MT4_LOGIN || '12345' }} + ANSIBLE_STDOUT_CALLBACK: ${{ runner.debug == '1' && 'debug' || 'ansible.builtin.default' }} + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + MOLECULE_REPORT: molecule-${{ matrix.scenario }}-report.html MT_RUNNER_MT4_PASSWORD: ${{ secrets.MT_RUNNER_MT4_PASSWORD || 'SETME' }} MT_RUNNER_MT5_LOGIN: ${{ secrets.MT_RUNNER_MT5_LOGIN || '12345' }} MT_RUNNER_MT5_PASSWORD: ${{ secrets.MT_RUNNER_MT5_PASSWORD || 'SETME' }} with: - molecule_args: --scenario-name ${{ matrix.scenario }} + molecule_args: >- + --scenario-name ${{ matrix.scenario }} molecule_command: test - molecule_options: --verbose - molecule_working_dir: "${{ github.repository }}" - - if: ${{ failure() }} + molecule_options: ${{ runner.debug == '1' && '--verbose' || '' }} + molecule_working_dir: ${{ github.repository }} + - if: always() + name: Ensure report file permissions are correct + run: sudo chmod 644 molecule-${{ matrix.scenario }}-report.html + working-directory: ${{ github.repository }} + - if: always() + name: Converts test report + uses: patrick-werner/fhir-html-validation-to-markdown@1.0.0 + with: + input_file: ${{ github.repository }}/molecule-${{ matrix.scenario }}-report.html + # Debug with tmate on failure when debug logging is enabled. + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..ee21875 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,66 @@ +--- +name: Test + +# yamllint disable-line rule:truthy +on: + pull_request: + paths-ignore: + - '**/*.cfg' + - '**/*.md' + - '.*' + - Pipfile* + push: + paths-ignore: + - '**/*.cfg' + - '**/*.md' + - '.*' + - Pipfile* + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ github.repository }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Python's requirements + run: pip install -r .devcontainer/requirements.txt + working-directory: ${{ github.repository }} + + - name: Install Ansible Galaxy requirements + run: ansible-galaxy install -r requirements.yml + working-directory: ${{ github.repository }} + + - name: Install Ansible Galaxy local requirements + run: | + jinja2 requirements-local.yml.j2 -D "pwd=$PWD" -o requirements-local.yml + ansible-galaxy install -r requirements-local.yml && rm requirements-local.yml + working-directory: ${{ github.repository }} + + - name: Check Ansible syntax + run: >- + ansible-playbook --syntax-check + -i tests/inventory/docker-containers.yml tests/playbooks/docker-containers.yml + --verbose + working-directory: ${{ github.repository }} + + - name: Run Ansible lint + run: ansible-lint tests/playbooks/docker-containers.yml + working-directory: ${{ github.repository }} + + - name: Run Ansible playbook + run: | + ansible-playbook -i tests/inventory/docker-containers.yml tests/playbooks/docker-containers.yml + working-directory: ${{ github.repository }} + + # Debug with tmate on failure when debug logging is enabled. + - if: ${{ failure() && runner.debug == '1' }} + uses: mxschmitt/action-tmate@v3 + timeout-minutes: 20 diff --git a/.gitignore b/.gitignore index b3c9e26..486ed7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ +.ansible +ansible-role-* +*.bak .cache +*.html +*.org +*.orig +*.png __pycache__ +requirements-local.yml +*.swp +*.verb diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..bdfc8e9 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,13 @@ +--- +ignore: + - LICENSE + +# MD013 line-length - Line length +MD013: + line_length: 120 +# MD033 no-inline-html - Inline HTML +MD033: + allowed_elements: [details] +# MD046 code-block-style - Code block style +MD046: + style: consistent diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 768669e..f42758b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,52 @@ +# Notes: +# - Keep the order of the hooks in lexicographical order. --- repos: + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.37.1 + hooks: + - id: yamllint + args: ["-c", ".yamllint", "-s"] + - repo: https://github.com/ansible-community/ansible-lint - rev: v24.7.0 + rev: v25.4.0 hooks: - id: ansible-lint + - repo: https://github.com/aristanetworks/j2lint.git + rev: v1.2.0 + hooks: + - id: j2lint + + - repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + + - repo: https://github.com/gitleaks/gitleaks + rev: v8.24.2 + hooks: + - id: gitleaks + + - repo: https://github.com/igorshubovych/markdownlint-cli.git + rev: v0.44.0 + hooks: + - id: markdownlint + + - repo: https://github.com/psf/black + rev: 24.10.0 + hooks: + - id: black + + - repo: https://github.com/pycqa/flake8 + rev: 7.1.1 + hooks: + - id: flake8 + args: ["--max-line-length=120"] + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-added-large-files - id: check-byte-order-marker @@ -18,11 +57,6 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/igorshubovych/markdownlint-cli.git - rev: v0.41.0 - hooks: - - id: markdownlint - - repo: https://github.com/jumanjihouse/pre-commit-hooks rev: 3.0.0 hooks: @@ -31,7 +65,12 @@ repos: - id: require-ascii - id: script-must-have-extension - - repo: https://github.com/adrienverge/yamllint.git - rev: v1.35.1 + - repo: https://github.com/rhysd/actionlint + rev: v1.7.7 hooks: - - id: yamllint + - id: actionlint + + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7cc338b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,70 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "ansible-lint: check ", + "type": "shell", + "command": "ansible-lint", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "new", + "focus": true + }, + "problemMatcher": [] + }, + { + "label": "ansible-playbook: run test in containers", + "type": "shell", + "command": "ansible-playbook -i tests/inventory/docker-containers.yml tests/playbooks/docker-containers.yml", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "new", + "focus": true + }, + "problemMatcher": [] + }, + { + "label": "molecule: run test", + "type": "shell", + "command": "molecule test", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "new", + "focus": true + }, + "problemMatcher": [] + }, + { + "label": "molecule: syntax check", + "type": "shell", + "command": "molecule syntax", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "new", + "focus": true + }, + "problemMatcher": [] + }, + { + "label": "pre-commit: run all checks", + "type": "shell", + "command": "pre-commit run -a", + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new", + "focus": true + }, + "problemMatcher": [] + } + ] +} diff --git a/.yamllint b/.yamllint index ffac88c..b4e4474 100644 --- a/.yamllint +++ b/.yamllint @@ -2,12 +2,21 @@ extends: default ignore: | + .cache .git rules: + comments: + min-spaces-from-content: 1 + comments-indentation: false + braces: + max-spaces-inside: 1 line-length: max: 120 level: warning + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true truthy: ignore: | ?appveyor.yml diff --git a/LICENSE b/LICENSE index f288702..58ca416 100644 --- a/LICENSE +++ b/LICENSE @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + EA31337 is a collection of free and open source Forex trading robots and libraries for MetaTrader platform. + Copyright (C) 2025 kenorb This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + EA31337 Copyright (C) 2025 kenorb This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..16ba4d7 --- /dev/null +++ b/Pipfile @@ -0,0 +1,16 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +docker = ">=7.1" +pipenv = "*" +molecule = "*" +molecule-docker = "*" +requests = "==2.31.0" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..dc9d657 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,766 @@ +{ + "_meta": { + "hash": { + "sha256": "c562c84e0c96260d614b0f2deb0376928d0054723eaa3550155ef84b4875edaf" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "ansible-compat": { + "hashes": [ + "sha256:25acf1bb49d8072e2737fc109fa9aa981ca9fed17b075af3c812635dad48ba2a", + "sha256:ebf8620021dd25c2d7c3e8e9382efbe7328db58ea396cbbe688ebef80dc8f8ae" + ], + "markers": "python_version >= '3.10'", + "version": "==25.1.4" + }, + "ansible-core": { + "hashes": [ + "sha256:c24cdc2bab19b910bbdb4a1074af5745e16c78c618f15829e7ddcf699f69a510", + "sha256:d2fde719fa8bcaa303ae9b289099c4d49d6566d06e233a47b01de0d4e5438f7b" + ], + "markers": "python_version >= '3.10'", + "version": "==2.17.9" + }, + "attrs": { + "hashes": [ + "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" + ], + "markers": "python_version >= '3.8'", + "version": "==25.3.0" + }, + "bracex": { + "hashes": [ + "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6", + "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.5.post1" + }, + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "cffi": { + "hashes": [ + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.1" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "click-help-colors": { + "hashes": [ + "sha256:b33c5803eeaeb084393b1ab5899dc5476c7196b87a18713045afe76f840b42db", + "sha256:f4cabe52cf550299b8888f4f2ee4c5f359ac27e33bcfe4d61db47785a5cc936c" + ], + "version": "==0.9.4" + }, + "cryptography": { + "hashes": [ + "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390", + "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41", + "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", + "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5", + "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", + "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d", + "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", + "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", + "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", + "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c", + "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a", + "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", + "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", + "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", + "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", + "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5", + "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562", + "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", + "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", + "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", + "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", + "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", + "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", + "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa", + "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb", + "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699", + "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", + "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", + "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", + "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", + "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9", + "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", + "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea", + "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", + "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308" + ], + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==44.0.2" + }, + "distlib": { + "hashes": [ + "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", + "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" + ], + "version": "==0.3.9" + }, + "distro": { + "hashes": [ + "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", + "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2" + ], + "markers": "python_version >= '3.6'", + "version": "==1.9.0" + }, + "docker": { + "hashes": [ + "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", + "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==7.1.0" + }, + "enrich": { + "hashes": [ + "sha256:0a2ab0d2931dff8947012602d1234d2a3ee002d9a355b5d70be6bf5466008893", + "sha256:f29b2c8c124b4dbd7c975ab5c3568f6c7a47938ea3b7d2106c8a3bd346545e4f" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.7" + }, + "filelock": { + "hashes": [ + "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", + "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de" + ], + "markers": "python_version >= '3.9'", + "version": "==3.18.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "jinja2": { + "hashes": [ + "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", + "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.6" + }, + "jsonschema": { + "hashes": [ + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + ], + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" + }, + "markdown-it-py": { + "hashes": [ + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.0" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" + ], + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, + "molecule": { + "hashes": [ + "sha256:48492238888f7a7453c8b493fdc698be9123020211540c30d22bd89b9fac9fdb", + "sha256:c8766907c8b8bfec88d7d1a5df1232bd4606a0c53d9cb95d38e84b455a6993a6" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==25.3.1" + }, + "molecule-docker": { + "hashes": [ + "sha256:195b97673cbc2335cfa6810816de5cbf807507bf350a9d16ca98b224b1647145", + "sha256:d439b075789be700b6594ed73f3254e2a25ed61dcf312d80ab6e718d13bf150e" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pipenv": { + "hashes": [ + "sha256:ab26ee98a7d83d342c1f562ee0564094ab1de091e5d5cec4eeaa95fb600de998", + "sha256:e8ea6105c1cdda7d5c19df7bd6439a006751f3d4e017602c791e7b51314adf84" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2024.4.1" + }, + "platformdirs": { + "hashes": [ + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" + ], + "markers": "python_version >= '3.8'", + "version": "==4.3.6" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "pycparser": { + "hashes": [ + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + ], + "markers": "python_version >= '3.8'", + "version": "==2.22" + }, + "pygments": { + "hashes": [ + "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", + "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" + ], + "markers": "python_version >= '3.8'", + "version": "==2.19.1" + }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, + "referencing": { + "hashes": [ + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" + ], + "markers": "python_version >= '3.9'", + "version": "==0.36.2" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.31.0" + }, + "resolvelib": { + "hashes": [ + "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309", + "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf" + ], + "version": "==1.0.1" + }, + "rich": { + "hashes": [ + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==13.9.4" + }, + "rpds-py": { + "hashes": [ + "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19", + "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c", + "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522", + "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31", + "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf", + "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4", + "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d", + "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b", + "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e", + "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6", + "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6", + "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec", + "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122", + "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf", + "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5", + "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93", + "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed", + "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2", + "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd", + "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5", + "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac", + "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c", + "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70", + "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3", + "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b", + "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5", + "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246", + "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495", + "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace", + "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f", + "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935", + "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64", + "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad", + "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957", + "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a", + "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a", + "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6", + "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef", + "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba", + "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722", + "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10", + "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee", + "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da", + "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b", + "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a", + "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731", + "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce", + "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4", + "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b", + "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707", + "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9", + "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3", + "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa", + "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa", + "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a", + "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57", + "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00", + "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f", + "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f", + "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8", + "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057", + "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017", + "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e", + "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165", + "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428", + "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c", + "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590", + "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4", + "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447", + "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e", + "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc", + "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1", + "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c", + "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6", + "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597", + "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a", + "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d", + "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8", + "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4", + "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35", + "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5", + "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5", + "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc", + "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966", + "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d", + "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef", + "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12", + "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d", + "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4", + "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149", + "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35", + "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae", + "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580", + "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07", + "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219", + "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7", + "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda", + "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013", + "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15", + "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd", + "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06", + "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4", + "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8" + ], + "markers": "python_version >= '3.9'", + "version": "==0.23.1" + }, + "selinux": { + "hashes": [ + "sha256:2a88b337ac46ad0f06f557b2806c3df62421972f766673dd8bf26732fb75a9ea", + "sha256:ecf7add45c939e9dda682c390a2cd0a845c94a4793a2cce9e8870d4ee9501f99" + ], + "markers": "python_version >= '3.9'", + "version": "==0.3.0" + }, + "setuptools": { + "hashes": [ + "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6", + "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4" + ], + "markers": "python_version >= '3.9'", + "version": "==76.0.0" + }, + "subprocess-tee": { + "hashes": [ + "sha256:21942e976715af4a19a526918adb03a8a27a8edab959f2d075b777e3d78f532d", + "sha256:91b2b4da3aae9a7088d84acaf2ea0abee3f4fd9c0d2eae69a9b9122a71476590" + ], + "markers": "python_version >= '3.8'", + "version": "==0.4.2" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "virtualenv": { + "hashes": [ + "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170", + "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac" + ], + "markers": "python_version >= '3.8'", + "version": "==20.29.3" + }, + "wcmatch": { + "hashes": [ + "sha256:0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a", + "sha256:e72f0de09bba6a04e0de70937b0cf06e55f36f37b3deb422dfaf854b867b840a" + ], + "markers": "python_version >= '3.8'", + "version": "==10.0" + } + }, + "develop": {} +} diff --git a/README.md b/README.md index 0862793..a9b5a57 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,84 @@ -# ansible-role-mt-runner +# Ansible Role: MT Runner + +[![CodeRabbit PR Reviews](https://img.shields.io/coderabbit/prs/github/EA31337/ansible-role-mt-runner?utm_source=oss&utm_medium=github&utm_campaign=EA31337%2Fansible-role-mt-runner&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+PR+Reviews)](https://github.com/EA31337/ansible-role-mt-runner/pulls) +[![License](https://img.shields.io/badge/license-GPLv3-brightgreen.svg)](LICENSE) Ansible role to run tests using MT platform. +## Requirements + +This role requires: + +- Ansible +- Python +- Administrative/root access on target hosts +- One of the following operating systems: + - Alpine Linux + - Debian/Ubuntu + - NixOS or systems with Nix package manager + ## Install +### Install from Ansible Galaxy + +To install this role from Ansible Galaxy, run the following command: + +```console +ansible-galaxy install ea31337.mt_runner +``` + +### Install from GitHub + To install this role, you can use the following terminal command: - ansible-galaxy install git+https://github.com/EA31337/ansible-role-mt-runner.git +```shell +ansible-galaxy install git+https://github.com/EA31337/ansible-role-mt-runner.git +``` + +## Role Variables + +For available variables, +check [`defaults/main.yml`](defaults/main.yml). + +## Testing + +### Docker + +Steps to test role on Docker containers. + +1. Install the current role by running the following commands in shell: + + ```shell + ansible-galaxy install -r requirements.yml + jinja2 requirements-local.yml.j2 -D "pwd=$PWD" -o requirements-local.yml + ansible-galaxy install -r requirements-local.yml + ``` + + Alternatively, for development purposes, you can consider using symbolic link, e.g. + + ```shell + ln -vs "$PWD" ~/.ansible/roles/ea31337.mt_runner + ``` + +2. Ensure Docker service (e.g. Docker Desktop) is running. +3. Run playbook from `tests/`: + + ```shell + ansible-playbook -i tests/inventory/docker-containers.yml tests/playbooks/docker-containers.yml + ``` + +### Molecule + +To test using Molecule, run: + +```shell +molecule test +``` + +## License + +GNU GPL v3 + +See: [LICENSE](./LICENSE) + + diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..273a1c6 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,14 @@ +; Config file for Ansible. +; @docs: https://docs.ansible.com/ansible/latest/reference_appendices/config.html +[defaults] +# Use the stdout_callback when running ad-hoc commands. +bin_ansible_callbacks = True +# Leave the 'cows' alone! +nocows = 1 +# Use the built-in default callback with YAML format +stdout_callback = ansible.builtin.default +callback_result_format = yaml + +[diff] +# Always print diff when running (same as always running with -D/--diff). +always = True diff --git a/defaults/main.yml b/defaults/main.yml index 8296b92..0fc8c15 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -22,17 +22,17 @@ mt_runner_bt_mt4_config: FTPEnable: false FTPLogin: anonymous FTPPassiveMode: false - FTPPassword: anonymous + FTPPassword: anonymous # pragma: allowlist secret FTPPath: /inetpub FTPPeriod: 10 FTPServer: ftp.example.com - Login: "{{ ansible_facts.env.MT_RUNNER_MT4_LOGIN | default('12345') }}" - Password: "{{ ansible_facts.env.MT_RUNNER_MT4_PASSWORD | default('12345') }}" + Login: "{{ ansible_facts.env.MT_RUNNER_MT4_LOGIN | default('12345') }}" # pragma: allowlist secret + Password: "{{ ansible_facts.env.MT_RUNNER_MT4_PASSWORD | default('12345') }}" # pragma: allowlist secret Period: M15 Profile: default ProxyEnable: false ProxyLogin: user45 - ProxyPassword: xxx + ProxyPassword: ProxyServer: example.com:3128 ProxyType: HTTP Script: @@ -144,4 +144,4 @@ mt_runner_bt_mt5_config: mt_runner_cmd_prefix: wine mt_runner_get_url_list: [] mt_runner_mt_version: '{{ metatrader_version | default(5) | int }}' -mt_runner_timeout: 120 +mt_runner_timeout: 600 diff --git a/lookup_plugins/decode_utf16.py b/lookup_plugins/decode_utf16.py index f6e9648..fffe220 100755 --- a/lookup_plugins/decode_utf16.py +++ b/lookup_plugins/decode_utf16.py @@ -1,11 +1,8 @@ #!/usr/bin/env python from ansible.errors import AnsibleError -from ansible.module_utils.common.text.converters import to_text, to_native +from ansible.module_utils.common.text.converters import to_native from ansible.plugins.lookup import LookupBase import base64 -import codecs -import logging -import string class LookupModule(LookupBase): diff --git a/meta/main.yml b/meta/main.yml index 2c42f6c..f2982aa 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,19 +1,31 @@ +# Documentation: https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html +# Note: Ensure the list is sorted alphabetically. --- dependencies: - name: ea31337.metatrader scm: git src: https://github.com/EA31337/ansible-role-metatrader.git - version: dev + version: v1.0.3 # This should match version in requirements.yml galaxy_info: - author: EA31337 Ltd + author: kenorb + company: EA31337 Ltd description: | Role to run MetaTrader platform (with Expert Advisors, Script and Indicators) galaxy_tags: + - desktop + - development + - docker + - emulator + - forex + - graphics + - gui - linux + - trading + - ubuntu - windows - issue_tracker_url: https://github.com/EA31337/ansible-role-mt-runner - license: GPLv3 + - wine + license: GPL-3.0-or-later min_ansible_version: "2.7" namespace: ea31337 platforms: @@ -23,7 +35,16 @@ galaxy_info: - name: Debian versions: - all + - bullseye + - buster + - stretch + # - name: NixOS + # versions: + # - all - name: Ubuntu versions: - all + - bionic + - focal + - xenial role_name: mt_runner diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index a8e26ac..20bb55d 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -1,29 +1,28 @@ --- - name: Converge hosts: all - tasks: - - name: Include main role - ansible.builtin.import_role: - name: ea31337.mt_runner - vars: - mt_runner_bt_mt5_config: - Common: - Login: "{{ ansible_facts.env.MT_RUNNER_MT5_LOGIN }}" - Password: "{{ ansible_facts.env.MT_RUNNER_MT5_PASSWORD }}" - Server: MetaQuotes-Demo - Tester: - Deposit: 10000 - ExecutionMode: 0 - Expert: EA31337-Libre-v1.013.ex5 - FromDate: 2024.01.01 - Leverage: 1:500 - Login: "{{ ansible_facts.env.MT_RUNNER_MT5_LOGIN }}" - Model: 1 - Report: report.html - ReplaceReport: 1 - ShutdownTerminal: 1 - Symbol: EURUSD - ToDate: 2024.01.11 - mt_runner_get_url_list: - - dest: "{{ mt_runner_mt_path }}/MQL5/Experts" - url: https://github.com/EA31337/EA31337-Libre/releases/download/v1.013/EA31337-Libre-v1.013.ex5 + gather_facts: true + roles: + - role: ea31337.mt_runner + vars: + mt_runner_bt_mt5_config: + Common: + Login: "{{ ansible_facts.env.MT_RUNNER_MT5_LOGIN }}" + Password: "{{ ansible_facts.env.MT_RUNNER_MT5_PASSWORD }}" + Server: MetaQuotes-Demo + Tester: + Deposit: 10000 + ExecutionMode: 0 + Expert: EA31337-Libre-v1.013.ex5 + FromDate: 2024.01.01 + Leverage: 1:500 + Login: "{{ ansible_facts.env.MT_RUNNER_MT5_LOGIN }}" + Model: 1 + Report: report.html + ReplaceReport: 1 + ShutdownTerminal: 1 + Symbol: EURUSD + ToDate: 2024.01.11 + mt_runner_get_url_list: + - dest: "{{ mt_runner_mt_path }}/MQL5/Experts" + url: https://github.com/EA31337/EA31337-Libre/releases/download/v1.013/EA31337-Libre-v1.013.ex5 diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index f2e3f4a..f587499 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -1,10 +1,21 @@ --- +# Molecule configuration file. +# Dependency management (download roles/collections) +# Note: Keep YAML keys sorted alphabetically. +dependency: + name: galaxy + options: + ignore-certs: false + ignore-errors: false + role-file: requirements.yml + requirements-file: requirements.yml driver: name: docker lint: | set -e - # yamllint . - # ansible-lint + yamllint . + molecule syntax + ansible-lint platforms: - env: MT_RUNNER_MT5_LOGIN: "${MT_RUNNER_MT5_LOGIN:-12345}" @@ -16,11 +27,52 @@ platforms: provisioner: config_options: defaults: + host_key_checking: false + # Use the built-in default callback with result_format instead of community.general.yaml remote_tmp: /tmp/.ansible-tmp-$${USER} - name: ansible + result_format: yaml + stdout_callback: ansible.builtin.default + verbosity: 1 + env: + ANSIBLE_FORCE_COLOR: "1" + ANSIBLE_LOAD_CALLBACK_PLUGINS: "1" inventory: group_vars: all: wine_install_winetricks: true + wine_release: stable + host_vars: + nixos-latest: + ansible_python_interpreter: /root/.nix-profile/bin/python3 + ssh_connection: + pipelining: true + name: ansible + options: + diff: true + force-handlers: true + playbooks: + cleanup: cleanup.yml + converge: converge.yml + create: create.yml + destroy: destroy.yml + prepare: prepare.yml + side_effect: side_effect.yml + verify: verify.yml + +scenario: + name: default + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - side_effect + - verify + - cleanup + - destroy verifier: name: ansible diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index e41dcfd..16f992d 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -1,4 +1,40 @@ --- -- name: Prepare - hosts: all +- name: Prepare hosts + hosts: "all:!nixos*" gather_facts: false + tasks: + + - name: Install Python for Ansible + ansible.builtin.raw: | + if command -v python3 || command -v python; then + exit 0 + elif command -v apk; then + apk add --no-cache python3 py3-pip + elif command -v apt; then + apt -y update && apt install -y python3-minimal + elif command -v dnf; then + dnf install -y python3 + elif command -v zypper; then + zypper --non-interactive install python3 + else + echo "No supported package manager found" >&2 + exit 1 + fi + changed_when: false + +- name: Prepare NixOS hosts + hosts: "nixos*" + gather_facts: false + tasks: + + - name: Install Python for Ansible on NixOS + ansible.builtin.raw: | + if command -v python3 || command -v python; then + exit 0 + fi + mkdir -p /etc/nix + printf "sandbox = false\n" > /etc/nix/nix.conf + export NIX_CONFIG="sandbox = false" + nix-env --option sandbox false \ + -iA nixpkgs.python3 nixpkgs.python3Packages.pip + changed_when: false diff --git a/molecule/default/requirements.yml b/molecule/default/requirements.yml deleted file mode 100644 index d212914..0000000 --- a/molecule/default/requirements.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Molecule's requirements file. ---- -- name: ea31337.metatrader - scm: git - src: https://github.com/EA31337/ansible-role-metatrader.git - version: dev diff --git a/molecule/mt4/molecule.yml b/molecule/mt4/molecule.yml index 0e74980..f02898a 100644 --- a/molecule/mt4/molecule.yml +++ b/molecule/mt4/molecule.yml @@ -1,10 +1,21 @@ --- +# Molecule configuration file. +# Dependency management (download roles/collections) +# Note: Keep YAML keys sorted alphabetically. +dependency: + name: galaxy + options: + ignore-certs: false + ignore-errors: false + role-file: requirements.yml + requirements-file: requirements.yml driver: name: docker lint: | set -e - # yamllint . - # ansible-lint + yamllint . + molecule syntax + ansible-lint platforms: - env: MT_RUNNER_MT4_LOGIN: "${MT_RUNNER_MT4_LOGIN:-12345}" @@ -16,11 +27,32 @@ platforms: provisioner: config_options: defaults: + host_key_checking: false + # Use the built-in default callback with result_format instead of community.general.yaml remote_tmp: /tmp/.ansible-tmp-$${USER} - name: ansible + result_format: yaml + stdout_callback: ansible.builtin.default + verbosity: 1 + env: + ANSIBLE_FORCE_COLOR: "1" + ANSIBLE_LOAD_CALLBACK_PLUGINS: "1" inventory: group_vars: all: wine_install_winetricks: true + wine_release: stable + host_vars: + nixos-latest: + ansible_python_interpreter: /root/.nix-profile/bin/python3 + ssh_connection: + pipelining: true + name: ansible + options: + diff: true + force-handlers: true + playbooks: + converge: ../default/converge.yml + prepare: ../default/prepare.yml + verify: ../default/verify.yml verifier: name: ansible diff --git a/molecule/mt4/requirements.yml b/molecule/mt4/requirements.yml deleted file mode 100644 index d212914..0000000 --- a/molecule/mt4/requirements.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Molecule's requirements file. ---- -- name: ea31337.metatrader - scm: git - src: https://github.com/EA31337/ansible-role-metatrader.git - version: dev diff --git a/molecule/mt5-ea/molecule.yml b/molecule/mt5-ea/molecule.yml index f2e3f4a..e6a9476 100644 --- a/molecule/mt5-ea/molecule.yml +++ b/molecule/mt5-ea/molecule.yml @@ -1,10 +1,21 @@ --- +# Molecule configuration file. +# Dependency management (download roles/collections) +# Note: Keep YAML keys sorted alphabetically. +dependency: + name: galaxy + options: + ignore-certs: false + ignore-errors: false + role-file: requirements.yml + requirements-file: requirements.yml driver: name: docker lint: | set -e - # yamllint . - # ansible-lint + yamllint . + molecule syntax + ansible-lint platforms: - env: MT_RUNNER_MT5_LOGIN: "${MT_RUNNER_MT5_LOGIN:-12345}" @@ -16,11 +27,28 @@ platforms: provisioner: config_options: defaults: + host_key_checking: false + # Use the built-in default callback with result_format instead of community.general.yaml remote_tmp: /tmp/.ansible-tmp-$${USER} - name: ansible + result_format: yaml + stdout_callback: ansible.builtin.default + verbosity: 1 + env: + ANSIBLE_FORCE_COLOR: "1" + ANSIBLE_LOAD_CALLBACK_PLUGINS: "1" inventory: group_vars: all: wine_install_winetricks: true + wine_release: stable + host_vars: + nixos-latest: + ansible_python_interpreter: /root/.nix-profile/bin/python3 + ssh_connection: + pipelining: true + name: ansible + options: + diff: true + force-handlers: true verifier: name: ansible diff --git a/molecule/mt5-ea/requirements.yml b/molecule/mt5-ea/requirements.yml deleted file mode 100644 index d212914..0000000 --- a/molecule/mt5-ea/requirements.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Molecule's requirements file. ---- -- name: ea31337.metatrader - scm: git - src: https://github.com/EA31337/ansible-role-metatrader.git - version: dev diff --git a/meta/requirements.txt b/molecule/requirements.txt similarity index 71% rename from meta/requirements.txt rename to molecule/requirements.txt index 108a51d..66589a4 100644 --- a/meta/requirements.txt +++ b/molecule/requirements.txt @@ -1,5 +1,7 @@ # Python's requirements # Usage: pip install -r requirements.txt -docker==4.4 +docker>=7.1 +pipenv molecule molecule-docker +requests==2.31.0 diff --git a/requirements-local.yml.j2 b/requirements-local.yml.j2 new file mode 100644 index 0000000..fb2edcd --- /dev/null +++ b/requirements-local.yml.j2 @@ -0,0 +1,11 @@ +# A file containing a list of collections to be installed. +# Usage: +# jinja2 requirements-local.yml.j2 -D "pwd=$PWD" -o requirements-local.yml +# ansible-galaxy install -r requirements-local.yml +--- +roles: + # Use a static or shell-expanded path; Jinja2 is not supported here + - name: ea31337.mt_runner + scm: git + src: "file://{{ pwd }}" + version: HEAD diff --git a/requirements.yml b/requirements.yml index b632fc0..17a363c 100644 --- a/requirements.yml +++ b/requirements.yml @@ -3,9 +3,15 @@ # ansible-galaxy install -r requirements.yml --- collections: - - name: community.general # For unixy. + - name: community.docker + - name: community.general # Required for apk, from_ini and supervisorctl modules. + version: ">=6.0.0" + - name: community.windows + - name: ansible.windows + roles: - name: ea31337.metatrader scm: git src: https://github.com/EA31337/ansible-role-metatrader.git - version: dev + # This should match version in meta/main.yml + version: v1.0.3 diff --git a/tasks/main.yml b/tasks/main.yml index 7d39fea..215ee5a 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -122,7 +122,7 @@ {{ mt_runner_mt_path ~ '/logs/' ~ ('%Y%m%d' | strftime(ansible_date_time.epoch | int)) }}.log sleep: 10 state: present - timeout: 60 + timeout: 120 register: task_wait_for_terminal_logs - name: Prints terminal log file (MT4) ansible.builtin.command: diff --git a/templates/4/ea.ini.j2 b/templates/4/ea.ini.j2 index d767c5d..07a4575 100644 --- a/templates/4/ea.ini.j2 +++ b/templates/4/ea.ini.j2 @@ -1,7 +1,7 @@ -{%- for key, value in mt_runner_bt_mt4_common.items() %} +{% for key, value in mt_runner_bt_mt4_common.items() %} {{ key ~ '=' ~ value }} -{%- endfor -%} +{% endfor %} foo=bar diff --git a/templates/4/tester.ini.j2 b/templates/4/tester.ini.j2 index a820a97..1ad5ba5 100644 --- a/templates/4/tester.ini.j2 +++ b/templates/4/tester.ini.j2 @@ -2,6 +2,6 @@ ; Terminal Configuration at Startup ; See: http://www.metatrader4.com/en/trading-platform/help/service/start_conf_file -{%- for key, value in mt_runner_bt_mt4_config.items() %} +{% for key, value in mt_runner_bt_mt4_config.items() %} {{ key ~ '=' ~ (value or '') }} -{%- endfor -%} +{% endfor %} diff --git a/templates/5/tester.ini.j2 b/templates/5/tester.ini.j2 index a850711..58b937b 100644 --- a/templates/5/tester.ini.j2 +++ b/templates/5/tester.ini.j2 @@ -2,9 +2,9 @@ ; Terminal Configuration at Startup ; @see: https://www.metatrader5.com/en/terminal/help/start_advanced/start -{%- for group_key, group in mt_runner_bt_mt5_config.items() %} +{% for group_key, group in mt_runner_bt_mt5_config.items() %} [{{ group_key }}] -{%- for key, value in group.items() %} -{{ key ~ '=' ~ (value or '') }} -{%- endfor -%} -{%- endfor -%} +{% for key, value in group.items() %} +{{ key ~ '=' ~ (value or '') }} +{% endfor %} +{% endfor %} diff --git a/tests/inventory/docker-containers.yml b/tests/inventory/docker-containers.yml new file mode 100644 index 0000000..ce30c38 --- /dev/null +++ b/tests/inventory/docker-containers.yml @@ -0,0 +1,30 @@ +--- +all: + children: + docker_containers: + hosts: + mt-runner-on-ubuntu-latest: + ansible_connection: docker + ansible_host: mt-runner-on-ubuntu-latest + ansible_python_interpreter: /usr/bin/python3 + mt-runner-on-ubuntu-noble: + ansible_connection: docker + ansible_host: mt-runner-on-ubuntu-noble + ansible_python_interpreter: /usr/bin/python3 + mt-runner-on-ubuntu-jammy: + ansible_connection: docker + ansible_host: mt-runner-on-ubuntu-jammy + ansible_python_interpreter: /usr/bin/python3 + mt-runner-on-debian-latest: + ansible_connection: docker + ansible_host: mt-runner-on-debian-latest + ansible_python_interpreter: /usr/bin/python3 + mt-runner-on-alpine-latest: + ansible_connection: docker + ansible_host: mt-runner-on-alpine-latest + ansible_python_interpreter: /usr/bin/python3 + mt-runner-on-nixos-latest: + ansible_connection: docker + ansible_distribution: NixOS + ansible_host: mt-runner-on-nixos-latest + ansible_python_interpreter: /root/.nix-profile/bin/python3 diff --git a/tests/playbooks/docker-containers.yml b/tests/playbooks/docker-containers.yml new file mode 100644 index 0000000..472d46c --- /dev/null +++ b/tests/playbooks/docker-containers.yml @@ -0,0 +1,95 @@ +--- +- name: Configure Docker container + # Note: Since facts are not gathered, we're checking for ansible_user_id, connection_user or UID instead. + become: >- + {{ (connection_user is defined and connection_user != 'root') + or (ansible_user_id is defined and ansible_user_id != 'root') + or (lookup('env', 'UID') | int != 0) + }} + # Use su as become_method as sudo is not available in all containers. + become_method: ansible.builtin.su + gather_facts: false + hosts: docker_containers + + pre_tasks: + - name: Ensure container is started + community.docker.docker_container: + name: "{{ inventory_hostname }}" + image: "{{ container_image }}" + state: started + command: sleep infinity + delegate_to: localhost + vars: + # Use system Python with requests installed for controller-side Docker modules. + ansible_python_interpreter: "{{ controller_python }}" + + - name: Wait for container to be ready + community.docker.docker_container_info: + name: "{{ inventory_hostname }}" + register: container_info + until: + - container_info is defined + - container_info.container.State.Running | default(false) | bool + changed_when: false + delay: 2 + delegate_to: localhost + retries: 10 + vars: + # Use system Python with requests installed for controller-side Docker modules. + ansible_python_interpreter: "{{ controller_python }}" + + - name: Install Python 3 on Alpine + ansible.builtin.raw: | + test -e "{{ ansible_python_interpreter }}" || (apk update && apk add --no-cache python3 py3-pip) + changed_when: false + when: container_image is search("alpine") + + - name: Install Python 3 on Ubuntu/Debian + ansible.builtin.raw: | + test -e "{{ ansible_python_interpreter }}" || (apt-get update && apt-get install -y python3 python3-pip) + changed_when: false + when: container_image is search("ubuntu") or container_image is search("debian") + + - name: Gather facts + ansible.builtin.setup: + + - name: Install Python packages for Ubuntu/Debian + ansible.builtin.apt: + name: + - python3 + - python3-pip + - python3-setuptools + state: present + update_cache: true + when: container_image is search("ubuntu") or container_image is search("debian") + + tags: always + vars: + controller_python: "{{ ansible_playbook_python }}" + container_image_map: + mt-runner-on-alpine-latest: alpine:latest + mt-runner-on-debian-latest: debian:latest + mt-runner-on-nixos-latest: nixos/nix + mt-runner-on-ubuntu-jammy: ubuntu:jammy + mt-runner-on-ubuntu-latest: ubuntu:latest + mt-runner-on-ubuntu-noble: ubuntu:noble + container_image: "{{ container_image_map[inventory_hostname] | default('ubuntu:latest') }}" + +- name: Install ea31337.mt_runner role on all containers + hosts: docker_containers + gather_facts: true + tags: always + vars: + controller_python: "{{ ansible_playbook_python }}" + tasks: + - name: Installs ea31337.mt_runner role + ansible.builtin.import_role: + name: ea31337.mt_runner + + post_tasks: + - name: Stop Docker containers + community.docker.docker_container: + name: "{{ inventory_hostname }}" + state: stopped + delegate_to: localhost + failed_when: false diff --git a/vars/main.yml b/vars/main.yml index 5fdff76..59e1365 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,4 +1,6 @@ --- +# Vars file for mt_runner role. +# Note: Keep YAML keys sorted alphabetically. mt_runner_mt_files: 4: terminal: terminal.exe