Skip to content
This repository was archived by the owner on Oct 27, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions scripts/julia-env-info
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C

have() { command -v "$1" >/dev/null 2>&1; }

# -------- parse julia_version from Manifest.toml (BSD/GNU portable) --------
read_manifest_version() {
awk -F= '
/^[[:space:]]*julia_version[[:space:]]*=/ {
v=$2
gsub(/^[[:space:]]+|[[:space:]]+$/, "", v)
gsub(/^"|"$/, "", v)
print v
exit
}
' "$1" 2>/dev/null || true
}

# -------- parse juliaup api getconfig1 (no jq needed) --------
read_juliaup_default() {
# Prints: "<channel_name>\t<version>\t<file>" OR nothing if unavailable
local cfg dc name ver file
cfg="$(juliaup api getconfig1 2>/dev/null || true)" || true
[ -z "${cfg:-}" ] && return 0
# Extract the DefaultChannel object
dc="$(printf '%s' "$cfg" | awk 'match($0,/"DefaultChannel"[[:space:]]*:[[:space:]]*\{[^}]*\}/){print substr($0,RSTART,RLENGTH)}')"
[ -z "${dc:-}" ] && return 0
# Pull fields (quoted strings)
name="$(printf '%s\n' "$dc" | grep -oE '"Name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*"Name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/' || true)"
ver="$( printf '%s\n' "$dc" | grep -oE '"Version"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*"Version"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/' || true)"
file="$(printf '%s\n' "$dc" | grep -oE '"File"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*"File"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/' || true)"
[ -n "$name" ] && printf '%s\t%s\t%s\n' "$name" "$ver" "$file"
}

# ---------- ENV ----------
ENV_TSV="$(mktemp)"; PROJ_TSV="$(mktemp)"; MAN_TSV="$(mktemp)"
trap 'rm -f "$ENV_TSV" "$PROJ_TSV" "$MAN_TSV"' EXIT

{
printf 'KEY\tVALUE\n'
jpath="$(command -v julia 2>/dev/null || true)"
julia_present="no"; julia_ver="unknown"
if [ -n "${jpath:-}" ]; then
julia_present="yes"
if "$jpath" -e 'print(VERSION)' >/dev/null 2>&1; then
julia_ver="$("$jpath" -e 'print(VERSION)' 2>/dev/null || printf 'unknown')"
fi
fi
printf 'julia_present\t%s\n' "$julia_present"
printf 'julia_path\t%s\n' "${jpath:-none}"
printf 'julia_version\t%s\n' "$julia_ver"

# juliaup details via API
juliaup_present="no"; uses_juliaup="no"; juliaup_default_channel="unknown"; juliaup_default_version="unknown"; juliaup_default_file="unknown"
if have juliaup; then
juliaup_present="yes"
case "${jpath:-}" in *".juliaup/"*) uses_juliaup="yes" ;; esac
if IFS=$'\t' read -r ch ver file < <(read_juliaup_default); then
juliaup_default_channel="$ch"
[ -n "${ver:-}" ] && juliaup_default_version="$ver"
[ -n "${file:-}" ] && juliaup_default_file="$file"
fi
fi
printf 'juliaup_present\t%s\n' "$juliaup_present"
printf 'uses_juliaup\t%s\n' "$uses_juliaup"
printf 'juliaup_default_channel\t%s\n' "$juliaup_default_channel"
printf 'juliaup_default_version\t%s\n' "$juliaup_default_version"
printf 'juliaup_default_file\t%s\n' "$juliaup_default_file"
} >"$ENV_TSV"

# ---------- PROJECTS ----------
{
printf 'PATH\n'
find . -type f -name 'Project.toml' -print0 2>/dev/null \
| while IFS= read -r -d '' p; do printf '%s\n' "$p"; done
} >"$PROJ_TSV"

# ---------- MANIFESTS ----------
{
printf 'PATH\tjulia_version\n'
find . -type f -name 'Manifest.toml' -print0 2>/dev/null \
| while IFS= read -r -d '' m; do
v="$(read_manifest_version "$m")"
printf '%s\t%s\n' "$m" "${v:-unknown}"
done
} >"$MAN_TSV"

# ---------- PRINT (pretty if `column` exists) ----------
print_table() { if have column; then column -t -s $'\t' "$1"; else cat "$1"; fi; }

printf 'ENV\n'; print_table "$ENV_TSV"; printf '\n'
printf 'PROJECTS\n'; print_table "$PROJ_TSV"; printf '\n'
printf 'MANIFESTS\n'; print_table "$MAN_TSV"; printf '\n'
169 changes: 169 additions & 0 deletions skills/testing/julia-tests/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
name: Environments and tests in Julia
description: How to correctly activate environments and run tests in Julia
when_to_use: When running Julia tests, getting "LoadError" or package not found errors, seeing "Manifest out of date" warnings, struggling with --project flag, need to run specific test files, or want to add test-only dependencies. When working with Julia projects that have Project.toml/Manifest.toml files. When you need to find Julia documentation for functions or understand what test_args does.
version: 2.1.0
languages: julia
---

