| ****************** |
| Contributing guide |
| ****************** |
| |
| Thanks for your interest in contributing to cpplint. |
| |
| Any kinds of contributions are welcome: Bug reports, Documentation, Patches. However, here are some contributions you probably shouldn't make: |
| |
| * Drastic reorganization |
| * Making the code conform to Google's Python style guidelines |
| * Features that could be regarded as a security vulnerability |
| |
| If you need some ideas, you may check out some of the tasks in our `issue tracker <https://github.com/cpplint/cpplint/issues>`_. |
| |
| Development |
| =========== |
| |
| For many tasks, it is okay to just develop using a single installed python version. But if you need to test/debug the project in multiple python versions, you need to install those versions: |
| |
| 1. (Optional) Install multiple python versions |
| |
| 1. (Optional) Install `pyenv <https://github.com/pyenv/pyenv-installer>`_ to manage python versions |
| 2. (Optional) Using pyenv, install the python versions used in testing:: |
| |
| pyenv install 3.<version> |
| # ... |
| pyenv local 3.<version> ... |
| |
| It may be okay to run and test python against locally installed libraries, but if you need to have a consistent build, it is recommended to manage your environment using virtualenv: `virtualenv <https://virtualenv.pypa.io/en/latest/>`_, `virtualenvwrapper <https://pypi.org/project/virtualenvwrapper/>`_:: |
| |
| mkvirtualenv cpplint [-p /usr/bin/python3] |
| pip install .[dev] |
| |
| Alternatively, you can locally install patches like this:: |
| |
| pip install -e .[dev] |
| # for usage without virtualenv, add --user |
| |
| Please install pre-commit locally to run the linters before committing:: |
| |
| pipx install pre-commit |
| pre-commit install |
| |
| Pull requests |
| ------------- |
| |
| When you're finished with a pull request, please: |
| |
| * add a relevant test case to cpplint_unittest.py |
| * add a summary of what your changes do to CHANGELOG.rst |
| * specify the problem solved in the pull request |
| * make sure that your code passes the tests and lints |
| * don't force-push to the branch. These make the commit history messy, and we squash all commits when merging anyways. |
| |
| .. _testing: |
| |
| Testing |
| ------- |
| |
| You can test your changes under your local python environment by running the tests and lints below: |
| |
| .. code-block:: bash |
| |
| # install test requirements |
| pip install .[test] |
| # run a single test |
| pytest --no-cov cpplint_unittest.py -k testName |
| # run a single CLI integration test |
| pytest --no-cov cpplint_clitest.py -k testSillySample |
| # run all tests. you don't have to run the above tests separately |
| pytest |
| # lint the code |
| pylint cpplint.py |
| pre-commit run --all-files |
| |
| Alternatively, you can run `tox` to automatically run all tests and lints. Use `-e ` followed by the python runner and version (which you must have installed) to automatically generate the testing environment and run the above tests and lints in it. For example, `tox -e py39` does the steps in Python 3.9, `tox -e py313` does the steps in Python 3.13, and `tox -e pypy3` does the steps using the latest version of the pypy interpreter. |
| |
| Releasing |
| ========= |
| |
| The release process first prepares the documentation, then publishes to testpypi to verify, then releases to real pypi. Testpypi acts like real pypi, so broken releases cannot be deleted. For a typical bugfixing release, no special issue on testpypi is expected (but it's still good practice). The commands are documented below, and assume you've went through the testing steps above. |
| |
| .. code-block:: bash |
| |
| # prepare files for release |
| $EDITOR cpplint.py # increment the version |
| $EDITOR CHANGELOG.rst # log changes |
| git add cpplint.py CHANGELOG.rst |
| git commit -m "Releasing x.y.z" |
| # Build |
| pip install --upgrade build wheel twine |
| rm -rf dist |
| python -m build --sdist --wheel |
| # Test release, requires account on testpypi |
| twine upload --repository testpypi dist/* |
| # ... Check website and downloads from https://test.pypi.org/project/cpplint/ |
| # Actual release |
| twine upload dist/* |
| git tag x.y.z |
| git push --tags |
| |
| After releasing, it is be good practice to comment on completed GitHub issues to notify authors. |
| |
| Catching up with Upstream |
| ========================= |
| |
| For maintainers, it is a regular duty to look at what cpplint changes were merged upstream and include them in this fork (though these updates happen rarely). |
| |
| Checkout here and upstream google: |
| |
| .. code-block:: bash |
| |
| git clone git@github.com:cpplint/cpplint.git |
| cd cpplint |
| git remote add google https://github.com/google/styleguide |
| |
| To incorporate google's changes: |
| |
| .. code-block:: bash |
| |
| git fetch google gh-pages |
| |
| ## Merge workflow (clean, no new commits) |
| git checkout develop -b updates |
| git merge google/gh-pages # this will have a lot of conflicts |
| # ... solve conflicts |
| git merge -- continue |
| |
| ## Rebase workflow (dirty, creates new commits) |
| git checkout -b updates FETCH_HEAD |
| git rebase develop # this will have a lot of conflicts, most of which can be solved with the next command (run repeatedly) |
| # solve conflicts with files deleted in our fork (this is idempotent and safe to be called. when cpplint.py has conflicts, it will do nothing) |
| git status | grep 'new file:' | awk '{print $3}' | xargs -r git rm --cached ; git status | grep 'deleted by us' | awk '{print $4}' | xargs -r git rm |
| git status --untracked-files=no | grep 'nothing to commit' && git rebase --skip |
| |
| git push -u origin updates |
| # check github action |
| git push origin --delete updates |
| |
| git rebase updates develop |
| git branch -D updates |
| git push |
| |
| Setup fetching of pull requests in .git/config: |
| |
| .. code-block:: bash |
| |
| [remote "origin"] |
| url = git@github.com:cpplint/cpplint.git |
| fetch = +refs/heads/*:refs/remotes/origin/* |
| # following line should be new, fetches PRs from cpplint |
| fetch = +refs/pull/*/head:refs/remotes/origin/pr/* |
| [remote "google"] |
| url = https://github.com/google/styleguide |
| fetch = +refs/heads/*:refs/remotes/google/* |
| # following line should be new, fetches PRs from google/styleguides |
| fetch = +refs/pull/*/head:refs/remotes/google/pr/* |
| |
| |
| To compare this for with upstream (after git fetch): |
| |
| .. code-block:: bash |
| |
| git diff google/gh-pages:cpplint/cpplint.py develop:cpplint.py |
| git diff google/gh-pages:cpplint/cpplint_unittest.py develop:cpplint_unittest.py |