Skip to content

Latest commit

 

History

History
137 lines (94 loc) · 5.28 KB

how-it-works.md

File metadata and controls

137 lines (94 loc) · 5.28 KB

Key Concepts

Lets take a look at some key concepts PyCI uses that are worth understanding.

Labels

PyCI uses two types of labels:

Commit categories

  • feature
  • bug

These labels indicate what type of change the associated commit introduces.

Semantic Versioning

  • patch
  • minor
  • major

These labels indicate how the version should be affected by the associated commit.

Issue detection

Many features of PyCI heavily rely on identifying which issue relates to which commit. Among others, it uses issues to generate changelogs and determine version numbers.

Issue detection is based on commit messages. There are two possible ways to reference an issue from a commit message:

  • Directly specify the issue number using #.
  • Specify a PR using #, and reference the issue number in the PR description. Notice that when you merge a PR in GitHub, it automatically suggests a reference to the PR in the commit message.

If a commit does not reference any issue, it is considered a Dangling commit

CLI detection

As we have seen, when PyCI releases a commit, it also tries to create a binary executable file and upload it as a release asset.

PyCI uses the entry_points argument in your setup.py to automatically determine if your project is in-fact a CLI or not. If the argument is missing, PyCI will not attempt to create a binary file.

If your project is a CLI, but for some reason you are missing the entry_points argument, you can specify a custom entrypoint path:

pyci pack binary --entrypoint my_project/main.py

pyci release --binary-entrypoint my_project/main.py

Triggering a release

Ideally, every push you make to the main branch should trigger a release.

However, sometimes you just want to push a README fix, or maybe some refactoring. It doesn't really make sense to trigger a release on every single commit. Also, releases should only be triggered if you push to the main branch, and not any other branch. For this reason, PyCI does some validation on the commit before it actually attempts to release it:

  • Build validation

    The build branch must be the main branch. That is, builds for tags, pr's, or branches that differ from the main branch, will not trigger the release process. Instead, you will see something like this:

    * Detected CI Provider: CircleCI
    → Releasing branch 'release'
      → Validating build https://circleci.com/gh/iliapolo/pyci/421
        * Build is not a PR... ✓
        * Build is not a TAG... ✓
        * Build branch is 'release'... ✗
    * Not releasing: Commit e2a88d94c322536a3fcfbaf26d0d1fb2a31bbbe4 does not reference any issue
    
  • Commit validation

    The commit must be associated with an issue, and the issue must be labeled with one of the release labels.

    Any other commit, will trigger your CI, but wont trigger a release. Instead, you will see something like:

    * Detected CI Provider: CircleCI
    → Releasing branch 'release'
      → Validating build https://circleci.com/gh/iliapolo/pyci/421
        * Build is not a PR... ✓
        * Build is not a TAG... ✓
        * Build branch is 'release'... ✓
      → Validating commit
        * Commit references an issue... ✗
    * Not releasing: Commit e2a88d94c322536a3fcfbaf26d0d1fb2a31bbbe4 does not reference any issue
    

Notice that in such cases, the command exists successfully, so as to not fail the build.

Versioning a release

PyCI uses the Semantic Versioning scheme along with Github issues to automatically determine the version of the next release.

The release command detects the issue that was referenced by the commit (that triggered the release) and fetches the issue labels. If the issue is labeled with the patch label, a patch bump is performed, and so forth...

Before the release is made, PyCI will create a version bump commit to the branch.

This commit replaces the current version in setup.py with the new one. The regex version=["\'](.*)["\'] is used to read/write the version, which means you can't do any fancy things for the version arg, like calculate stuff or invoke functions. Keep it simple and let PyCI manipulate and determine version numbers.

Changelog Generation

Changelog is generated by analyzing the commits made to the branch after the previous (not last!) release. Basically, here is how it works:

  1. Fetch all commits prior (including) mine in descending order.
  2. Iterate over them and stop when we find a commit that points to a release.
  3. All commits before we stop, should be a part of the changelog.

Note that this guarantees that you can generate a changelog for every commit, always, regardless of which versions are released.

Each commit is then categorized into one of: (see Issue detection)

- Feature
- Bug
- Issue
- Dangling Commit 

If a feature (or bug) label if found, the commit is categorized as a feature (or bug). If these labels are not found, the commit is categorized as a regular issue. If the commit does not reference any issue, the commit is left "Dangling".