Auto Deploying Python PyPI Package with Gitlab CI/CD Simplified.

Python Package Index abbreviated as "PyPI" is a third-party software repository for python.

Auto Deploying Python PyPI Package with Gitlab CI/CD Simplified.
Gitlab CI/CD Auto Deployment to PyPI

Python is a great tool for the automation of tasks, web development, IoT, AI, robotics, and several other fields.
It’s among the top 5 most-used programming languages in the world. The reason for the popularity of Python is because of the general approach of Python which emphasizes code readability and the thousands of Python packages available.

It makes sense to understand how to create your package, this way you can share your codes with the world or even contribute your codes to open-source packages that have been essential in your programming journey.

Python Package Index abbreviated as "PyPI" is a third-party software repository for Python. Anyone with the might and will can publish their packages on PyPi which anyone in the world can install and use.

Creating Package Locally and Deploying to PyPI

Run the following command to upgrade pip and ensure you are using the latest pip package.

python3 -m pip install --upgrade pip

upgrade pip

Structuring Your Project

We will be structuring our code as below.

packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── setup.cfg
├── src/
│   └── example_package/
│       ├── __init__.py
│       └── example.py
└── tests/

The package __init__.py is required to import the directory as a package, and should be empty.

File: Example.py

This is where we write our Python module. In our case, the module does simple addition.

def add_one(number):
    return number + 1

Simple addition

File: pyproject. toml

This tells build tools pip and build what is required to build your project in our case we’ll use setuptools.

[build-system]
requires = [
    "setuptools>=42",
    "wheel"
]
build-backend = "setuptools.build_meta"

File: setup.cfg

This gives more information to setuptools about the package.

NB: Change the name to include your username; this ensures that you have a unique package name and that your package doesn’t conflict with packages uploaded by other people following this tutorial

[metadata]
name = example-pkg-YOUR-USERNAME-HERE
version = 0.0.1
author = Example Author
author_email = author@example.com
description = A small example package
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/pypa/sampleproject
project_urls =
    Bug Tracker = https://github.com/pypa/sampleproject/issues
classifiers =
    Programming Language :: Python :: 3
    License :: OSI Approved :: MIT License
    Operating System :: OS Independent

[options]
package_dir =
    = src
packages = find:
python_requires = >=3.6

[options.packages.find]
where = src

File: README

# Example Package

This is a simple example package. You can use
[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

File: LICENSE

Copyright (c) 2018 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Generating Distribution and Publishing Locally

You will need a PyPI account for this. So go ahead and create a PyPI account. https://pypi.org/ .

To securely upload your project, you’ll need a PyPI API token. Create one at https://pypi.org/manage/account/#api-tokens, setting the “Scope” to “Entire account”. Don’t close the page until you have copied and saved the token — you won’t see that token again.

Now run the following commands while inside your :

$ python3 -m pip install — upgrade build  // Upgrade PIP
$ python3 -m build  // Build distribution, will create dist folder
$ python3 -m pip install --upgrade twine // Install twine
$ python3 -m twine upload --repository pypi dist/* // Upload package

Test Package

Test the package by trying to install it.

pip install PackageName

Auto deploying on GitLab CI

Now that we know the process for manually deploying a package on PyPI the next task is automating deployment of code using GitLab CI.

Navigate to your project settings under CI/CD, add to variables,PYPI_PASSWORD and PYPI_USERNAME. The value of the keys should be the PyPI password which is the token we created and your PyPI username respectively.

creating variables

We are also required to protect the tags we will be using since we will be using tags to auto-deploy. Otherwise, our deployment will fail.

To do that Navigate to Settings>Repositories

protected tags

In this case, we protect v*. This implies tags that start with v will be run as protected and will be supplied with the variable we created. Tags that don't start with v will not be supplied with variables.

Crafting our CI/CD with .gitlab-ci.yml

We will let our GitLab auto-deploy our code however to do that we require .gitlab-ci.yml.

The main challenge we face during auto-deployment is the management of the project version. We sort this by only deploying when we tag the project version.

Go ahead and create it and add the following code:

build-package:
  stage: deploy
  image: python:3.7
  before_script:
    - python3 -m pip install --upgrade twine
    - python3 -m pip install --upgrade build
    - sed -i -e "s/v-latest/$CI_COMMIT_TAG/" setup.cfg
    - cat setup.cfg
  variables:
    TWINE_USERNAME: $PYPI_USERNAME
    TWINE_PASSWORD: $PYPI_PASSWORD
  script:
    - python3 -m build
    - python3 -m twine upload dist/*
  only:
    - tags

For the package version to be replaced with the version we want to release, we use sed command to replace v-latest with the version we specify in our tag. We are therefore required to change the version in setup.cfg from 0.0.1 to v-latest

[metadata]
name = example-pkg-YOUR-USERNAME-HERE
version = v-latest
author = Example Author
author_email = author@example.com
description = A small example package
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/pypa/sampleproject
project_urls =
    Bug Tracker = https://github.com/pypa/sampleproject/issues
classifiers =
    Programming Language :: Python :: 3
    License :: OSI Approved :: MIT License
    Operating System :: OS Independent

[options]
package_dir =
    = src
packages = find:
python_requires = >=3.6

[options.packages.find]
where = src

Conclusion

With the above codes, our project should automatically deploy every time we tag the project.

tag release

Subscribe to Bluedoa Digest

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
alexander@example.com
Subscribe