Skip to content

Commit 1ead0b8

Browse files
committed
chore(release): bump crate to v0.3.8
1 parent 4a9d71e commit 1ead0b8

File tree

7 files changed

+131
-9
lines changed

7 files changed

+131
-9
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/target
2+
__pycache__/
3+
*.py[cod]
24
*.env
35
.envtool-cache
46
.uv-cache

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919

2020
### Security
2121

22+
## [0.3.8] - 2026-02-16
23+
24+
### Added
25+
26+
### Changed
27+
28+
### Deprecated
29+
30+
### Removed
31+
32+
### Fixed
33+
34+
### Security
35+
36+
## [0.3.6] - 2026-02-16
37+
38+
### Added
39+
40+
### Changed
41+
42+
### Deprecated
43+
44+
### Removed
45+
46+
### Fixed
47+
48+
### Security
49+
2250
## [0.3.3] - 2026-02-16
2351

2452
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "envgen"
3-
version = "0.3.3"
3+
version = "0.3.8"
44
edition = "2021"
55
description = "Generate and validate .env files from one spec - self-documenting config, consistent across environments, secrets stay out of git."
66
readme = "README.md"

Makefile

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,28 @@ check-security: check-tools-security ## Security/dependency checks
171171
cargo machete
172172
typos
173173

174+
.PHONY: sync-lockfile
175+
sync-lockfile: ## Regenerate Cargo.lock using pinned Rust toolchain (1.88.0)
176+
cargo +1.88.0 generate-lockfile
177+
178+
.PHONY: check-lockfile
179+
check-lockfile: ## Validate lockfile parity using pinned Rust toolchain (1.88.0)
180+
cargo +1.88.0 check --locked
181+
174182
.PHONY: check-release
175183
check-release: ## Release readiness checks
176-
ENVGEN_HINTS=0 $(MAKE) check-core
184+
@tmp_file="$$(mktemp)"; \
185+
trap 'rm -f "$$tmp_file"' EXIT; \
186+
if ENVGEN_HINTS=0 $(MAKE) check-core > "$$tmp_file" 2>&1; then \
187+
cat "$$tmp_file"; \
188+
else \
189+
rc=$$?; \
190+
cat "$$tmp_file"; \
191+
if grep -E 'lock file .* needs to be updated but --locked was passed' "$$tmp_file" >/dev/null; then \
192+
echo "ERROR: lockfile is out of sync with Cargo.toml. Run: make sync-lockfile" >&2; \
193+
fi; \
194+
exit $$rc; \
195+
fi
177196
cargo publish --dry-run --locked --allow-dirty
178197
@python3 $(VERSION_BUMP_SCRIPT) status | awk -F= '/^crate_version=/{print "✓ Release readiness checks passed for crate v"$$2}'
179198
@python3 $(VERSION_BUMP_SCRIPT) next-step --stage crate-after-check-release

RELEASING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ This mapping must match the publish job in `.github/workflows/release.yml` exact
3939
- `make check-msrv`
4040
- `make check-security`
4141
- `make check-release`
42+
- `make sync-lockfile`
43+
- `make check-lockfile`
4244
- `make precommit-fast`
4345
- `make prepush-full`
4446
- `make bump-crate LEVEL=patch|minor|major`
@@ -194,6 +196,7 @@ make bump-dry-run MODE=schema VERSION=A.B.C
194196
- `make bump-dry-run MODE=crate LEVEL=patch`
195197
3. Apply the crate bump:
196198
- `make bump-crate LEVEL=patch` (or `VERSION=X.Y.Z`)
199+
- This updates `Cargo.toml`, `CHANGELOG.md`, and synchronizes `Cargo.lock`.
197200
4. Validate:
198201
- `make check-release`
199202
5. Commit release prep (recommended):
@@ -238,6 +241,15 @@ Pushing `schema-v*.*.*` tags does not trigger crates.io publish.
238241
- Missing local tag on push:
239242
- `make push-tag-crate` fails if `vX.Y.Z` has not been created locally.
240243
- `make push-tag-schema` fails if `schema-vA.B.C` has not been created locally.
244+
- Empty `Unreleased` section during bump:
245+
- Crate override: `make bump-crate-patch ALLOW_EMPTY_CHANGELOG=1`
246+
- Schema override: `make bump-schema-patch ALLOW_EMPTY_SCHEMA_CHANGELOG=1`
247+
- Lockfile mismatch during locked checks:
248+
- Symptom: `Cargo.lock needs to be updated but --locked was passed`
249+
- Fix: `make sync-lockfile`
250+
- Partial update on bump failure:
251+
- A failed bump can leave version/changelog edits before later steps complete.
252+
- Recovery: run `make sync-lockfile` and retry the bump after fixing the reported error.
241253

242254
## Emergency fallback (temporary)
243255

scripts/version_bump.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
RELEASE_WORKFLOW_URL = (
5555
"https://github.com/smorinlabs/envgen/actions/workflows/release.yml"
5656
)
57+
LOCKFILE_SYNC_ARGS = ["cargo", "+1.88.0", "generate-lockfile"]
5758

5859

5960
class BumpError(RuntimeError):
@@ -99,12 +100,19 @@ def render_next_step(
99100
crate_version: str | None = None,
100101
schema_version: str | None = None,
101102
tag_name: str | None = None,
103+
lockfile_synced: bool | None = None,
102104
) -> tuple[str, list[str]]:
103105
if stage == "crate-after-bump":
104106
resolved_crate_version = crate_version or read_cargo_version()
107+
lines: list[str] = []
108+
if lockfile_synced is True:
109+
lines.append("Cargo.lock synchronized for locked checks.")
110+
elif lockfile_synced is False:
111+
lines.append("Cargo.lock sync runs only in non-dry-run bump mode.")
112+
lines.append("$ make check-release")
105113
return (
106114
f"Crate release prep updated to v{resolved_crate_version}.",
107-
["$ make check-release"],
115+
lines,
108116
)
109117

