DevOps инженеры часто пишут скрипты и консольные утилиты на python, которые хочется распространять не в первозданном виде, а в качестве пакета, поставив который из приватного registry вашей компании, на машине сразу появился бинарный файл для использования утилиты.
Сначала заведем тестовый репозиторий в gitlab с такой структурой проекта:
Наш тестовый проект будет уметь читать переданный через аргумент CLI yaml файлик и выводить его в консоли.
Структура проекта:
src — наш пакет тут.
test_package — имя пакета. Внутри этой директории лежит код.
depends — директория(модуль) с нашим вспомогательным кодом, который нужен для пакета.
Все файлы __init__.py в данном примере пустые и нужны, только чтобы python понял, что это пакет, а не просто директория. Также считается хорошим тоном заводить эти файлы, пусть и пустые.
Рассмотрим main.py:
from depends.yaml_reader import YamlReader
from depends.cli import CommandLineParser
args = CommandLineParser.create_parser().parse_args()
cmd_args = CommandLineParser(**vars(args))
read_yaml = YamlReader(cmd_args.file)
def main():
yaml_data = read_yaml.read_yaml()
print(yaml_data)
if __name__ == "__main__":
main()
Тут импортируем нужные нам пакеты и создаем CLI, читаем yaml и «принтуем» его.
cli.py:
import argparse
from dataclasses import dataclass
@dataclass
class CommandLineParser:
file: str
@classmethod
def create_parser(cls):
parser = argparse.ArgumentParser(description="Test CMD")
parser.add_argument(
"-f", "--file", dest="file",
required=True,
help="Path to yaml file"
)
return parser
Это класс, в котором мы реализуем на CLI. В тестовом варианте всего один аргумент, этого достаточно.
yaml_reader.py:
import yaml
from dataclasses import dataclass
@dataclass
class YamlReader:
yaml_path: str
def read_yaml(self):
with open(self.yaml_path, "r") as yaml_file:
data = yaml.safe_load(yaml_file)
return data
Класс который принимает на вход путь из аргумента CLI до нашего yaml файлика.
setup.py:
from setuptools import setup, find_packages
setup(
name='test_package',
author="Trusikhin Andrei",
version='0.1',
description="Test packages",
packages=find_packages(where='src/test_package'),
package_dir={'': 'src/test_package'},
install_requires=[
"PyYAML",
"requests"
],
entry_points={
'console_scripts': ['cmd_test = test_package.main:main']
},
python_requires='>=3.8'
)
Здесь описано то, как мы будем собирать наш пакет с использованием setuptools. Обязательно используем метод find_packages для автоматического поиска всех пакетов и указываем директорию поиска.
entry_points — это точка входа в нашу консольную тулзу. cmd_test — бинарь, который прилетит вместе с установкой пакета и автоматически будет добавлен в PATH переменную. Он равняется имени пакета, функции и файлу из которого вызываем функцию. В нашем случае это main:main.
Файл requirements.txt:
setuptools
wheel
twine
И тестовый test.yaml:
test: test
Сборка пакета:
Устанавливаем нужные зависимости:
pip3 install -r src/requirements.txt
Собираем пакет:
python3 src/setup.py sdist bdist_wheel
После сборки внутри директории dist будут нужные нам файлы:
Уже сейчас мы можем установить пакет вот так:
pip3 install dist/test_package-0.1-py3-none-any.whl
И использовать нашу утилиту:
cmd_test -f test.yaml
Публикация пакета в gitlab registry:
Чтобы опубликовать пакет, нужно авторизоваться. Для этого существует далеко не один вариант, я же использую авторизацию через deploy_token. Когда определен deploy token в проекте, при запуске pipeline автоматически становятся доступны переменные CI_DEPLOY_USERNAME и CI_DEPLOY_PASSWORD.
Также можно использовать и CI_JOB_TOKEN, это временный токен, который существует во время выполнения pipeline и он обладает правами пользователя, который этот pipeline запустил.
Создать deploy token можно в Settings — Repository — Deploy tokens:
Токен создан, креды получены. Теперь мы можем опубликовать наш пакет:
TWINE_PASSWORD=${CI_DEPLOY_PASSWORD} TWINE_USERNAME=${CI_DEPLOY_USERNAME} python3 -m twine upload --repository ci_generator --repository-url http://localhost:8080/projects/1/packages/pypi dist/* --verbose
После этого мы можем увидеть его в gitlab package registry:
Чтобы скачать пакет из registry нужно воспользоваться командой:
pip install test-package --index-url http://__token__:<your_personal_token>@localhost:8080/api/v4/projects/1/packages/pypi/simple
Таким образом можно распространять python скрипты удобным способом.