GitHub Actions
El repositorio incluye una Action compuesta, así que un workflow no necesita cadena de herramientas de Go: descarga un binario de release y lo llama.
- uses: jmrplens/ghchronicle@v2 with: token: ${{ secrets.GHCHRONICLE_TOKEN }} mode: once config: .github/ghchronicle.yamlEntradas
Sección titulada «Entradas»| Entrada | Por omisión | Qué hace |
|---|---|---|
token | obligatoria | Un token personal. El GITHUB_TOKEN automático no basta |
config | "" | Ruta a un fichero de configuración. Omítela para usar valores por defecto a partir de user, cuyo estado dura una ejecución y no se puede guardar en caché |
user | el dueño del repositorio | La cuenta que recoger cuando no se da fichero de configuración |
mode | once | once, backfill, card o migrate |
backfill- | "" | Límite para backfill: una fecha, 90d, 2y o una duración de Go. Vacío es sin límite |
card | "" | Ruta del SVG que escribir. Vacío significa sin tarjeta |
card- | summary | Uno de los trece diseños registrados |
card- | auto | dark, light, auto, o both para una tarjeta clara y su gemela _dark |
card- | "" | Campos separados por comas. Vacío es el conjunto por defecto del diseño |
card- | once | once, loop u off; loop solo cambia terminal y ticker |
card- | "" | Ancho de la tarjeta en píxeles. Vacío dibuja el diseño con su propio ancho; cada uno dibuja entre dos extremos propios, que dice su sección. Solo activity-heatmap se gasta el sitio en datos, un año entero del calendario en su extremo lejano |
card- | "" | A qué velocidad se reproduce un diseño animado, como decimal de 0 a 1. Vacío significa 0.5, el ritmo con el que siempre se han dibujado las tarjetas; por debajo la tarjeta va más lenta y por encima más rápida, y todos los diseños animados se escalan juntos. 0 es la animación más lenta y no una tarjeta quieta, eso es card-motion: off |
include- | false | true cuenta los repositorios privados cuando no se da fichero de configuración. Ver el aviso más abajo |
version | latest | La release que instalar: latest para la más nueva, o una release con o sin su v, así que 2.6.5 y v2.6.5 son la misma. La etiqueta mayor v2 es lo que toma uses:, no una release, y se rechaza |
Los cuatro modos
Sección titulada «Los cuatro modos»Una pasada contra un fichero de configuración que tú das, que es como un workflow alimenta una base de datos.
name: Collecton: schedule: - cron: "*/30 * * * *" workflow_dispatch:
jobs: collect: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: jmrplens/ghchronicle@v2 with: token: ${{ secrets.GHCHRONICLE_TOKEN }} mode: once config: .github/ghchronicle.yaml env: INFLUX_TOKEN: ${{ secrets.INFLUX_TOKEN }}El fichero de configuración referencia las credenciales de la base de datos
como ${VAR}, así que entran como secretos y nunca al repositorio.
Una pasada y un SVG, y nada escrito en ninguna base de datos. Este es el único modo que no necesita almacén alguno configurado.
name: Profile cardon: schedule: - cron: "17 6 * * *" workflow_dispatch:
permissions: contents: write
jobs: card: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: jmrplens/ghchronicle@v2 with: token: ${{ secrets.GHCHRONICLE_TOKEN }} mode: card card: generated/github-stats.svg card-layout: github-stats card-theme: both - name: Commit if it changed run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add generated/ git diff --staged --quiet || git commit -m "Update the profile card" git pushEl SVG es idéntico byte a byte para la misma entrada, así que un día sin cambios no produce ningún commit.
Llega tan atrás como GitHub permita y espera al límite de peticiones en vez de detenerse. Ejecútalo una vez, a mano.
name: Backfillon: workflow_dispatch: inputs: since: description: "A date, 90d, 2y, or empty for no bound" default: "2y"
jobs: backfill: runs-on: ubuntu-latest timeout-minutes: 360 steps: - uses: actions/checkout@v7 - uses: jmrplens/ghchronicle@v2 with: token: ${{ secrets.GHCHRONICLE_TOKEN }} mode: backfill backfill-since: ${{ inputs.since }} config: .github/ghchronicle.yamlDale un timeout-minutes generoso: un relleno sin límite aparca en cada
reinicio de la ventana, y un job que muere a medias ha gastado la cuota y se
ha quedado con parte del beneficio.
Pone al día los almacenes en los que escribe la configuración después de
una actualización: ejecuta -migrate -yes, que aplica cada cambio que el
plan encuentra pendiente,
también los que necesitan la palabra de alguien, y vuelve a leer lo que
despejó. Ejecútalo a mano, una vez, después de leer lo que dice -migrate
sobre la misma configuración.
name: Migrateon: workflow_dispatch:
jobs: migrate: runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@v7 - uses: jmrplens/ghchronicle@v2 with: token: ${{ secrets.GHCHRONICLE_TOKEN }} mode: migrate config: .github/ghchronicle.yamlNo admite tarjeta. Un almacén que guarda filas de cuentas que esta
configuración no recoge, o cuyas filas no se pudieron comparar con ella, se
deja sin aplicar y el paso falla, porque solo -migrate-others lo despeja,
y esa es una decisión para tomar en una terminal, no en un workflow. Sin un
fichero de estado restaurado entre ejecuciones,
cada ejecución de la Action empieza con uno nuevo, así que un almacén al que
no se le puede preguntar, un fichero SQL, un Graphite o lo que haya detrás
de un Telegraf, no tiene historia aquí y nunca se da por necesitado de un
cambio; con uno restaurado, esos siguen su registro como en una máquina. Un
job que agotó su tiempo mientras volvía a leer la historia no deja nada que
el siguiente pueda retomar, porque actions/cache no guarda nada de un job
que no terminó bien: ejecuta después mode: backfill con la misma
configuración.
En once y backfill, un arranque comprueba los almacenes igual y avisa de lo
pendiente. Sobre un fichero de estado nuevo, que es cada ejecución sin uno
restaurado, no aplica nada por su cuenta ni siquiera con migrate: auto: el
fichero de estado se va con el runner, y con él el registro de que aún se debe
una relectura, así que una relectura que falló o un job cancelado a medias
dejaría un almacén despejado y nada que lo dijera. Con un fichero de estado
restaurado aplica lo que es seguro aplicar sin supervisión, como una máquina.
La Action convierte cada línea que dice que un cambio está pendiente, que se
aplicó uno al arrancar, que uno falló o que se debe una relectura en una
anotación de la ejecución en cuanto se escribe la línea, así que se ve en la
página de resumen del workflow y no solo en su registro, también en un job
cancelado a medias.
Una tarjeta en el README de tu perfil
Sección titulada «Una tarjeta en el README de tu perfil»GitHub muestra en lo alto de tu perfil el README del repositorio que se llama
como tu cuenta, <tú>/<tú>. La tarjeta vive en ese repositorio como un fichero,
el README apunta a ella una vez y un workflow programado sustituye el fichero.
El README no se reescribe nunca.
-
Crea un token personal (ver el token) y guárdalo en
<tú>/<tú>como el secretoGHCHRONICLE_TOKEN. ElGITHUB_TOKENautomático no sirve, ni siquiera para números públicos: no es un usuario, así que la Action no puede listar tus repositorios con él y la tarjeta sale vacía. -
Añade
.github/workflows/card.yml:name: Profile cardon:schedule:- cron: "17 6 * * *"workflow_dispatch:permissions:contents: write# One run at a time: two that overlap would race each other to push.concurrency:group: profile-cardcancel-in-progress: falsejobs:card:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v7- uses: jmrplens/ghchronicle@v2with:token: ${{ secrets.GHCHRONICLE_TOKEN }}mode: cardcard: generated/card.svgcard-layout: animated-counterscard-theme: bothcard-motion: once- name: Commit if it changedrun: |git config user.name "github-actions[bot]"git config user.email "41898282+github-actions[bot]@users.noreply.github.com"git add generated/git diff --staged --quiet || git commit -m "Update the profile card"git push -
Pega esta línea en
README.mddonde deba aparecer la tarjeta, una sola vez:<picture><source media="(prefers-color-scheme: dark)" srcset="generated/card_dark.svg"><img src="generated/card.svg" alt="Mis estadísticas de GitHub"></picture> -
Ejecuta el workflow a mano desde la pestaña Actions la primera vez, para que los ficheros existan antes de la primera ejecución programada.
Más de una tarjeta. Repite el paso uses: jmrplens/ghchronicle@v2 con otra
ruta en card y otro diseño, y pega un <picture> por tarjeta. Cada paso es una
pasada propia, y cada una vuelve a pedir todos los números: una pasada que
escribe una tarjeta recoge todas las familias diga lo que diga su cadencia, y
una en modo card no escribe nada en el fichero de estado. Así que varios pasos
de tarjeta pueden compartir un config, y por tanto un state_file, y cada
tarjeta es la cuenta entera. Eso es también lo que cuesta cada una: una tarjeta
es una pasada en frío de todas las familias, así que N tarjetas son N pasadas
al precio por familia.
Un README que no está en la raíz. Esto es para otros repositorios, porque
GitHub muestra el README de un perfil solo desde la raíz de <tú>/<tú>. Las
rutas del <picture> son relativas al README, así que un docs/README.md
apunta a ../generated/card.svg.
Dos cosas que un runner alojado no conserva
Sección titulada «Dos cosas que un runner alojado no conserva»El fichero de estado no sobrevive entre ejecuciones. Sin él cada ejecución
es una primera ejecución. Corren todas las familias, diga lo que diga su
cadencia, porque nada recuerda cuándo corrieron por última vez. Se vuelve a
recorrer entera la lista de estrellas, y se lee entero el historial diario de
estrellas de cada repositorio, una página por cada treinta semanas de su vida.
achievements recorre enteras las pull requests fusionadas de la cuenta para
su recuento de coautorías, que fueron 35 consultas y 23,7 MB en una cuenta con
2.315. Y sin fichero de caché
junto al estado, nada se pregunta con un ETag, así que ninguna respuesta es un
304 gratis. En una cuenta pequeña son un puñado de llamadas; en una cuenta con
muchas estrellas, repositorios antiguos o una historia larga, guárdalo en
caché.
Guardarlo en caché necesita un fichero config:. Sin él la Action escribe una
configuración propia y pone el estado en un directorio temporal nuevo dentro de
RUNNER_TEMP en cada ejecución, que ningún paso de caché puede nombrar. Con
él, apunta state_file al directorio personal:
state_file: ~/.ghchronicle/state.jsony restaura y guarda ese directorio con un paso anterior al de ghchronicle:
- uses: actions/cache@v6 with: path: ~/.ghchronicle key: ghchronicle-state-${{ github.run_id }} restore-keys: ghchronicle-state-Una ~ en state_file es el directorio personal a partir de la 2.6.1. Una
versión anterior la lee tal como está escrita, un directorio llamado ~ dentro
del checkout que el paso de caché nunca ve, así que con un version anterior a
la 2.6.1 escribe la ruta entera: /home/runner/.ghchronicle/state.json en un
runner Ubuntu alojado por GitHub.
El directorio guarda entonces también el fichero de caché, que un paso once
escribe y un paso backfill solo lee, así que una ejecución restaurada de él
pregunta además a GitHub con los validadores que guardó la anterior, y solo
paga lo que cambió. Una pasada en modo card lee el
estado restaurado, que es lo que le permite saltarse los dos recorridos, y nunca
lo vuelve a escribir, ni tampoco el fichero de caché que hay a su lado: entrega
sus puntos a la tarjeta y a ningún almacén, así que nada de lo que aprendió
puede decirle a la siguiente recogida que una familia ya está hecha. Quien llena
la entrada de actions/cache es un paso once, con los dos ficheros, o un paso
backfill, solo con el fichero de estado. Ningún paso deja ahí un registro de
escrituras: una ejecución que termina con su pasada no abre ninguno.
Sin la Action
Sección titulada «Sin la Action»Lo mismo a mano, si prefieres no depender de ella:
- uses: actions/setup-go@v7 with: go-version: stable- run: go install github.com/jmrplens/ghchronicle/v2/cmd/ghchronicle@latest- run: ghchronicle -config .github/ghchronicle.yaml -card profile.svg -card-only env: GITHUB_TOKEN: ${{ secrets.GHCHRONICLE_TOKEN }}