diff --git a/.github/changelog_template.md b/.github/changelog_template.md new file mode 100644 index 000000000..2672536df --- /dev/null +++ b/.github/changelog_template.md @@ -0,0 +1,8 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +{{changelog}} diff --git a/.github/get-changelog-diff.sh b/.github/get-changelog-diff.sh new file mode 100755 index 000000000..1c2185346 --- /dev/null +++ b/.github/get-changelog-diff.sh @@ -0,0 +1,4 @@ +git remote add upstream https://github.com/PSLmodels/OG-Core.git +git fetch --tags upstream +last_tagged_commit=`git describe --tags --abbrev=0 --first-parent` +git --no-pager diff $last_tagged_commit -- CHANGELOG.md diff --git a/.github/has-functional-changes.sh b/.github/has-functional-changes.sh new file mode 100755 index 000000000..d3b47ca99 --- /dev/null +++ b/.github/has-functional-changes.sh @@ -0,0 +1,12 @@ +#! /usr/bin/env bash + +IGNORE_DIFF_ON="README.md CONTRIBUTING.md Makefile .gitignore LICENSE* .github/* environment.yml" + +last_tagged_commit=$(git describe --tags --abbrev=0 --first-parent) # --first-parent ensures we don't follow tags not published in master through an unlikely intermediary merge commit + +if git diff-index --name-only --exit-code $last_tagged_commit -- . $(echo " $IGNORE_DIFF_ON" | sed 's/ / :(exclude)/g'); then # Check if any file that has not be listed in IGNORE_DIFF_ON has changed since the last tag was published. + echo "No functional changes detected." + exit 1 +else + echo "The functional files above were changed." +fi diff --git a/.github/is-version-number-acceptable.sh b/.github/is-version-number-acceptable.sh new file mode 100755 index 000000000..d49defebe --- /dev/null +++ b/.github/is-version-number-acceptable.sh @@ -0,0 +1,33 @@ +#! /usr/bin/env bash + +if [[ ${GITHUB_REF#refs/heads/} == master ]] +then + echo "No need for a version check on master." + exit 0 +fi + +if ! $(dirname "$BASH_SOURCE")/has-functional-changes.sh +then + echo "No need for a version update." + exit 0 +fi + +current_version=`python setup.py --version` + +if git rev-parse --verify --quiet $current_version +then + echo "Version $current_version already exists in commit:" + git --no-pager log -1 $current_version + echo + echo "Update the version number in setup.py before merging this branch into master." + echo "Look at the changelog_entry.yaml documentation file to learn how the version number should be updated." + exit 1 +fi + +if ! $(dirname "$BASH_SOURCE")/has-functional-changes.sh | grep --quiet CHANGELOG.md +then + echo "CHANGELOG.md has not been modified, while functional changes were made." + echo "Explain what you changed before merging this branch into master." + echo "Look at the contributor_guide.md documentation file to learn how to write the changelog_entry.yaml." + exit 2 +fi diff --git a/.github/publish-git-tag.sh b/.github/publish-git-tag.sh new file mode 100755 index 000000000..8c6fd46ec --- /dev/null +++ b/.github/publish-git-tag.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash + +git tag -a v`python setup.py --version` +git push --tags || true # update the repository version diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 8222b88a6..d051bd51b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -21,6 +21,25 @@ on: - '**.pkl' - '**.pbz2' jobs: + check-version: + name: Check version + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build changelog + run: pip install yaml-changelog>=0.1.7 && make changelog + - name: Preview changelog update + run: ".github/get-changelog-diff.sh" + - name: Check version number has been properly updated + run: .github/is-version-number-acceptable.sh build: runs-on: ${{ matrix.os }} strategy: diff --git a/.github/workflows/check_black.yml b/.github/workflows/check_format.yml similarity index 57% rename from .github/workflows/check_black.yml rename to .github/workflows/check_format.yml index ca27c0693..1176d48c7 100644 --- a/.github/workflows/check_black.yml +++ b/.github/workflows/check_format.yml @@ -1,5 +1,5 @@ -name: Check Black formatting +name: Check code formatting on: [push, pull_request] @@ -7,9 +7,9 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 - uses: psf/black@stable with: options: "-l 79 --check" - src: "." \ No newline at end of file + src: "." diff --git a/.github/workflows/publish_to_pypi.yml b/.github/workflows/publish_to_pypi.yml index ea1acb773..07a90b72b 100644 --- a/.github/workflows/publish_to_pypi.yml +++ b/.github/workflows/publish_to_pypi.yml @@ -1,4 +1,4 @@ -name: Publish package to PyPI +name: Tag, release, and publish package to PyPI on: push: @@ -6,8 +6,37 @@ on: - master jobs: + versioning: + name: Update versioning + if: | + (github.repository == 'PSLmodels/OG-Core') + && !(github.event.head_commit.message == 'Update OG-Core') + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + token: ${{ secrets.OGCORE_GITHUB }} + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build changelog + run: pip install yaml-changelog && make changelog + - name: Preview changelog update + run: ".github/get-changelog-diff.sh" + - name: Update changelog + uses: EndBug/add-and-commit@v9 + with: + add: "." + committer_name: Github Actions[bot] + author_name: Github Actions[bot] + message: Update OG-Core + github_token: ${{ secrets.OGCORE_GITHUB }} deploy: - name: Publish to PyPI + name: Tag, release, Publish to PyPI if: github.repository == 'PSLmodels/OG-Core' runs-on: ubuntu-latest steps: @@ -17,6 +46,15 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.12" + - name: Publish new git tag + run: ".github/publish-tag.sh || true" + - name: Publish new release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + body: | + ${{ steps.preview.outputs.changelog }} + name: ${{ github.ref[1:] }} - name: Build package run: make pip-package - name: Publish a Python distribution to PyPI diff --git a/Makefile b/Makefile index a32fd53c5..7b4888666 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,18 @@ # to work in that environment (and not on Windows). # USAGE: OG-Core$ make [TARGET] +changelog: + build-changelog changelog.yaml --output changelog.yaml --update-last-date --start-from 0.11.9 --append-file changelog_entry.yaml + build-changelog changelog.yaml --org PSLmodels --repo OG-Core --output CHANGELOG.md --template .github/changelog_template.md + bump-version changelog.yaml setup.py + rm changelog_entry.yaml || true + touch changelog_entry.yaml +format: + black . -l 79 + linecheck . --fix +documentation: + jb clean ./docs/book + jb build ./docs/book .PHONY=help help: @echo "USAGE: make [TARGET]" diff --git a/README.md b/README.md index ae96b2ae1..e506ec173 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ | | | | --- | --- | | Org | [![PSL cataloged](https://img.shields.io/badge/PSL-cataloged-a0a0a0.svg)](https://www.PSLmodels.org) [![OS License: CCO-1.0](https://img.shields.io/badge/OS%20License-CCO%201.0-yellow)](https://github.com/PSLmodels/OG-Core/blob/master/LICENSE) [![Jupyter Book Badge](https://jupyterbook.org/badge.svg)](https://pslmodels.github.io/OG-Core/) | -| Package | [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-3916/) [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3108/) [![Python 3.11](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3118/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | -| Testing | ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/build_and_test.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/deploy_docs.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/check_black.yml/badge.svg?branch=master) [![Codecov](https://codecov.io/gh/PSLmodels/OG-Core/branch/master/graph/badge.svg)](https://codecov.io/gh/PSLmodels/OG-Core) | +| Package | [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3108/) [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3118/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | +| Testing | ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/build_and_test.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/deploy_docs.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/check_format.yml/badge.svg?branch=master) [![Codecov](https://codecov.io/gh/PSLmodels/OG-Core/branch/master/graph/badge.svg)](https://codecov.io/gh/PSLmodels/OG-Core) | OG-Core is an overlapping-generations (OG) model core theory, logic, and solution method algorithms that allow for dynamic general equilibrium analysis of fiscal policy. OG-Core provides a general framework and is a dependency of several country-specific OG models, such as [OG-USA](https://github.com/PSLmodels/OG-USA) and [OG-UK](https://github.com/PSLmodels/OG-UK). The model output includes changes in macroeconomic aggregates (GDP, investment, consumption), wages, interest rates, and the stream of tax revenues over time. Regularly updated documentation of the model theory--its output, and solution method--and the Python API is available [here](https://pslmodels.github.io/OG-Core). @@ -15,9 +15,9 @@ OG-Core is an overlapping-generations (OG) model core theory, logic, and solutio The model is constantly under development, and model components could change significantly. The package will have released versions, which will be checked against existing code prior to release. Stay tuned for an upcoming release! -## Using/contributing to OG-Core +## Using OG-Core -There are two primary methods for installing and running OG-Core on your computer locally. The first and simplest method is to download the most recent `ogcore` Python package from the Python Package Index ([PyPI.org]()). A second option is to fork and clone the most recent version of OG-Core from its GitHub repository and create the conda environment for the `ogcore` package. We detail both of these methods below. +There are two primary methods for installing and running OG-Core on your computer locally. The first and simplest method is to download the most recent `ogcore` Python package from the Python Package Index ([PyPI.org](https://pypi.org/)). A second option is to fork and clone the most recent version of OG-Core from its GitHub repository and create the conda environment for the `ogcore` package. We detail both of these methods below. ### Installing and Running OG-Core from Python Package Index (PyPI.org) @@ -84,12 +84,17 @@ If you run into errors running the example script, please open a new issue in th The CSV output file `./run_examples/ogcore_example_output.csv` can be compared to the `./run_examples/expected_ogcore_example_output.csv` file that is checked into the repository to confirm that you are generating the expected output. The easiest way to do this is to use the `sh example-diffs` command (or `example-diffs` on Windows) from the `run_examples` directory. If you run into errors running the example script, please open a new issue in the OG-Core repo with a description of the issue and any relevant tracebacks you receive. +## Contributing to OG-Core + +Instructions for how to submit changes to the OG-Core repository can be found in the "[Contributor Guide](https://pslmodels.github.io/OG-Core/content/contributing/contributor_guide.html)" chapter in the online Jupyter Book documentation (https://pslmodels.github.io/OG-Core/content/contributing/contributor_guide.html). This open source project follows a standard fork/branch/pull request workflow described here (https://guides.github.com/introduction/flow/), and we use semantic versioning 2.0.0 (http://semver.org/). Please follow the approach described in the [Contributor Guide](https://pslmodels.github.io/OG-Core/content/contributing/contributor_guide.html) to submit changes to the model. + + ## Core Maintainers The core maintainers of the OG-Core repository are: * [Jason DeBacker](https://www.jasondebacker.com/) (GitHub handle: [jdebacker](https://github.com/jdebacker)), Associate Professor, Department of Economics, Darla Moore School of Business, University of South Carolina; President, PSL Foundation; Vice President of Research and Co-founder, Open Research Group, Inc. -* [Richard W. Evans](https://sites.google.com/site/rickecon/) (GitHub handle: [rickecon](https://github.com/rickecon)), Advisory Board Visiting Fellow, Center for Public Finance, Baker Institute for Public Policy at Rice University; President, Open Research Group, Inc.; Director, Open Source Economics Laboratory +* [Richard W. Evans](https://sites.google.com/site/rickecon/) (GitHub handle: [rickecon](https://github.com/rickecon)), Senior Economist, Abundance Institute; President, Open Research Group, Inc.; Director, Open Source Economics Laboratory ## Citing OG-Core diff --git a/changelog.yaml b/changelog.yaml new file mode 100644 index 000000000..1f1391091 --- /dev/null +++ b/changelog.yaml @@ -0,0 +1,7 @@ +- changes: + added: + - The first release of the OG-Core model was version 0.7.0 on 2021-08-30 (see CHANGELOG.md) + - Many releases were tagged between 2021-08-30 and 2024-06-12 (see CHANGELOG.md) + - The most recent release is 0.11.9 (see CHANGELOG.md) + date: 2024-06-12 01:00:00 + version: 0.11.9 diff --git a/changelog_entry.yaml b/changelog_entry.yaml new file mode 100644 index 000000000..91716a94f --- /dev/null +++ b/changelog_entry.yaml @@ -0,0 +1,12 @@ +- bump: patch + changes: + added: + - Adds the following files for automatic versioning, `.github/changelog_template.md`, `.github/get-changelog-diff.sh`, `.github/has-functional-changes.sh`, `.github/is-version-number-acceptable.sh` + - Adds "Check version" job to `build_and_test.yml` GH Action. + - Adds `tag_version.yml` GH Action on push to master branch. + - Adds three new functions to `Makefile` + - Adds starting `changelog.yaml`. + - Updates `contributor_guide.md`. + - Updates `README.md`. + - Renamed code formatting GH Action from `check_black.yml` to `check_format.yml` and updated the actions within. + - Removes hard reference to version number in `./ogcore/__init__.py` so that the version reference automatically updates. diff --git a/docs/book/content/contributing/contributor_guide.md b/docs/book/content/contributing/contributor_guide.md index 50643280e..a3753a9bf 100644 --- a/docs/book/content/contributing/contributor_guide.md +++ b/docs/book/content/contributing/contributor_guide.md @@ -63,18 +63,9 @@ If you have already completed the {ref}`Sec_SetupPython` and {ref}`Sec_SetupGit` OG-Core$ pip install -e . ``` -If you have made it this far, you've successfully made a remote copy (a -fork) of the central `OG-Core` repo. That remote repo is hosted on GitHub.com at [https://github.com/PSLmodels/OG-Core](https://github.com/PSLmodels/OG-Core). You have also created a local repo (a [clone](https://help.github.com/articles/github-glossary/#clone)) that lives -on your machine and only you can see; you will make your changes to -the OG-Core model by editing the files in the `OG-Core` -directory on your machine and then submitting those changes to your -local repo. As a new contributor, you will push your changes from your -local repo to your remote repo when you're ready to share that work -with the team. - -Don't be alarmed if the above paragraph is confusing. The following -section introduces some standard Git practices and guides you through -the contribution process. +If you have made it this far, you've successfully made a remote copy (a fork) of the central `OG-Core` repo. The main repository is hosted in the cloud at https://github.com/PSLmodels/OG-Core. Your fork of that repository is hosted in the cloud on your GitHub account at https://github.com/[YourGitHubHandle]/OG-Core. For example, Richard Evans' fork of OG-Core is at https://github.com/rickecon/OG-Core. You have also created a local repository (a [clone](https://help.github.com/articles/github-glossary/#clone)) of your fork that exists in the memory of your local machine that only you can see. You will make your changes to the OG-Core model by editing the files in the `OG-Core` directory on your machine and then submitting those changes to your local repo. As a new contributor, you will push your changes from your local repo to your remote repo when you're ready to share that work with the team. + +Don't be alarmed if the above paragraph is confusing. The following section introduces some standard Git practices and guides you through the contribution process. (Sec_Workflow)= ## Workflow @@ -87,17 +78,11 @@ GitHub "issues" are an excellent way to ask questions, include code examples, an (Sec_GitHubPR)= ### Submitting a GitHub Pull Request -The following text describes a typical workflow for changing -`OG-Core`. Different workflows may be necessary in some -situations, in which case other contributors are here to help. +The following text describes a typical workflow for changing `OG-Core`. Different workflows may be necessary in some situations, in which case other contributors are here to help. -1. Before you edit the `OG-Core` source code on your machine, - make sure you have the latest version of the central OG-Core - repository by executing the following **four** Git commands: +1. Before you edit the `OG-Core` source code on your machine, make sure you have the latest version of the central OG-Core repository by executing the following **four** Git commands: - a. Tell Git to switch to the master branch in your local repo. - Navigate to your local `OG-Core` directory and enter the - following text at the command line: + a. Tell Git to switch to the master branch in your local repo. Navigate to your local `OG-Core` directory and enter the following text at the command line: ```console OG-Core$ git checkout master @@ -109,9 +94,7 @@ situations, in which case other contributors are here to help. OG-Core$ git fetch upstream ``` - c. Update your local master branch to contain the latest content of - the central master branch using [merge](https://help.github.com/articles/github-glossary/#merge). This step ensures that - you are working with the latest version of `OG-Core`: + c. Update your local master branch to contain the latest content of the central master branch using [merge](https://help.github.com/articles/github-glossary/#merge). This step ensures that you are working with the latest version of `OG-Core`: ```console OG-Core$ git merge upstream/master @@ -123,20 +106,13 @@ situations, in which case other contributors are here to help. OG-Core$ git push origin master ``` -2. Create a new [branch](https://help.github.com/articles/github-glossary/#branch) on your local machine. Think of your - branches as a way to organize your projects. If you want to work on - this documentation, for example, create a separate branch for that - work. If you want to change an element of the `OG-Core` model, create - a different branch for that project: +2. Create a new [branch](https://help.github.com/articles/github-glossary/#branch) on your local machine. Think of your branches as a way to organize your projects. If you want to work on this documentation, for example, create a separate branch for that work. If you want to change an element of the `OG-Core` model, create a different branch for that project: ```console OG-Core$ git checkout -b [new-branch-name] ``` -3. As you make changes, frequently check that your changes do not - introduce bugs or degrade the accuracy of the `OG-Core`. To do - this, run the following command from the command line from inside - the `OG-Core/ogcore` directory: +3. As you make changes, frequently check that your changes do not introduce bugs or degrade the accuracy of the `OG-Core`. To do this, run the following command from the command line from inside the `OG-Core/ogcore` directory: ```console OG-Core/ogcore$ pytest @@ -162,15 +138,42 @@ situations, in which case other contributors are here to help. You may need to resolve conflicts that arise when another contributor changed the same section of code that you are changing. Feel free to ask other contributors for guidance if this happens to you. If you do need to fix a merge conflict, re-run the test suite afterwards (step 4.) -6. When you are ready for other team members to review your code, make your final commit and push your local branch to your remote repo: +6. Make sure your changes conform to the formatting requirements of the OG-Core repository. We use the [`black`](https://pypi.org/project/black/) formatting package. You can automatically check the formatting of your changes by making sure your `ogcore-dev` conda environment is activated and typing the following commands. If you are on a Mac or Linux operating system, type the following commands in your terminal. + ```console + [Mac or Linux]OG-Core$ make format or [Windows]OG-Core$ black . -l 79 and [Windows]OG-Core$ linecheck . --fix + OG-Core$ git status + OG-Core$ git add -A + OG-Core$ git commit -m "Black formatted files" + OG-Core$ git push origin [BranchName] + ``` + +7. Update the empty [`changelog_entry.yaml`](https://github.com/PSLmodels/OG-Core/blob/master/changelog_entry.yaml) file. Our versioning process requires an updated to the version number for every pull request. This file describes the changes you have made in your pull request. It has the following format: + ```yaml + - bump: {major, minor, patch} + changes: + {added, removed, changed, fixed}: + - Updates these files and functions + - Removes these files and functions + - Solved this error or Issue + - Fixed this error or issue introduced in this PR + ``` + A `major` bump moves the first digit of the version number up by one and would be used for a major update, refactor, or campatibility change. A `minor` bump moves the second digit of the version number up by one and would be used for adding a new significant feature or module. And a `patch` bump moves the third digit of the version number up by one and would be used for a minor addition, fix, or change to already existing calculation. Here is an example of an fictional `changelog_entry.yaml` file that could be submitted with a PR. + ```yaml + - bump: patch + changes: + added: + - Adds automatic versioning workflow by updating `build_and_test.yml`, adding ` + - Updates `README.md` + ``` + +8. When you are ready for other team members to review your code, make your final commit and push your local branch to your remote repo: ```console OG-Core$ git push origin [new-branch-name] ``` +9. From the GitHub.com user interface, [open a pull request](https://help.github.com/articles/creating-a-pull-request/#creating-the-pull-request). -7. From the GitHub.com user interface, [open a pull request](https://help.github.com/articles/creating-a-pull-request/#creating-the-pull-request). - -8. When you open a GitHub pull request, a code coverage report will be automatically generated. If your branch adds new code that is not tested, the code coverage percent will decline and the number of untested statements ("misses" in the report) will increase. If this happens, you need to add to your branch one or more tests of your newly added code. Add tests so that the number of untested statements is the same as it is on the master branch. +10. When you open a GitHub pull request, a code coverage report will be automatically generated. If your branch adds new code that is not tested, the code coverage percent will decline and the number of untested statements ("misses" in the report) will increase. If this happens, you need to add to your branch one or more tests of your newly added code. Add tests so that the number of untested statements is the same as it is on the master branch. (Sec_SimpleUsage)= diff --git a/ogcore/__init__.py b/ogcore/__init__.py index c360e7800..bcedd04ba 100644 --- a/ogcore/__init__.py +++ b/ogcore/__init__.py @@ -2,6 +2,7 @@ Specify what is available to import from the ogcore package. """ +import ogcore from ogcore.SS import * from ogcore.TPI import * from ogcore.aggregates import *