-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathMakefile
More file actions
181 lines (154 loc) · 8.47 KB
/
Copy pathMakefile
File metadata and controls
181 lines (154 loc) · 8.47 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
# Release automation for reflexio-ai (PyPI).
#
# Usage:
# make bump VERSION=0.2.16 Update version in pyproject.toml + refresh uv.lock
# make release VERSION=0.2.16 Bump, commit, tag v0.2.16, publish to PyPI, push
# make publish Build and publish current version to PyPI
# make publish-dry Build only; inspect dist/ without uploading
# make test-pypi Build and publish current version to TestPyPI
# make client-release VERSION=0.2.16
# Bump, test, tag, and publish reflexio-client only
#
# Requires:
# - uv (UV_PUBLISH_TOKEN set for PyPI uploads, or ~/.pypirc)
# - git (for the release flow)
.PHONY: help bump release publish publish-dry test-pypi clean version \
check-version check-clean check-branch check-up-to-date \
check-tag-free verify-dist \
client-version check-client-version check-client-tag-free \
client-clean client-bump client-test client-publish \
client-publish-dry client-test-pypi client-release \
verify-client-dist
PYPROJECT := pyproject.toml
CLIENT_DIR := client_dist
CLIENT_PYPROJECT := $(CLIENT_DIR)/pyproject.toml
VERSION_CURRENT := $(shell grep -E '^version = ' $(PYPROJECT) | head -1 | cut -d'"' -f2)
CLIENT_VERSION_CURRENT := $(shell grep -E '^version = ' $(CLIENT_PYPROJECT) | head -1 | cut -d'"' -f2)
help:
@awk 'BEGIN{FS=":.*##"} /^[a-zA-Z_-]+:.*##/{printf " %-18s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
version: ## Print the current package version
@echo $(VERSION_CURRENT)
client-version: ## Print the current reflexio-client package version
@echo $(CLIENT_VERSION_CURRENT)
check-version:
ifndef VERSION
$(error VERSION is required, e.g. make bump VERSION=0.2.16)
endif
@printf '%s' '$(VERSION)' | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9.-]+)?$$' \
|| { echo "error: VERSION '$(VERSION)' is not valid semver" >&2; exit 1; }
check-clean:
@git diff --quiet && git diff --cached --quiet \
|| { echo "error: working tree is dirty — commit or stash first" >&2; exit 1; }
check-branch:
@branch=$$(git rev-parse --abbrev-ref HEAD); \
[ "$$branch" = "main" ] || { echo "error: not on main (on $$branch)" >&2; exit 1; }
check-up-to-date:
@git fetch origin
@[ -z "$$(git log HEAD..origin/main --oneline)" ] \
|| { echo "error: local main is behind origin/main — pull first" >&2; exit 1; }
check-tag-free: check-version
@if git rev-parse -q --verify "refs/tags/v$(VERSION)" >/dev/null; then \
echo "error: tag v$(VERSION) already exists locally" >&2; exit 1; fi
@if git ls-remote --exit-code --tags origin "refs/tags/v$(VERSION)" >/dev/null 2>&1; then \
echo "error: tag v$(VERSION) already exists on origin" >&2; exit 1; fi
check-client-version:
ifndef VERSION
$(error VERSION is required, e.g. make client-release VERSION=0.2.16)
endif
@printf '%s' '$(VERSION)' | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9.-]+)?$$' \
|| { echo "error: VERSION '$(VERSION)' is not valid semver" >&2; exit 1; }
check-client-tag-free: check-client-version
@if git rev-parse -q --verify "refs/tags/reflexio-client-v$(VERSION)" >/dev/null; then \
echo "error: tag reflexio-client-v$(VERSION) already exists locally" >&2; exit 1; fi
@if git ls-remote --exit-code --tags origin "refs/tags/reflexio-client-v$(VERSION)" >/dev/null 2>&1; then \
echo "error: tag reflexio-client-v$(VERSION) already exists on origin" >&2; exit 1; fi
verify-dist:
@actual=$$(grep -E '^version = ' $(PYPROJECT) | head -1 | cut -d'"' -f2); \
ls dist/*-$$actual* >/dev/null 2>&1 \
|| { echo "error: dist/ has no artifacts for version $$actual" >&2; exit 1; }; \
echo "✓ dist/ contains artifacts for version $$actual"
verify-client-dist:
@actual=$$(grep -E '^version = ' $(CLIENT_PYPROJECT) | head -1 | cut -d'"' -f2); \
ls $(CLIENT_DIR)/dist/*-$$actual* >/dev/null 2>&1 \
|| { echo "error: $(CLIENT_DIR)/dist/ has no artifacts for version $$actual" >&2; exit 1; }; \
wheel=$$(ls $(CLIENT_DIR)/dist/reflexio_client-$$actual-*.whl | head -1); \
[ -n "$$wheel" ] \
|| { echo "error: $(CLIENT_DIR)/dist/ has no wheel artifact for version $$actual" >&2; exit 1; }; \
uv run python -c 'import sys, zipfile; names=zipfile.ZipFile(sys.argv[1]).namelist(); has_client=any(n.startswith("reflexio/client/") for n in names); has_models=any(n.startswith("reflexio/models/") for n in names); has_server=any(n.startswith("reflexio/server/") for n in names); raise SystemExit("error: client wheel is missing reflexio/client" if not has_client else "error: client wheel is missing reflexio/models" if not has_models else "error: client wheel must not include reflexio/server" if has_server else 0)' "$$wheel"; \
uv run --no-project --with "$$wheel" python -c "from reflexio import ReflexioClient" \
|| { echo "error: client wheel fails to import in isolation (likely a reflexio/models module importing reflexio/server)" >&2; exit 1; }; \
echo "✓ $(CLIENT_DIR)/dist/ contains client-only artifacts for version $$actual"
clean: ## Remove build artifacts
rm -rf dist/ build/ *.egg-info
client-clean: ## Remove reflexio-client build artifacts
rm -rf $(CLIENT_DIR)/dist/ $(CLIENT_DIR)/build/ $(CLIENT_DIR)/*.egg-info
bump: check-version check-clean ## Rewrite version in pyproject.toml and refresh uv.lock
@echo "→ bumping to $(VERSION)"
@sed -i.bak -E 's/^version = "[^"]+"/version = "$(VERSION)"/' $(PYPROJECT)
@rm -f $(PYPROJECT).bak
@echo "→ refreshing uv lockfile"
@uv lock
@echo "→ resulting version:"
@grep -E '^version = ' $(PYPROJECT)
client-bump: check-client-version check-clean ## Rewrite reflexio-client version and refresh its uv.lock
@echo "→ bumping reflexio-client to $(VERSION)"
@sed -i.bak -E 's/^version = "[^"]+"/version = "$(VERSION)"/' $(CLIENT_PYPROJECT)
@rm -f $(CLIENT_PYPROJECT).bak
@echo "→ refreshing reflexio-client uv lockfile"
cd $(CLIENT_DIR) && uv lock
@echo "→ resulting reflexio-client version:"
@grep -E '^version = ' $(CLIENT_PYPROJECT)
client-test: ## Run client-only lint, type checks, and tests
uv run ruff check reflexio/client reflexio/models tests/client tests/models
uv run pyright reflexio/client reflexio/models tests/client tests/models
uv run pytest tests/client tests/models -q -o addopts=
publish: clean ## Build and publish current version to PyPI
@echo "→ uv build"
uv build
@$(MAKE) verify-dist
@echo "→ uv publish"
uv publish dist/*
publish-dry: clean ## Build only; show what would ship without uploading
@echo "→ uv build (dry: inspect dist/ manually)"
uv build
@ls -la dist/
test-pypi: clean ## Build and publish current version to TestPyPI
@echo "→ uv build"
uv build
@echo "→ uv publish --publish-url https://test.pypi.org/legacy/"
uv publish --publish-url https://test.pypi.org/legacy/ dist/*
client-publish: client-clean ## Build and publish reflexio-client to PyPI
@echo "→ uv build $(CLIENT_DIR)"
cd $(CLIENT_DIR) && uv build
@$(MAKE) verify-client-dist
@echo "→ uv publish $(CLIENT_DIR)/dist/*"
cd $(CLIENT_DIR) && uv publish dist/*
client-publish-dry: client-clean ## Build reflexio-client only; inspect dist/ without uploading
@echo "→ uv build $(CLIENT_DIR) (dry: inspect $(CLIENT_DIR)/dist/ manually)"
cd $(CLIENT_DIR) && uv build
@$(MAKE) verify-client-dist
@ls -la $(CLIENT_DIR)/dist/
client-test-pypi: client-clean ## Build and publish reflexio-client to TestPyPI
@echo "→ uv build $(CLIENT_DIR)"
cd $(CLIENT_DIR) && uv build
@$(MAKE) verify-client-dist
@echo "→ uv publish --publish-url https://test.pypi.org/legacy/"
cd $(CLIENT_DIR) && uv publish --publish-url https://test.pypi.org/legacy/ dist/*
release: check-version check-clean check-branch check-up-to-date check-tag-free bump ## Bump + commit + tag + publish + push
@echo "→ committing release v$(VERSION)"
git add $(PYPROJECT) uv.lock
git commit -m "Release v$(VERSION)"
git tag -a v$(VERSION) -m "Release v$(VERSION)"
@$(MAKE) publish
@echo "→ pushing commit + tag"
git push --follow-tags
@echo "✓ released reflexio-ai v$(VERSION) to PyPI"
client-release: check-client-version check-clean check-branch check-up-to-date check-client-tag-free client-bump client-test ## Bump, test, commit, tag, publish, and push reflexio-client only
@echo "→ committing reflexio-client release v$(VERSION)"
git add $(CLIENT_PYPROJECT) $(CLIENT_DIR)/uv.lock
git commit -m "Release reflexio-client v$(VERSION)"
git tag -a reflexio-client-v$(VERSION) -m "Release reflexio-client v$(VERSION)"
@$(MAKE) client-publish
@echo "→ pushing commit + tag"
git push --follow-tags
@echo "✓ released reflexio-client v$(VERSION) to PyPI"