/ justfile
justfile
1 # Auths project recipes 2 3 # Run all tests (nextest + doc tests). 4 test: 5 cargo nextest run --workspace --all-features 6 cargo test --workspace --doc 7 8 # Run only integration tests (tests/ directories across all crates). 9 intest: 10 cargo nextest run --workspace -E 'kind(test)' 11 12 # Run all build targets in parallel and report pass/fail cleanly. 13 # Optional targets (wasm-pack, cross/aarch64) are skipped if the tool is not installed. 14 # Install optional tools: 15 # cargo install wasm-pack --version "=0.12.1" --locked 16 # cargo install cross --locked (also needs Docker running) 17 build: 18 #!/usr/bin/env bash 19 set -uo pipefail 20 21 GREEN='\033[0;32m' 22 RED='\033[0;31m' 23 BOLD='\033[1m' 24 DIM='\033[2m' 25 NC='\033[0m' 26 27 TMP=$(mktemp -d) 28 trap 'rm -rf "$TMP"' EXIT 29 30 pids=() 31 names=() 32 logs=() 33 34 _run() { 35 local label="$1"; shift 36 local log="$TMP/${#pids[@]}.log" 37 names+=("$label") 38 logs+=("$log") 39 "$@" >"$log" 2>&1 & 40 pids+=($!) 41 } 42 43 # --- Always-run builds --- 44 _run "native (auths-cli)" cargo build --release --package auths-cli 45 # Run from inside the crate to avoid workspace resolver v3 feature-scoping 46 # issues. From the workspace root, `--features wasm` (with or without the 47 # pkg/feature qualifier) triggers "cannot specify features for packages 48 # outside of workspace" under resolver = "3". cd-ing in sidesteps this. 49 _run "wasm32 check" bash -c 'rustup target add wasm32-unknown-unknown 2>/dev/null; cd crates/auths-verifier && cargo check --target wasm32-unknown-unknown --features wasm' 50 _run "python bindings" cargo check --manifest-path packages/auths-verifier-python/Cargo.toml 51 52 # --- Optional: wasm-pack (full wasm-pack pipeline, not just cargo check) --- 53 if command -v wasm-pack >/dev/null 2>&1; then 54 _run "wasm-pack build" bash -c 'cd crates/auths-verifier && wasm-pack build --target bundler --features wasm' 55 fi 56 57 # --- Optional: aarch64 cross build (requires cross + Docker) --- 58 if command -v cross >/dev/null 2>&1 && docker info >/dev/null 2>&1; then 59 _run "aarch64 cross build" cross build --release --package auths-cli --target aarch64-unknown-linux-gnu 60 fi 61 62 echo "" 63 echo -e "${BOLD}Running ${#pids[@]} builds in parallel...${NC}" 64 echo "" 65 66 failed=0 67 for i in "${!pids[@]}"; do 68 wait "${pids[$i]}" 69 rc=$? 70 label="${names[$i]}" 71 log="${logs[$i]}" 72 73 if [ "$rc" -eq 0 ]; then 74 printf " ${GREEN}✓${NC} %-32s built\n" "$label" 75 else 76 printf " ${RED}✗${NC} %-32s failed\n" "$label" 77 # Show error lines and their file locations; skip Compiling/Checking noise 78 errors=$(grep -E "^error" "$log" 2>/dev/null | head -8 || true) 79 locs=$(grep -E "^ +--> " "$log" 2>/dev/null | head -4 || true) 80 if [ -n "$errors" ]; then 81 echo "$errors" | sed 's/^/ /' 82 [ -n "$locs" ] && echo "$locs" | sed 's/^/ /' 83 else 84 # Fallback: last few non-blank lines if no ^error lines found 85 tail -6 "$log" | grep -v '^\s*$' | sed 's/^/ /' 86 fi 87 failed=1 88 fi 89 done 90 91 echo "" 92 if [ "$failed" -eq 0 ]; then 93 echo -e "${GREEN}${BOLD}All builds passed${NC}" 94 else 95 echo -e "${RED}${BOLD}One or more builds failed — see above${NC}" 96 exit 1 97 fi 98 99 # Run the Radicle multi-device e2e demo (requires rad CLI). 100 e2e-radicle: 101 bash scripts/radicle-e2e.sh 102 103 # Private server recipes (e2e, sitedemo, logindemo, chatdemo) have been moved to auths-cloud. 104 105 # Bump the workspace version, commit, tag, and push to trigger the release workflow. 106 # Usage: just release 0.0.1-rc.10 107 release VERSION: 108 #!/usr/bin/env bash 109 set -euo pipefail 110 111 # Colors 112 GREEN='\033[0;32m' 113 YELLOW='\033[1;33m' 114 CYAN='\033[0;36m' 115 RED='\033[0;31m' 116 BOLD='\033[1m' 117 DIM='\033[2m' 118 NC='\033[0m' 119 120 VERSION="{{VERSION}}" 121 TAG="v${VERSION}" 122 123 echo "" 124 echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}" 125 echo -e "${CYAN}║${NC}${BOLD} Release Publisher ${NC}${CYAN}║${NC}" 126 echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}" 127 echo "" 128 echo -e "${BOLD}Version:${NC} ${CYAN}${TAG}${NC}" 129 130 # Check if on main/master branch 131 CURRENT_BRANCH=$(git branch --show-current) 132 if [[ "$CURRENT_BRANCH" != "main" && "$CURRENT_BRANCH" != "master" ]]; then 133 echo -e "${YELLOW}⚠ Warning:${NC} You're on branch ${CYAN}${CURRENT_BRANCH}${NC}, not ${CYAN}main${NC}" 134 read -p "Continue anyway? [y/N] " -n 1 -r 135 echo 136 if [[ ! $REPLY =~ ^[Yy]$ ]]; then 137 echo -e "${RED}✗${NC} Release cancelled" 138 exit 1 139 fi 140 fi 141 142 # Check for uncommitted changes (before we make our own) 143 if ! git diff-index --quiet HEAD --; then 144 echo -e "${RED}✗ Error:${NC} Uncommitted changes detected" 145 echo "" 146 git status --short 147 echo "" 148 echo -e "${DIM}Commit or stash your changes before releasing${NC}" 149 exit 1 150 fi 151 152 # Bump version in root Cargo.toml (single source of truth via workspace.package) 153 CURRENT=$(grep '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/') 154 echo -e "${BOLD}Bumping:${NC} ${DIM}${CURRENT}${NC} → ${CYAN}${VERSION}${NC}" 155 sed -i '' "s/^version = \"${CURRENT}\"/version = \"${VERSION}\"/" Cargo.toml 156 # Refresh Cargo.lock 157 cargo metadata --no-deps --format-version 1 -q > /dev/null 158 git add Cargo.toml Cargo.lock 159 git diff --cached --quiet || git commit -m "chore: release ${TAG}" 160 161 # Check if tag already exists 162 if git rev-parse "$TAG" >/dev/null 2>&1; then 163 echo -e "${YELLOW}⚠ Warning:${NC} Tag ${CYAN}${TAG}${NC} already exists" 164 read -p "Delete and recreate? [y/N] " -n 1 -r 165 echo 166 if [[ $REPLY =~ ^[Yy]$ ]]; then 167 echo -e "${DIM}Deleting local and remote tag...${NC}" 168 git tag -d "$TAG" 2>/dev/null || true 169 git push origin ":refs/tags/$TAG" 2>/dev/null || true 170 echo -e "${GREEN}✓${NC} Deleted existing tag" 171 else 172 echo -e "${RED}✗${NC} Release cancelled" 173 exit 1 174 fi 175 fi 176 177 # Pre-flight checks 178 echo "" 179 echo -e "${BOLD}Pre-flight Checks:${NC}" 180 181 # Check if release workflow exists 182 if [ ! -f ".github/workflows/release.yml" ]; then 183 echo -e " ${RED}✗${NC} Release workflow not found at .github/workflows/release.yml" 184 exit 1 185 fi 186 echo -e " ${GREEN}✓${NC} Release workflow exists" 187 188 # Check if we can push 189 if ! git ls-remote --exit-code origin >/dev/null 2>&1; then 190 echo -e " ${RED}✗${NC} Cannot reach remote origin" 191 exit 1 192 fi 193 echo -e " ${GREEN}✓${NC} Remote accessible" 194 195 # Sync with remote 196 echo -e " ${DIM}Fetching latest from origin...${NC}" 197 git fetch origin --quiet 198 199 # Check if local is behind remote 200 LOCAL=$(git rev-parse @) 201 REMOTE=$(git rev-parse @{u} 2>/dev/null || echo "") 202 if [ -n "$REMOTE" ] && [ "$LOCAL" != "$REMOTE" ]; then 203 BASE=$(git merge-base @ @{u} 2>/dev/null || echo "") 204 if [ "$LOCAL" = "$BASE" ]; then 205 echo -e " ${RED}✗${NC} Your branch is behind origin. Run: git pull" 206 exit 1 207 elif [ "$REMOTE" = "$BASE" ]; then 208 echo -e " ${YELLOW}⚠${NC} Your branch is ahead of origin (unpushed commits)" 209 else 210 echo -e " ${RED}✗${NC} Your branch has diverged from origin" 211 exit 1 212 fi 213 fi 214 echo -e " ${GREEN}✓${NC} Branch is up to date" 215 216 echo "" 217 218 # Confirmation 219 echo -e "${BOLD}Release Summary:${NC}" 220 echo -e " Tag: ${CYAN}${TAG}${NC}" 221 echo -e " Branch: ${CYAN}${CURRENT_BRANCH}${NC}" 222 echo -e " Commit: ${DIM}$(git rev-parse --short HEAD)${NC}" 223 echo -e " Remote: ${DIM}$(git remote get-url origin)${NC}" 224 echo "" 225 echo -e "${BOLD}This will:${NC}" 226 echo -e " 1. Create tag ${CYAN}${TAG}${NC}" 227 echo -e " 2. Push tag to origin" 228 echo -e " 3. Trigger GitHub Actions release workflow" 229 echo -e " 4. Build binaries for all platforms" 230 echo -e " 5. Create GitHub release with artifacts" 231 echo -e " 6. Trigger Homebrew formula update" 232 echo "" 233 234 read -p "$(echo -e ${BOLD}Proceed with release?${NC}) [y/N] " -n 1 -r 235 echo 236 if [[ ! $REPLY =~ ^[Yy]$ ]]; then 237 echo -e "${RED}✗${NC} Release cancelled" 238 exit 1 239 fi 240 241 echo "" 242 echo -e "${BOLD}Creating Release...${NC}" 243 244 # Create tag 245 echo -e " ${DIM}Creating tag ${TAG}...${NC}" 246 git tag -a "$TAG" -m "Release ${VERSION}" 247 echo -e " ${GREEN}✓${NC} Tag created" 248 249 # Push tag 250 echo -e " ${DIM}Pushing tag to origin...${NC}" 251 git push origin "$TAG" 252 echo -e " ${GREEN}✓${NC} Tag pushed" 253 254 echo "" 255 echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" 256 echo -e "${BOLD} Release ${TAG} Initiated!${NC}" 257 echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" 258 echo "" 259 260 # Get repo info 261 REPO_URL=$(git remote get-url origin | sed 's/\.git$//' | sed 's|git@github.com:|https://github.com/|') 262 263 echo -e "${BOLD}Monitor Progress:${NC}" 264 echo -e " Workflow: ${CYAN}${REPO_URL}/actions/workflows/release.yml${NC}" 265 echo -e " Release: ${CYAN}${REPO_URL}/releases/tag/${TAG}${NC}" 266 echo "" 267 268 # Try to open browser 269 if command -v gh &> /dev/null; then 270 echo -e "${DIM}Waiting for workflow to start...${NC}" 271 sleep 3 272 273 # Try to get workflow run 274 WORKFLOW_URL=$(gh run list --workflow=release.yml --limit 1 --json databaseId,url --jq '.[0].url' 2>/dev/null || echo "") 275 276 if [ -n "$WORKFLOW_URL" ]; then 277 echo -e "${BOLD}Opening workflow run...${NC}" 278 if command -v open &> /dev/null; then 279 open "$WORKFLOW_URL" 280 elif command -v xdg-open &> /dev/null; then 281 xdg-open "$WORKFLOW_URL" 282 fi 283 fi 284 else 285 echo -e "${DIM}Install 'gh' CLI to auto-open workflow runs${NC}" 286 fi 287 288 echo "" 289 echo -e "${BOLD}What Happens Next:${NC}" 290 echo -e " 1. ${DIM}GitHub Actions builds binaries (5-10 min)${NC}" 291 echo -e " 2. ${DIM}Creates GitHub release with artifacts${NC}" 292 echo -e " 3. ${DIM}Triggers Homebrew formula update (automated)${NC}" 293 echo -e " 4. ${DIM}Review & merge Homebrew PR${NC}" 294 echo "" 295 echo -e "${BOLD}If Workflow Fails:${NC}" 296 echo -e " • Check Actions tab for error logs" 297 echo -e " • Fix the issue and re-run: ${CYAN}just release ${VERSION}${NC}" 298 echo -e " • Delete failed release if needed: ${CYAN}gh release delete ${TAG}${NC}" 299 echo "" 300 echo -e "${BOLD}After Successful Release:${NC}" 301 echo -e " • Verify binaries uploaded: ${CYAN}${REPO_URL}/releases/tag/${TAG}${NC}" 302 echo -e " • Check Homebrew PR: ${CYAN}https://github.com/bordumb/homebrew-auths-cli/pulls${NC}" 303 echo -e " • Test installation: ${CYAN}brew upgrade auths && auths --version${NC}" 304 echo "" 305 echo -e "${DIM}Happy releasing! 🚀${NC}" 306 echo "" 307 308 # Check release workflow status 309 release-status: 310 #!/usr/bin/env bash 311 set -euo pipefail 312 313 if ! command -v gh &> /dev/null; then 314 echo "Error: 'gh' CLI not installed" 315 echo "Install: brew install gh" 316 exit 1 317 fi 318 319 echo "" 320 echo "Recent release workflow runs:" 321 echo "" 322 gh run list --workflow=release.yml --limit 5 323 echo "" 324 325 # Delete a release tag (local and remote) 326 release-delete TAG: 327 #!/usr/bin/env bash 328 set -euo pipefail 329 330 echo "Deleting release tag: {{TAG}}" 331 git tag -d "{{TAG}}" 2>/dev/null || echo "Local tag not found" 332 git push origin ":refs/tags/{{TAG}}" 2>/dev/null || echo "Remote tag not found" 333 334 if command -v gh &> /dev/null; then 335 gh release delete "{{TAG}}" --yes 2>/dev/null || echo "GitHub release not found" 336 fi 337 338 echo "✓ Deleted {{TAG}}" 339 340 # Install auths-cli from local source into ~/.cargo/bin 341 install: 342 cargo install --path crates/auths-cli 343 344 # One-time setup: create a CI release-signing device and export secrets for GitHub 345 # Run this once locally, then add the printed values as GitHub secrets 346 # Delegates to the xtask crate for cross-platform correctness. 347 ci-setup: 348 cargo xt ci-setup