Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: adjust the release process to handle publishing ops and ops-scenario #1432

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ coverage.xml
/dist
/build
/docs/_build
/testing/ops_scenario.egg-info/
/testing/src/ops_scenario.egg-info/
ops_scenario.egg-info
/testing/build/
/testing/dist/

Expand Down
189 changes: 138 additions & 51 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,65 +318,152 @@ the build frontend is [build](https://pypi.org/project/build/).

# Publishing a Release

To make a release of the ops library, do the following:

1. Visit the [releases page on GitHub](https://github.com/canonical/operator/releases).
2. Click "Draft a new release"
3. The "Release Title" is the full version numbers of ops and ops-scenario, in
the form `ops <major>.<minor>.<patch> & ops-scenario <major>.<minor>.<patch>`
and a brief summary of the main changes in the releases. If the release only
includes one of `ops` and `ops-scenario`, leave out the other one.
To make a release of the `ops` and/or `ops-scenario` packages, do the following:

1. Check if there's a `chore: update charm pins` auto-generated PR in the queue.
If it looks good, merge it and check that tests still pass. If needed, you
can re-trigger the `Update Charm Pins` workflow manually to ensure latest
charms and ops get tested.
2. Visit the [releases page on GitHub](https://github.com/canonical/operator/releases).
3. Click "Draft a new release"
4. The "Release Title" is the full version numbers of ops and/or ops-scenario,
in the form `ops <major>.<minor>.<patch> and ops-scenario <major>.<minor>.<patch>`
and a brief summary of the main changes in the release.
For example: `ops 2.3.12 Bug fixes for the Juju foobar feature when using Python 3.12`
4. Have the release create a new tag, in the form `<major>.<minor>.<patch>`
5. Use the "Generate Release Notes" button to get a copy of the changes into the
notes field.
6. Group the changes first by package (`ops` and `ops-scenario`) and then by
the commit type (feat, fix, etc.) and use full names (e.g., "Features",
not "feat") for group headings. Strip the commit type prefix from the bullet point,
and capitalise the first word. Strip the username (who did each commit) if the
author is a member of the Charm Tech team.
For example: the PR `docs: clarify where StoredState is stored`
becomes `* Clarify where StoredState is stored` in the "Documentation" section.
7. Where appropriate, collapse multiple tightly related bullet points into a
single point that refers to multiple commits.
8. Create a new branch, and copy this text to the [CHANGES.md](CHANGES.md) file,
stripping out links, who did each commit, the new contributor list, and the
link to the full changelog.
9. Change [version.py](ops/version.py)'s `version` to the
[appropriate string](https://semver.org/).
10. Check if there's a `chore: update charm pins` auto-generated PR in the queue. If it looks
good, merge it and check that tests still pass. If needed, you can re-trigger the
`Update Charm Pins` workflow manually to ensure latest charms and ops get tested.
11. Add, commit, and push, and open a PR to get the changelog and version bump
5. Have the release create a new tag, in the form `<major>.<minor>.<patch>` for
`ops` and `scenario-<major>.<minor>.<patch>` for `ops-scenario`. If releasing
both packages, use the ops tag.
6. Use the "Generate Release Notes" button to get a copy of the changes into the
notes field. The 'Release Documentation' section below details the form that
the release notes and changelog should take.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding a note about choosing the previous release tag to compare to?

I think the rule is: find the previous release tag for each thing you're releasing, and if there is more than one (i.e. an ops only release and a scenario only release), use the older of the two.

Say you had an ops release, then a scenario release, and are now doing a joint release -- you'd want to choose the ops release to generate release notes.

But you'd need to filter out any scenario PRs from before the last scenario release, since they'd have been covered already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding a note about choosing the previous release tag to compare to?

I think the rule is: find the previous release tag for each thing you're releasing, and if there is more than one (i.e. an ops only release and a scenario only release), use the older of the two.

Say you had an ops release, then a scenario release, and are now doing a joint release -- you'd want to choose the ops release to generate release notes.

But you'd need to filter out any scenario PRs from before the last scenario release, since they'd have been covered already.

Yes, this is another place where it gets messy, at least in theory. I think in practice it will be unusual to release only one of the packages, so it ends up being fairly simple. The rule is indeed to pick the oldest I think.

The instructions also don't cover what to do for a patch release, or when doing a normal release after a patch release. I'm leaving that for someone else to explain :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add it to the release instructions! "If you're the first one to do a patch release, update the release instructions with what you did and remove this directive."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification: mostly joking. I'll hit approve now as I don't think any of this is worth blocking merging over (though you have two approvals anyway)

7. For `ops`, change [version.py](ops/version.py)'s `version` to the
appropriate string. For `ops-scenario`, change the version in
[testing/pyproject.toml](testing/pyproject.toml). Both packages use
[semantic versioning]](https://semver.org/), and adjust independently
(that is: ops 2.18 doesn't imply ops-scenario 2.18, or any other number).
8. Add, commit, and push, and open a PR to get the changelogs and version bumps
into main (and get it merged).
12. Back in the GitHub releases page, tweak the release notes - for example,
you might want to have a short paragraph at the intro on particularly
noteworthy changes.
13. Have someone else in the Charm-Tech team proofread the release notes.
14. When you are ready, click "Publish". (If you are not ready, click "Save as Draft".)
15. If the release includes an `ops-scenario` package, then create a new tag in
the form `scenario-<major>.<minor>.<patch>`.

This will trigger automatic builds for the Python packages and publish them to
PyPI ([ops](https://pypi.org/project/ops/) and
[ops-scenario](https://pypi.org/project/ops-scenario)) (authorisation is handled via a
[Trusted Publisher](https://docs.pypi.org/trusted-publishers/) relationship).
9. Save the release notes as a draft, and have someone else in the Charm-Tech
team proofread the release notes.
10. If the release includes both `ops` and `ops-scenario` packages, then push a
new tag in the form `scenario-<major>.<minor>.<patch>`. This is done by
executing `git tag scenario-x.y.z`, then `git push upstream --tags` locally
tonyandrewmeyer marked this conversation as resolved.
Show resolved Hide resolved
(assuming you have configured `canonical/operator` as a remote named
`upstream`).
11. When you are ready, click "Publish". GitHub will create the additional tag.

Pushing the tags will trigger automatic builds for the Python packages and
publish them to PyPI ([ops](https://pypi.org/project/ops/) and
[ops-scenario](https://pypi.org/project/ops-scenario)) (authorisation is handled
via a [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) relationship).
Note that it sometimes take a bit of time for the new releases to show up.

To do a release that does not include an `ops-scenario` package, skip the
step above where a `scenario-` tag is created. To do a release that does not
include an `ops` package, create the `scenario-<major>.<minor>.<patch>` tag as
part of the GitHub release process instead of the `<major>.<minor>.<patch>` one.

See [.github/workflows/publish-ops.yaml](.github/workflows/publish-ops.yaml) and
[.github/workflows/publish-ops-scenario.yaml](.github/workflows/publish-ops-scenario.yaml) for details.
(Note that the versions in the YAML refer to versions of the GitHub actions, not the versions of the ops library.)

You can troubleshoot errors on the [Actions Tab](https://github.com/canonical/operator/actions).

16. Announce the release on [Discourse](https://discourse.charmhub.io/c/framework/42) and [Matrix](https://matrix.to/#/#charmhub-charmdev:ubuntu.com). Mention both the `ops` and `ops-scenario` releases in the same posts, but avoid the word "Scenario", preferring "unit testing API" or "state transition testing".
12. Announce the release on [Discourse](https://discourse.charmhub.io/c/framework/42) and [Matrix](https://matrix.to/#/#charmhub-charmdev:ubuntu.com).

13. Open a PR to change the version strings to the expected
next version, with ".dev0" appended (for example, if 3.14.1 is the next
expected version, use `'3.14.1.dev0'`).

## Release Documentation

`ops` and `ops-scenario` releases have several documentation artifacts, each
serving a separate purpose and covering a different level.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence left me wondering what these different artefacts are specifically and what the implications are for someone doing a release.

Aren't all our docs always tracking main, rather than specific releases?

Are the release artifacts changing from just being zipped source code?

Oh also today I learned that artifacts is US English, and artefacts is British English.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`ops` and `ops-scenario` releases have several documentation artifacts, each
serving a separate purpose and covering a different level.
`ops` and `ops-scenario` releases have several documentation artefacts, each
serving a separate purpose and covering a different level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence left me wondering what these different artefacts are specifically and what the implications are for someone doing a release.

Hmm, I maybe need to use a different term then. They are the things outlined in the subsequent sections: raw logs, changelogs, release notes, release post.

Aren't all our docs always tracking main, rather than specific releases?

Yes, except for these documents that are specifically about the release.

Are the release artifacts changing from just being zipped source code?

The zipped and tar.gz repository dump (what GitHub calls "assets") stay the same: I don't think we can change those, and no-one should really be using them. The CI pipeline produces .tar.gz and wheels of the two packages (unchanged for ops, minor change for ops-scenario in that it previously was wheel-only) that are uploaded to PyPI and attestations for each of those (unchanged for ops, new for ops-scenario). We manually create the CHANGES.md files (unchanged for ops, new for ops-scenario), which are included in both the "assets" and PyPI artefacts. We also manually create the GitHub Releases text and Discourse post, which only live in those places.

Any suggestions for a better/clearer title here? Or clearer text?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see now. I just immediately jumped to build artefacts. Probably just my unfamiliarity with terminology. Mentally substituting with "We produce several pieces of documentation for ops and ops-scenario releases, each serving ..." makes everything make sense for me.


Avoid using the word "Scenario", preferring "unit testing API" or "state
transition testing". Users should install `ops-scenario` with
`pip install ops[testing]` rather than using the `ops-scenario` package name
directly.

### `git log`

`git log` is used to see every change since a previous release. Obviously, no
special work needs to be done so that this is available. A link to the GitHub
view of the log will be included at the end of the GitHub release notes when
the "Generate Release Notes" button is used, in the form:

```
**Full Changelog**: https://github.com/canonical/operator/compare/2.17.0...2.18.0
```

These changes include both `ops` and `ops-scenario`. If someone needs to see
changes only for one of the packages, then the `/testing/` folder can be
filtered in/out.

### CHANGES.md

A changelog is kept in version control that simply lists the changes in each
release, other than chores like bumping version numbers. The changelog for `ops`
is at the top level, in [CHANGES.md](CHANGES.md), and the changelog for
`ops-scenario` is in the `/testing` folder, [CHANGES.md](testing/CHANGES.md).
There will be overlap between the two files, as many PRs will include changes to
common infrastructure, or will adjust both `ops` and also the testing API in
`ops-scenario`.

Adding the changes is done in preparation for a release. Use the "Generate
Release Notes" button in the GitHub releases page, and copy the text to the
CHANGES.md files.

* Group the changes by the commit type (feat, fix, and so on) and use full names
("Features", not "feat", "Fixes", not "fix") for group headings.
* Remove any bullets that do not apply to the package (`ops` only changes for
`ops-scenario`, and `ops-scenario` only changes for `ops`).
* Strip the commit type prefix from the bullet point, and capitalise the first
word.
* Strip the username (who did each commit) if the author is a member of the
Charm Tech team.
* Replace the link to the pull request with the PR number in parentheses.
* Where appropriate, collapse multiple tightly related bullet points into a
single point that refers to multiple commits.

For example: the PR

```
* docs: clarify where StoredState is stored by @benhoyt in https://github.com/canonical/operator/pull/2006
```

is added to the "Documentation" section as:

```
* Clarify where StoredState is stored (#2006)
```

### GitHub Release Notes

The GitHub release notes include the list of changes found in the changelogs,
but:

* If both `ops` and `ops-scenario` packages are being released, include all the
changes in the same set of release notes. If only one package is being
released, remove any bullets that apply only to the other package.
* The links to the PRs are left in full.
* Add a section above the list of changes that briefly outlines any key changes
in the release.

### Discourse Release Announcement

Post to the [framework category](https://discourse.charmhub.io/c/framework/42)
with a subject matching the GitHub release title.

The post should resemble this:

```
The Charm Tech team has just released version x.y.z of ops!

It’s available from PyPI by using `pip install ops`, and `pip install ops[testing]`,
which will pick up the latest version. Upgrade by running `pip install --upgrade ops`.

The main improvements in this release are ...

Read more in the [full release notes on GitHub](link to the GitHub release).
```

17. Open a PR to change [version.py](ops/version.py)'s `version` to the expected
next version, with ".dev0" appended (for example, if 3.14.1 is the next expected version, use
`'3.14.1.dev0'`) and [testing/pyproject.toml](testing/pyproject.toml)'s
`version` similarly.
In the post, outline the key improvements both in `ops` and `ops-scenario` -
the point here is to encourage people to check out the full notes and to upgrade
promptly, so ensure that you entice them with the best that the new versions
have to offer.
Loading