Search code examples
pythonautomationgitlabgitlab-cipyinstaller

python - Automated building of executables


I have a GUI program I'm managing, written in Python. For the sake of not having to worry about environments, it's distributed as an executable built with PyInstaller. I can run this build from a function defined in the module as MyModule.build() (because to me it makes more sense to manage that script alongside the project itself).

I want to automate this to some extent, such that when a new release is added on Gitlab, it can be built and attached to the release by a runner. The approach I currently have to this is functional but hacky:

I use the Gitlab API to download the source of the tag for the release. I run python -m pip install -r {requirements_path} and python -m pip install {source_path} in the runner's environment. Then import and run the MyModule.build() function to generate an executable. Which is then uploaded and linked to the release with the Gitlab API.

Obviously the middle section is wanting. What are best approaches for similar projects? Can the package and requirments be installed in a separate venv than the one the runner script it running in?


Solution

  • One workflow would be to push a tag to create your release. The following jobs have a rules: configuration so they only run on tag pipelines.

    One job will build the executable file. Another job will create the GitLab release using the file created in the first job.

    build:
      rules:
        - if: "$CI_COMMIT_TAG"  # Only run when tags are pushed
      image: python:3.9-slim
      variables:
        PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
      cache: # https://docs.gitlab.com/ee/ci/caching/#cache-python-dependencies
        paths:
          - .cache/pip
          - venv/
      script:
        - python -m venv venv
        - source venv/bin/activate
        - python -m pip install -r requirements.txt # package requirements
        - python -m pip install pyinstaller # build requirements
        - pyinstaller --onefile --name myapp mypackage/__main__.py
      artifacts:
        paths:
          - dist
    create_release:
      rules:
        - if: "$CI_COMMIT_TAG"
      needs: [build]
      image: registry.gitlab.com/gitlab-org/release-cli:latest
      script: # zip/upload your binary wherever it should be downloaded from
        - echo "Uploading release!"
      release:  # create GitLab release
        tag_name: $CI_COMMIT_TAG
        name: 'Release of myapp version $CI_COMMIT_TAG'
        description: 'Release created using the release-cli.'
        assets: # link uploaded asset(s) to the release
          - name: 'release-zip'
            url: 'https://example.com/downloads/myapp/$CI_COMMIT_TAG/myapp.zip'