-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
650 lines (556 loc) · 27.7 KB
/
Makefile
File metadata and controls
650 lines (556 loc) · 27.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
.PHONY: build-jacs build-jacsbook build-jacsbook-pdf \
test test-all test-all-pq test-rust-pr test-bindings-fast test-rust-slow test-jacs test-jacs-fast test-jacs-fast-lib test-jacs-fast-bin-shard-a test-jacs-fast-bin-shard-b test-jacs-features test-jacs-pq test-jacs-cli test-jacs-cross-language test-jacs-observability \
test-jacs-mcp test-jacs-binding-core test-jacs-binding-core-pq \
test-jacs-duckdb test-jacs-redb test-jacs-surrealdb test-jacs-postgresql test-jacs-storage \
test-jacspy test-jacspy-parallel test-jacsnpm test-jacsnpm-parallel \
audit-jacs \
publish-jacs publish-jacs-core publish-jacs-binding-core publish-jacs-mcp publish-jacs-cli publish-jacspy publish-jacsnpm \
publish-jacs-storage publish-jacs-duckdb publish-jacs-redb publish-jacs-surrealdb publish-jacs-postgresql \
release-jacs release-jacspy release-jacsnpm release-cli release-jacs-storage release-all release-everything release-delete-tags \
retry-jacs retry-jacspy retry-jacsnpm retry-cli retry-everything \
bump-patch bump-minor bump-major \
version versions check-versions check-version-jacs check-version-jacspy check-version-jacsnpm check-version-cli \
install-githooks regen-cross-lang-fixtures \
help
# ============================================================================
# VERSION DETECTION
# ============================================================================
# Extract versions from source files. These are used for release tagging.
# Rust core library version (from jacs/Cargo.toml)
JACS_VERSION := $(shell grep '^version' jacs/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Rust MCP server version (from jacs-mcp/Cargo.toml)
JACS_MCP_VERSION := $(shell grep '^version' jacs-mcp/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Shared Rust binding core version (from binding-core/Cargo.toml)
BINDING_CORE_VERSION := $(shell grep '^version' binding-core/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Python bindings version (from jacspy/pyproject.toml)
JACSPY_VERSION := $(shell grep '^version' jacspy/pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Python Rust extension crate version (from jacspy/Cargo.toml)
JACSPY_RUST_VERSION := $(shell grep '^version' jacspy/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Node.js bindings version (from jacsnpm/package.json)
JACSNPM_VERSION := $(shell grep '"version"' jacsnpm/package.json | head -1 | sed 's/.*: *"\(.*\)".*/\1/')
# Node.js Rust extension crate version (from jacsnpm/Cargo.toml)
JACSNPM_RUST_VERSION := $(shell grep '^version' jacsnpm/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Go FFI Rust library version (from jacsgo/lib/Cargo.toml)
JACSGO_VERSION := $(shell grep '^version' jacsgo/lib/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Storage backend crate versions (independent version track)
JACS_DUCKDB_VERSION := $(shell grep '^version' jacs-duckdb/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
JACS_REDB_VERSION := $(shell grep '^version' jacs-redb/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
JACS_SURREALDB_VERSION := $(shell grep '^version' jacs-surrealdb/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
JACS_POSTGRESQL_VERSION := $(shell grep '^version' jacs-postgresql/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
# Fast Rust lane for the core crate: exclude dedicated CLI, interop, observability,
# and PQ-only binaries so the default PR path stays bounded.
JACS_TEST_BINS := $(basename $(notdir $(shell find jacs/tests -maxdepth 1 -name '*.rs' -print | sort)))
JACS_FAST_TEST_BINS := $(filter-out a2a_cross_language_tests attestation_cross_lang_tests cli_flags cli_tests cross_language_tests observability_oltp_meter observability_tests pq2025_tests pq_tests,$(JACS_TEST_BINS))
# Alphabetical shard split for CI parallelization.
# Shard A: test names starting with a-d. Shard B: test names starting with e-z.
JACS_FAST_BIN_SHARD_A := $(filter a% b% c% d%,$(JACS_FAST_TEST_BINS))
JACS_FAST_BIN_SHARD_B := $(filter-out a% b% c% d%,$(JACS_FAST_TEST_BINS))
# ============================================================================
# BUILD
# ============================================================================
build-jacs:
cargo install --path jacs-cli --force
~/.cargo/bin/jacs --help
~/.cargo/bin/jacs version
build-jacspy:
cd jacspy && maturin develop
build-jacsnpm:
cd jacsnpm && npm run build
build-jacsbook:
cd jacs/docs/jacsbook && mdbook build
build-jacsbook-pdf:
./jacs/docs/jacsbook/scripts/build-pdf.sh
# ============================================================================
# TEST
# ============================================================================
test-jacs:
cd jacs && RUST_BACKTRACE=1 cargo test --lib --tests -- --nocapture
# Fast test run: ed25519 only (no post-quantum keygen)
test-jacs-fast:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation --lib $(foreach test,$(JACS_FAST_TEST_BINS),--test $(test)) -- --nocapture
# Sharded fast targets for CI parallelization (each maps to one local command).
test-jacs-fast-lib:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation --lib -- --nocapture
test-jacs-fast-bin-shard-a:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation $(foreach test,$(JACS_FAST_BIN_SHARD_A),--test $(test)) -- --nocapture
test-jacs-fast-bin-shard-b:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation $(foreach test,$(JACS_FAST_BIN_SHARD_B),--test $(test)) -- --nocapture
# Full test run: includes post-quantum algorithm tests (slow keygen)
test-jacs-pq:
RUST_BACKTRACE=1 cargo test -p jacs --features agreements,a2a,attestation,pq-tests --lib --tests --verbose
test-jacs-features: test-jacs-pq
test-jacs-cli:
cargo build -p jacs-cli
cd jacs && RUST_BACKTRACE=1 cargo test --test cli_tests --test cli_flags -- --nocapture
RUST_BACKTRACE=1 cargo test -p jacs-cli --test cli_convert_tests -- --nocapture
test-jacs-cross-language:
cd jacs && RUST_BACKTRACE=1 cargo test --features "agreements a2a attestation" --test cross_language_tests --test a2a_cross_language_tests --test attestation_cross_lang_tests -- --nocapture
test-jacs-observability:
cd jacs && RUST_BACKTRACE=1 cargo test --features "observability-convenience otlp-logs otlp-metrics otlp-tracing" --test observability_tests --test observability_oltp_meter -- --nocapture
test-jacs-mcp:
RUST_BACKTRACE=1 cargo test -p jacs-mcp --lib --tests --verbose
test-jacs-binding-core:
RUST_BACKTRACE=1 cargo test -p jacs-binding-core --lib --tests --verbose
test-jacs-binding-core-pq:
RUST_BACKTRACE=1 cargo test -p jacs-binding-core --features pq-tests --lib --tests --verbose
# Storage backend crates (extracted from jacs core)
test-jacs-duckdb:
RUST_BACKTRACE=1 cargo test -p jacs-duckdb --lib --tests --verbose
test-jacs-redb:
RUST_BACKTRACE=1 cargo test -p jacs-redb --lib --tests --verbose
test-jacs-surrealdb:
RUST_BACKTRACE=1 cargo test -p jacs-surrealdb --lib --tests --verbose
test-jacs-postgresql:
RUST_BACKTRACE=1 cargo test -p jacs-postgresql --lib --tests --verbose
test-jacs-storage: test-jacs-duckdb test-jacs-redb test-jacs-surrealdb test-jacs-postgresql
audit-jacs:
@command -v cargo-audit >/dev/null 2>&1 || (echo "cargo-audit is required. Install with: cargo install cargo-audit --locked --version 0.22.1"; exit 1)
cargo audit --ignore RUSTSEC-2023-0071
test-jacspy:
cd jacspy && maturin develop && python -m pytest tests/ -v
test-jacspy-parallel:
cd jacspy && PYTEST_XDIST_WORKERS=$${PYTEST_XDIST_WORKERS:-auto} make test-python-parallel
test-jacsnpm:
cd jacsnpm && npm test
test-jacsnpm-parallel:
cd jacsnpm && npm run test:parallel
test: test-jacs
# Default PR suite: fast Rust lanes plus parallel binding runners.
test-rust-pr: test-jacs-fast test-jacs-cli test-jacs-binding-core test-jacs-mcp
test-bindings-fast: test-jacspy-parallel test-jacsnpm-parallel
# Slower Rust compatibility and infrastructure suites.
test-rust-slow: test-jacs-storage test-jacs-cross-language test-jacs-observability
# Run the default fast suite used for everyday PR validation.
test-all: test-rust-pr test-bindings-fast
# Run the extended suite: slow Rust lanes plus post-quantum coverage.
test-all-pq: test-all test-rust-slow test-jacs-pq test-jacs-binding-core-pq
# Regenerate all canonical cross-language fixtures in sequence.
# This intentionally mutates tracked fixture files.
regen-cross-lang-fixtures:
UPDATE_CROSS_LANG_FIXTURES=1 cargo test -p jacs --test cross_language_tests -- --nocapture
cd jacspy && UPDATE_CROSS_LANG_FIXTURES=1 pytest tests/test_cross_language.py -q
cd jacsnpm && UPDATE_CROSS_LANG_FIXTURES=1 npm run test:cross-language --silent
# Install repo-local git hooks (pre-commit guard for fixture changes).
install-githooks:
git config core.hooksPath .githooks
@echo "Configured git hooks path to .githooks"
# ============================================================================
# VERSION INFO
# ============================================================================
# Bump version across all files: make bump-patch / bump-minor / bump-major
bump-patch:
./scripts/bump-version.sh patch
bump-minor:
./scripts/bump-version.sh minor
bump-major:
./scripts/bump-version.sh major
# Show all detected versions
versions:
@echo "Detected versions from source files:"
@echo " jacs (Cargo.toml): $(JACS_VERSION)"
@echo " jacs-mcp (Cargo.toml): $(JACS_MCP_VERSION)"
@echo " binding-core (Cargo.toml):$(BINDING_CORE_VERSION)"
@echo " jacspy (pyproject.toml): $(JACSPY_VERSION)"
@echo " jacspy (Cargo.toml): $(JACSPY_RUST_VERSION)"
@echo " jacsnpm (package.json): $(JACSNPM_VERSION)"
@echo " jacsnpm (Cargo.toml): $(JACSNPM_RUST_VERSION)"
@echo " jacsgo/lib (Cargo.toml): $(JACSGO_VERSION)"
@echo " jacs-duckdb: $(JACS_DUCKDB_VERSION)"
@echo " jacs-redb: $(JACS_REDB_VERSION)"
@echo " jacs-surrealdb: $(JACS_SURREALDB_VERSION)"
@echo " jacs-postgresql: $(JACS_POSTGRESQL_VERSION)"
@echo ""
@if [ "$(JACS_VERSION)" = "$(JACS_MCP_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(BINDING_CORE_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(JACSPY_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(JACSPY_RUST_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(JACSNPM_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(JACSNPM_RUST_VERSION)" ] && \
[ "$(JACS_VERSION)" = "$(JACSGO_VERSION)" ]; then \
echo "✓ All release versions match: $(JACS_VERSION)"; \
else \
echo "⚠ WARNING: Versions do not match!"; \
fi
version: versions
# Check that all versions match (fails if they don't)
check-versions:
@if [ "$(JACS_VERSION)" != "$(JACS_MCP_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacs-mcp ($(JACS_MCP_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(BINDING_CORE_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != binding-core ($(BINDING_CORE_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(JACSPY_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacspy ($(JACSPY_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(JACSPY_RUST_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacspy Cargo.toml ($(JACSPY_RUST_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(JACSNPM_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacsnpm ($(JACSNPM_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(JACSNPM_RUST_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacsnpm Cargo.toml ($(JACSNPM_RUST_VERSION))"; \
exit 1; \
fi
@if [ "$(JACS_VERSION)" != "$(JACSGO_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacsgo/lib ($(JACSGO_VERSION))"; \
exit 1; \
fi
@echo "✓ All release versions match: $(JACS_VERSION)"
# ============================================================================
# DIRECT PUBLISH (requires local credentials)
# ============================================================================
# Publish all Rust crates to crates.io in dependency order with delays.
# Requires ~/.cargo/credentials or CARGO_REGISTRY_TOKEN.
publish-jacs:
cd jacs && cargo publish
@echo "Waiting 30s for crates.io to index jacs..."
sleep 30
cd binding-core && cargo publish
@echo "Waiting 30s for crates.io to index jacs-binding-core..."
sleep 30
cd jacs-mcp && cargo publish
@echo "Waiting 30s for crates.io to index jacs-mcp..."
sleep 30
cd jacs-cli && cargo publish
# Individual crate publish targets (use when resuming a partial publish)
publish-jacs-core:
cd jacs && cargo publish
publish-jacs-binding-core:
cd binding-core && cargo publish
publish-jacs-mcp:
cd jacs-mcp && cargo publish
publish-jacs-cli:
cd jacs-cli && cargo publish
# Publish storage backend crates to crates.io (requires jacs already published).
publish-jacs-storage:
cd jacs-duckdb && cargo publish
@echo "Waiting 30s for crates.io to index jacs-duckdb..."
sleep 30
cd jacs-redb && cargo publish
@echo "Waiting 30s for crates.io to index jacs-redb..."
sleep 30
cd jacs-surrealdb && cargo publish
@echo "Waiting 30s for crates.io to index jacs-surrealdb..."
sleep 30
cd jacs-postgresql && cargo publish
# Individual storage crate publish targets
publish-jacs-duckdb:
cd jacs-duckdb && cargo publish
publish-jacs-redb:
cd jacs-redb && cargo publish
publish-jacs-surrealdb:
cd jacs-surrealdb && cargo publish
publish-jacs-postgresql:
cd jacs-postgresql && cargo publish
# Dry run for crates.io publish
publish-jacs-dry:
cd jacs && cargo publish --dry-run
cd binding-core && cargo publish --dry-run
cd jacs-mcp && cargo publish --dry-run
cd jacs-cli && cargo publish --dry-run
publish-jacs-storage-dry:
cd jacs-duckdb && cargo publish --dry-run
cd jacs-redb && cargo publish --dry-run
cd jacs-surrealdb && cargo publish --dry-run
cd jacs-postgresql && cargo publish --dry-run
# Publish to PyPI (requires MATURIN_PYPI_TOKEN or ~/.pypirc)
publish-jacspy:
cd jacspy && maturin publish
# Dry run for PyPI publish
publish-jacspy-dry:
cd jacspy && maturin build --release
# Publish to npm (requires npm login or NPM_TOKEN)
publish-jacsnpm:
cd jacsnpm && npm publish --access public
# Dry run for npm publish
publish-jacsnpm-dry:
cd jacsnpm && npm publish --access public --dry-run
# ============================================================================
# GITHUB CI RELEASE (via git tags)
# ============================================================================
# These commands create git tags that trigger GitHub Actions release workflows.
# Versions are auto-detected from source files. Tags are verified before pushing.
#
# Required GitHub Secrets:
# - CRATES_IO_TOKEN (for crate/v* tags)
# - PYPI_API_TOKEN (for pypi/v* tags)
# - NPM_TOKEN (for npm/v* tags)
# ============================================================================
# Verify version and tag for crates.io release
check-version-jacs:
@echo "jacs version: $(JACS_VERSION)"
@if git tag -l | grep -q "^crate/v$(JACS_VERSION)$$"; then \
echo "ERROR: Tag crate/v$(JACS_VERSION) already exists"; \
exit 1; \
fi
@echo "✓ Tag crate/v$(JACS_VERSION) is available"
# Verify version and tag for PyPI release
check-version-jacspy:
@echo "jacspy version: $(JACSPY_VERSION)"
@if git tag -l | grep -q "^pypi/v$(JACSPY_VERSION)$$"; then \
echo "ERROR: Tag pypi/v$(JACSPY_VERSION) already exists"; \
exit 1; \
fi
@echo "✓ Tag pypi/v$(JACSPY_VERSION) is available"
# Verify version and tag for npm release
check-version-jacsnpm:
@echo "jacsnpm version: $(JACSNPM_VERSION)"
@if git tag -l | grep -q "^npm/v$(JACSNPM_VERSION)$$"; then \
echo "ERROR: Tag npm/v$(JACSNPM_VERSION) already exists"; \
exit 1; \
fi
@echo "✓ Tag npm/v$(JACSNPM_VERSION) is available"
# Verify version and tag for CLI binary release
check-version-cli:
@echo "cli version: $(JACS_VERSION)"
@if [ "$(JACS_VERSION)" != "$(JACS_MCP_VERSION)" ]; then \
echo "ERROR: jacs ($(JACS_VERSION)) != jacs-mcp ($(JACS_MCP_VERSION))"; \
exit 1; \
fi
@if git tag -l | grep -q "^cli/v$(JACS_VERSION)$$"; then \
echo "ERROR: Tag cli/v$(JACS_VERSION) already exists"; \
exit 1; \
fi
@echo "✓ Tag cli/v$(JACS_VERSION) is available"
# Tag and push to trigger crates.io release via GitHub CI
release-jacs: check-version-jacs
git tag crate/v$(JACS_VERSION)
git push origin crate/v$(JACS_VERSION)
@echo "Tagged crate/v$(JACS_VERSION) - GitHub CI will publish to crates.io"
# Tag and push to trigger PyPI release via GitHub CI
release-jacspy: check-version-jacspy
git tag pypi/v$(JACSPY_VERSION)
git push origin pypi/v$(JACSPY_VERSION)
@echo "Tagged pypi/v$(JACSPY_VERSION) - GitHub CI will publish to PyPI"
# Tag and push to trigger npm release via GitHub CI
release-jacsnpm: check-version-jacsnpm
git tag npm/v$(JACSNPM_VERSION)
git push origin npm/v$(JACSNPM_VERSION)
@echo "Tagged npm/v$(JACSNPM_VERSION) - GitHub CI will publish to npm"
# Tag and push to trigger CLI binary release via GitHub CI
release-cli: check-version-cli
git tag cli/v$(JACS_VERSION)
git push origin cli/v$(JACS_VERSION)
@echo "Tagged cli/v$(JACS_VERSION) - GitHub CI will publish GitHub release binaries"
# Tag and push to trigger storage crate releases via GitHub CI
release-jacs-storage:
@for crate in jacs-duckdb jacs-redb jacs-surrealdb jacs-postgresql; do \
ver=$$(grep '^version' $$crate/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/'); \
tag="crate/$$crate/v$$ver"; \
if git tag -l | grep -q "^$$tag$$"; then \
echo "SKIP: Tag $$tag already exists"; \
else \
echo "Tagging $$tag..."; \
git tag "$$tag"; \
git push origin "$$tag"; \
echo "Tagged $$tag - GitHub CI will publish to crates.io"; \
fi; \
done
# Release all packages via GitHub CI (verifies all versions match first)
release-all: check-versions release-jacs release-jacspy release-jacsnpm
@echo "All release tags pushed for v$(JACS_VERSION). GitHub CI will handle publishing."
# Release all packages plus CLI binaries and storage crates via GitHub CI
release-everything: release-all release-cli release-jacs-storage
@echo "All release tags, including CLI binaries and storage crates, pushed for v$(JACS_VERSION)."
# Delete release tags for current versions (use with caution - for fixing failed releases)
release-delete-tags:
@echo "Deleting tags for version $(JACS_VERSION)..."
-git tag -d crate/v$(JACS_VERSION) pypi/v$(JACSPY_VERSION) npm/v$(JACSNPM_VERSION) cli/v$(JACS_VERSION)
-git push origin --delete crate/v$(JACS_VERSION) pypi/v$(JACSPY_VERSION) npm/v$(JACSNPM_VERSION) cli/v$(JACS_VERSION)
@echo "Deleted release tags"
# Retry a failed crates.io release: delete old tags (local+remote), retag, push
retry-jacs:
@echo "Retrying crates.io release for v$(JACS_VERSION)..."
-git tag -d crate/v$(JACS_VERSION)
-git push origin --delete crate/v$(JACS_VERSION)
git tag crate/v$(JACS_VERSION)
git push origin crate/v$(JACS_VERSION)
@echo "✓ Re-tagged crate/v$(JACS_VERSION) - GitHub CI will retry crates.io publish"
# Retry a failed PyPI release: delete old tags (local+remote), retag, push
retry-jacspy:
@echo "Retrying PyPI release for v$(JACSPY_VERSION)..."
-git tag -d pypi/v$(JACSPY_VERSION)
-git push origin --delete pypi/v$(JACSPY_VERSION)
git tag pypi/v$(JACSPY_VERSION)
git push origin pypi/v$(JACSPY_VERSION)
@echo "✓ Re-tagged pypi/v$(JACSPY_VERSION) - GitHub CI will retry PyPI publish"
# Retry a failed npm release: delete old tags (local+remote), retag, push
retry-jacsnpm:
@echo "Retrying npm release for v$(JACSNPM_VERSION)..."
-git tag -d npm/v$(JACSNPM_VERSION)
-git push origin --delete npm/v$(JACSNPM_VERSION)
git tag npm/v$(JACSNPM_VERSION)
git push origin npm/v$(JACSNPM_VERSION)
@echo "✓ Re-tagged npm/v$(JACSNPM_VERSION) - GitHub CI will retry npm publish"
# Retry a failed CLI release: delete old tags (local+remote), retag, push
retry-cli:
@echo "Retrying CLI release for v$(JACS_VERSION)..."
-git tag -d cli/v$(JACS_VERSION)
-git push origin --delete cli/v$(JACS_VERSION)
git tag cli/v$(JACS_VERSION)
git push origin cli/v$(JACS_VERSION)
@echo "✓ Re-tagged cli/v$(JACS_VERSION) - GitHub CI will retry CLI binary release"
# Smart retry: check each registry and only retry releases that haven't published yet.
# Checks crates.io, PyPI, npm, and GitHub Releases for the current version.
retry-everything:
@echo "Checking which releases need retrying for v$(JACS_VERSION)..."
@echo ""
@NEED_RETRY=""; \
if curl -sf "https://crates.io/api/v1/crates/jacs/$(JACS_VERSION)" > /dev/null 2>&1; then \
echo " crates.io jacs $(JACS_VERSION) — already published, skipping"; \
else \
echo " crates.io jacs $(JACS_VERSION) — NOT found, will retry"; \
NEED_RETRY="$$NEED_RETRY crate"; \
fi; \
if curl -sf "https://pypi.org/pypi/jacs/$(JACSPY_VERSION)/json" > /dev/null 2>&1; then \
echo " PyPI jacs $(JACSPY_VERSION) — already published, skipping"; \
else \
echo " PyPI jacs $(JACSPY_VERSION) — NOT found, will retry"; \
NEED_RETRY="$$NEED_RETRY pypi"; \
fi; \
if npm view "@hai.ai/jacs@$(JACSNPM_VERSION)" version > /dev/null 2>&1; then \
echo " npm @hai.ai/jacs $(JACSNPM_VERSION) — already published, skipping"; \
else \
echo " npm @hai.ai/jacs $(JACSNPM_VERSION) — NOT found, will retry"; \
NEED_RETRY="$$NEED_RETRY npm"; \
fi; \
if gh release view "cli/v$(JACS_VERSION)" --repo HumanAssisted/JACS > /dev/null 2>&1; then \
echo " CLI cli/v$(JACS_VERSION) — release exists, skipping"; \
else \
echo " CLI cli/v$(JACS_VERSION) — NOT found, will retry"; \
NEED_RETRY="$$NEED_RETRY cli"; \
fi; \
echo ""; \
if [ -z "$$NEED_RETRY" ]; then \
echo "✓ All releases already published for v$(JACS_VERSION). Nothing to retry."; \
else \
echo "Retrying:$$NEED_RETRY"; \
echo ""; \
for target in $$NEED_RETRY; do \
case $$target in \
crate) \
echo "--- Retrying crates.io ---"; \
git tag -d crate/v$(JACS_VERSION) 2>/dev/null || true; \
git push origin --delete crate/v$(JACS_VERSION) 2>/dev/null || true; \
git tag crate/v$(JACS_VERSION); \
git push origin crate/v$(JACS_VERSION); \
echo "✓ Re-tagged crate/v$(JACS_VERSION)"; \
;; \
pypi) \
echo "--- Retrying PyPI ---"; \
git tag -d pypi/v$(JACSPY_VERSION) 2>/dev/null || true; \
git push origin --delete pypi/v$(JACSPY_VERSION) 2>/dev/null || true; \
git tag pypi/v$(JACSPY_VERSION); \
git push origin pypi/v$(JACSPY_VERSION); \
echo "✓ Re-tagged pypi/v$(JACSPY_VERSION)"; \
;; \
npm) \
echo "--- Retrying npm ---"; \
git tag -d npm/v$(JACSNPM_VERSION) 2>/dev/null || true; \
git push origin --delete npm/v$(JACSNPM_VERSION) 2>/dev/null || true; \
git tag npm/v$(JACSNPM_VERSION); \
git push origin npm/v$(JACSNPM_VERSION); \
echo "✓ Re-tagged npm/v$(JACSNPM_VERSION)"; \
;; \
cli) \
echo "--- Retrying CLI ---"; \
git tag -d cli/v$(JACS_VERSION) 2>/dev/null || true; \
git push origin --delete cli/v$(JACS_VERSION) 2>/dev/null || true; \
git tag cli/v$(JACS_VERSION); \
git push origin cli/v$(JACS_VERSION); \
echo "✓ Re-tagged cli/v$(JACS_VERSION)"; \
;; \
esac; \
done; \
echo ""; \
echo "✓ Retry tags pushed. GitHub CI will handle publishing."; \
fi
# ============================================================================
# HELP
# ============================================================================
help:
@echo "JACS Makefile Commands"
@echo ""
@echo "VERSION BUMP:"
@echo " make bump-patch Bump patch version (0.9.6 -> 0.9.7) across all files"
@echo " make bump-minor Bump minor version (0.9.6 -> 0.10.0) across all files"
@echo " make bump-major Bump major version (0.9.6 -> 1.0.0) across all files"
@echo ""
@echo "VERSION INFO:"
@echo " make versions Show all detected versions from source files"
@echo " make check-versions Verify all package versions match"
@echo ""
@echo "BUILD:"
@echo " make build-jacs Build and install Rust CLI"
@echo " make build-jacspy Build Python bindings (dev mode)"
@echo " make build-jacsnpm Build Node.js bindings"
@echo " make build-jacsbook Generate jacsbook (mdbook build)"
@echo " make build-jacsbook-pdf Generate single PDF book at docs/jacsbook.pdf"
@echo ""
@echo "TEST:"
@echo " make test Run Rust library tests (alias for test-jacs)"
@echo " make test-all Run the default fast PR suite"
@echo " make test-all-pq Run the extended suite (slow Rust lanes + post-quantum)"
@echo " make test-rust-pr Run the default fast Rust lanes"
@echo " make test-bindings-fast Run Python and Node bindings with their parallel runners"
@echo " make test-rust-slow Run storage, cross-language, and observability suites"
@echo " make test-jacs Run Rust library tests"
@echo " make test-jacs-fast Run Rust tests with features, ed25519 only (fast)"
@echo " make test-jacs-pq Run Rust tests with features + post-quantum tests"
@echo " make test-jacs-features Alias for test-jacs-pq (full coverage)"
@echo " make test-jacs-cli Run CLI integration tests"
@echo " make test-jacs-cross-language Run Rust cross-language and fixture-interop tests"
@echo " make test-jacs-mcp Run MCP server tests"
@echo " make test-jacs-binding-core Run binding-core tests (ed25519)"
@echo " make test-jacs-binding-core-pq Run binding-core tests (+ post-quantum)"
@echo " make test-jacs-storage Run all storage backend tests (duckdb, redb, surrealdb, postgresql)"
@echo " make test-jacs-duckdb Run DuckDB storage tests"
@echo " make test-jacs-redb Run Redb storage tests"
@echo " make test-jacs-surrealdb Run SurrealDB storage tests"
@echo " make test-jacs-postgresql Run PostgreSQL storage tests"
@echo " make test-jacs-observability Run observability tests"
@echo " make audit-jacs Run cargo-audit (required security gate)"
@echo " make test-jacspy Run Python binding tests"
@echo " make test-jacsnpm Run Node.js binding tests"
@echo " make regen-cross-lang-fixtures Regenerate Rust->Python->Node fixtures"
@echo ""
@echo "GIT HOOKS:"
@echo " make install-githooks Configure core.hooksPath=.githooks"
@echo ""
@echo "DIRECT PUBLISH (local credentials required):"
@echo " make publish-jacs Publish all Rust crates in dependency order"
@echo " make publish-jacs-core Publish jacs core only"
@echo " make publish-jacs-binding-core Publish jacs-binding-core only"
@echo " make publish-jacs-mcp Publish jacs-mcp only"
@echo " make publish-jacs-cli Publish jacs-cli only"
@echo " make publish-jacs-dry Dry run crates.io publish"
@echo " make publish-jacspy Publish to PyPI"
@echo " make publish-jacspy-dry Dry run PyPI publish"
@echo " make publish-jacsnpm Publish to npm"
@echo " make publish-jacsnpm-dry Dry run npm publish"
@echo ""
@echo "GITHUB CI RELEASE (via git tags - versions auto-detected):"
@echo " make release-jacs Tag crate/v<version> -> triggers crates.io release"
@echo " make release-jacspy Tag pypi/v<version> -> triggers PyPI release"
@echo " make release-jacsnpm Tag npm/v<version> -> triggers npm release"
@echo " make release-cli Tag cli/v<version> -> triggers CLI binary release"
@echo " make release-all Verify versions match, then release crates/PyPI/npm"
@echo " make release-everything Verify versions match, then release crates/PyPI/npm/CLI"
@echo " make release-delete-tags Delete release tags (for fixing failed releases)"
@echo " make retry-jacs Retry failed crates.io release (delete tags, retag, push)"
@echo " make retry-jacspy Retry failed PyPI release (delete tags, retag, push)"
@echo " make retry-jacsnpm Retry failed npm release (delete tags, retag, push)"
@echo " make retry-cli Retry failed CLI release (delete tags, retag, push)"
@echo " make retry-everything Smart retry: check registries, only retry unpublished"
@echo ""
@echo "Required GitHub Secrets:"
@echo " CRATES_IO_TOKEN - for crate/v* tags"
@echo " PYPI_API_TOKEN - for pypi/v* tags"
@echo " NPM_TOKEN - for npm/v* tags"