diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 73e24cf6626d8399d1f86a9f99a3f7dcca5dd60e..ac219a78d332db7116531f0207ee88888611d64d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,7 @@ include: - local: 'templates/python/code_quality/isort/isort.yml' - local: 'templates/python/code_quality/mypy/mypy.yml' - local: 'templates/python/code_quality/ruff/ruff.yml' + - local: 'templates/python/dependency_management/requirements-compile/requirements-compile.yml' python_install: extends: @@ -57,3 +58,11 @@ ruff: needs: [ "python_install" ] variables: PROJECT_PATH: "tests/ruff_project" + +requirements-compile: + stage: templates + needs: [ "python_install" ] + variables: + PROJECT_PATH: "tests/requirements-compile_project" + REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements.in" + OUTPUT_FILE_PATH: "${PROJECT_PATH}/requirements.txt" diff --git a/AUTHORS.rst b/AUTHORS.rst index bddd8b1893f285517eb9c8181d41b16ee5c3a3e2..2d3d9d2fcc3afa66ab618d849c5c9484dbbc33ef 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -10,4 +10,4 @@ Development Lead Contributors ------------ -None yet. Why not be the first? +* Simon Desnoe <0d3s3n@gmail.com> diff --git a/pyproject.toml b/pyproject.toml index 8e52531e530ce394f08c59a2e551d8907b3c3915..61f7768f48ea66d41bffd1193571667dee581593 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,8 @@ dependencies = [ [project.optional-dependencies] QUALITY = [ + "black", + "mypy", "pre-commit", ] @@ -29,3 +31,10 @@ QUALITY = [ strict-config = true plugins.line-length.enabled = false +[[tool.mypy.overrides]] +module = [ + "packaging.requirements", + "packaging.specifiers", + "packaging", +] +ignore_missing_imports = true \ No newline at end of file diff --git a/r2_metadata/requirements-compile.r2.yml b/r2_metadata/requirements-compile.r2.yml new file mode 100644 index 0000000000000000000000000000000000000000..729ed0f49f8e9aa72e58ceb0ea4abf8997e16675 --- /dev/null +++ b/r2_metadata/requirements-compile.r2.yml @@ -0,0 +1,16 @@ +files: + template: ../templates/python/dependency_management/requirements-compile/requirements-compile.yml + documentation: ../templates/python/dependency_management/requirements-compile/README.md + changelog: ../templates/python/dependency_management/requirements-compile/CHANGELOG.md +data: + description: "Run pip-compile to generate a requirements.txt and create a merge + request on your repository with the updated requirements.txt" + icon: âš« + public: true + labels: + - Utilities + - Dependency management + - Gitlab + - Python + license: MIT + deprecated: false diff --git a/templates/python/dependency_management/requirements-compile/CHANGELOG.md b/templates/python/dependency_management/requirements-compile/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..31e92f039b5e5f9a1c909308d5e054b6276513e8 --- /dev/null +++ b/templates/python/dependency_management/requirements-compile/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this job will be documented in this file + +## [0.1.0] - 2023-09-05 + +* Initial version diff --git a/templates/python/dependency_management/requirements-compile/README.md b/templates/python/dependency_management/requirements-compile/README.md new file mode 100644 index 0000000000000000000000000000000000000000..45497f5dedbe30b9c90db9f47ea4376171b8751e --- /dev/null +++ b/templates/python/dependency_management/requirements-compile/README.md @@ -0,0 +1,44 @@ +# requirements-compile template + +## Objective + +The objective of the `requirements-compile` job is to provide a way to update the +requirements.txt file and create a merge request on a Gitlab instance. This reusable job +can help speed up other jobs creation and ensure consistent configuration across CI +jobs. + +## How to use it + +1. Include the requirements-compile template in your CI/CD configuration (see quick use + above). +2. Create a job that extend the `requirements-compile` job template. +3. If you need to customize the job, check + the [jobs customization](https://docs.r2devops.io/get-started/use-templates/#job-templates-customization). + +## Variables + +| Name | Description | Default | +|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------| +| `PROJECT_PATH` | The path to the project root directory. | `"."` | +| `REQUIREMENTS_FILE_PATH` | the path to the requirements file. | `"${PROJECT_PATH}/requirements.txt"` | +| `IMAGE_TAG` | The default tag for the docker image. See [Python Docker Official Image](https://hub.docker.com/_/python) for supported tags and respective Dockerfile links. | `"latest"` | +| `GITLAB_API_URL` | The host name of the GitLab instance | `${CI_SERVER_HOST}` | + +## Example of use + +```yaml +include: + # Include the python_install job template (don't forget to replace the version tag) + - remote: 'https://api.r2devops.io/job/r/gitlab/dorianturba/r2devops_catalog/r2_metadata/requirements-compile@0.1.0.yaml' + +requirements311: + extends: + - .requirements-compile # extends the python_install job template + stage: dependency_management + variables: + REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements-py312.txt" # override the default REQUIREMENTS_FILE_PATH variable + IMAGE_TAG: "3.12" # override the default IMAGE_TAG variable + GITLAB_API_URL: "gitlab.example.com" # override the default GITLAB_API_URL + script: + - !reference [ script ] # reuse the script from the requirements-compile job template +``` diff --git a/templates/python/dependency_management/requirements-compile/requirements-compile.yml b/templates/python/dependency_management/requirements-compile/requirements-compile.yml new file mode 100644 index 0000000000000000000000000000000000000000..c2b1b388e6108cbae47a1827aab05e462cf35c20 --- /dev/null +++ b/templates/python/dependency_management/requirements-compile/requirements-compile.yml @@ -0,0 +1,51 @@ +include: + - remote: 'https://api.r2devops.io/job/r/gitlab/dorianturba/r2devops_catalog/r2_metadata/python_install@latest.yaml' + +requirements-compile: + extends: + - .python_install + stage: build + image: python:${IMAGE_TAG} + + variables: + PYTHON_SETUP: pip install pip-tools requirements-compare + GITLAB_API_URL: "${CI_SERVER_HOST}" + REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements.in" + OUTPUT_FILE_PATH: "${PROJECT_PATH}/requirements${IMAGE_TAG}.txt" + CI_DEBUG_TRACE: "true" + + script: + - !reference [.python_install, script] + - DEPS_BRANCH="requirements-compile/requirements-txt/$(date +%s)" + - | + COMMIT_MESSAGE="build(deps): bump new versions" + - $([ -f ${OUTPUT_FILE_PATH} ]) && ACTION="update" || ACTION="create" + - pip-compile --quiet --strip-extras -o ${OUTPUT_FILE_PATH} ${REQUIREMENTS_FILE_PATH} + - if [ -n "$(git status --porcelain ${OUTPUT_FILE_PATH})" ]; then + - | + curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \ + --form "branch=$DEPS_BRANCH" \ + --form "ref=${CI_DEFAULT_BRANCH}" \ + "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/branches" + - | + curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \ + --form "branch=$DEPS_BRANCH" \ + --form "commit_message=$COMMIT_MESSAGE" \ + --form "actions[][action]=$ACTION" \ + --form "actions[][file_path]=${OUTPUT_FILE_PATH}" \ + --form "actions[][content]=<${OUTPUT_FILE_PATH}" \ + "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/commits" + - requirements_compare ${OUTPUT_FILE_PATH} # Debug + - requirements_compare ${OUTPUT_FILE_PATH} > description.md + - | + curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \ + --form "source_branch=$DEPS_BRANCH" \ + --form "target_branch=${CI_DEFAULT_BRANCH}" \ + --form "title=$COMMIT_MESSAGE" \ + --form "description=<description.md" \ + "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/merge_requests" + - fi + + + + diff --git a/tests/flake8_project/src/flake8_project/__init__.py b/tests/flake8_project/src/flake8_project/__init__.py index 58505af1f84165e36769758d2fe06f4cdc2b1a0e..22ee9155c7c60b928c68eaf1fdb321ed3f638a83 100644 --- a/tests/flake8_project/src/flake8_project/__init__.py +++ b/tests/flake8_project/src/flake8_project/__init__.py @@ -1,3 +1,3 @@ from flake8_project.main import main -__all__ = ['main'] +__all__ = ["main"] diff --git a/tests/flake8_project/src/flake8_project/main.py b/tests/flake8_project/src/flake8_project/main.py index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644 --- a/tests/flake8_project/src/flake8_project/main.py +++ b/tests/flake8_project/src/flake8_project/main.py @@ -7,5 +7,5 @@ def main() -> bool: return True -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/tests/isort_project/src/isort_project/z_module.py b/tests/isort_project/src/isort_project/z_module.py index 651a32811b82c11d6e60c6021cddb6ff34008867..b8f1ab80d341118568895ad2e3264e9166bd6219 100644 --- a/tests/isort_project/src/isort_project/z_module.py +++ b/tests/isort_project/src/isort_project/z_module.py @@ -1,2 +1,2 @@ def barfoo(): - ... \ No newline at end of file + ... diff --git a/tests/pytest_project/src/pytest_project/__init__.py b/tests/pytest_project/src/pytest_project/__init__.py index d4cc63e287d1f9b8e3f12a55c9a24e34eb3241c3..c835af4b921fc971797af114b2008373041b26eb 100644 --- a/tests/pytest_project/src/pytest_project/__init__.py +++ b/tests/pytest_project/src/pytest_project/__init__.py @@ -1,3 +1,3 @@ from pytest_project.main import main -__all__ = ['main'] +__all__ = ["main"] diff --git a/tests/pytest_project/src/pytest_project/main.py b/tests/pytest_project/src/pytest_project/main.py index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644 --- a/tests/pytest_project/src/pytest_project/main.py +++ b/tests/pytest_project/src/pytest_project/main.py @@ -7,5 +7,5 @@ def main() -> bool: return True -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/tests/python_install_project/src/python_install_project/__init__.py b/tests/python_install_project/src/python_install_project/__init__.py index d4cc63e287d1f9b8e3f12a55c9a24e34eb3241c3..c835af4b921fc971797af114b2008373041b26eb 100644 --- a/tests/python_install_project/src/python_install_project/__init__.py +++ b/tests/python_install_project/src/python_install_project/__init__.py @@ -1,3 +1,3 @@ from pytest_project.main import main -__all__ = ['main'] +__all__ = ["main"] diff --git a/tests/python_install_project/src/python_install_project/main.py b/tests/python_install_project/src/python_install_project/main.py index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644 --- a/tests/python_install_project/src/python_install_project/main.py +++ b/tests/python_install_project/src/python_install_project/main.py @@ -7,5 +7,5 @@ def main() -> bool: return True -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/tests/requirements-compile_project/requirements.in b/tests/requirements-compile_project/requirements.in new file mode 100644 index 0000000000000000000000000000000000000000..f2293605cf1b01dca72aad0a15c45b72ed5429a2 --- /dev/null +++ b/tests/requirements-compile_project/requirements.in @@ -0,0 +1 @@ +requests diff --git a/tests/requirements-compile_project/test_requirements.in b/tests/requirements-compile_project/test_requirements.in new file mode 100644 index 0000000000000000000000000000000000000000..e079f8a6038dd2dc8512967540f96ee0de172067 --- /dev/null +++ b/tests/requirements-compile_project/test_requirements.in @@ -0,0 +1 @@ +pytest diff --git a/tests/ruff_project/src/ruff_project/__init__.py b/tests/ruff_project/src/ruff_project/__init__.py index 58505af1f84165e36769758d2fe06f4cdc2b1a0e..22ee9155c7c60b928c68eaf1fdb321ed3f638a83 100644 --- a/tests/ruff_project/src/ruff_project/__init__.py +++ b/tests/ruff_project/src/ruff_project/__init__.py @@ -1,3 +1,3 @@ from flake8_project.main import main -__all__ = ['main'] +__all__ = ["main"] diff --git a/tests/ruff_project/src/ruff_project/main.py b/tests/ruff_project/src/ruff_project/main.py index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644 --- a/tests/ruff_project/src/ruff_project/main.py +++ b/tests/ruff_project/src/ruff_project/main.py @@ -7,5 +7,5 @@ def main() -> bool: return True -if __name__ == '__main__': +if __name__ == "__main__": main()