Skip to content

Commit

Permalink
ci: update scripts and workflow for automatic release
Browse files Browse the repository at this point in the history
  • Loading branch information
wpbonelli committed Dec 16, 2022
1 parent 58dff9f commit 02f7015
Show file tree
Hide file tree
Showing 13 changed files with 568 additions and 22 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,15 @@ jobs:
key: modflow6-examples-${{ hashFiles('modflow6-examples/data/**') }}

- name: Install extra Python packages
# can't build examples on Python 3.7, requires Python 3.8
if: steps.cache-examples.outputs.cache-hit != 'true' && matrix.python != '3.7'
working-directory: modflow6-examples/etc
run: |
pip install -r requirements.pip.txt
pip install -r requirements.usgs.txt
- name: Build modflow6 example models
# can't build examples on Python 3.7, requires Python 3.8
if: steps.cache-examples.outputs.cache-hit != 'true' && matrix.python != '3.7'
working-directory: modflow6-examples/etc
run: python ci_build_files.py
Expand Down
244 changes: 229 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,50 +1,264 @@
name: Release
on:
push:
tags:
branches:
- master
- v*
jobs:
release:
name: Release & publish
types:
- published
jobs:
prep:
name: Prepare release
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && github.ref_name != 'master' }}
permissions:
contents: write
pull-requests: write
defaults:
run:
shell: bash
steps:

- name: Checkout repo
- name: Checkout release branch
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.7
cache: 'pip'
cache-dependency-path: setup.cfg

- name: Install Python packages
- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install build twine
pip install .
pip install ".[lint, test, optional]"
- name: Print version
- name: Update version
id: version
run: |
python -c "import modflow_devtools; print(modflow_devtools.__version__)"
ref="${{ github.ref_name }}"
version="${ref#"v"}"
python scripts/update_version.py -v "$version"
python scripts/lint.py
python -c "import modflow_devtools; print('Version: ', modflow_devtools.__version__)"
echo "version=$version" >> $GITHUB_OUTPUT
- name: Build package
- name: Touch changelog
run: touch HISTORY.md

- name: Generate changelog
id: cliff
uses: orhun/git-cliff-action@v1
with:
config: cliff.toml
args: --verbose --unreleased --tag ${{ steps.version.outputs.version }}
env:
OUTPUT: CHANGELOG.md

- name: Update changelog
id: update-changelog
run: |
python -m build
- name: Check distribution
# move changelog
clog="CHANGELOG_${{ steps.version.outputs.version }}.md"
echo "changelog=$clog" >> $GITHUB_OUTPUT
sudo cp "${{ steps.cliff.outputs.changelog }}" "$clog"
# show current release changelog
cat "$clog"
# substitute full group names
sed -i 's/#### Ci/#### Continuous integration/' "$clog"
sed -i 's/#### Feat/#### New features/' "$clog"
sed -i 's/#### Fix/#### Bug fixes/' "$clog"
sed -i 's/#### Refactor/#### Refactoring/' "$clog"
sed -i 's/#### Test/#### Testing/' "$clog"
cat "$clog" HISTORY.md > temp_history.md
sudo mv temp_history.md HISTORY.md
# show full changelog
cat HISTORY.md
- name: Upload changelog
uses: actions/upload-artifact@v3
with:
name: changelog
path: ${{ steps.update-changelog.outputs.changelog }}