110118
if stage == "crate-after-check-release":
@@ -186,6 +194,7 @@ def emit_next_step(
186194
crate_version: str | None = None,
187195
schema_version: str | None = None,
188196
tag_name: str | None = None,
197+
lockfile_synced: bool | None = None,
189198
) -> None:
190199
if not hints_enabled():
191200
return
@@ -195,6 +204,7 @@ def emit_next_step(
195204
crate_version=crate_version,
196205
schema_version=schema_version,
197206
tag_name=tag_name,
207+
lockfile_synced=lockfile_synced,
198208
)
199209
print("")
200210
print(f"Hint: {summary}")
@@ -349,6 +359,7 @@ def rotate_changelog(
349359
default_sections: list[str],
350360
allow_empty: bool,
351361
dry_run: bool,
362+
make_override_command: str | None = None,
352363
) -> None:
353364
text = path.read_text(encoding="utf-8")
354365
match = UNRELEASED_RE.search(text)
@@ -361,10 +372,13 @@ def rotate_changelog(
361372
headings = default_sections
362373

363374
if not changelog_has_entries(body) and not allow_empty:
364-
fail(
365-
f"Unreleased section in {path} has no entries. "
366-
"Use --allow-empty-changelog to override."
367-
)
375+
if make_override_command:
376+
fail(
377+
f"Unreleased section in {path} has no entries.\n"
378+
"Override from Make target:\n"
379+
f" {make_override_command}"
380+
)
381+
fail(f"Unreleased section in {path} has no entries.")
368382

369383
unreleased_block = "## [Unreleased]\n\n"
370384
unreleased_block += "".join(f"### {heading}\n\n" for heading in headings)
@@ -427,6 +441,20 @@ def run_git_command(args: list[str], dry_run: bool) -> None:
427441
fail(f"Command failed: {quoted}")
428442

429443

444+
def sync_cargo_lockfile(dry_run: bool) -> None:
445+
command = shlex.join(LOCKFILE_SYNC_ARGS)
446+
if dry_run:
447+
print(f"[dry-run] would run: {command}")
448+
return
449+
450+
result = subprocess.run(LOCKFILE_SYNC_ARGS, cwd=ROOT, check=False)
451+
if result.returncode != 0:
452+
fail(
453+
"Failed to synchronize Cargo.lock after crate version bump.\n"
454+
"Run: make sync-lockfile"
455+
)
456+
457+
430458
def create_tag(tag_name: str, message: str, dry_run: bool) -> None:
431459
if local_tag_exists(tag_name):
432460
fail(f"Local tag already exists: {tag_name}")
@@ -485,6 +513,17 @@ def do_status(_args: argparse.Namespace) -> None:
485513

486514

487515
def do_bump_crate(args: argparse.Namespace) -> None:
516+
if args.level:
517+
make_override_command = (
518+
f"make bump-crate-{args.level} ALLOW_EMPTY_CHANGELOG=1"
519+
)
520+
elif args.version:
521+
make_override_command = (
522+
f"make bump-crate VERSION={args.version} ALLOW_EMPTY_CHANGELOG=1"
523+
)
524+
else:
525+
make_override_command = "make bump-crate ALLOW_EMPTY_CHANGELOG=1"
526+
488527
old, new = update_cargo_version(
489528
resolve_next_version(read_cargo_version(), args.level, args.version),
490529
dry_run=args.dry_run,
@@ -496,15 +535,36 @@ def do_bump_crate(args: argparse.Namespace) -> None:
496535
default_sections=CRATE_SECTIONS,
497536
allow_empty=args.allow_empty_changelog,
498537
dry_run=args.dry_run,
538+
make_override_command=make_override_command,
499539
)
500540

541+
sync_cargo_lockfile(args.dry_run)
542+
501543
print(f"crate version: {old} -> {new}")
502544
print(f"updated: {CARGO_TOML}")
503545
print(f"updated: {CHANGELOG}")
504-
emit_next_step("crate-after-bump", crate_version=new)
546+
if not args.dry_run:
547+
print(f"updated: {ROOT / 'Cargo.lock'}")
548+
emit_next_step(
549+
"crate-after-bump",
550+
crate_version=new,
551+
lockfile_synced=not args.dry_run,
552+
)
505553

506554

507555
def do_bump_schema(args: argparse.Namespace) -> None:
556+
if args.level:
557+
make_override_command = (
558+
f"make bump-schema-{args.level} ALLOW_EMPTY_SCHEMA_CHANGELOG=1"
559+
)
560+
elif args.version:
561+
make_override_command = (
562+
f"make bump-schema VERSION={args.version} "
563+
"ALLOW_EMPTY_SCHEMA_CHANGELOG=1"
564+
)
565+
else:
566+
make_override_command = "make bump-schema ALLOW_EMPTY_SCHEMA_CHANGELOG=1"
567+
508568
old = read_schema_version_file()
509569
new = resolve_next_version(old, args.level, args.version)
510570
if old == new:
@@ -529,6 +589,7 @@ def do_bump_schema(args: argparse.Namespace) -> None:
529589
default_sections=SCHEMA_SECTIONS,
530590
allow_empty=args.allow_empty_changelog,
531591
dry_run=args.dry_run,
592+
make_override_command=make_override_command,
532593
)
533594

534595
if args.dry_run:

0 commit comments

Comments
 (0)