diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e7aa023eead2a3518860c2af9e7f81421764a4b8..e33e8435d11899c59de5961c40b21946c2429e8a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,6 +4,7 @@ stages:
 - testing
 - security
 - docs
+- release
 
 # Change pip's cache directory to be inside the project directory since we can
 # only cache local items.
@@ -86,6 +87,25 @@ include:
   - template: Security/Dependency-Scanning.gitlab-ci.yml
   - template: Security/License-Scanning.gitlab-ci.yml
 
+upload_to_pip:
+  stage: release
+  script:
+    - pip install build twine
+    - python3 -m build
+    - TWINE_PASSWORD=${CI_JOB_TOKEN} TWINE_USERNAME=gitlab-ci-token python3 -m twine upload --repository-url https://test.pypi.org/simple/ dist/* 
+  when: manual
+
+release_job:
+  stage: release
+  image: registry.gitlab.com/gitlab-org/release-cli:latest
+  rules:
+    - if: $CI_COMMIT_TAG  # Run this job when a tag is created
+  script:
+    - echo "running release_job"
+  release:  # See https://docs.gitlab.com/ee/ci/yaml/#release for available properties
+    tag_name: '$CI_COMMIT_TAG'
+    description: '$CI_COMMIT_TAG'
+
 # You can override the included template(s) by including variable overrides
 # SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
 # Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings