Skip to content

Commit 0b28f09

Browse files
authored
fix: prepare for v1.0.0 release (#107)
1 parent 6b26893 commit 0b28f09

6 files changed

Lines changed: 132 additions & 16 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ jobs:
206206
# the same `--locked` the deploy workflow publishes with. The step runs
207207
# after the drift check, which leaves a clean tree, because `cargo
208208
# package` refuses a dirty one.
209-
- name: Check the published package builds and stays trim
209+
#
210+
# The step also runs the packaged binary once. `cargo package` rewrites
211+
# the manifest, so code that reads it can work in the workspace and fail
212+
# only once published. Building alone does not find that.
213+
- name: Check the published package builds, runs, and stays trim
210214
run: make verify-package
211215

212216
lint-prettier:

Makefile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ verify-generated: ## Regenerate all generated files and fail when they differ fr
9292
@echo "Generated files are up to date."
9393

9494
.PHONY: verify-package
95-
verify-package: ## Fail when the published package does not build, or when it carries the test suite
95+
verify-package: ## Fail when the published package does not build or run, or when it carries the test suite
9696
@set -euo pipefail; \
9797
files="$$(cargo package -p oapi-codegen --locked --list)"; \
9898
if grep -q '^tests/' <<< "$$files"; then \
@@ -101,7 +101,21 @@ verify-package: ## Fail when the published package does not build, or when it ca
101101
exit 1; \
102102
fi
103103
cargo package -p oapi-codegen --locked
104-
@echo "The package builds and carries no tests."
104+
@set -euo pipefail; \
105+
version="$$(cargo metadata --format-version 1 --no-deps --locked \
106+
| jq -er '.packages[] | select(.name == "oapi-codegen") | .version')"; \
107+
work="$$(mktemp -d)"; \
108+
trap 'rm -rf "$$work"' EXIT; \
109+
tar xzf target/package/oapi-codegen-$$version.crate -C "$$work"; \
110+
cd "$$work/oapi-codegen-$$version" && cargo build --locked -q; \
111+
cp -R $(CURDIR)/examples/bookstore "$$work/example"; \
112+
cd "$$work/example" && \
113+
"$$work/oapi-codegen-$$version/target/debug/oapi-codegen" \
114+
--config-file oapi-codegen-catalog.yaml schemas/catalog.yaml \
115+
< /dev/null; \
116+
diff -u $(CURDIR)/examples/bookstore/generated/apimodel/catalog.rs \
117+
"$$work/example/generated/apimodel/catalog.rs"
118+
@echo "The package builds, runs, and carries no tests."
105119

106120
.PHONY: docs
107121
docs: ## Generate and open Rust documentation

crates/oapi-codegen/Cargo.toml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ version.workspace = true
55
edition.workspace = true
66
repository.workspace = true
77
license.workspace = true
8+
homepage = "https://github.com/alchemaxinc/oapi-codegen-rust"
9+
documentation = "https://docs.rs/oapi-codegen"
10+
rust-version = "1.88"
11+
keywords = ["openapi", "codegen", "swagger", "axum", "rest"]
12+
categories = [
13+
"development-tools",
14+
"command-line-utilities",
15+
"web-programming",
16+
"api-bindings",
17+
]
818

9-
# An allowlist, not an `exclude`. A new directory in the crate then stays out of
10-
# a publish until someone names it here. `include` overrides `exclude`, so the
11-
# manifest carries one of the two and not both.
12-
#
13-
# The `tests` directory holds the fixtures and their generated files, which is
14-
# almost the whole of the package. A consumer builds the crate and does not run
15-
# its suite, so the files stay in the repository only.
16-
include = ["src/**/*.rs"]
19+
include = ["src/**/*.rs", "README.md", "LICENSE"]
20+
readme = "README.md"
1721

1822
[[bin]]
1923
name = "oapi-codegen"

crates/oapi-codegen/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE

crates/oapi-codegen/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../README.md

crates/oapi-codegen/src/deps.rs

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,28 @@ fn manifest_version(crate_name: &str) -> &'static str {
4444

4545
/// Find the version requirement declared for `crate_name` in `manifest`, or
4646
/// `None` when it is not declared.
47+
///
48+
/// Two layouts have to work: the one-line form the repository manifest uses,
49+
/// and the `[dependencies.name]` table that `cargo package` rewrites it into.
50+
/// The published binary reads the second.
4751
fn parse_manifest_version<'a>(manifest: &'a str, crate_name: &str) -> Option<&'a str> {
52+
let mut inside_table_for_crate = false;
4853
for line in manifest.lines() {
4954
let line = line.trim();
55+
56+
if let Some(header) = line.strip_prefix('[').and_then(|rest| return rest.strip_suffix(']')) {
57+
inside_table_for_crate = is_dependency_table_for(header, crate_name);
58+
continue;
59+
}
60+
61+
if inside_table_for_crate
62+
&& let Some(rest) = line.strip_prefix("version")
63+
&& let Some(value) = rest.trim_start().strip_prefix('=')
64+
&& let Some(version) = first_quoted(value)
65+
{
66+
return Some(version);
67+
}
68+
5069
let Some(rest) = line.strip_prefix(crate_name) else {
5170
continue;
5271
};
@@ -69,16 +88,32 @@ fn parse_manifest_version<'a>(manifest: &'a str, crate_name: &str) -> Option<&'a
6988
},
7089
None => value,
7190
};
72-
if let Some(open) = scan.find('"') {
73-
let after = &scan[open + 1..];
74-
if let Some(close) = after.find('"') {
75-
return Some(&after[..close]);
76-
}
91+
if let Some(version) = first_quoted(scan) {
92+
return Some(version);
7793
}
7894
}
7995
return None;
8096
}
8197

98+
/// Whether `header` names the dependency table for `crate_name`, in any of the
99+
/// three dependency scopes `cargo package` can write.
100+
fn is_dependency_table_for(header: &str, crate_name: &str) -> bool {
101+
for scope in ["dependencies.", "dev-dependencies.", "build-dependencies."] {
102+
if let Some(name) = header.strip_prefix(scope)
103+
&& name == crate_name
104+
{
105+
return true;
106+
}
107+
}
108+
return false;
109+
}
110+
111+
/// The text between the first pair of double quotes in `text`.
112+
fn first_quoted(text: &str) -> Option<&str> {
113+
let after = text.split_once('"')?.1;
114+
return after.split_once('"').map(|(value, _)| return value);
115+
}
116+
82117
/// A crate the generated code references, with the version requirement and Cargo
83118
/// features a consumer must declare in `Cargo.toml`.
84119
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -244,6 +279,63 @@ mod tests {
244279
assert_eq!(parse_manifest_version(manifest, "axum"), Some("0.8.9"));
245280
}
246281

282+
#[test]
283+
fn a_version_is_found_in_the_layout_cargo_publishes() {
284+
// The shape `cargo package` writes: a table per dependency, rather than
285+
// the one line per dependency the repository manifest uses. The crates
286+
// are invented, so no dependency bump reaches this.
287+
let manifest = r#"
288+
[package]
289+
name = "specimen"
290+
version = "9.9.9"
291+
292+
[dependencies.plain]
293+
version = "1.2.3"
294+
295+
[dependencies.with-features]
296+
version = "4.5.6"
297+
features = ["one", "two"]
298+
299+
[dependencies.multi-line-features]
300+
version = "7.8.9"
301+
features = [
302+
"one",
303+
"two",
304+
]
305+
306+
[dependencies.prefix]
307+
version = "0.1.0"
308+
309+
[dependencies.prefix_extended]
310+
version = "0.2.0"
311+
312+
[dev-dependencies.only-for-tests]
313+
version = "5.0.0"
314+
315+
[build-dependencies.only-for-build]
316+
version = "6.0.0"
317+
"#;
318+
319+
for (crate_name, expected) in [
320+
("plain", Some("1.2.3")),
321+
("with-features", Some("4.5.6")),
322+
("multi-line-features", Some("7.8.9")),
323+
("prefix", Some("0.1.0")),
324+
("prefix_extended", Some("0.2.0")),
325+
("only-for-tests", Some("5.0.0")),
326+
("only-for-build", Some("6.0.0")),
327+
("absent", None),
328+
// The package table carries a `version` of its own.
329+
("specimen", None),
330+
] {
331+
assert_eq!(
332+
parse_manifest_version(manifest, crate_name),
333+
expected,
334+
"the published layout should report `{crate_name}` as {expected:?}"
335+
);
336+
}
337+
}
338+
247339
#[test]
248340
fn toml_renders_short_and_table_forms() {
249341
assert_eq!(

0 commit comments

Comments
 (0)