![cicd](https://github.com/upciti/ops2deb/actions/workflows/cicd.yml/badge.svg)
[![codecov](https://codecov.io/gh/upciti/ops2deb/branch/main/graph/badge.svg)](https://codecov.io/gh/upciti/ops2deb)
[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
[![Generic badge](https://img.shields.io/badge/type_checked-mypy-informational.svg)](https://mypy.readthedocs.io/en/stable/introduction.html)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
[![PyPI version shields.io](https://img.shields.io/pypi/v/ops2deb.svg)](https://pypi.python.org/pypi/ops2deb/)
[![Downloads](https://pepy.tech/badge/ops2deb/month)](https://pepy.tech/project/ops2deb)
[![WakeMeOps](https://docs.wakemeops.com/badges/ops2deb.svg)](https://docs.wakemeops.com/packages/ops2deb)
# ops2deb
Are you tired of checking if your favorite devops tools are up-to-date? Are you using a debian based GNU/Linux distribution?
`ops2deb` is designed to generate Debian packages for common devops tools such as kubectl, kustomize, helm, ...,
but can be used to package any portable application. In short, it consumes a configuration file and outputs `.deb` packages.
`ops2deb` can also track new releases of upstream applications and automatically bump application versions in its configuration file.
- [Installation](#installation)
- [With <a href="https://docs.wakemeops.com" rel="nofollow">wakemeops</a>](#with-wakemeops)
- [With <a href="https://github.com/pipxproject/pipx">pipx</a>](#with-pipx)
- [Dependencies](#dependencies)
- [Getting started](#getting-started)
- [Usage examples](#usage-examples)
- [Packaging kubectl](#packaging-kubectl)
- [Creating a metapackage](#creating-a-metapackage)
- [Packaging ops2deb with ops2deb](#packaging-ops2deb-with-ops2deb)
- [Building packages for multiple architectures at once](#building-packages-for-multiple-architectures-at-once)
- [Using environment variables](#using-environment-variables)
- [Configuration file](#configuration-file)
- [Development](#development)
- [Important notes](#important-notes)
- [Migration guides](#migration-guides)
- [Migrating to v1](#migrating-to-v1)
- [Breaking changes in v2](#breaking-changes-in-v2)
## Installation
### With [wakemeops](https://docs.wakemeops.com)
```shell
sudo apt-get install ops2deb
```
### With [pipx](https://github.com/pipxproject/pipx)
```shell
pipx install ops2deb
```
## Dependencies
- Python >= 3.10 if installed with `pip` or `pipx`
- To build debian packages with `ops2deb build` you need the following packages on your host:
```shell
sudo apt install build-essential fakeroot debhelper
```
If you plan to build packages for `armhf` and `arm64` you will also need the following packages:
```shell
sudo apt install binutils-aarch64-linux-gnu binutils-arm-linux-gnueabihf
```
## Getting started
In a test directory run:
```shell
curl https://raw.githubusercontent.com/upciti/ops2deb/main/ops2deb.yml
ops2deb lock # generate lockfile where downloaded file hashes are stored
ops2deb # equivalent to ops2deb generate && ops2deb build
```
To check for new releases run:
```shell
ops2deb update
```
This command updates each blueprint in the `ops2deb.yml` configuration file with the latest version of the upstream application.
By default `ops2deb` caches downloaded content in `/tmp/ops2deb_cache`:
```shell
tree /tmp/ops2deb_cache
```
The cache can be flushed with:
```shell
ops2deb purge
```
For more information about existing subcommands and options run `ops2deb --help`.
## Usage examples
### Packaging `kubectl`
The `fetch` field tells ops2deb to download a file. `ops2deb` will check the hash
of downloaded files against a lockfile. To generate/update this lockfile, run
`ops2dbe lock`. By default, the lockfile is named `ops2deb.lock.yml`.
```yaml
name: kubectl
version: 1.20.1
summary: command line client for controlling a Kubernetes cluster
description: |
kubectl is a command line client for running commands against Kubernetes clusters.
fetch: https://storage.googleapis.com/kubernetes-release/release/v{{version}}/bin/linux/amd64/kubectl
install:
- kubectl:/usr/bin/
```
### Creating a metapackage
Ops2deb can be used to create [metapackages](https://www.debian.org/blends/hamradio/get/metapackages):
```yaml
name: allthethings
version: 0.1.9
architecture: all
summary: install various devops tools
description: Some great description.
depends:
- kubectl
- kustomize
- helm
- helmfile
- devspace
```
### Packaging ops2deb with ops2deb
Note that when the fetch key is not used, ops2deb will run the build script from the directory where it was called.
Hence for the following blueprint to succeed, you have to run ops2deb from the root directory of this github project.
```yaml
name: ops2deb
version: 0.15.0
homepage: https://github.com/upciti/ops2deb
summary: debian packaging tool for portable applications
description: |-
Ops2deb is primarily designed to easily generate Debian packages for portable
applications such as single binary applications and scripts. Packages are
described using a simple configuration file format. Ops2deb can track new
releases of upstream applications and automatically bump application versions
in its configuration file.
script:
- poetry install -E pyinstaller
- poetry run task single_binary_application
- install -m 755 build/x86_64-unknown-linux-gnu/release/install/ops2deb {{src}}/usr/bin/
```
### Building packages for multiple architectures at once
If the upstream application is released for multiple architectures,
use the `matrix` object to generate one source package for each architecture:
```yaml
name: helm
matrix:
architectures:
- amd64
- armhf
- arm64
version: 3.7.2
homepage: https://helm.sh/
summary: Kubernetes package manager
description: |-
Tool for managing Kubernetes charts.
Charts are packages of pre-configured Kubernetes resources.
depends:
- kubectl
fetch: https://get.helm.sh/helm-v{{version}}-linux-{{goarch}}.tar.gz
script:
- mv linux-*/helm {{src}}/usr/bin/
```
The blueprint above will generate three packages: `helm_3.7.2-1~ops2deb_armhf.deb`, `helm_3.7.2-1~ops2deb_arm64.deb` and `helm_3.7.2-1~ops2deb_amd64.deb`
Note the use of the `{{goarch}}` variable which maps debian architectures to sensible go architectures.
You can also define your own architure maps using the `fetch.targets` field and the `{{target}}` jinja variable:
```yaml
name: bottom
matrix:
architectures:
- amd64
- armhf
version: 0.6.6
revision: 2
homepage: https://clementtsang.github.io/bottom
summary: cross-platform graphical process/system monitor
description: |-
A cross-platform graphical process/system monitor with a customizable interface
and a multitude of features. Supports Linux, macOS, and Windows.
Inspired by gtop, gotop, and htop.
fetch:
url: https://github.com/ClementTsang/bottom/releases/download/{{version}}/bottom_{{target}}.tar.gz
targets:
amd64: x86_64-unknown-linux-gnu
armhf: armv7-unknown-linux-gnueabihf
install:
- btm:/usr/bin/
```
### Using environment variables
You can use `{{env("VARIABLE", "a_default")}}` in all fields except `fetch.targets.*`.
The example below uses environment variables set by Gitlab CI:
```yaml
name: "{{env('CI_PROJECT_NAME')}}"
version: "{{env('CI_COMMIT_TAG', '0')}}"
homepage: "{{env('CI_PROJECT_URL')}}"
summary: awesome application for doing things
description: |-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
script:
- install -m 755 build/x86_64-unknown-linux-gnu/release/install/great-app {{src}}/usr/bin/
```
## Configuration file
Written in YAML and composed of a single blueprint object or a list of blueprints objects. A blueprint is defined by the following:
| Field | Meaning | Default |
| -------------- | ---------------------------------------------------------------------------------------------------- | ------- |
| `name` | Component name, e.g. `kustomize`. | |
| `matrix` | Generate multiple packages from a single blueprint. | `None` |
| `version` | Application release to package. | |
| `revision` | Package revistion. | `1` |
| `epoch` | Package epoch. | `0` |
| `architecture` | Package architecture. | `amd64` |
| `homepage` | Upstream project homepage. | `None` |
| `summary` | Package short description. | |
| `description` | Package full description. | |
| `depends` | List of package dependencies. Corresponds to `Depends` entry in `debian/control`. | `[]` |
| `recommends` | List of package recommended dependencies. Corresponds to `Recommends` entry in `debian/control`. | `[]` |
| `conflicts` | List of conflicting packages. Corresponds to `Conflicts` entry in `debian/control`. | `[]` |
| `fetch` | A file to download. `tar.gz`, `tar.xz`, `tar`, `zip` and `deb` archives are extracted automatically. | `None` |
| `install` | List of here-documents and files/directories to add to the debian package. | `[]` |
| `script` | List of build instructions templated with jinja2 and intepreted with the default `shell`. | `[]` |
## Development
You will need [poetry](https://python-poetry.org/), and probably [pyenv](https://github.com/pyenv/pyenv) if you don't have python 3.10 on your host.
```shell
poetry install
```
To run ops2deb test suite run:
```shell
poetry run task check
```
To build a python wheel:
```shell
poetry run poetry build
```
Note that the `poetry run` is important to enable [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning)
which is installed as a dev dependency.
To build a single binary application:
Install required build dependencies:
```shell
sudo apt install binutils python3-dev
poetry install -E pyinstaller
```
And run:
```shell
poetry run task single_binary_application
```
## Important notes
`ops2deb` **DOES NOT** sandbox build instructions so if you do something like:
```shell
script:
- rm -rf ~/*
```
You will loose your files... To make sure that you won't mess with your system, run it within a container.
## Migration guides
### Migrating to v1
Lockfile `ops2deb.lock.yml` was introduced in ops2deb v1.0.0, before that downloaded file hashes where stored in the configuration file, in the blueprint `fetch` object.
To migrate from ops2deb <= 1.0.3 to ops2deb > 1.0.3:
- Install ops2deb 1.0.3
- Run `ops2deb migrate`
### Breaking changes in v2
- `GITHUB_TOKEN` environment variable renamed to `OPS2DEB_GITHUB_TOKEN`
- Command line argument `-k` was removed. Start `ops2deb.yml` with `# lockfile={path_to_lockfile}` to override the default lockfile path.
Raw data
{
"_id": null,
"home_page": "https://github.com/upciti/ops2deb",
"name": "ops2deb",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.10,<3.11",
"maintainer_email": "",
"keywords": "Debian,DevOps,Automation,Kubernetes,APT",
"author": "Upciti",
"author_email": "support@upciti.com",
"download_url": "https://files.pythonhosted.org/packages/84/88/16d1c8ff5518902bd48c6ade146e6f48f3b43352892e06b0aaf598e01b07/ops2deb-2.3.0.tar.gz",
"platform": null,
"description": "![cicd](https://github.com/upciti/ops2deb/actions/workflows/cicd.yml/badge.svg)\n[![codecov](https://codecov.io/gh/upciti/ops2deb/branch/main/graph/badge.svg)](https://codecov.io/gh/upciti/ops2deb)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)\n[![Generic badge](https://img.shields.io/badge/type_checked-mypy-informational.svg)](https://mypy.readthedocs.io/en/stable/introduction.html)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n[![PyPI version shields.io](https://img.shields.io/pypi/v/ops2deb.svg)](https://pypi.python.org/pypi/ops2deb/)\n[![Downloads](https://pepy.tech/badge/ops2deb/month)](https://pepy.tech/project/ops2deb)\n[![WakeMeOps](https://docs.wakemeops.com/badges/ops2deb.svg)](https://docs.wakemeops.com/packages/ops2deb)\n\n# ops2deb\n\nAre you tired of checking if your favorite devops tools are up-to-date? Are you using a debian based GNU/Linux distribution?\n`ops2deb` is designed to generate Debian packages for common devops tools such as kubectl, kustomize, helm, ...,\nbut can be used to package any portable application. In short, it consumes a configuration file and outputs `.deb` packages.\n`ops2deb` can also track new releases of upstream applications and automatically bump application versions in its configuration file.\n\n- [Installation](#installation)\n - [With <a href=\"https://docs.wakemeops.com\" rel=\"nofollow\">wakemeops</a>](#with-wakemeops)\n - [With <a href=\"https://github.com/pipxproject/pipx\">pipx</a>](#with-pipx)\n- [Dependencies](#dependencies)\n- [Getting started](#getting-started)\n- [Usage examples](#usage-examples)\n - [Packaging kubectl](#packaging-kubectl)\n - [Creating a metapackage](#creating-a-metapackage)\n - [Packaging ops2deb with ops2deb](#packaging-ops2deb-with-ops2deb)\n - [Building packages for multiple architectures at once](#building-packages-for-multiple-architectures-at-once)\n - [Using environment variables](#using-environment-variables)\n- [Configuration file](#configuration-file)\n- [Development](#development)\n- [Important notes](#important-notes)\n- [Migration guides](#migration-guides)\n - [Migrating to v1](#migrating-to-v1)\n - [Breaking changes in v2](#breaking-changes-in-v2)\n\n## Installation\n\n### With [wakemeops](https://docs.wakemeops.com)\n\n```shell\nsudo apt-get install ops2deb\n```\n\n### With [pipx](https://github.com/pipxproject/pipx)\n\n```shell\npipx install ops2deb\n```\n\n## Dependencies\n\n- Python >= 3.10 if installed with `pip` or `pipx`\n- To build debian packages with `ops2deb build` you need the following packages on your host:\n\n```shell\nsudo apt install build-essential fakeroot debhelper\n```\n\nIf you plan to build packages for `armhf` and `arm64` you will also need the following packages:\n\n```shell\nsudo apt install binutils-aarch64-linux-gnu binutils-arm-linux-gnueabihf\n```\n\n## Getting started\n\nIn a test directory run:\n\n```shell\ncurl https://raw.githubusercontent.com/upciti/ops2deb/main/ops2deb.yml\nops2deb lock # generate lockfile where downloaded file hashes are stored\nops2deb # equivalent to ops2deb generate && ops2deb build\n```\n\nTo check for new releases run:\n\n```shell\nops2deb update\n```\n\nThis command updates each blueprint in the `ops2deb.yml` configuration file with the latest version of the upstream application.\n\nBy default `ops2deb` caches downloaded content in `/tmp/ops2deb_cache`:\n\n```shell\ntree /tmp/ops2deb_cache\n```\n\nThe cache can be flushed with:\n\n```shell\nops2deb purge\n```\n\nFor more information about existing subcommands and options run `ops2deb --help`.\n\n## Usage examples\n\n### Packaging `kubectl`\n\nThe `fetch` field tells ops2deb to download a file. `ops2deb` will check the hash\nof downloaded files against a lockfile. To generate/update this lockfile, run\n`ops2dbe lock`. By default, the lockfile is named `ops2deb.lock.yml`.\n\n```yaml\nname: kubectl\nversion: 1.20.1\nsummary: command line client for controlling a Kubernetes cluster\ndescription: |\n kubectl is a command line client for running commands against Kubernetes clusters.\nfetch: https://storage.googleapis.com/kubernetes-release/release/v{{version}}/bin/linux/amd64/kubectl\ninstall:\n - kubectl:/usr/bin/\n```\n\n### Creating a metapackage\n\nOps2deb can be used to create [metapackages](https://www.debian.org/blends/hamradio/get/metapackages):\n\n```yaml\nname: allthethings\nversion: 0.1.9\narchitecture: all\nsummary: install various devops tools\ndescription: Some great description.\ndepends:\n - kubectl\n - kustomize\n - helm\n - helmfile\n - devspace\n```\n\n### Packaging ops2deb with ops2deb\n\nNote that when the fetch key is not used, ops2deb will run the build script from the directory where it was called.\nHence for the following blueprint to succeed, you have to run ops2deb from the root directory of this github project.\n\n```yaml\nname: ops2deb\nversion: 0.15.0\nhomepage: https://github.com/upciti/ops2deb\nsummary: debian packaging tool for portable applications\ndescription: |-\n Ops2deb is primarily designed to easily generate Debian packages for portable\n applications such as single binary applications and scripts. Packages are\n described using a simple configuration file format. Ops2deb can track new\n releases of upstream applications and automatically bump application versions\n in its configuration file.\nscript:\n - poetry install -E pyinstaller\n - poetry run task single_binary_application\n - install -m 755 build/x86_64-unknown-linux-gnu/release/install/ops2deb {{src}}/usr/bin/\n```\n\n### Building packages for multiple architectures at once\n\nIf the upstream application is released for multiple architectures,\nuse the `matrix` object to generate one source package for each architecture:\n\n```yaml\nname: helm\nmatrix:\n architectures:\n - amd64\n - armhf\n - arm64\nversion: 3.7.2\nhomepage: https://helm.sh/\nsummary: Kubernetes package manager\ndescription: |-\n Tool for managing Kubernetes charts.\n Charts are packages of pre-configured Kubernetes resources.\ndepends:\n - kubectl\nfetch: https://get.helm.sh/helm-v{{version}}-linux-{{goarch}}.tar.gz\nscript:\n - mv linux-*/helm {{src}}/usr/bin/\n```\n\nThe blueprint above will generate three packages: `helm_3.7.2-1~ops2deb_armhf.deb`, `helm_3.7.2-1~ops2deb_arm64.deb` and `helm_3.7.2-1~ops2deb_amd64.deb`\n\nNote the use of the `{{goarch}}` variable which maps debian architectures to sensible go architectures.\n\nYou can also define your own architure maps using the `fetch.targets` field and the `{{target}}` jinja variable:\n\n```yaml\nname: bottom\nmatrix:\n architectures:\n - amd64\n - armhf\nversion: 0.6.6\nrevision: 2\nhomepage: https://clementtsang.github.io/bottom\nsummary: cross-platform graphical process/system monitor\ndescription: |-\n A cross-platform graphical process/system monitor with a customizable interface\n and a multitude of features. Supports Linux, macOS, and Windows.\n Inspired by gtop, gotop, and htop.\nfetch:\n url: https://github.com/ClementTsang/bottom/releases/download/{{version}}/bottom_{{target}}.tar.gz\n targets:\n amd64: x86_64-unknown-linux-gnu\n armhf: armv7-unknown-linux-gnueabihf\ninstall:\n - btm:/usr/bin/\n```\n\n### Using environment variables\n\nYou can use `{{env(\"VARIABLE\", \"a_default\")}}` in all fields except `fetch.targets.*`.\nThe example below uses environment variables set by Gitlab CI:\n\n```yaml\nname: \"{{env('CI_PROJECT_NAME')}}\"\nversion: \"{{env('CI_COMMIT_TAG', '0')}}\"\nhomepage: \"{{env('CI_PROJECT_URL')}}\"\nsummary: awesome application for doing things\ndescription: |-\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\n incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis\n nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nscript:\n - install -m 755 build/x86_64-unknown-linux-gnu/release/install/great-app {{src}}/usr/bin/\n```\n\n## Configuration file\n\nWritten in YAML and composed of a single blueprint object or a list of blueprints objects. A blueprint is defined by the following:\n\n| Field | Meaning | Default |\n| -------------- | ---------------------------------------------------------------------------------------------------- | ------- |\n| `name` | Component name, e.g. `kustomize`. | |\n| `matrix` | Generate multiple packages from a single blueprint. | `None` |\n| `version` | Application release to package. | |\n| `revision` | Package revistion. | `1` |\n| `epoch` | Package epoch. | `0` |\n| `architecture` | Package architecture. | `amd64` |\n| `homepage` | Upstream project homepage. | `None` |\n| `summary` | Package short description. | |\n| `description` | Package full description. | |\n| `depends` | List of package dependencies. Corresponds to `Depends` entry in `debian/control`. | `[]` |\n| `recommends` | List of package recommended dependencies. Corresponds to `Recommends` entry in `debian/control`. | `[]` |\n| `conflicts` | List of conflicting packages. Corresponds to `Conflicts` entry in `debian/control`. | `[]` |\n| `fetch` | A file to download. `tar.gz`, `tar.xz`, `tar`, `zip` and `deb` archives are extracted automatically. | `None` |\n| `install` | List of here-documents and files/directories to add to the debian package. | `[]` |\n| `script` | List of build instructions templated with jinja2 and intepreted with the default `shell`. | `[]` |\n\n## Development\n\nYou will need [poetry](https://python-poetry.org/), and probably [pyenv](https://github.com/pyenv/pyenv) if you don't have python 3.10 on your host.\n\n```shell\npoetry install\n```\n\nTo run ops2deb test suite run:\n\n```shell\npoetry run task check\n```\n\nTo build a python wheel:\n\n```shell\npoetry run poetry build\n```\n\nNote that the `poetry run` is important to enable [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning)\nwhich is installed as a dev dependency.\n\nTo build a single binary application:\n\nInstall required build dependencies:\n\n```shell\nsudo apt install binutils python3-dev\npoetry install -E pyinstaller\n```\n\nAnd run:\n\n```shell\npoetry run task single_binary_application\n```\n\n## Important notes\n\n`ops2deb` **DOES NOT** sandbox build instructions so if you do something like:\n\n```shell\nscript:\n- rm -rf ~/*\n```\n\nYou will loose your files... To make sure that you won't mess with your system, run it within a container.\n\n## Migration guides\n\n### Migrating to v1\n\nLockfile `ops2deb.lock.yml` was introduced in ops2deb v1.0.0, before that downloaded file hashes where stored in the configuration file, in the blueprint `fetch` object.\n\nTo migrate from ops2deb <= 1.0.3 to ops2deb > 1.0.3:\n\n- Install ops2deb 1.0.3\n- Run `ops2deb migrate`\n\n### Breaking changes in v2\n\n- `GITHUB_TOKEN` environment variable renamed to `OPS2DEB_GITHUB_TOKEN`\n- Command line argument `-k` was removed. Start `ops2deb.yml` with `# lockfile={path_to_lockfile}` to override the default lockfile path.\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Build debian packages",
"version": "2.3.0",
"split_keywords": [
"debian",
"devops",
"automation",
"kubernetes",
"apt"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "42d60a796858e32e0b867f722e49b74ae92ce9665d3501ed24de75ed49e46030",
"md5": "b24c02d9b07012243747ba55b267ca10",
"sha256": "1c87ebc5d21cd007bd46131914a069f56caf946efb0f478a625874b187f3cd5a"
},
"downloads": -1,
"filename": "ops2deb-2.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b24c02d9b07012243747ba55b267ca10",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10,<3.11",
"size": 31740,
"upload_time": "2023-03-20T15:54:43",
"upload_time_iso_8601": "2023-03-20T15:54:43.452543Z",
"url": "https://files.pythonhosted.org/packages/42/d6/0a796858e32e0b867f722e49b74ae92ce9665d3501ed24de75ed49e46030/ops2deb-2.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "848816d1c8ff5518902bd48c6ade146e6f48f3b43352892e06b0aaf598e01b07",
"md5": "7549fa73a4824a6655428c9ae9e43c5e",
"sha256": "e63aa09d6977f486e5764a1621a3e917ac561455c7997b125f9bc69efd2b109b"
},
"downloads": -1,
"filename": "ops2deb-2.3.0.tar.gz",
"has_sig": false,
"md5_digest": "7549fa73a4824a6655428c9ae9e43c5e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10,<3.11",
"size": 29995,
"upload_time": "2023-03-20T15:54:45",
"upload_time_iso_8601": "2023-03-20T15:54:45.326046Z",
"url": "https://files.pythonhosted.org/packages/84/88/16d1c8ff5518902bd48c6ade146e6f48f3b43352892e06b0aaf598e01b07/ops2deb-2.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-03-20 15:54:45",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "upciti",
"github_project": "ops2deb",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ops2deb"
}