Instalación y Uso de Just Command Runner

Just es un ejecutor de comandos moderno escrito en Rust que usa archivos justfile con una sintaxis limpia y expresiva, diseñado específicamente como alternativa a Make para automatización de proyectos. A diferencia de Makefile, Just no confunde tarea con sistema de archivos y tiene manejo de errores predecible. Esta guía cubre la instalación, sintaxis y patrones más útiles para automatizar proyectos en Linux.

Requisitos Previos

  • Linux (Ubuntu/Debian o CentOS/Rocky)
  • Terminal con bash o zsh
  • Acceso sudo para instalación global (opcional)

Instalación de Just

# Método 1: Con el gestor de paquetes cargo (Rust)
cargo install just

# Método 2: Script de instalación (recomendado, sin necesitar Rust)
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin

# Método 3: Con Homebrew en Linux
brew install just

# Método 4: En Ubuntu/Debian con apt (versión puede ser antigua)
sudo apt install just

# Método 5: Descarga manual del binario desde GitHub
curl -L https://github.com/casey/just/releases/latest/download/just-x86_64-unknown-linux-musl.tar.gz | tar xz
sudo mv just /usr/local/bin/

# Verificar la instalación
just --version

Configurar autocompletado

# Generar completado para bash
just --completions bash > /etc/bash_completion.d/just

# Para zsh (agregar a ~/.zshrc)
just --completions zsh > ~/.zfunc/_just
echo 'fpath=(~/.zfunc $fpath)' >> ~/.zshrc
autoload -Uz compinit && compinit

# Para fish
just --completions fish > ~/.config/fish/completions/just.fish

Sintaxis Básica de Justfile

Crea un archivo llamado justfile (o Justfile) en la raíz del proyecto:

# justfile - comentarios con #

# La receta por defecto se ejecuta con solo 'just'
default:
    just --list

# Receta simple de construcción
build:
    echo "Compilando proyecto..."
    go build -o bin/app ./cmd/main.go

# Receta con descripción (aparece en just --list)
# Compilar y ejecutar la aplicación
run: build
    ./bin/app

# Receta con dependencias (se ejecutan antes)
test: lint
    go test ./... -v

lint:
    golangci-lint run ./...

# Receta de limpieza
clean:
    rm -rf bin/
    rm -rf dist/
# Listar todas las recetas disponibles
just --list

# Ejecutar la receta por defecto
just

# Ejecutar una receta específica
just build

# Ejecutar múltiples recetas en orden
just clean build test

# Ver los comandos que ejecutaría sin ejecutarlos
just --dry-run build

Argumentos y Parámetros

# Receta con argumento obligatorio
deploy entorno:
    echo "Desplegando en {{entorno}}"
    ./scripts/deploy.sh {{entorno}}

# Receta con argumento con valor por defecto
saludo nombre="mundo":
    echo "Hola, {{nombre}}!"

# Múltiples argumentos
crear-usuario nombre email rol="usuario":
    echo "Creando usuario {{nombre}} ({{email}}) con rol {{rol}}"
    ./scripts/crear-usuario.sh "{{nombre}}" "{{email}}" "{{rol}}"

# Argumento variádico (captura todo lo que queda)
ejecutar +args:
    echo "Argumentos: {{args}}"
    ./bin/app {{args}}

# Argumento variádico opcional
probar *flags:
    go test ./... {{flags}}
# Llamar con argumentos posicionales
just deploy produccion
just saludo "Juan"
just crear-usuario "Ana García" "[email protected]" "admin"

# Llamar con argumentos nombrados
just deploy entorno=staging
just saludo nombre="María"

# Argumento variádico
just probar -race -count=2 ./pkg/...

Variables y Expresiones

# Variables estáticas
app := "mi-aplicacion"
version := "1.0.0"
registry := "registry.empresa.com"

# Variables calculadas con backtick (se evalúan al cargar)
git_hash := `git rev-parse --short HEAD`
fecha := `date +%Y%m%d`

# Variables de entorno (con valor por defecto)
entorno := env_var_or_default("DEPLOY_ENV", "development")
puerto := env_var_or_default("PORT", "8080")

# Variable que puede fallar
usuario := `whoami`

# Mostrar información del proyecto
info:
    echo "Aplicación: {{app}}"
    echo "Versión: {{version}}"
    echo "Commit: {{git_hash}}"
    echo "Entorno: {{entorno}}"
    echo "Puerto: {{puerto}}"

# Usar variables en comandos complejos
build:
    docker build \
        --build-arg VERSION={{version}} \
        --build-arg GIT_HASH={{git_hash}} \
        -t {{registry}}/{{app}}:{{version}}-{{git_hash}} \
        .

Cargar desde archivo .env

# Cargar variables desde .env automáticamente
set dotenv-load

# Ahora las variables de .env están disponibles
conectar-db:
    psql $DATABASE_URL

Condicionales y Plataformas

# Detectar sistema operativo
os := os()
arch := arch()

# Seleccionar binario según plataforma
binario := if os() == "linux" {
    "app-linux"
} else if os() == "macos" {
    "app-macos"
} else {
    "app-windows.exe"
}