- name: Push release branch
run: |
rm ${{ steps.update-changelog.outputs.changelog }}
git config core.sharedRepository true
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "ci(release): set version to ${{ steps.version.outputs.version }}, update changelog"
git push origin "${{ github.ref_name }}"
- name: Draft pull request
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
ver="${{ steps.version.outputs.version }}"
title="Release $ver"
changelog=$(cat ${{ steps.cliff.outputs.changelog }} | grep -v "### Version \[$ver\]")
body='
# Release '$ver'
The release can be approved by merging this pull request into `master`. This will trigger jobs to publish the release to PyPI and reset `develop` from `master`, incrementing the patch version number.
## Changelog
'$changelog'
'
gh pr create -B "main" -H "${{ github.ref_name }}" --title "$title" --draft --body "$body"
release:
name: Draft release
# runs only when changes are merged to master
if: ${{ github.event_name == 'push' && github.ref_name == 'master' }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:

- name: Checkout repo
uses: actions/checkout@v3
with:
ref: master

# actions/download-artifact won't look at previous workflow runs but we need to in order to get changelog
- name: Download artifacts
uses: dawidd6/action-download-artifact@v2

- name: Draft release
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
version=$(cat version.txt)
title="MODFLOW developer tools $version"
notes=$(cat changelog/CHANGELOG.md)
gh release create "$version" \
--target master \
--title "$title" \
--notes "$notes" \
--draft \
--latest
publish:
name: Publish package
# runs only after release is published (manually promoted from draft)
if: ${{ github.event_name == 'release' }}
runs-on: ubuntu-22.04
permissions:
contents: write
pull-requests: write
steps:

- name: Checkout master branch
uses: actions/checkout@v3
with:
ref: master

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.7

- name: Install Python dependencies
run: |
twine check --strict dist/*
pip install --upgrade pip
pip install build twine
pip install .
- name: Build package
run: python -m build

- name: Check package
run: twine check --strict dist/*

- name: Publish package
if: ${{ env.TWINE_USERNAME != '' }}
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
twine upload dist/*
run: twine upload dist/*

- name: Create release
uses: marvinpinto/action-automatic-releases@latest
with:
prerelease: true
repo_token: ${{ github.token }}
repo_token: ${{ github.token }}

reset:
name: Draft reset PR
if: ${{ github.event_name == 'release' }}
runs-on: ubuntu-22.04
permissions:
contents: write
pull-requests: write
steps:

- name: Checkout master branch
uses: actions/checkout@v3
with:
ref: master

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.7
cache: 'pip'
cache-dependency-path: setup.cfg

- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install .
pip install ".[lint, test, optional]"
- name: Get release tag
uses: oprypin/find-latest-tag@v1
id: latest_tag
with:
repository: ${{ github.repository }}
releases-only: true

- name: Draft pull request
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
# create reset branch from master
reset_branch="post-release-${{ steps.latest_tag.outputs.tag }}-reset"
git switch -c $reset_branch
# increment patch version
major_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f1)
minor_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f2)
patch_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f3)
version="$major_version.$minor_version.$((patch_version + 1))"
python scripts/update_version.py -v "$version"
python scripts/lint.py
# commit and push reset branch
git config core.sharedRepository true
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "ci(release): update to development version $version"
git push -u origin $reset_branch
# create PR into develop
body='
# Reinitialize for development
Updates the `develop` branch from `master` following a successful release. Increments the patch version number.
'
gh pr create -B "develop" -H "$reset_branch" --title "Reinitialize develop branch" --draft --body "$body"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,5 @@ dmypy.json
modflow_devtools/bin/
modflow_devtools/utilities/temp/

# git-cliff-action likes to add app/ folder to the project root
app
84 changes: 84 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Contributing

Contributions to this repository are welcome. To make a contribution we ask that you follow a few guidelines.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Issues and features](#issues-and-features)
- [Pull requests](#pull-requests)
- [Commit messages](#commit-messages)
- [Commit Message Format](#commit-message-format)
- [Type](#type)
- [Subject](#subject)
- [Body](#body)
- [Footer](#footer)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Issues and features

Before filing a bug report or making a feature request, please check the issues to make sure yours isn't a duplicate.

## Pull requests

Feel free to submit pull requests to the `develop` branch with small fixes or improvements. Before implementing new features or contributing broadly-scoped changes we ask that you first open an issue or discussion.

Before submitting a PR, please test your changes in your own fork. Please do not open a pull request immediately and add to it frequently during development &mdash; this will saturate the `modflowpy` organization's CI.

If `develop` changes while your work is still in progress, please rebase and fix any conflicts, then force push your branch to update the pull request.

## Commit messages

Commit messages must conform to the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. This makes the commit history easier to follow and allows an automatically generated changelog.

### Commit Message Format

Each commit message consists of a **header**, a **body** and a **footer**. The **header** is mandatory, while **body** and **footer** are optional.

```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```

Note the header's format, which includes a **type**, a **scope** and a **subject**. Header **type** and **subject** are mandatory while header **scope** is optional.

No line of the commit message may be longer 100 characters. This makes messages easier to read on GitHub as well as in various `git` tools.

If a commit closes an issue, the footer should contain a [closing reference](https://help.github.com/articles/closing-issues-via-commit-messages/).

#### Type

Must be one of the following:

* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
* **revert**: Reverts a previous commit

#### Subject

The subject contains a succinct description of the change:

* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* do not include a dot (.) at the end

#### Body

Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.

#### Footer

The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.

**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
global-exclude .DS_Store *.pyc *.pyo *.pyd *.swp *.bak *~ .* *.sh *.yml *.md *.toml
exclude autotest/*
include pyproject.toml
include version.txt
Loading

0 comments on commit 02f7015

Please sign in to comment.