mirror of
https://git.pumpin.online/funkpower/typikon.git
synced 2026-10-22 18:57:13 +00:00
1.1.2 — one sentence, in all five places a reader meets it
1.1.1 changed the description in Cargo.toml and in the npm package and missed pyproject.toml, which is the one maturin publishes. PyPI took the old summary and neither registry lets that be edited afterwards, so the correction needs a version of its own. The two READMEs had drifted further than the description fields. A registry page leads with the README rather than the summary, and npm's opened by saying the package needs no network without ever saying it covers the Byzantine Catholic churches — which is most of what the sentence was changed to convey. Five files now carry it, and a test reads all five and names the ones that disagree. It was written against the mistake above and fails on it.
This commit is contained in:
@@ -4,6 +4,17 @@ Notable changes, in the terms [docs/versioning.md](docs/versioning.md) sets out.
|
||||
**Calendar** entries change what a day reports, whatever the version number
|
||||
does.
|
||||
|
||||
## 1.1.2
|
||||
|
||||
### Fixed
|
||||
|
||||
- The published description says what the package covers, and says the same
|
||||
thing in both registries. PyPI takes its summary from `pyproject.toml`, which
|
||||
1.1.1 did not update, so it went out with the old one-line text while npm got
|
||||
the new one. The two READMEs had drifted apart as well: npm's opened without
|
||||
mentioning the Byzantine Catholic churches at all. All four now carry one
|
||||
sentence, and a test fails if any of them moves without the others.
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### Fixed
|
||||
|
||||
Generated
+1
-1
@@ -404,7 +404,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
||||
|
||||
[[package]]
|
||||
name = "typikon"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"js-sys",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "typikon"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
description = "The Orthodox liturgical day: feasts, seasons and the fast, computed rather than fetched. Twenty Orthodox jurisdictions and four Byzantine Catholic churches, across the Julian, Revised Julian and Gregorian reckonings."
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# typikon
|
||||
|
||||
The Orthodox liturgical day: feasts, seasons and the fast, computed rather
|
||||
than fetched. The Byzantine Catholic churches are here too, on their own
|
||||
calendars and, where the law has been sourced, under their own particular law.
|
||||
than fetched. Twenty Orthodox jurisdictions and four Byzantine Catholic
|
||||
churches, across the Julian, Revised Julian and Gregorian reckonings.
|
||||
|
||||
Everything derives from the paschalion and the fixed calendar, so it needs no
|
||||
network, cannot go stale, and answers for any year you ask about. No API key,
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
# typikon
|
||||
|
||||
The Orthodox liturgical day: feasts, seasons and the fast, computed rather
|
||||
than fetched. No network, no data files, no service to be up.
|
||||
than fetched. Twenty Orthodox jurisdictions and four Byzantine Catholic
|
||||
churches, across the Julian, Revised Julian and Gregorian reckonings.
|
||||
|
||||
No network, no data files, no service to be up.
|
||||
|
||||
```sh
|
||||
npm install typikon
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "typikon"
|
||||
description = "The Orthodox liturgical day: feasts, seasons and the fast, computed rather than fetched"
|
||||
description = "The Orthodox liturgical day: feasts, seasons and the fast, computed rather than fetched. Twenty Orthodox jurisdictions and four Byzantine Catholic churches, across the Julian, Revised Julian and Gregorian reckonings."
|
||||
readme = "README.md"
|
||||
license = "GPL-2.0-only"
|
||||
license-files = ["LICENSE"]
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
//! The packaging metadata, which lives in three files and is published to two
|
||||
//! registries.
|
||||
//!
|
||||
//! `Cargo.toml` describes the crate, `pyproject.toml` is what maturin puts on
|
||||
//! PyPI, and `npm/package.json.in` is what npm shows. Nothing makes them agree
|
||||
//! and nothing notices when they stop: a description edited in one of the three
|
||||
//! reaches one registry and not the other, and the wrong one is then frozen
|
||||
//! into a release, because neither registry lets published metadata be edited.
|
||||
//! That has happened once already.
|
||||
//!
|
||||
//! The two READMEs open with the same sentence, because that paragraph is the
|
||||
//! first thing shown on both registry pages and is what most people will read
|
||||
//! instead of the description field.
|
||||
|
||||
use std::fs;
|
||||
|
||||
/// The value of a `key = "…"` line, from the first section that has one.
|
||||
fn toml_string(path: &str, key: &str) -> String {
|
||||
let text = fs::read_to_string(path).unwrap_or_else(|e| panic!("{path}: {e}"));
|
||||
for line in text.lines() {
|
||||
let line = line.trim();
|
||||
let Some(rest) = line.strip_prefix(key) else { continue };
|
||||
let Some(rest) = rest.trim_start().strip_prefix('=') else { continue };
|
||||
let rest = rest.trim();
|
||||
if let Some(v) = rest.strip_prefix('"').and_then(|v| v.strip_suffix('"')) {
|
||||
return v.to_string();
|
||||
}
|
||||
}
|
||||
panic!("{path}: no `{key} = \"…\"` line");
|
||||
}
|
||||
|
||||
/// The value of a `"key": "…"` line. Enough for a hand-written file with no
|
||||
/// escapes in it, and the test below fails loudly rather than quietly if that
|
||||
/// ever stops being true.
|
||||
fn json_string(path: &str, key: &str) -> String {
|
||||
let text = fs::read_to_string(path).unwrap_or_else(|e| panic!("{path}: {e}"));
|
||||
let needle = format!("\"{key}\":");
|
||||
for line in text.lines() {
|
||||
let Some(rest) = line.trim().strip_prefix(&needle) else { continue };
|
||||
let rest = rest.trim().trim_end_matches(',').trim();
|
||||
if let Some(v) = rest.strip_prefix('"').and_then(|v| v.strip_suffix('"')) {
|
||||
assert!(!v.contains('\\'), "{path}: {key} has escapes this reader cannot handle");
|
||||
return v.to_string();
|
||||
}
|
||||
}
|
||||
panic!("{path}: no `\"{key}\": \"…\"` line");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_three_descriptions_are_the_same_sentence() {
|
||||
let cargo = toml_string("Cargo.toml", "description");
|
||||
let pyproject = toml_string("pyproject.toml", "description");
|
||||
let npm = json_string("npm/package.json.in", "description");
|
||||
|
||||
assert_eq!(
|
||||
cargo, pyproject,
|
||||
"Cargo.toml and pyproject.toml disagree; pyproject.toml is the one PyPI shows"
|
||||
);
|
||||
assert_eq!(
|
||||
cargo, npm,
|
||||
"Cargo.toml and npm/package.json.in disagree; the latter is the one npm shows"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_description_says_what_the_crate_is_called() {
|
||||
// Cheap guard against a description edited into something that no longer
|
||||
// describes this package at all.
|
||||
let d = toml_string("Cargo.toml", "description");
|
||||
assert!(d.len() > 40, "description is too short to be one: {d:?}");
|
||||
assert!(!d.ends_with(' '), "description has a trailing space");
|
||||
assert!(d.contains("Orthodox"), "description no longer mentions Orthodox: {d:?}");
|
||||
}
|
||||
|
||||
/// The opening paragraph of a README, unwrapped to one line.
|
||||
fn lede(path: &str) -> String {
|
||||
let text = fs::read_to_string(path).unwrap_or_else(|e| panic!("{path}: {e}"));
|
||||
let body = text
|
||||
.split("\n\n")
|
||||
.find(|p| !p.trim().is_empty() && !p.trim_start().starts_with('#'))
|
||||
.unwrap_or_else(|| panic!("{path}: no opening paragraph"));
|
||||
body.split_whitespace().collect::<Vec<_>>().join(" ")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_readmes_open_with_the_description() {
|
||||
// A registry page leads with the README, not with the description field,
|
||||
// so the sentence a reader actually meets is this one. npm's README is a
|
||||
// separate file from the crate's and had gone its own way: it described
|
||||
// the package without mentioning that it covers Byzantine Catholic
|
||||
// churches at all.
|
||||
let description = toml_string("Cargo.toml", "description");
|
||||
assert_eq!(
|
||||
lede("README.md"),
|
||||
description,
|
||||
"README.md does not open with the published description"
|
||||
);
|
||||
assert_eq!(
|
||||
lede("npm/README.md"),
|
||||
description,
|
||||
"npm/README.md does not open with the published description"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user