From 57c5a3f3a3d619aacbec11d15b1151f69ce86058 Mon Sep 17 00:00:00 2001 From: Jash Parekh Date: Wed, 20 Oct 2021 11:37:54 -0400 Subject: [PATCH] Add bump2version (#151) --- .bumpversion.cfg | 12 +++++ .github/dependabot.yml | 8 +++ .github/workflows/detect_version_bump.yml | 36 +++++++++++++ docker-compose.yaml | 11 ++++ docker/bump_version.sh | 57 ++++++++++++++++++++ docs/development-guide.md | 64 +++++++++++++++++++++-- docs/index.md | 2 +- requirements-test.txt | 1 + 8 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 .bumpversion.cfg create mode 100644 .github/workflows/detect_version_bump.yml create mode 100755 docker/bump_version.sh diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..df08d81 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,12 @@ +[bumpversion] +current_version = 0.13.0 +commit = True +tag = False + +[bumpversion:file:docs/index.md] +search = pygitops - {current_version} +replace = pygitops - {new_version} + +[bumpversion:file:setup.cfg] +search = version = {current_version} +replace = version = {new_version} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 44cece1..a5fb308 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,11 @@ updates: directory: "/" schedule: interval: "daily" + - package-ecosystem: "docker" + directory: "/docker" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/detect_version_bump.yml b/.github/workflows/detect_version_bump.yml new file mode 100644 index 0000000..12fe39e --- /dev/null +++ b/.github/workflows/detect_version_bump.yml @@ -0,0 +1,36 @@ +name: Version Bump merged + +on: + pull_request: + types: + - "closed" + branches: + - "main" + +jobs: + trigger-release: + runs-on: ubuntu-latest + if: github.event.pull_request.merged && + startsWith(github.head_ref, 'bump_version_to_') && + startsWith(github.event.pull_request.title, 'Bump version') && + contains(github.event.pull_request.title, ' → ') + environment: Create Release + steps: + - name: Get new version + id: get-new-version + run: | + NEW_VERSION=$(echo ${{ github.head_ref }} | cut -d _ -f4 ) + echo "::set-output name=version::$NEW_VERSION" + - name: Is prerelease? + id: is-prerelease + run: | + IS_PRERELEASE=$([[ "${{ steps.get-new-version.outputs.version }}" == *-[a-z]* ]] && echo true || echo false) + echo "::set-output name=result::$IS_PRERELEASE" + - name: Create Release + # use hash for security since this has access to the access token + uses: ncipollo/release-action@880be3d0a71bc0fa98db60201d2cbdc27324f547 # v1.8.6 + with: + token: ${{ secrets.ACCESS_TOKEN }} + tag: v${{ steps.get-new-version.outputs.version }} + name: v${{ steps.get-new-version.outputs.version }} Release + commit: main \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 93ad777..b4e7199 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,10 @@ version: '3.4' + +x-mount-app-and-user-git-config: &mount-app-and-user-git-config + volumes: + - ./:/app + - ~/.gitconfig:/home/gbq/.gitconfig # allow script to commit as user + services: # a fully loaded development environment to test new code @@ -28,3 +34,8 @@ services: mike: <<: *mkdocs entrypoint: "mike" + + bump: + <<: *devbox + <<: *mount-app-and-user-git-config + entrypoint: docker/bump_version.sh diff --git a/docker/bump_version.sh b/docker/bump_version.sh new file mode 100755 index 0000000..a047342 --- /dev/null +++ b/docker/bump_version.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Referenced From: https://github.com/wayfair-incubator/columbo/blob/main/docker/bump_version.sh + +set -eo pipefail + +DEFAULT_BRANCH="main" + +function usage() { + echo "usage: bump_version.sh major|minor|patch" + echo "" + echo " major|minor|patch : Part of version string to updated." + exit 1 +} + +if [[ $# != 1 || ! "${1}" =~ major|minor|patch ]]; then + usage +else + PART="${1}" +fi + +CURRENT_BRANCH=$(git branch --show-current) +CURRENT_STATUS=$(git status --short --untracked-files=no) + +if [[ "${CURRENT_BRANCH}" != "${DEFAULT_BRANCH}" ]]; then + echo "A version bump must be run from the default branch." + echo "Run 'git switch ${DEFAULT_BRANCH}'" + exit 2 +elif [[ "$CURRENT_STATUS" != "" ]]; then + echo "The working tree has uncommitted changes." + echo "Commit or stash the changes before running a version bump." + exit 3 +fi +# Ensure on default branch +git switch --no-guess main +# Capture value of new version +NEW_VERSION=$(bump2version --dry-run --list "${PART}" | grep new_version | sed -r s,"^.*=",,) +# Create bump branch +BUMP_BRANCH_NAME="bump_version_to_${NEW_VERSION}" +git switch -c "${BUMP_BRANCH_NAME}" +# Update files +bump2version "${PART}" + +# Updating the changelog has to be done manually +# - bump2version doesn't support inserting dates https://github.com/c4urself/bump2version/issues/133 +# - It is not possible to have a multiline string in an INI file where a line after the first line starts with '#'. +# The config parser reads it as a comment line. +TODAY=$(date +%Y-%m-%d) +sed -i "s/## \[Unreleased\]/## \[Unreleased\]\n\n## \[${NEW_VERSION}\] - ${TODAY}/g" CHANGELOG.md + +# Add changelog to bump commit +git add CHANGELOG.md +git commit --amend --no-edit +# Show effected files +git show --pretty="" --name-only + +echo "Run 'git push --set-upstream origin ${BUMP_BRANCH_NAME}' to " diff --git a/docs/development-guide.md b/docs/development-guide.md index 05b5ad3..3cc5d3e 100644 --- a/docs/development-guide.md +++ b/docs/development-guide.md @@ -86,13 +86,69 @@ grab the version from `__init__.py` without actually importing any dependencies. * **requirements.txt** - Lists all direct dependencies (packages imported by the library). * **Requirements-test.txt** - Lists all direct requirements needed to run the test suite & lints. -## Publishing the Package +## Publishing a New Version -TODO: Document package publish process +Once the package is ready to be released, there are a few things that need to be done: + +1. Start with a local clone of the repo on the default branch with a clean working tree. +2. Run the version bump script with the appropriate part name (`major`, `minor`, or `patch`). + Example: `docker-compose run --rm bump minor` + + This wil create a new branch, updates all affected files with the new version, and commit the changes to the branch. + +3. Push the new branch to create a new pull request. +4. Get the pull request approved. +5. Merge the pull request to the default branch. + +Merging the pull request will trigger a GitHub Action that will create a new release. The creation of this new +release will trigger a GitHub Action that will trigger a wheel build & a source distributions of the package and push them to +[PyPI][pypi]. + +!!! warning + The action that uploads the files to PyPI will not run until a repository maintainer acknowledges that the job is + ready to run. This is to keep the PyPI publishing token secure. Otherwise, any job would have access to the token. + +In addition to uploading the files to PyPI, the documentation website will be updated to include the new version. If the +new version is a full release, it will be made the new `latest` version. ## Continuous Integration Pipeline -TODO: Add CI documentation. +The Continuous Integration (CI) Pipeline runs to confirm that the repository is in a good state. It will run when +someone creates a pull request or when they push new commits to the branch for an existing pull request. The pipeline +runs multiple different jobs that helps verify the state of the code. + +This same pipeline also runs on the default branch when a maintainer merges a pull request. + +### Lints + +The first set of jobs that run as part of the CI pipline are linters that perform static analysis on the code. This +includes: [MyPy][mypy-docs], [Black][black-docs], [Isort][isort-docs], [Flake8][flake8-docs], and [Bandit][bandit-docs]. + +### Tests + +The next set of jobs run the unit tests using [PyTest][pytest-docs]. The pipeline runs the tests cases across each +supported version of Python to ensure compatibility. + +For each run of the test cases, the job will record the test results and code coverage information. The pipeline uploads +the code coverage information to [CodeCov][codecov] to ensure that a pull request doesn't significantly reduce the total +code coverage percentage or introduce a large amount of code that is untested. + +### Distribution Verification + +The next set of jobs build the wheel distribution, installs in into a virtual environment, and then runs Python to +import the library version. This works as a smoke test to ensure that the library can be packaged correctly and used. +The pipeline runs the tests cases across each supported version of Python to ensure compatibility. + +### Documentation + +The remaining jobs are all related to documentation. + +* A job runs each of the code examples that are used in the documentation to verify they produce the expected results. +* A job builds the documentation in strict mode so that it will fail if there are any errors. The job records the + generated files so that the documentation website can be viewed in its rendered form. +* When the pipeline is running as a result of a maintainer merging a pull request to the default branch, a job runs that + publishes the current state of the documentation to as the `dev` version. This will allow users to view the state of + the documentation as it has changed since a maintainer published the `latest` version. [usage-guide]: usage-guide/fundamentals.md [code of conduct]: https://github.com/wayfair-incubator/pygitops/blob/main/CODE_OF_CONDUCT.md @@ -108,3 +164,5 @@ TODO: Add CI documentation. [isort-docs]: https://pycqa.github.io/isort/ [flake8-docs]: http://flake8.pycqa.org/en/stable/ [bandit-docs]: https://bandit.readthedocs.io/en/stable/ +[pypi]: https://pypi.org/project/pygitops/ +[codecov]: https://about.codecov.io/ diff --git a/docs/index.md b/docs/index.md index d1f9cb7..92a8ef7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,4 @@ -# pygitops - 0.12.0 +# pygitops - 0.13.0 [![CI pipeline status](https://github.com/wayfair-incubator/pygitops/workflows/CI/badge.svg?branch=main)][ci] diff --git a/requirements-test.txt b/requirements-test.txt index 1d25137..d57c3d9 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,5 +1,6 @@ bandit==1.7.0 black==21.9b0 +bump2version==1.0.1 flake8==3.9.2 isort==5.9.3 mypy==0.910