# Receta condicional
instalar-deps:
    #!/usr/bin/env bash
    # Usar bash para lógica compleja
    if command -v apt-get &>/dev/null; then
        sudo apt-get install -y curl git jq postgresql-client
    elif command -v dnf &>/dev/null; then
        sudo dnf install -y curl git jq postgresql
    else
        echo "Gestor de paquetes no reconocido"
        exit 1
    fi

# Verificar precondiciones
deploy entorno:
    #!/usr/bin/env bash
    # Verificar que estamos en la rama correcta
    rama_actual=$(git branch --show-current)
    if [ "{{entorno}}" = "produccion" ] && [ "$rama_actual" != "main" ]; then
        echo "Error: solo se puede desplegar en producción desde la rama main"
        exit 1
    fi
    echo "Desplegando en {{entorno}}..."
    kubectl apply -f k8s/{{entorno}}/

Recetas específicas por shell

# Por defecto just usa sh, pero puedes cambiar el intérprete
set shell := ["bash", "-uc"]

# O por receta individual
tarea-python:
    #!/usr/bin/env python3
    import os
    print(f"Ejecutando desde Python: {os.getcwd()}")

tarea-node:
    #!/usr/bin/env node
    console.log("Ejecutando desde Node.js");

tarea-bash:
    #!/usr/bin/env bash
    set -euo pipefail
    echo "Script bash con manejo de errores estricto"
    for archivo in src/*.go; do
        echo "Procesando: $archivo"
    done

Patrones Avanzados

Justfile para proyecto completo

# justfile completo para aplicación web con Docker

set dotenv-load
set shell := ["bash", "-uc"]

# Variables del proyecto
app := "portal-web"
registry := env_var_or_default("REGISTRY", "registry.empresa.com")
version := `git describe --tags --always --dirty 2>/dev/null || echo "0.0.0-dev"`
imagen := registry + "/" + app + ":" + version

# Muestra ayuda por defecto
default:
    @just --list

# Entorno de desarrollo
dev:
    docker compose -f docker-compose.dev.yml up --build

# Calidad de código
lint:
    eslint src/ --ext .js,.ts
    prettier --check "src/**/*.{js,ts,css}"

# Pruebas
test *flags:
    jest --coverage {{flags}}

test-watch:
    jest --watch

# Construcción
build: lint test
    npm run build
    @echo "Construcción completada: dist/"

# Docker
docker-build:
    docker build -t {{imagen}} --build-arg VERSION={{version}} .
    @echo "Imagen creada: {{imagen}}"

docker-push: docker-build
    docker push {{imagen}}
    @echo "Imagen publicada: {{imagen}}"

# Despliegue
[confirm("¿Estás seguro de desplegar en producción?")]
deploy-prod: docker-push
    kubectl set image deployment/{{app}} app={{imagen}}
    kubectl rollout status deployment/{{app}} --timeout=5m

deploy-staging: docker-push
    kubectl set image deployment/{{app}}-staging app={{imagen}} -n staging
    kubectl rollout status deployment/{{app}}-staging -n staging

# Base de datos
db-migrate:
    ./bin/migrate -database $DATABASE_URL up

db-rollback:
    ./bin/migrate -database $DATABASE_URL down 1

db-shell:
    psql $DATABASE_URL

# Limpieza
clean:
    rm -rf dist/ node_modules/.cache
    docker image prune -f

Recetas con confirmación

# Pedir confirmación antes de ejecutar (just >= 1.17)
[confirm]
limpiar-bd:
    psql $DATABASE_URL -c "TRUNCATE TABLE sesiones CASCADE"

# Con mensaje personalizado
[confirm("Esto eliminará datos de producción. ¿Continuar?")]
reset-produccion:
    ./scripts/reset-prod.sh

Importar justfiles externos

# Importar recetas de otro archivo
import "justfiles/docker.just"
import "justfiles/kubernetes.just"
import? "justfiles/local.just"  # El ? hace que sea opcional

Solución de Problemas

Receta no encontrada

# Verificar que el archivo se llama 'justfile' o 'Justfile'
ls -la justfile Justfile 2>/dev/null

# Just busca el justfile en el directorio actual y superiores
just --list --justfile /ruta/a/tu/justfile

Error de sintaxis en justfile

# Verificar la sintaxis del justfile
just --evaluate

# Just es sensible a la indentación: usa TABS, no espacios
# Revisar con:
cat -A justfile | head -20
# Los tabs aparecen como ^I, los espacios como espacios

Variable de entorno no disponible

# Verificar que .env está en el directorio correcto
# y que tiene 'set dotenv-load' en el justfile

# Depurar variables
just --evaluate | grep MI_VARIABLE

Conflicto de nombre con dependencia del sistema

# Just busca recetas, no ejecutables del sistema
# Si necesitas ejecutar un comando del sistema con el mismo nombre:
test-real:
    /usr/bin/test -f archivo.txt

Conclusión

Just ofrece una experiencia de automatización superior a Make para proyectos modernos: sintaxis clara, soporte nativo de argumentos con valores por defecto, variables expresivas y manejo de errores predecible. Su diseño específico para ejecutar recetas (no para gestión de dependencias de archivos) evita la confusión más común de Make y lo convierte en una herramienta ideal para estandarizar comandos de desarrollo, build y despliegue en cualquier tipo de proyecto.