/ 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