Hasta la 0.21.0 la única forma de tener CrawlForge era
clonar el repositorio y compilarlo con Rust, que pone a prueba la paciencia de cualquiera y es mala
manera de probar una herramienta. La 0.22.0 cambia cómo se consigue y deja el motor como estaba: lo que
comprueba y lo que escribe es lo mismo que en la 0.21.0. Lo nuevo es que ya la puede instalar alguien que no
ha escrito cargo en su vida.
brew install dcarrero/tap/crawlforge # macOS y Linux
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dcarrero/crawlforge/releases/latest/download/crawlforge-installer.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/dcarrero/crawlforge/releases/latest/download/crawlforge-installer.ps1 | iex"
cargo install crawlforge # Rust 1.88 o posterior
En la última versión publicada hay
binarios para macOS en Apple Silicon e Intel, Linux en x86_64 y ARM64 y Windows en x86_64, cada uno
con su suma de verificación. En crates.io hay tres paquetes: crawlforge, que es la línea de
comandos, y el motor y el catálogo de reglas por separado, como crawlforge-core y
crawlforge-rules.
Un aviso antes de seguir. Los binarios de macOS todavía no están notarizados, y aunque Homebrew los
instala sin quejarse, uno descargado a mano necesita xattr -d com.apple.quarantine crawlforge
para que Gatekeeper lo deje ejecutarse.
Cómo se compila una versión sin pagar nada
Las versiones las compila GitHub Actions, que es gratis en un repositorio público, con dist 0.34
(antes se llamaba cargo-dist). Basta con subir un tag. A partir de ahí compila para macOS en
aarch64 y x86_64, Linux en x86_64 y aarch64 (el de ARM64 en el runner ARM de GitHub) y Windows en
x86_64, calcula las sumas de verificación, genera los instaladores para la terminal y para
PowerShell, crea la versión en GitHub y sube la fórmula de Homebrew a dcarrero/homebrew-tap. Un
tap puede tener varias herramientas, y este ya tenía otro proyecto mío.
En la ejecución de la 0.22.0, Linux tardó entre 2m36s y 2m50s, macOS en Apple Silicon 3m16s, Windows 5m11s y macOS en Intel 10m35s. Casi todo lo de Intel es espera, porque la cola de ese runner es la lenta.
El binario sale de un perfil dist que hereda el perfil release sin tocar nada. Eso importa
porque la regresión de rendimiento se mide sobre la compilación release, así que lo que se publica
es justo lo que se mide.
El flujo escribe en el tap con un token de GitHub limitado al contenido de ese único repositorio, guardado como secreto del repositorio.
Lo que salió mal, por orden
Windows y los saltos de línea. El CI de la 0.21.0 falló solo en Windows. Un test comparaba byte a byte el JSON Schema publicado con el generado, y al hacer checkout Windows convierte los saltos de línea a CRLF. Ahora el test compara el contenido.
Un test de tiempos en un runner cargado. Hay un test que comprueba que el descubrimiento por sitemap rellena la cola de forma continua y no a tandas. En local pasaba en 0,7 s, pero en el runner de macOS de GitHub, que está compartido y va cargado, tardó 2,1 s dos veces con un umbral de 1,5 s. Subir el umbral a ojo habría hecho pasar el test sin que demostrara nada, así que lo que hice fue volver más lento el sitemap del test, de 600 ms a 1,5 s. Con eso, ir a tandas tardaría como mínimo 4,5 s y rellenar de forma continua unos 1,5 s, y el umbral quedó en 3,5 s, con margen de sobra por los dos lados.
Un tag sin versión. La 0.21.1 se etiquetó y nunca llegó a publicarse. Todas las compilaciones
fallaron con profile 'dist' is not defined porque faltaba el perfil en Cargo.toml. El tag ya era
público, así que lo dejé como estaba en vez de reescribirlo. La 0.21.2 añadió el perfil y fue la
primera versión con binarios, todavía con los nombres antiguos crawlforge-cli-*.
Un cambio de nombre que rompió un enlace. La 0.22.0 renombró el paquete de crawlforge-cli a
crawlforge para que se instale con cargo install crawlforge. Eso cambió también el nombre de
los ficheros de la versión, y el enlace al instalador que se publicó con la 0.21.2,
crawlforge-cli-installer.sh, dejó de funcionar con esta. Por eso la web esperó a la 0.22.0 para
explicar cómo instalarla.
Empaquetar para crates.io. Un crate publicado en crates.io solo lleva su propia carpeta. Las
diez traducciones vivían en la raíz del repositorio y el código las leía con rutas como
../../locales, de modo que, empaquetado, no habría compilado. Se movieron dentro de
crawlforge-rules, que ahora le pasa los textos a la línea de comandos. Antes de publicar
desempaqueté los tres crates en una carpeta vacía y los compilé juntos, como si vinieran de
crates.io. Salió crawlforge 0.22.0, con la salida en japonés y en polaco bien.
Publicar sin guardar ningún token
La primera publicación en crates.io tenía que ser a mano, con un token de la API limitado a estos tres crates y a publicar. El primer token lo rechazó con un 403 porque tenía mal los permisos, y no se subió nada. El segundo funcionó.
A partir de ahí el flujo de publicación usa Trusted Publishing de crates.io. El flujo demuestra quién es ante crates.io con el OpenID Connect de GitHub y recibe una credencial de vida corta para esa ejecución. No queda ningún token permanente guardado en ninguna parte, y el manual se revocó y se borró.
El trabajo de los crates consulta además la API de crates.io antes de publicar y se salta las versiones que ya están, así que al relanzarlo no intenta publicar la misma versión dos veces. Con la 0.22.0 hizo justo eso, en 9 segundos.
Comprobaciones que ahora corren en GitHub
cargo-deny, con el deny.toml del proyecto, se ejecuta en cada pull request, en cada push y todos
los lunes. Lo del lunes es porque un aviso nuevo de RustSec puede aparecer sin que nadie toque el
código.
Cada pull request que toca código lleva también un A/B de rendimiento. La base y la rama se compilan en el mismo runner y se miden en seis rondas alternas, y el resumen del trabajo enseña una tabla. Nunca bloquea la pull request. En el primero, la mediana de la base fue de 106.567 elementos por segundo y la de la rama de 106.046, un −0,5 %, con rondas entre 102.527 y 110.510 (más o menos ±3 %). En mi portátil, el mismo banco de pruebas había llegado a moverse un 20 % cuando la máquina estaba ocupada compilando otras cosas, y por eso se fue a un runner.
Un test falla ahora si se separan los números de versión que tienen que coincidir: el del
workspace, los de las dos dependencias internas y el del package.json que esta web instala por
tag.
Probado en un Mac
Antes de escribir esto instalé la 0.22.0 de las tres maneras en un Mac. Con Homebrew fueron unos
segundos, 14,6 MB y sin cuarentena de Gatekeeper. El instalador de la terminal y
cargo install crawlforge devolvieron los dos crawlforge 0.22.0.
Lo siguiente es notarizar los binarios de macOS y un paquete de winget para Windows.