# Environments and Tests in Julia

## Overview

**Core principle:** Every Julia process needs `--project=DIR` to activate the correct environment. Tests need their own environment with test-specific dependencies.

**Julia projects:** Each has a `Project.toml` (dependencies) and optionally `Manifest.toml` (lockfile).

## Quick Reference

| Task | Command |
|------|---------|
| Find all projects | `${SUPERPOWERS_SKILLS_ROOT}/scripts/julia-env-info` |
| Get function documentation | `julia -e 'using Pkg; println(@doc Pkg.test)'` |
| Run all tests | `julia --project=. -e 'using Pkg; Pkg.test()'` |
| Run specific test file | `julia --project=. -e 'using TestEnv; TestEnv.activate(); include("test/file.jl")'` |
| Fix "Manifest out of date" | `julia --project=. -e 'using Pkg; Pkg.resolve()'` |
| Instantiate environment | `julia --project=. -e 'using Pkg; Pkg.instantiate()'` |
| Add test-only dependency | `julia --project=test -e 'using Pkg; Pkg.add("Dep")'` OR `Pkg.add("Dep"; target=:extras)` |

## Starting a Julia Task

**1. Find all Julia projects in the repo:**
```sh
${SUPERPOWERS_SKILLS_ROOT}/scripts/julia-env-info
```

Shows:
- Julia version
- All Project.toml locations
- All Manifest.toml files with their Julia versions

**2. Activate the right project:**
```sh
julia --project=subdir -e '...' # for subdir/Project.toml
julia --project=. -e '...' # for ./Project.toml
```

**Always use `--project` flag.** Without it, Julia uses the global environment.

## Running Tests

### Option 1: Run All Tests (Standard)

```sh
julia --project=. -e 'using Pkg; Pkg.test()'
```

**Use this when:**
- Running full test suite
- CI/CD
- Not sure how tests are organized

Pkg finds the test environment automatically.

### Option 2: Run Specific Test Files

**Requirements:**
- TestEnv.jl installed globally: `julia -e 'using Pkg; Pkg.add("TestEnv")'`

**Command:**
```sh
julia --project=. -e 'using TestEnv; TestEnv.activate(); include("test/mytests.jl")'
```

**Use this when:**
- Full suite takes too long
- Only changed specific code
- Developing test-first

### Option 3: Direct Test Environment Activation

If `test/Project.toml` exists:
```sh
julia --project=test -e 'include("test/mytests.jl")'
```

Options 1 and 2 still work in this case.

## Test-Only Dependencies

Julia has two patterns:

### Pattern 1: test/Project.toml

**If `test/Project.toml` exists**, activate it:
```sh
julia --project=test -e 'using Pkg; Pkg.add("BenchmarkTools")'
```

### Pattern 2: [extras] in Main Project.toml

**If main Project.toml has `[extras]` section:**

**1. Add to [extras]:**
```sh
julia --project=. -e 'using Pkg; Pkg.add("BenchmarkTools"; target=:extras)'
```

**2. Manually update [targets]:**
```toml
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"

[targets]
test = ["Test", "BenchmarkTools"] # Add BenchmarkTools here
```

**Which to use:** Check what exists. Don't mix both.

## Common Issues

### "Manifest out of date" Warning

**Cause:** Project.toml changed (e.g., after `git pull`)

**Fix:**
```sh
julia --project=. -e 'using Pkg; Pkg.resolve()'
```

### Version Mismatches

**Cause:** Manifest.toml created with different Julia version

**Check versions:**
```sh
${SUPERPOWERS_SKILLS_ROOT}/scripts/julia-env-info
```

Shows your Julia version and each Manifest's Julia version.

**Fix:** Re-resolve manifest or delete it (ask user before deleting).

### Tests Fail with LoadError

**Cause:** Wrong environment activated or dependencies not installed

**Fix:**
1. Check `--project` flag points to correct directory
2. Run `Pkg.instantiate()` to install dependencies
3. For tests, use `Pkg.test()` not direct file execution

## Common Mistakes

| Mistake | Fix |
|---------|-----|
| `julia test/runtests.jl` | `julia --project=. test/runtests.jl` |
| `Pkg.test(test_args=["file.jl"])` | `test_args` are command-line arguments (ARGS), NOT file selectors. Use TestEnv to run specific files. |
| Deleting Manifest.toml carelessly | Ask user before deleting |
| Missing `--project` flag | Add `--project=.` or `--project=DIR` |
| Forgetting to resolve after pull | Run `Pkg.resolve()` |

## Environment Types

**Global:** Used without `--project`. Install dev tools here (TestEnv.jl).

**Local:** Activated with `--project`. Package dependencies.

**Stacked:** Local environment can use global packages, but packages can't declare undeclared global deps.
Loading