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

RFC: Crate changelog field #3779

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from all 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
305 changes: 305 additions & 0 deletions text/0000-crate-changelog-field.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
- Feature Name: crate-changelog-field
- Start Date: 2025-02-25
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

Add changelog support to `cargo`, [crates.io](https://crates.io/) and [doc.rs](https://doc.rs/).

# Motivation
[motivation]: #motivation

Citing [keepachangelog.com](http://keepachangelog.com):

> What is a changelog?
>
> A changelog is a file which contains a curated, chronologically ordered list of notable changes for each version of a project.
>
> Why keep a changelog?
>
> To make it easier for users and contributors to see precisely what notable changes have been made between each release (or version) of the project.
>
> Who needs a changelog?
>
> People do. Whether consumers or developers, the end users of software are
> human beings who care about what's in the software. When the software changes,
> people want to know why and how.

Encouraging crate authors to keep changelogs and increase its visibility for
crate users will definitely benefit crates ecosystem.

From a consumer's perspective, this feature could make the discovery of the changelog much easier.
For instance, the "crates" plugin could leaverage this field to show a link to
the changelog when a user hovers on a dependency in `Cargo.toml`.

![crates-hover](https://github.com/user-attachments/assets/1f6c075b-fffb-4bd8-92d9-6bee16b0f6e3)

Current situation: a consumer usually needs to jump through several hops to find the changelog:

```mermaid
flowchart LR;
editor["crates" plugin in vscode]
crates-io[crates.io crate page]
doc-rs[doc.rs crate page]
crate-web[crate website]
github[crate repository]
google["Google search result"]
repo-changelog[changelog in repository]
web-changelog[changelog on a website]
doc-changelog[changelog on doc.rs]
editor --> crates-io
editor --> doc-rs
crates-io --> github
github --> repo-changelog
github --> web-changelog
github --> doc-changelog
google --> crates-io
google --> github
google --> doc-rs
google -->|unlikely| repo-changelog
google --> web-changelog
google --> doc-changelog
google --> crate-web
crate-web --> web-changelog
crate-web --> repo-changelog
crate-web --> doc-changelog
doc-rs --> doc-changelog
doc-rs --> web-changelog
doc-rs --> crates-io
doc-rs --> crate-web
doc-rs --> github
```

This topic was brought several times, most notable notions are:

- [Previously closed RFC](https://github.com/rust-lang/rfcs/pull/2129)
- [Rustaceans: Please Keep a Changelog!](https://blog.dbrgn.ch/2015/12/1/rust-crates-keep-a-changelog/) ([reddit](https://www.reddit.com/r/rust/comments/3v1ndl/))
- [Cargo issue](https://github.com/rust-lang/cargo/issues/2188)
- [Reddit thread](https://www.reddit.com/r/rust/comments/6vvhjh/)

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

An optional `changelog` field is available, which is currently in the format
of a URL to an external resource.

Examples:

```toml
[package]
name = "foo"
version = "0.1.0"
changelog = "https://github.com/foo-org/foo/releases"
```

```toml
[package]
name = "bar"
version = "1.0.0"
changelog = "https://github.com/bar-org/bar/blob/main/CHANGELOG.md"
```

For crates with `changelog` field, crates.io and docs.rs show a link to the
changelog in the corresponding page of the crate.

# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation

## Cargo

A new `changelog` field will be added to crate manifest,
which only accepts valid URL for now.
However, it is explicitly stated that in the future the field could be
extended to handle other formats than URL and such a change is not considered
breaking.
So external tools should expect that the field could contain contents that are
not valid URL and handle it with caution.

For a cargo workspace, it is possible for several crates to share a changelog
via the usage of `changelog.workspace`, just like
[`documentation.workspace`](https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table).
Comment on lines +120 to +122
Copy link
Contributor

Choose a reason for hiding this comment

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

Mechanism vs policy is tricky.

From a mechanism perspective, this seems ok (these two pieces fit together, let people create whatever solution they want).

From a policy perspective, I worry this will lead to a lot of incorrect links. A repository link is rightfully shared in a workspace. clap, clap_derive, and clap_builer can rightfully share a changelog. But once its in workspace.package, it is unclear what all its relevant for. For example, cargo new will automatically inherit everything in workspace.package which can lead to inheriting irrelevant changelogs. For example, if I run cargo new clap_complete_fish, I'll get claps changelog. That could be easy to overlook and only find out if you test our your own links once published.

The example is given of documentation.workspace. We didn't think too much on what field to include (there are other, more clear cases of regrets for what we allowed to inherit) and have often overlooked that because it rarely needs to be set these days because crates.io infers it.


For now, `cargo publish` will check if the `changelog` field is a valid URL,
unless `--no-verify` is also specified.
Copy link
Member

Choose a reason for hiding this comment

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

--no-metadata is a better fit.

Suggested change
unless `--no-verify` is also specified.
unless `--no-metadata` is also specified.

Copy link
Contributor

@epage epage Feb 28, 2025

Choose a reason for hiding this comment

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

If its a url, shouldn't that be part of the schema and always error (on any command), if present?

Copy link
Author

Choose a reason for hiding this comment

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

My initial idea was that when non-url path become supported for changelog in the future, someone publishing a crate with it using an older cargo might want to skip this check.

But I agree with @weihanglo that we should use a different flag because --no-verify is skipping too many checks.

Copy link
Contributor

Choose a reason for hiding this comment

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

If parsers are supposed to get any meaning from the field, it likely needs one format. Alternative formats could be handled with alternate fields (like license and license-file) or dotted keys (e.g. this could be changelog.url)

Copy link
Member

Choose a reason for hiding this comment

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

If parsers are supposed to get any meaning from the field…

Agree with this. It depends on how much functionality we expect from this field.

`cargo publish` does not check if the URL in the `changelog` field points
to a valid changelog resource.

## Crates.io and docs.rs

A new link to the changelog will show up in crates.io and docs.rs for crates
that uses the `changelog` field.

crates.io and docs.rs should again check if the field is valid URL.
If the field is not valid URL, nothing shows.

For docs.rs, this link can be added to the `Links` section of the
`<crate-name>-<version>` drop-down menu.

For crates.io, this link can be placed in the right(in desktop mode) sidebar,
alongside with other links like `Repository` and `Documentation`.
And additionally, the link can show in the crate cards in crates.io search
results, as `Homepage` and `Repository` links also show there.

# Drawbacks
[drawbacks]: #drawbacks

- This proposal does not check if the `changelog` field points to a valid
external changelog, requiring crate authors to do that check themselves.
- This proposal does not require the changelog to be present in the crate,
making offline usage of the `chagelog` field impractical.
- This proposal does not constrain the format of the changelog, making it hard
for external tools to consume the contents of the changelog.
Comment on lines +145 to +153
Copy link
Contributor

Choose a reason for hiding this comment

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

Another drawback: this requires treating packages in a workspace as a pet (individual care), rather than cattle (only group care) which we've been moving away from with features like workspace inheritance, automatic docs.rs links etc.

If I were to use this in a workspace, I have to manually set up the link when creating or moving a workspace member without any way to verify it until I push to the upstream repo. By the time the new package is merged, I'm unlikely to remember to go back and test the link. I'm also unlikely to remember to test when publishing. Most likely, I'll only discover there is a problem when someone reports it. Today, the amount of per-package metadata I have to enter is minimal and is almost all verified locally or at least before publish.

Choose a reason for hiding this comment

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

These last few comments let me to conclusion that cargo publish shall require publication from tagged commit (tricky as git is golden standard, but not only VCS used), then commits list starting from previous tag shall be included as formal changelog - this would eliminate crates without references to repositories (plenty) and provide guarantee the content published on the crates.io is consisted with code changes on that repository (today rouge party could publish something not in the repo if managed to steal the key).

But I feel I'm running too far with this idea in the context of this RFC.

Whatever angle I look at this, I see (as with docs.rs) there should be sensible defaults for the changelog (peekable from crates.io for each new release/publication), for me this looks like CHANGELOG.md in directory of each crate with fallback to CHANGLOG.md of a workspace with some flag of this being the case.

The whole idea only makes sense of the changelog shows changes for particular release, not some generic journal of changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't just require deeper git integration (and lack of support for other vcs') but Cargo to know your tag format and to handle changes in tag formats. As mentioned elsewhere, commits are also a fairly low quality changelog. That can be improved through conventions but then we'd need to enforce those conventions. Those conventions also do not help when a commit crosses multiple packages.

The whole idea only makes sense of the changelog shows changes for particular release, not some generic journal of changes.

The challenge is doing so without running into the problems #2129 ran into.

At least with this RFC, if I were to feel comfortable setting this up for all workspace members, I would tweak my changlogs so the anchors are more predictable and setup a cargo-release regex to update the url anchor used in package.changlog every release so it at least points to the right location.

- Although `changelog` URL usually won't change from release to release,
sometimes a crate might change its `changelog` URL, which could invalidate
the `changelog` URLs in previously published versions. This is a clear indication
that `changelog` URL is inheritly a piece of mutable metadata that could be kept per
crate instead of per crate version. However, currently there is no ideal solution
to handle mutable metadata associated with crates.

# Rationale and Alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

## Rationale
[rationale]: #rationale

Most of the time, the producer of changelogs are crate authors
and the consumer of changelogs are other crate authors.
For human consumption, it is ideal to have the changelog in a rendered format.
But handling rendering of various formats in crates.io is a heavy task.
However, many existing crates already have changelogs available in their
repository and the websites backing their repositories can already render the
changelogs. So, in order to avoid unnecessary efforts, this RFC proposes to
just use a valid URL for the `changelog` field.

## Alternative: Previously closed RFC
[alternative-previously-closed-rfc]: #alternative-previously-closed-rfc

[Previously closed RFC](https://github.com/rust-lang/rfcs/pull/2129)
proposed to use a strictly formatted Markdown file or an external link for the
changelog field. The strict format, while ideal for machine consumption,
imposes too much constraint and lead to a refusal.

Another critic of the previous RFC is that if this field is just a link that will be displayed,
then it seems to not bring much value over placing a link within a README.
However, placing a link in README adds another indirection for discovering the changelog,
and it effectively prevents other sources from making the changelog more discoverable.
For example, third-party editor plugins showing crate information in the context of cargo
manifest files cannot leverage the link from README to make changelog more discoverable.

## Alternative: Local File
[alternative-local-file]: #alternative-local-file

The `changelog` field can be a path to a file within the crate,
which opens the possibility for crates.io to render it directly.
However, people have different opinions when it comes to what format the
changelog should use. While markdown is currently the most popular choice,
plain text and reStructuredText are also in use.
Instead of handling the rendering of various different formats of changelog in
crates.io, it is much easier to just have an external link, where an external
website handles the rendering of the changelog so that crate authors can use
any format they see fit for their changelogs.

And changelogs grow over time, which can take significant amount of disk spaces
for crates.io, considering that usually every single release of a crate
will contain all changelogs up to that release.
This particular drawback can be solved by introducing new linting rules.

From another perspective, using an external link can guarantee that we can
always link to the latest changelog, which is supposed to contain all
changelog entries from initial versions to unreleased commits.
If we adopt the local file approach, when we view an outdated version of a
crate on docs.rs, we only get a link to the outdated changelog, which is not
helpful for viewing the breaking changes introduced in new versions, requiring
another click on the doc.rs page to switch to the latest version.

## Alternative: Do Nothing
[alternative-do-nothing]: #alternative-do-nothing

It has been several years after the initial changelog RFC.
We can continue to live without this enhancement.

It is possible to create an external registry that collects the links of
changelogs. However, such effort is neither scalable nor ideal.

# Prior art
[prior-art]: #prior-art

## NPM

[Before npm v7, files named `CHANGES` / `CHANGELOG` / `HISTORY` are always included regardless of settings](https://docs.npmjs.com/cli/v6/configuring-npm/package-json#files).
In npm v7, [those files are no longer always included](https://github.com/npm/npm-packlist/pull/61).
npm does not impose any constraint on the format of those files.
And the website of npm registry doesn't make the changelog more accessible to users.

[A changelog RFC that purposes to introduce `changelog` command to npm](https://github.com/npm/rfcs/pull/8)
was approved in 2018 but got [withdrawn](https://github.com/npm/rfcs/blob/main/withdrawn/0002-changelog.md) later in 2021.
This command makes it easy to view the changelog for a library.

The main points for withdrawal are

- npm no longer always include `CHANGES` / `CHANGELOG` / `HISTORY` files after v7.
- Managing changelog is considered outside of the scope of the **npm cli**
- The RFC is long inactive after being approved.
- Current **npm cli** team is unlikely to implement it

## PyPI

`pyproject.toml` supports `project.urls` table which includes a list of URLs associated with the project.
And these URLs are displayed on the left sidebar of the project page on PyPI.

```toml
[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
Issues = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
```

They keeps [a list of well-known labels](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#urls)
which includes `changelog`(with alias `changes`, `whatsnew` and `history`) and `releasenotes`.

A [search](https://grep.app/search?f.lang=TOML&f.lang.pattern=toml&f.path.pattern=pyproject.toml&q=Changelog+%3D)
for the usage of `changelog` url in `pyproject.toml` yields many results.

## CRAN

The R community follows the GNU convention for [`NEWS`](https://www.gnu.org/prep/standards/standards.html#NEWS-File)
and [`ChangeLog`](https://www.gnu.org/prep/standards/standards.html#Change-Logs) files.

The `NEWS` file contains a list of user-visible changes worth mentioning. Items for old versions are not discarded.
When `NEWS` file become too big, some of the older items should be moved into `ONEWS` file and
a note referring the user to that file should be put at the end of `NEWS` file.

The `NEWS` file can be in plaintext(`NEWS`), Markdown(`NEWS.md`) or R document(`inst/NEWS.Rd`) formats.


The `Changelog` file is more detailed and accurate, including developer-facing changes.

By default, `NEWS` file will be included into a CRAN package but `Changelog` will not,
as documented in the [package structure of an R package](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Package-structure-1).

The CRAN website shows a link to the [rendered `NEWS` file](https://cran.r-project.org/web/packages/ggplot2/news/news.html)
on the package's web page.

R also provides a function `news()` for building and querying R or package news information,
which comes handy when in a REPL or IDE like RStudio.

# Unresolved questions
[unresolved]: #unresolved-questions


# Future possibilities
[future-possibilities]: #future-possibilities

Future RFC could make other formats of the `changelog` field possible
as this RFC has explicitly reserved that possibility.

Future RFC could introduce `changelog.generator`/`changelog.format` fields
which could indicate the generator or the format of the changelog.
This is helpful for machine consumption.

Future RFC could introduce a clippy warning that warns if the crate does not
contain a `changelog` field.