First read the overall Qiskit project contributing guidelines.
In addition to the general guidelines, there are specific details for contributing to qiskit_sphinx_theme, these are documented below.
There are a few important subfolders to be aware of:
This subfolder contains the HTML, CSS, and Python files that are used for the qiskit-ecosystem
theme. It has these folders:
assets
: CSStheme
: HTML templates and thetheme.conf
config file
The top-level Python files are used for logic used by the theme, such as translations.py
determining what URLs the HTML should use for translations support.
This subfolder contains a scaled down version of the Sphinx build that builds the documentation for the Qiskit repos.
It pulls styles from the /src
subfolder. You can check any changes you are making to theme by building the documentation (see running locally section) and opening the HTML files generated in example_docs/docs/_build
.
This subfolder contains guidance on how to write documentation and build sphinx projects for Qiskit and Qiskit Ecosystem projects. You can view the fully rendered docs guide at https://qisk.it/docs-guide
We use Tox, which you will need to install globally (e.g. using pipx
).
- Run Python tests:
tox -e py
- Build
example_docs/
:tox -e docs
- Open up
example_docs/docs/_build/index.html
in your browser
- Build
docs_guide
:tox -e docs-guide
- Open up
docs_guide/_build/html/index.html
in your browser.
- Run doctests for the docs guide:
tox -e doctest
Sometimes Sphinx's caching can get in a bad state. First, try running tox -e clean
, which will remove Sphinx's cache. If you are still having issues, try adding -r
your command, e.g. tox -e docs -r
. -r
tells Tox to reinstall the dependencies.
We use visual regression testing via Playwright to take screenshots of the site and check that every change we make is intentional. If a screenshot has changed, the test will fail.
If the change was intentional, we need to update the screenshot. Otherwise, it means your change unintentionally impacted something, so you need to tweak your change.
The test runner creates a folder called snapshot_results
, which is useful to determine what the difference is. For each failed test, there will be three files:
<my-test-name>-actual.png
, what your change resulted in.<my-test-name>-expected.png
, what we expected.<my-test-name>-diff.png
, a heat map showing where the differences are.
We upload snapshot_results
in CI. So, you can get the changed snapshot from GitHub Actions:
- Navigate to the GitHub Actions page for the "Tests" action.
- Open the "Summary" page with the house icon.
- Under the "Artifacts" section, there should be a "snapshot_results" entry. Download it.
You can also run the tests locally for faster iteration, although it requires a little setup. If you don't want to install the below tools, it is okay to use CI for snapshot testing.
First, you need to install:
- Node.js. If you expect to use JavaScript in other projects, consider using NVM. Otherwise, consider using Homebrew or installing Node.js directly.
- Docker. You must also ensure that it is running.
- If you cannot install Docker Desktop (such as IBM contributors), you can use Rancher Desktop. When installing, choose Moby/Dockerd as the engine, rather than nerdctl. To ensure it's running, open up the app "Rancher Desktop".
Then, to run the tests locally:
npm install
npm run test
.- Warning: the very first time you run the tests, they will fail because the
snapshot-results
folder will not yet exist. Try running again.
- Warning: the very first time you run the tests, they will fail because the
The docs will rebuild every time you run npm run test
.
First, get the snapshot_results
folder, either by downloading it from CI or by running the tests locally. Then:
- Find the "actual" snapshot for the failing test, such as
api-docs-class-page-1-actual.png
. - Copy that snapshot into the folder
tests/js/tests.js-snapshots
. Rename the-actual.png
file ending to be-linux.png
and overwrite the prior file.
Copy the tests in tests.js
for inspiration. Make sure the selector you use in page.locator()
is accurate. Title the tests with a useful but concise description of what you're testing.
Then, run the tests either locally or in CI to generate the snapshots. When running locally, the files will be added automatically. When using CI, follow the section How to update the expected snapshot for intentional changes.
We upload the docs builds to CI. So, you can download what the site will look like from GitHub Actions:
- Navigate to the GitHub Actions page for the "Tests" action.
- Open the "Summary" page with the house icon.
- Under the "Artifacts" section, there should be a "html_docs" entry. Download it. Un-tar it, then open the
index.html
page in a browswer.
Contributors with write access can also use live previews of the docs: GitHub will deploy a website using your changes. To use live previews, push your branch to upstream
rather than your fork. GitHub will leave a comment with the link to the site. Please prefix your branch name with your initials, e.g. EA/add-translations
, for good Git hygiene.
We use Sphinx's inheritance feature because our theme is built on top of Furo. The furo
inheritance is configured in theme/qiskit-sphinx-theme/theme.conf
. Sphinx will default to using all the files from Furo. But if we have a file with the same name as Furo, then Sphinx will use our copy. That allows us to override only what we care about.
We try to keep changes to a minimum because every divergence we make from base Furo increases our maintenance burden. Hence we prioritise only making changes that are important to the Qiskit Ecosystem brand. If the change would be generally useful to other users of Furo, we try to contribute upstream to the Furo project itself.
Copy the HTML template from Furo and save it in the same file path. Then, at the top of the file, add this header:
{#-
This file is vendored from Furo (created by Pradyun Gedam) and used under the MIT license.
When adding custom Qiskit code, surround it with `QISKIT CHANGE: start` and
`QISKIT CHANGE: end` Jinja-style comments.
-#}
When making changes, use those comments to make clear where and what we changed. For example:
{#- QISKIT CHANGE: start. -#}
{% include "custom_templates/extra_head.html" %}
{#- QISKIT CHANGE: end. -#}
If the change is greater than 1-3 lines, write the code in a new file in theme/qiskit-sphinx-theme/custom_templates
, then use Jinja's include
directive, as shown in the example right above.
Make CSS changes in the file assets/styles/qiskit-sphinx-theme.css
. It takes precedence over any CSS rules from Furo.
When adding changes, document the rationale unless the code is already self-documenting and obvious. Group similar changes into sections.
You can change Furo's CSS variable values by setting them in the body
rule at the top. When introducing our own CSS variables, prefix it with --qiskit
for clarity, e.g. --qiskit-my-variable
.
Update the version in pyproject.toml
. Always pin to an exact version of Furo.
However, when updating, closely analyze each commit in the release to check for any changes that would break our fork. We want to make sure that our HTML files are always in sync with Furo. If they have made any changes, then add them back to our copy of the file.
Edit the file theme/qiskit-sphinx-theme/partials/icons.html
. Copy the HTML code of the <svg></svg>
tags and add them as the first element within the <symbol>
tag. Don't forget to include the id
attribute, which will serve as the name associated with the icon.
To use the icon, reference it with #
.
We use semantic versioning. Every release is part of one specific "minor version release series"; for example, 1.11.0rc1 and 1.11.3 are both part of the 1.11 release series.
When starting a new minor release series like 1.11
, we create a new Git branch 1.11
. That allows us to keep making breaking changes to main
without impacting prior releases. We can then cherry-pick relevant bug fixes from main
to the release branch like 1.11
.
The release process changes whether you are releasing the very first rc1
for that release series, e.g. 1.11.0rc1
or 1.12.0rc1
. Otherwise, all other releases follow the same process.
rc1
s for patch releases (e.g. 1.11.1rc1
) should use the other process below. This process is only for the first release in the release series, e.g. 1.11.0rc1
.
- Bump the version:
git checkout main
git pull upstream main
git checkout -b release-<version-number>
, e.g.release-1.11.0rc1
- Bump
src/qiskit_sphinx_theme/__init__.py
to use the new version, e.g. Qiskit#207 - PR the change and land it
- Push the Git tag:
git checkout main
git pull upstream main
to pull the version bump. If other commits have landed since the version bump, usegit revert --hard <sha>
to change to the version bump's commit (you can find the SHA withgit log --oneline
).git tag <full-version>
, e.g. 1.11.0rc1git push upstream <full-version>
- Create the new Git branch:
- Make sure that you are still on
main
and on the commit of the version bump. git checkout -b <minor-release-version>
, e.g.1.11
. This should not include the patch version.git push upstream <minor-release-version>
- Make sure that you are still on
- Follow the instructions in the section "Final steps shared by both processes".
Use this process for:
- All release candidates other than
rc1
- All stable releases, like
1.11.1
- Cherry-pick all relevant changes to the release branch, e.g.
1.11
:- Look for PRs that have the label
needs cherrypick
: https://github.com/Qiskit/qiskit_sphinx_theme/issues?q=label%3A%22needs+cherrypick%22+ git fetch --all
git checkout <release-branch>
, e.g.1.11
.- For each PR:
git checkout -b cp-<short-description>
, e.g.cp-scrolling-fix
- Find the commit SHA at the bottom of the PR. There will be a message like
merged commit 9e02144 into ...
git cherry-pick <commit SHA>
git push origin <branch-name-from-step-1>
, e.g.cp-scrolling-fix
. Open a pull request. Change the PR's merge base in the top to the release branch; it defaults tomain
.- Remove the
needs cherrypick
label from the original PR.
- Look for PRs that have the label
- Bump the version:
git checkout <release-branch>
, e.g.1.11
.git pull upstream <release-branch>
, e.g.1.11
.git checkout -b release-<full-version>
, e.g.release-1.11.0rc3
- Bump
src/qiskit_sphinx_theme/__init__.py
to use the new version, e.g. Qiskit#207 - PR the change and land it. Change the PR's merge base in the top to the release branch; it defaults to
main
.
- Push the Git tag:
git checkout <release-branch>
, e.g.1.11
.git pull upstream <release-branch>
to pull the version bump. If other commits have landed since the version bump, usegit revert --hard <sha>
to change to the version bump's commit (you can find the SHA withgit log --oneline
).git tag <full-version>
, e.g. 1.11.0git push upstream <full-version>
- Follow the instructions in the section "Final steps shared by both processes".
- Check that the release worked:
- Check that the tag shows up in https://github.com/Qiskit/qiskit_sphinx_theme/tags
- The pip release is automated with GitHub Actions. After a few minutes, check that https://pypi.org/project/qiskit-sphinx-theme/#history has the release. (You can skip to the next step while waiting)
- Announce the release on GitHub:
- On https://github.com/Qiskit/qiskit_sphinx_theme/tags, click the
...
to the right of the released tag's row. Click "Create release" - Add release notes, e.g. https://github.com/Qiskit/qiskit_sphinx_theme/releases/tag/1.11.0rc1
- Add the sections
**Features / API Changes:**
and**Bug Fixes:**
. - Use
git log --oneline
to see what changes have been made. Copy and paste those entries as bullets into the relevant sections. Ignore any "internal only" changes like CI changes or updates to the README. - Preview the release notes with the "Preview" tab.
- Add the sections
- Click "Publish release"
- On https://github.com/Qiskit/qiskit_sphinx_theme/tags, click the