{"id":16398991,"url":"https://github.com/iliapolo/pyci","last_synced_at":"2025-10-08T23:55:04.909Z","repository":{"id":53667475,"uuid":"128361749","full_name":"iliapolo/pyci","owner":"iliapolo","description":"PyCI - CI toolchain for Python projects","archived":false,"fork":false,"pushed_at":"2022-12-26T20:55:16.000Z","size":5819,"stargazers_count":7,"open_issues_count":14,"forks_count":1,"subscribers_count":2,"default_branch":"release","last_synced_at":"2025-09-21T01:59:30.883Z","etag":null,"topics":["ci","devops","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iliapolo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-04-06T07:10:43.000Z","updated_at":"2022-12-20T17:58:22.000Z","dependencies_parsed_at":"2023-01-31T01:31:17.727Z","dependency_job_id":null,"html_url":"https://github.com/iliapolo/pyci","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/iliapolo/pyci","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliapolo%2Fpyci","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliapolo%2Fpyci/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliapolo%2Fpyci/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliapolo%2Fpyci/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iliapolo","download_url":"https://codeload.github.com/iliapolo/pyci/tar.gz/refs/heads/release","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iliapolo%2Fpyci/sbom","scorecard":{"id":484131,"data":{"date":"2025-08-11","repo":{"name":"github.com/iliapolo/pyci","commit":"85784c556a0760d560378ef6edcfb32ab87048a5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":8,"reason":"binaries present in source code","details":["Warn: binary detected: pyci/resources/virtualenv_support/pip-19.1.1-py2.py3-none-any.whl:1","Warn: binary detected: pyci/resources/virtualenv_support/setuptools-41.0.1-py2.py3-none-any.whl:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact 0.8.3 not signed: https://api.github.com/repos/iliapolo/pyci/releases/22271157","Warn: release artifact 0.8.2 not signed: https://api.github.com/repos/iliapolo/pyci/releases/22049244","Warn: release artifact 0.8.0 not signed: https://api.github.com/repos/iliapolo/pyci/releases/19057623","Warn: release artifact 0.7.3 not signed: https://api.github.com/repos/iliapolo/pyci/releases/18757661","Warn: release artifact 0.7.2 not signed: https://api.github.com/repos/iliapolo/pyci/releases/18756388","Warn: release artifact 0.8.3 does not have provenance: https://api.github.com/repos/iliapolo/pyci/releases/22271157","Warn: release artifact 0.8.2 does not have provenance: https://api.github.com/repos/iliapolo/pyci/releases/22049244","Warn: release artifact 0.8.0 does not have provenance: https://api.github.com/repos/iliapolo/pyci/releases/19057623","Warn: release artifact 0.7.3 does not have provenance: https://api.github.com/repos/iliapolo/pyci/releases/18757661","Warn: release artifact 0.7.2 does not have provenance: https://api.github.com/repos/iliapolo/pyci/releases/18756388"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 14 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T17:22:50.492Z","repository_id":53667475,"created_at":"2025-08-19T17:22:50.492Z","updated_at":"2025-08-19T17:22:50.492Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000708,"owners_count":26082862,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","devops","python"],"created_at":"2024-10-11T05:14:29.471Z","updated_at":"2025-10-08T23:55:04.877Z","avatar_url":"https://github.com/iliapolo.png","language":"Python","readme":"[![Build Status](https://travis-ci.org/iliapolo/pyci.svg?branch=release)](https://travis-ci.org/iliapolo/pyci)\n[![Requirements Status](https://requires.io/github/iliapolo/pyci/requirements.svg?branch=release)](https://requires.io/github/iliapolo/pyci/requirements/?branch=release)\n[![Coverage Status](https://coveralls.io/repos/github/iliapolo/pyci/badge.svg?branch=release)](https://coveralls.io/github/iliapolo/pyci?branch=release)\n[![PyPI Version](http://img.shields.io/pypi/v/py-ci.svg)](https://pypi.org/project/py-ci/)\n[![Supported Python Versions](https://img.shields.io/pypi/pyversions/py-ci.svg)](https://pypi.org/project/py-ci/)\n[![Is Wheel](https://img.shields.io/pypi/wheel/py-ci.svg?style=flat)](https://pypi.org/project/py-ci/)\n[![PyCI release](https://img.shields.io/badge/pyci-release-brightgreen.svg)](https://github.com/iliapolo/pyci)\n\nPyCI provides a set of opinionated CI related operations, specifically built for Python projects.\n\n## Why should I use it?\n\nWhat if I were to tell you, that you could, **automatically**:\n\n- Turn your CLI into self-contained, python embedded, binary executables (Linux, Mac and Windows).\n- Semantically bump version numbers\n- Generate changelogs\n- Create GitHub releases\n- Upload wheels to PyPI\n\nAll in a CI agnostic way, with a command line tool you can run locally.\n\nWould that be something you might be interested in?\n\nIf your answer is yes, or if you just got the reference, carry on 😎\n\n## Show me the money\n\nPyCI integrates with your existing CI providers and enables continuous release of \nthe project. All you have to do is invoke the `pyci release` at the end of your CI workflow. It will detect the CI \nprovider and perform a release of the associated commit.\n \n **Currently only supported for projects hosted on Github and running CI on either \n [Travis](https://travis-ci.org/), [Circle](https://circleci.com/), \n or [Appveyor](https://www.appveyor.com/)**\n\n\n```text\n    ___    _  _    ___     ___\n   | _ \\  | || |  / __|   |_ _|\n   |  _/   \\_, | | (__     | |\n  _|_|_   _|__/   \\___|   |___|\n_| \"\"\" |_| \"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|\n\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\n\n* Detected CI Provider: Travis-CI\n→ Validating build https://travis-ci.org/iliapolo/pyci/builds/554632781\n  * Build is not a PR... ✓\n  * Build is not a TAG... ✓\n  * Build branch is 'release'... ✓\n* Validation passed\n→ Validating commit\n  * Commit references an issue... ✓\n  * Issue is labeled with a release label... ✓\n* Validation passed\n→ Releasing branch 'release'\n  → Generating changelog\n    * Collecting commits\n    → Analyzing 1 commits\n      * 38 windows installer packages (#39) ✓\n  * Changelog generation completed\n  * Creating a GitHub release\n  * Release created: https://github.com/iliapolo/pyci/releases/tag/0.7.0\n  * Uploading changelog... ✓\n  * Uploaded changelog to release 0.7.0\n  * Bumping version to 0.7.0\n  * Updating release branch...Branch release is now at 7e7919864a6258e93b3772fae56a372b3d8e30f7  ✓\n  * Updating master branch...Branch master is now at 7e7919864a6258e93b3772fae56a372b3d8e30f7  ✓  \n  → Closing issues\n    * Closing issue number 38... ✓\n* Successfully released: https://github.com/iliapolo/pyci/releases/tag/0.7.0\n→ Creating packages\n  * Packaging binary... ✓\n  * Binary package created: /home/travis/build/iliapolo/pyci/py-ci-x86_64-Linux\n  * Packaging wheel... ✓\n  * Wheel package created: /home/travis/build/iliapolo/pyci/py_ci-0.7.0-py2.py3-none-any.whl\n→ Uploading packages\n  * Uploading py-ci-x86_64-Linux to release 0.7.0... ✓\n  * Asset uploaded: https://github.com/iliapolo/pyci/releases/download/0.7.0/py-ci-x86_64-Linux\n  * Uploading py_ci-0.7.0-py2.py3-none-any.whl to release 0.7.0... ✓\n  * Asset uploaded: https://github.com/iliapolo/pyci/releases/download/0.7.0/py_ci-0.7.0-py2.py3-none-any.whl\n  * Uploading py_ci-0.7.0-py2.py3-none-any.whl to PyPI... ✓\n  * Wheel uploaded: https://pypi.org/manage/project/py-ci/release/0.7.0/\n→ Hip Hip, Hurray! :). Your new version is released and ready to go.\n  * Github: https://github.com/iliapolo/pyci/releases/tag/0.7.0\n```\n\nOnce the command completes, navigate to the release on GitHub. You should see something like this:\n\n[![release](./assets/release.png)](./assets/release.png)\n\nNotice the assets that the release contains:\n\n#### Wheel\n\nPyCI attempts to create a wheel and publish it to PyPI. You can choose to skip the PyPI publishing part by using the \n`--no-wheel-publish` option. Since the wheel is still uploaded to GitHub, you can inspect and test it before \nactually publishing it. \n\nYou can also choose to skip creating wheels altogether by using the `--no-wheel` option.\n\n#### Binary\n\nPyCI creates and uploads a platform dependent binary executable file. In this case, since the CI was executed from all \nthree platform - we see 3 different files. Under the hood, these files are created using the [PyInstaller](https://www.pyinstaller.org/) project.\n\nNote that these binaries are only created if PyCI detects that your project can be invoked as a command line tool (i\n.e, its not just a library). To understand how exactly it does that, see [CLI Detection](./docs/how-it-works.md#cli-detection).\n\nHowever, you can forcefully have PyCI ignore binary creation by using the `--no-binary` option.\n\n#### NSIS \n\nIn addition to a binary **executable**, PyCI will also create a binary **installer** for windows. The installer is \nsimply a graphical installation wizard, which is the common way of installing software in windows environments (go \nfigure). Under the hood, it is created using the [NSIS](https://nsis.sourceforge.io/Main_Page) project.\n\nYou can skip the installer creation by using the `--no-installer` option.\n\n\n*All of these packages can be created independently of the release process by using the `pyci pack` command.* \n\n## Installation\n\n```bash\npip install py-ci\n```\n\nOr, since PyCI itself uses PyCI for releases, you can simply download the executable from the [releases](https://github.com/iliapolo/pyci/releases) page.\n\n## Credentials\n\nThere are several credentials used by PyCI. All credentials are passed via environment variables,\nnever via the command line. All credentials can be prompted interactively in case the appropriate\nenv variable is not defined.\n\nEvery supported CI provider has a way of securely injecting environment variables to a job.\n\n### GitHub\n\nPyCI uses a [Github Authentication Token](https://github.com/settings/tokens) for authentication. \nIt is passed via the `GITHUB_ACCESS_TOKEN` env variable.\n\nYou must create the token with the necessary scopes for full control over your repository.\n\n### PyPI\n\nPyCI needs your PyPI account credentials in order to upload wheels to PyPI. These credentials are:\n\n- `TWINE_USERNAME`\n- `TWINE_PASSWORD`\n\n## Tell me more\n\n- [Genesis](./docs/genesis.md)\n\nIts also worth understanding some key concepts and how exactly PyCI implements them.\n\n- [How it works](./docs/how-it-works.md)\n\n\n## Not planning to use PyCI?\n\nNo hard feelings, but I would really love to know why :)\n\n- Are you missing a feature?\n- Does it not fit with your project workflow?\n\nIf you could spare a minute or two to simply explain your choice as a comment in \n[this](https://github.com/iliapolo/pyci/issues/30) issue, that would be great, if not, that's ok \ntoo.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filiapolo%2Fpyci","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filiapolo%2Fpyci","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filiapolo%2Fpyci/lists"}