Maintaining cocotb#
This section describes how to maintain cocotb, i.e., the more or less frequent tasks performed by the cocotb maintainers.
Managing of Issues and Pull Requests#
The cocotb project makes use of GitHub labels attached to issues and pull requests to structure the development process. Each issue and pull request can have multiple labels assigned.
The type labels define the type of issue or PR:
type:bug: a bug in existing functionalitytype:feature: new functionalitytype:cleanup: cleanup or refactoring on code, documentation, or other areastype:deprecation: API that should warn and eventually be removedtype:change: an API breaking change that isn’t a deprecation or removaltype:backport: a backport of another PR from master onto a stable branchtype:task: a generic label for anything that doesn’t fall into the above
The status labels give a quick impression of the current status of the issue or PR:
status:worksforme: the issue it not reproducible, or intended behavior (i.e. not a bug)status:blocked: further progress is blocked by a dependency, e.g. other code which must be committed first.status:needs-info: feedback from someone is required. The issue/PR text gives more details.status:duplicate: the same issue is already being handled in another issue/PR.status:close?: issues which can probably be closed, but need a second pair of eyesstatus:needs-proprietary-testing: Help needed testing on a proprietary toolstatus:out-of-scope: An issue or PR that was closed because the feature or bug was deemed to be out of scope
For the use in pull requests the following additional status labels are defined:
status:needs-review: this PR needs at least one reviewstatus:ready-for-merge: this PR is ready (according to the Patch Requirements) to be mergedstatus:needs-rebase: needs a git rebasestatus:needs-newsfragment: Needs a towncrier newsfragment for the changelogstatus:needs-test: needs tests writtenstatus:needs-proprietary-testing: needs testing the change in a simulator we don’t have access to
We occasionally find bugs in upstream projects, such as simulators, Python dependencies, CI tools, etc. The following labels are used for those issues.
upstream: marks the issue as being a issue with an upstream projectstatus:needs-upstream-report: the issue has been diagnosed as an upstream issue, but no upstream report has been filedstatus:upstream-report-filed: the issue has been reported upstream
The category labels help maintainers to filter issues which are relevant to their area of expertise:
category:OS:MacOS: Mac OS/OS X specific issuescategory:OS:Linux: Linux specific issuescategory:OS:Windows: Microsoft Windows-specific issuescategory:simulators: simulator support, including VPI/GPI/etc.category:simulators:activehdl: Aldec Active-HDLcategory:simulators:cvc: Tachyon CVCcategory:simulators:ghdl: GHDLcategory:simulators:icarus: Icarus Verilog (iverilog)category:simulators:ius: Cadence Incisive (IUS)category:simulators:modelsim: Mentor Modelsimcategory:simulators:nvc: NVCcategory:simulators:questa: Mentor Questacategory:simulators:riviera: Aldec Riviera-PROcategory:simulators:vcs: Synopsys VCScategory:simulators:verilator: Verilatorcategory:simulators:xcelium: Cadence Xceliumcategory:codebase:gpi: relating to the GPI or one of the implementationcategory:codebase:pygpi: relating to the Python wrapper around the GPI (embed library and simulator module)category:codebase:scheduler: relating to the coroutine schedulercategory:codebase:triggers: related to triggerscategory:codebase:tasks: related to tasks or coroutinescategory:codebase:tests: relating to code for automating test runs (regression manager)category:codebase:handle: relating to handlescategory:codebase:types: relating to modelling typescategory:codebase:project-automation: relating to included project automation (makefiles, Python runner)category:building: relating to build C/C++ libraries and extension modulescategory:packaging: issues related to (PyPi) packaging, etc.category:docs: documentation issues and fixescategory:hardware-in-the-loop: relating to real-life hardware (HIL)category:performance: performance topicscategory:ci-free: continuous integration and unit testscategory:meta: cocotb repo, maintainers, or communitycategory:extensions: cocotb extension modulescategory:debugging: debugging features
To help new contributors find a good issue to work on one more label is used (following GitHub standard practices):
good first issue: this issue is a good starting point for new contributors. The issue should give an actionable description of what to do to complete this task, along with contact information of a mentor for this task.
cocotb explicitly uses no priority labels, as experience indicates that they provide little value.
Issues and pull requests which are invalid, or where feedback is lacking for four weeks, should be closed.
cocotb Releases#
cocotb aims to keep the master branch always in a releasable state.
At least four times a year an official release should be created.
It is the job of the maintainers to find a suitable time for a release, to communicate it to the community, and to coordinate it.
Doing a Release#
Release notes are always filed under the version being released, e.g. 2.1.0, never under a release candidate.
An rc is tagged from the very notes the final release will ship, so steps 1 and 2 are done once per release, before the first rc.
Run Release 1: Prepare release with the version being released, e.g.
2.1.0or2.1.1.Review, hand-edit if needed, and merge the release notes PR it opens. If a new series was branched off, also merge the “Start X.Y.0 development” PR it opens against
master.Run Release 2: Tag with the version to tag, e.g.
2.1.0rc1first and2.1.0later.For a final release (not an rc): once PyPI publishing succeeds, review and merge the release notes backport PR opened automatically against
master, and the “Start X.Y.Z release cycle” PR opened against the release branch.
If a change lands on the release branch between an rc and the final release, fold it into the existing release notes section by hand and delete its newsfragment in the same PR. “Release 2: Tag” refuses to tag while newsfragments are still pending on the branch, because they would not be covered by the release notes.
Doing a Release Manually#
Do this instead of the steps above if GitHub Actions isn’t available, or a step needs to be redone with something non-standard.
Check out the release branch (
stable/<major>.<minor>, e.g.stable/2.1for version2.1.1), creating it frommasterfirst if this is the first release of the series:VER_MAJOR_MINOR=2.1 VER_FULL=$VER_MAJOR_MINOR.0 # Only for the first release of a new series (major.minor) git fetch origin master git checkout -b stable/$VER_MAJOR_MINOR origin/master git push origin stable/$VER_MAJOR_MINOR # Otherwise: git fetch origin stable/$VER_MAJOR_MINOR git checkout stable/$VER_MAJOR_MINOR
Bump the
VERSIONfile onmasterto the next minor release.Generate the release notes and open a PR against the release branch for review, instead of committing directly:
nox -s release_notes git add docs/source/release_notes.rst docs/source/newsfragments git commit -m "Generate release notes for v$VER_FULL" git push origin HEAD:release-notes/$VER_FULL gh pr create --base stable/$VER_MAJOR_MINOR --title "Release notes for v$VER_FULL" --fill
Review, hand-edit if needed, and merge that PR.
Tag the merged commit and push it. Use the same tag for a release candidate, e.g.
v2.1.0rc1:git fetch origin stable/$VER_MAJOR_MINOR git checkout stable/$VER_MAJOR_MINOR git tag -a v$VER_FULL -m "Release $VER_FULL" git push origin v$VER_FULL
For a final release only (not an rc): once PyPI publishing succeeds, backport the notes to
master:git fetch origin master git checkout master git pull nox -s backport_release_notes -- --until=v$VER_FULL git add docs/source/release_notes.rst docs/source/newsfragments git commit -m "Backport release notes for v$VER_FULL to master" git push origin HEAD:backport-release-notes/$VER_FULL gh pr create --base master --title "Backport release notes for v$VER_FULL to master" --fill
Review and merge that PR too.
Bump the
VERSIONfile on the release branch to the next patch version.
How Releases Work#
Releases are made by pushing an annotated vX.Y.Z tag; that push alone triggers the whole build, test, and PyPI publish pipeline (.github/workflows/build-test-release.yml), so it is the actual point of no return in the process above – every step before it can be redone or abandoned freely.
The only thing that can stop a release after the tag exists is a protection rule on the pypi environment (see below).
That is also why “Release 2: Tag” checks before tagging that the release notes for the version exist on the branch and that no newsfragments are left pending.
Two situations are handled the same way:
The first release of a new minor series (e.g.
2.1.0): a newstable/2.1branch is created offmaster.A patch release on an existing series (e.g.
2.1.1): the existingstable/2.1branch is reused. Any fixes it needs must be backported there first, as described above.
Release 1: Prepare release derives the release branch from the version and creates it from master if it doesn’t exist yet – but only when the version’s patch component is 0, i.e. it’s genuinely the first release of the series; otherwise a missing branch is treated as a typo and the workflow fails rather than guessing.
It then runs towncrier on that branch (via nox -s release_notes) to consume the pending newsfragments into docs/source/release_notes.rst, and opens a PR with the result. Merging that PR is what marks the branch ready to tag, and is the manual gate before anything gets tagged – there’s no automated substitute for it by design.
Release 2: Tag tags the release branch’s current HEAD as vX.Y.Z and pushes it, which triggers build-test-release.yml: it builds the wheels and sdist, runs the full regression suite against them, and – once that passes – publishes to PyPI using Trusted Publishing and creates a GitHub Release for the tag.
The VERSION file names the release the current branch is working towards, as a full X.Y.Z.
It feeds setuptools-git-versioning, which uses it to version the dev builds made from every commit that isn’t tagged, and it is where nox -s release_notes takes the version to file the notes under.
It therefore has to move on whenever a branch starts working towards a different version: to the next minor on master when a series is branched off (done by “Release 1”), and to the next patch on the release branch once a final release is tagged (done by “Release 2”).
Both are proposed as PRs, like everything else these workflows do.
master’s docs/source/release_notes.rst should always show the full release history, including patch releases, even though patch releases only ever run towncrier on a stable branch. For a final release (vX.Y.Z, no rc suffix), build-test-release.yml handles this automatically once publishing succeeds, by calling Release 3: Backport release notes to master: it copies the notes section that was just generated on the release branch back into master, removes the newsfragments it consumed there so they aren’t listed again under the next release, and opens a PR. Release candidates are skipped, since they ship the final release’s notes rather than a section of their own.
The actual work is done by the backport_release_notes nox session, which can also be run locally:
nox -s backport_release_notes -- --until=v$VER_FULL
It takes the finished section out of release_notes.rst as of the tag – hand-edits included – and inserts it into master’s copy in version order, so that backporting a patch release of an older series after a newer series has been released puts it in the right place rather than at the top.
The newsfragments to drop are those the release consumed between --since and the tag.
--since defaults to whichever is more recent of the previous tag reachable from --until and the point where the release branch forked from master; pass it explicitly to override.
If the automatic backport PR needs to be regenerated, or a release from before this automation existed needs backporting, run the same “Release 3” workflow directly instead – it also accepts since_ref.
Release Automation Setup#
The release workflows do not use the default GITHUB_TOKEN: a tag pushed with it does not start any workflow run (so nothing would ever be built or published), and pull requests created with it don’t run any CI.
They authenticate as a GitHub App instead, which needs Contents: Read and write and Pull requests: Read and write on the repository, and to be able to push to master and stable/* if those branches are protected.
Its credentials are read from the repository secrets COCOTB_CI_REPOACCESS_APP_ID and COCOTB_CI_REPOACCESS_APP_PRIVATE_KEY.
Publishing to PyPI runs in the pypi environment.
Adding required reviewers to that environment is the way to get a human confirmation step between the tag and the upload; without protection rules it publishes straight away.
The environment name has to match what cocotb’s Trusted Publishing configuration on PyPI expects – either pypi, or no environment at all.
Backport Changes#
All changes should generally be merged into the master branch first.
If those changes are also needed in a different branch, e.g., a stable branch, they need to be backported.
PRs can be backported fully automated through GitHub, or semi-automated with the ability to resolve merge conflicts.
Start with the automated backport process, and fall back to the manual one if necessary.
Automated PR Backports#
The backporting process starts from an open or already merged PR, typically targeting the master branch.
This PR can then be ported over to any of the stable/* branches.
Open the source PR you’d like to backport on GitHub.
Add the label
backport-to:STABLE_BRANCH_NAME, e.g.backport-to:1.9to backport a change to the branchstable/1.9.If not done yet: Merge the source PR.
Once the source PR is merged, backport automation (in GitHub Actions) will kick in.
If the backport can be performed automatically (i.e., there are no merge conflicts), a new PR is opened against the stable branch.
Otherwise, a comment is left in the source PR with instructions how to perform a manual backport. Follow the instructions below to continue.
Manual PR Backport#
The most convenient way to backport a PR is using the Backport CLI Tool, which also powers the automated backport process.
Install npx on your machine.
Configure authentication for Backport, as described at in their documentation.
In the master branch of the cocotb source tree run
npx backport --pr MY_SOURCE_PR.
Answer questions as necessary.
In case of a merge conflict, Backport will ask for a manual conflict resolution.
This resolution needs to happen in the separate backport repository, typically located at ~/.backport/repositories/cocotb/cocotb.
Backport will create a branch in your fork of the cocotb repository, and create a pull request to merge this branch into the selected stable branch, just like in the automated process.