# Reporter de Playwright en proveedores de CI

> Pipelines completos de @probara/playwright-reporter en GitHub Actions, GitLab CI, Jenkins, CircleCI, Azure Pipelines, Bitbucket Pipelines y Buildkite, con secretos a salvo de los forks.

El reporter se ejecuta dentro de `npx playwright test`: pasa el token a ese paso, y cada prueba se
envía mientras se ejecuta. No hace falta un paso de envío aparte. En todos los proveedores:

- Guarda un token de aplicación de la tarjeta **Playwright** en **Workspace › Integraciones**
  ([primeros pasos](https://docs.probara.net/es/developers/ci-integrations/playwright/#1-crea-un-token-de-aplicación)) como
  un secreto llamado `PROBARA_API_TOKEN`. El ID del Proyecto no es un secreto: ponlo en
  `playwright.config` (`projectId`) o en el pipeline (`PROBARA_PROJECT`).
- Usa Node.js 22.12 o posterior, como el resto de tu ejecución de Playwright.
- Las pruebas que fallan hacen fallar el paso; los problemas de envío, no. El código de salida de
  Playwright sigue siendo el de las pruebas.
- Fija la versión del reporter en `package.json` (o en el lockfile), para que una versión nueva
  nunca cambie un pipeline por sorpresa. La CLI no es una dependencia del reporter: los pasos de
  abajo que la usan fijan su versión en el propio comando (`npx --yes @probara/cli@0.2`). Con
  `@probara/cli` en tus `devDependencies`, `npx @probara/cli` después de `npm ci` ejecuta la versión
  del lockfile.
- Mantén el secreto lejos del código en el que no confías. Un build de un pull request desde un fork
  ejecuta el código de ese fork: cada sección explica cómo el proveedor mantiene el token fuera de
  su alcance. Sin el token, el reporter no envía nada (si el proyecto está definido, registra que
  falta el token), y las pruebas se ejecutan como siempre. La CLI termina con código 2 sin token,
  así que las recetas desactivan el envío (`PROBARA_ENABLED=false`) donde la ejecutaría el build de
  un fork: entonces termina con código 0.

Para una sola ejecución con varios shards, consulta
[shards](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/).

## GitHub Actions

### Añade el secreto

En el repositorio (o en la organización): **Settings → Secrets and variables → Actions → New
repository secret**, con el nombre `PROBARA_API_TOKEN`.

### El workflow

```yaml
name: Playwright

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps
      - name: Run Playwright tests
        run: npx playwright test
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
```

### Jobs con shards en GitHub Actions

Los shards escriben informes blob de Playwright, y un job los combina con el reporter: todo el
pipeline se convierte en una ejecución, con los intentos y los adjuntos incluidos. Registra `blob`
en CI y el reporter en el resto de entornos:

```ts
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: process.env.CI ? 'blob' : [['list'], ['@probara/playwright-reporter']],
});
```

```yaml
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4]
        shardTotal: [4]
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: blob-report-${{ matrix.shardIndex }}
          path: blob-report
          retention-days: 1

  report:
    needs: test
    if: ${{ !cancelled() }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npm ci
      - uses: actions/download-artifact@v4
        with:
          path: all-blob-reports
          pattern: blob-report-*
          merge-multiple: true
      - run: npx playwright merge-reports --reporter @probara/playwright-reporter ./all-blob-reports
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
```

### Jobs en paralelo: una ejecución, cerrada por el job final

En GitHub Actions los jobs de un mismo workflow envían a una misma ejecución: el origen de la
ejecución identifica la ejecución del workflow por su repositorio, su id y su intento, y el primer job
que envía crea la ejecución. Por defecto, cada job cierra su ejecución al terminar, así que los jobs
en paralelo definen `PROBARA_CLOSE_RUN: false`. Un job final cierra la ejecución con
`probara run close`, que no necesita aquí el ULID: `needs` hace que espere a todos los jobs de
pruebas, y `if: always()` lo ejecuta aunque fallen.

```yaml
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2]
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test --shard=${{ matrix.shard }}/2
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
          # A shard leaves the run open for the others.
          PROBARA_CLOSE_RUN: false

  probara:
    needs: test
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npx --yes @probara/cli@0.6 run close
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
```

- **Un job tras el cierre** recibe `409 ci_run_closed`: el reporter registra el motivo, no envía nada
  más, y las pruebas conservan su código de salida
  ([solución de problemas](https://docs.probara.net/es/developers/ci-integrations/playwright/troubleshooting/#un-job-envía-después-de-cerrarse-su-ejecución)).
  Mantén cada job que envía en `needs`.
- **Una nueva ejecución del workflow** (re-run) es otro intento: envía a una ejecución propia.
- **Un solo job** no necesita nada de esto: su ejecución se cierra al terminar, como en cualquier otro caso.

### Qué rellena GitHub Actions

| Campo                  | Desde                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------ |
| Nombre de la ejecución | `GITHUB_WORKFLOW #GITHUB_RUN_NUMBER`, por ejemplo `Playwright #42`                               |
| Rama                   | `GITHUB_HEAD_REF` (la rama del pull request), si no `GITHUB_REF_NAME`; ninguna para una etiqueta |
| Commit                 | `GITHUB_SHA`                                                                                     |
| URL del build          | `GITHUB_SERVER_URL/GITHUB_REPOSITORY/actions/runs/GITHUB_RUN_ID`                                 |
| Repositorio            | `GITHUB_REPOSITORY`                                                                              |
| Autor del commit       | `GITHUB_ACTOR`                                                                                   |
| Pull request           | `<n>` de `GITHUB_REF` `refs/pull/<n>/merge`                                                      |
| Workflow               | `GITHUB_WORKFLOW`                                                                                |
| Ejecución de CI        | `GITHUB_RUN_ID`, intento `GITHUB_RUN_ATTEMPT`                                                    |
| Job de CI              | `GITHUB_JOB`                                                                                     |

En los eventos `pull_request`, `GITHUB_SHA` es el commit de merge que crea GitHub, no el último
commit de la rama. Para registrar este último, añade
`PROBARA_COMMIT: ${{ github.event.pull_request.head.sha }}` al `env` del paso. En GitHub Actions el commit debe ser un SHA hexadecimal de 7 a 40 caracteres: otro
valor se descarta con una advertencia.

### Forks en GitHub Actions

Los workflows lanzados por un pull request desde un fork reciben los secretos vacíos, así que los
builds de forks ejecutan sus pruebas y no envían nada, sin ningún ajuste extra. No uses
`pull_request_target` para llevar el secreto a un build de un fork: ejecuta el código del fork con
tus secretos.

## GitLab CI

### Añade la variable

**Settings → CI/CD → Variables → Add variable**: clave `PROBARA_API_TOKEN`, el token como valor,
con **Mask variable** activado. **Protect variable** la limita a las ramas y etiquetas protegidas:
actívalo solo si envías resultados únicamente desde ellas.

### El pipeline

Un `.gitlab-ci.yml` con la imagen de Playwright:

```yaml
stages:
  - test

playwright:
  stage: test
  image: mcr.microsoft.com/playwright:v1.56.1-noble
  variables:
    PROBARA_PROJECT: SHOP
  script:
    - npm ci
    - npx playwright test
  artifacts:
    when: always
    paths:
      - test-results/
```

- Haz coincidir la versión de Playwright de la imagen con la de tu `package.json`.
- Un job sin la variable (el pipeline de un fork, una rama no protegida con una variable protegida)
  ejecuta sus pruebas y no envía nada.

### Jobs con shards en GitLab CI

Los shards de `parallel:` escriben informes blob, y un job los combina con el reporter en una sola
ejecución. Registra `blob` en CI y el reporter en el resto de entornos, como en
[shards](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-1-combinar-los-informes-blob):

```yaml
stages:
  - test
  - report

playwright:
  stage: test
  image: mcr.microsoft.com/playwright:v1.56.1-noble
  parallel: 4
  script:
    - npm ci
    - npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
  artifacts:
    when: always
    paths:
      - blob-report/

report-to-probara:
  stage: report
  image: mcr.microsoft.com/playwright:v1.56.1-noble
  needs:
    - job: playwright
      artifacts: true
  variables:
    PROBARA_PROJECT: SHOP
  rules:
    # After failed shards too, and only where the token is set.
    - if: $PROBARA_API_TOKEN
      when: always
  script:
    - npm ci
    - npx playwright merge-reports --reporter @probara/playwright-reporter ./blob-report
```

Un `needs:` sobre un job `parallel:` descarga los artefactos de todas las instancias en la misma
carpeta; el informe blob de cada shard tiene su propio nombre de archivo (`report-1.zip`...), así
que quedan uno junto a otro.

### Qué rellena GitLab CI

| Campo                  | Desde                                                                                                                                 |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Nombre de la ejecución | `CI_PROJECT_NAME #CI_PIPELINE_IID`, por ejemplo `shop #42`                                                                            |
| Rama                   | `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` en un pipeline de merge request, si no `CI_COMMIT_REF_NAME`; ninguna en un pipeline de etiqueta |
| Commit                 | `CI_COMMIT_SHA`                                                                                                                       |
| URL del build          | `CI_PIPELINE_URL`                                                                                                                     |

### Forks en GitLab CI

Un merge request desde un fork ejecuta su pipeline en el proyecto del fork, que no tiene tus
variables de CI/CD: allí el reporter queda desactivado. Si los maintainers ejecutan pipelines de
forks en el proyecto principal, esos pipelines sí reciben la variable, así que revisa el cambio
antes de ejecutarlo.

## Jenkins

### Añade la credencial

**Manage Jenkins → Credentials → (un dominio) → Add Credentials**: tipo **Secret text**, ID
`probara-api-token`, y el token como secreto.

### El pipeline

Un `Jenkinsfile` declarativo con Node.js 22 en el agente vincula la credencial a la etapa de
pruebas con `withCredentials`:

```groovy
pipeline {
  agent any
  environment {
    PROBARA_PROJECT = 'SHOP'
  }
  stages {
    stage('Test') {
      steps {
        sh 'npm ci'
        sh 'npx playwright install --with-deps'
        withCredentials([string(credentialsId: 'probara-api-token', variable: 'PROBARA_API_TOKEN')]) {
          sh 'npx playwright test'
        }
      }
    }
  }
}
```

Jenkins oculta el secreto vinculado en el log del build. Para etapas en paralelo que comparten una
ejecución, créala en una primera etapa y pasa `PROBARA_RUN_ULID` a cada una
([ejecución compartida](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-2-compartir-una-ejecución)).

Con `JENKINS_URL` definida, la ejecución se llama `JOB_NAME #BUILD_NUMBER`, y su rama, su commit y
la URL del build salen de `BRANCH_NAME` (o `GIT_BRANCH`), `GIT_COMMIT` y `BUILD_URL`.

### Forks en Jenkins

Jenkins no oculta por sí mismo las credenciales a los builds de pull requests: un job multibranch
que construye forks puede entregar el token a su código.

1. Configura **Discover pull requests from forks → Trust** para que un pull request de cualquier
   otra persona se construya con el `Jenkinsfile` de su rama de destino: en el branch source de
   GitHub, **From users with Admin or Write permission** (o **Nobody**); en el de Bitbucket,
   **Nobody**, o **Forks in the same account** desde la versión 871 del plugin (la corrección de
   CVE-2024-28152). **Everyone** construye un fork con su propio `Jenkinsfile`, que puede vincular
   la credencial por su cuenta, y deja inútil la protección de abajo.
2. En el `Jenkinsfile` de la rama de destino, vincula la credencial solo cuando `env.CHANGE_FORK` no
   está definida (Jenkins la define para un pull request desde un fork), y desactiva el envío en un
   build de un fork:

```groovy
pipeline {
  agent any
  environment {
    PROBARA_PROJECT = 'SHOP'
  }
  stages {
    stage('Test') {
      steps {
        sh 'npm ci'
        sh 'npx playwright install --with-deps'
        script {
          if (env.CHANGE_FORK) {
            withEnv(['PROBARA_ENABLED=false']) {
              sh 'npx playwright test'
            }
          } else {
            withCredentials([string(credentialsId: 'probara-api-token', variable: 'PROBARA_API_TOKEN')]) {
              sh 'npx playwright test'
            }
          }
        }
      }
    }
  }
}
```

Para etapas en paralelo que comparten una ejecución, envuelve cada `withCredentials` del mismo modo:
con el envío desactivado, `run create` no escribe ningún ULID y `run close` termina con código 0 sin
token.

## CircleCI

### Añade el token

**Organization Settings → Contexts → Create Context** (por ejemplo `probara-reporting`), y añade la
variable de entorno `PROBARA_API_TOKEN`. Una variable de entorno del proyecto (**Project Settings →
Environment Variables**) también sirve; en ese caso quita `context:` de abajo.

### El pipeline

Un `.circleci/config.yml` con la imagen de Playwright, dividido en shards con `parallelism` en una
sola ejecución creada de antemano
([ejecución compartida](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-2-compartir-una-ejecución));
sin `parallelism`, deja solo los pasos de prueba:

```yaml
version: 2.1

jobs:
  create-run:
    docker:
      - image: mcr.microsoft.com/playwright:v1.56.1-noble
    environment:
      PROBARA_PROJECT: SHOP
    steps:
      - run: |
          # Without the token (a fork's build), turn reporting off: run create prints nothing.
          [ -n "$PROBARA_API_TOKEN" ] || export PROBARA_ENABLED=false
          PROBARA_RUN_ULID=$(npx --yes @probara/cli@0.2 run create)
          echo "PROBARA_RUN_ULID=$PROBARA_RUN_ULID" > probara.env
      - persist_to_workspace:
          root: .
          paths: [probara.env]
  test:
    docker:
      - image: mcr.microsoft.com/playwright:v1.56.1-noble
    parallelism: 4
    environment:
      PROBARA_PROJECT: SHOP
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run: npm ci
      - run: |
          export $(cat probara.env)
          npx playwright test --shard=$((CIRCLE_NODE_INDEX + 1))/$CIRCLE_NODE_TOTAL
  close-run:
    docker:
      - image: mcr.microsoft.com/playwright:v1.56.1-noble
    environment:
      PROBARA_PROJECT: SHOP
    steps:
      - attach_workspace:
          at: .
      - run:
          when: always
          command: |
            export $(cat probara.env)
            [ -n "$PROBARA_API_TOKEN" ] || export PROBARA_ENABLED=false
            npx --yes @probara/cli@0.2 run close

workflows:
  playwright:
    jobs:
      - create-run:
          context: probara-reporting
      - test:
          context: probara-reporting
          requires: [create-run]
      - close-run:
          context: probara-reporting
          requires:
            - test: [success, failed]
```

- `CIRCLE_NODE_INDEX` empieza en 0; los shards de Playwright, en 1.
- Con `CIRCLECI=true`, la ejecución se llama `CIRCLE_PROJECT_REPONAME #CIRCLE_BUILD_NUM`, con la
  rama `CIRCLE_BRANCH`, el commit `CIRCLE_SHA1` y la URL del build `CIRCLE_BUILD_URL`.

### Forks en CircleCI

CircleCI no pasa los contextos ni las variables del proyecto a los builds de pull requests desde
forks salvo que **Pass secrets to builds from forked pull requests** esté activado: déjalo
desactivado. Los jobs de un fork que usan un contexto no llegan a ejecutarse (CircleCI muestra un
error de autorización). Con variables del proyecto se ejecutan sin el token: el reporter no envía
nada, y la línea `PROBARA_ENABLED=false` de `create-run` y `close-run` hace que `run create` no
imprima nada y que ambos terminen con código 0.

## Azure Pipelines

### Añade la variable

**Pipelines → tu pipeline → Edit → Variables → New variable**: nombre `PROBARA_API_TOKEN`, el token
como valor, con **Keep this value secret** activado. Un grupo de variables de la biblioteca también
sirve. Las variables secretas nunca llegan solas a los scripts: pásalas al `env` de cada paso, como
abajo.

### El pipeline

Un `azure-pipelines.yml`, dividido en shards con `parallel` en una sola ejecución creada por un
primer job
([ejecución compartida](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-2-compartir-una-ejecución));
sin shards, deja solo `variables` y el job de pruebas, sin `strategy` ni `PROBARA_RUN_ULID`:

```yaml
variables:
  # Off in a fork's build, which gets no secrets (see forks below).
  PROBARA_ENABLED: $[ ne(variables['System.PullRequest.IsFork'], 'True') ]

jobs:
  - job: create_run
    pool:
      vmImage: ubuntu-latest
    steps:
      - task: NodeTool@0
        inputs:
          versionSpec: '22.x'
      - script: |
          set -e
          ulid=$(npx --yes @probara/cli@0.2 run create)
          echo "##vso[task.setvariable variable=ulid;isOutput=true]$ulid"
        name: probara
        env:
          PROBARA_API_TOKEN: $(PROBARA_API_TOKEN)
          PROBARA_PROJECT: SHOP

  - job: test
    dependsOn: create_run
    strategy:
      parallel: 4
    variables:
      PROBARA_RUN_ULID: $[ dependencies.create_run.outputs['probara.ulid'] ]
    pool:
      vmImage: ubuntu-latest
    steps:
      - task: NodeTool@0
        inputs:
          versionSpec: '22.x'
      - script: npm ci
      - script: npx playwright install --with-deps
      - script: npx playwright test --shard=$(System.JobPositionInPhase)/$(System.TotalJobsInPhase)
        env:
          PROBARA_API_TOKEN: $(PROBARA_API_TOKEN)
          PROBARA_PROJECT: SHOP
          PROBARA_RUN_ULID: $(PROBARA_RUN_ULID)

  - job: close_run
    dependsOn: [create_run, test]
    condition: always()
    variables:
      PROBARA_RUN_ULID: $[ dependencies.create_run.outputs['probara.ulid'] ]
    pool:
      vmImage: ubuntu-latest
    steps:
      - task: NodeTool@0
        inputs:
          versionSpec: '22.x'
      - script: npx --yes @probara/cli@0.2 run close
        env:
          PROBARA_API_TOKEN: $(PROBARA_API_TOKEN)
          PROBARA_PROJECT: SHOP
          PROBARA_RUN_ULID: $(PROBARA_RUN_ULID)
```

- `set -e` hace que un `run create` fallido haga fallar el primer job: Azure solo comprueba el
  último comando de un script, y de lo contrario cada shard crearía su propia ejecución.
- Con `TF_BUILD=True`, la ejecución se llama `BUILD_DEFINITIONNAME #BUILD_BUILDNUMBER`, y su rama,
  su commit y la URL del build salen de las variables del pipeline.

### Forks en Azure Pipelines

Los builds de pull requests desde forks no reciben variables secretas salvo que **Make secrets
available to builds of forks** esté activado: déjalo desactivado. Azure deja tal cual una macro que
no puede resolver, así que en el build de un fork `$(PROBARA_API_TOKEN)` llega al paso como ese
texto literal, un token que Probara rechaza con 401: `run create` haría fallar el primer job, y el
reporter registraría el 401 en cada ejecución (el código de salida sigue siendo el de las pruebas).
La variable `PROBARA_ENABLED` del pipeline vale `False` cuando `System.PullRequest.IsFork` es
`True`, así que el build de un fork ejecuta sus pruebas con el envío desactivado, y `run create` y
`run close` terminan con código 0.

## Bitbucket Pipelines

### Añade la variable

**Repository settings → Pipelines → Repository variables**: nombre `PROBARA_API_TOKEN`, el token
como valor, con **Secured** activado. Bitbucket pasa las variables del repositorio a cada paso, así
que el reporter la encuentra en `npx playwright test`.

### El pipeline

Un `bitbucket-pipelines.yml` con la imagen de Playwright, con dos shards en paralelo que combinan sus
informes blob en una sola ejecución
([combinar los informes blob](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-1-combinar-los-informes-blob));
sin shards, deja un solo paso que ejecute `npx playwright test`:

```yaml
image: mcr.microsoft.com/playwright:v1.56.1-noble

pipelines:
  default:
    - parallel:
        - step:
            name: Shard 1
            script:
              - npm ci
              - npx playwright test --shard=1/2 || touch shard-1.failed
            artifacts:
              - blob-report/**
              - shard-*.failed
        - step:
            name: Shard 2
            script:
              - npm ci
              - npx playwright test --shard=2/2 || touch shard-2.failed
            artifacts:
              - blob-report/**
              - shard-*.failed
    - step:
        name: Report to Probara
        script:
          - npm ci
          - export PROBARA_PROJECT=SHOP
          - npx playwright merge-reports --reporter @probara/playwright-reporter ./blob-report
          - if ls shard-*.failed >/dev/null 2>&1; then echo "Tests failed in a shard" >&2; exit 1; fi
```

Bitbucket no ejecuta ningún paso después de uno fallido, así que un shard que hiciera fallar su paso
impediría que el paso de envío mandara nada. En su lugar, cada shard deja constancia de las pruebas
fallidas en un artefacto `shard-<n>.failed`, y el paso de envío manda todos los resultados y luego
hace fallar el pipeline si algún shard dejó uno: los shards aparecen como correctos, y el fallo lo
muestra el paso de envío.

Con `BITBUCKET_BUILD_NUMBER` definida, la ejecución se llama
`BITBUCKET_REPO_SLUG #BITBUCKET_BUILD_NUMBER`, con la rama `BITBUCKET_BRANCH`, el commit
`BITBUCKET_COMMIT` y un enlace al pipeline.

### Forks en Bitbucket Pipelines

Los pull requests desde forks no reciben variables seguras: el reporter no envía nada allí.

## Buildkite

### Añade el token

Expón `PROBARA_API_TOKEN` a los pasos desde un almacén de secretos: un hook `environment` del agente
que lo lea de tu gestor de secretos, o los
[secretos de Buildkite](https://buildkite.com/docs/pipelines/security/secrets/buildkite-secrets).

### El pipeline

Un `pipeline.yml` cuyos jobs en paralelo envían a una sola ejecución creada por un primer paso
([ejecución compartida](https://docs.probara.net/es/developers/ci-integrations/playwright/sharding/#patrón-2-compartir-una-ejecución)):

```yaml
env:
  PROBARA_PROJECT: SHOP

steps:
  - label: Create the Probara run
    key: create-run
    command: |
      PROBARA_RUN_ULID="$(npx --yes @probara/cli@0.2 run create)"
      if [ -n "$$PROBARA_RUN_ULID" ]; then buildkite-agent meta-data set probara-run "$$PROBARA_RUN_ULID"; fi

  - label: Playwright
    depends_on: create-run
    parallelism: 4
    command: |
      npm ci
      export PROBARA_RUN_ULID="$(buildkite-agent meta-data get probara-run --default '')"
      npx playwright test --shard=$((BUILDKITE_PARALLEL_JOB + 1))/$$BUILDKITE_PARALLEL_JOB_COUNT

  - wait: ~
    continue_on_failure: true

  - label: Close the Probara run
    command: PROBARA_RUN_ULID="$(buildkite-agent meta-data get probara-run --default '')" npx --yes @probara/cli@0.2 run close
```

- `buildkite-agent pipeline upload` sustituye `$NAME` y `${NAME}` al subir el pipeline, y una
  variable que todavía no conoce, como `BUILDKITE_PARALLEL_JOB_COUNT`, que solo reciben los jobs en
  paralelo, queda vacía. Un `$$` se deja como un solo `$` para el shell del job, mientras que
  `$(...)` y `$((...))` se dejan tal cual.
- La ejecución se crea en una línea propia, así que un `run create` fallido hace fallar el primer
  paso en lugar de guardar un ULID vacío. Con el envío desactivado (un build de un fork en un agente que define `PROBARA_ENABLED=false`, como se explica abajo),
  `run create` no imprime ningún ULID y termina con código 0: no se guarda nada,
  `meta-data get --default ''` da a los demás pasos un ULID vacío en lugar de un error, y se
  ejecutan también con el envío desactivado.
- `BUILDKITE_PARALLEL_JOB` empieza en 0; los shards de Playwright, en 1.
- Con `BUILDKITE=true`, la ejecución se llama `BUILDKITE_PIPELINE_SLUG #BUILDKITE_BUILD_NUMBER`, con
  la rama `BUILDKITE_BRANCH`, el commit `BUILDKITE_COMMIT` y la URL del build
  `BUILDKITE_BUILD_URL`.

### Forks en Buildkite

Buildkite construye pull requests desde forks solo si el pipeline lo permite (desactivado por
defecto). Esos builds se ejecutan en tus agentes, y `pipeline upload` lee el `pipeline.yml` del
propio fork, que también elige la cola de los agentes. El código del fork se ejecuta en el shell del
job con el usuario del agente, así que en un agente que puede leer el token de tu almacén de
secretos, el código del fork también puede leerlo: ningún hook ni paso lo impide.

Mantén desactivados los builds de forks, o mantenlos lejos de esos agentes: su hook `environment`
rechaza un build de un fork (`BUILDKITE_PULL_REQUEST_REPO` lo nombra), y los forks solo se
construyen en una cola o un clúster aparte cuyos agentes no pueden leer el almacén de secretos:

```bash
# The environment hook of the agents that can read the token: no build of a fork runs there.
if [ -n "$BUILDKITE_PULL_REQUEST_REPO" ]; then
  case "${BUILDKITE_PULL_REQUEST_REPO#*://}" in
    github.com/acme/shop.git) ;;
    *)
      echo "Refusing a build of a fork: $BUILDKITE_PULL_REQUEST_REPO" >&2
      exit 1
      ;;
  esac
fi
export PROBARA_API_TOKEN="$(your-secrets-manager get probara-api-token)"
```

`BUILDKITE_PULL_REQUEST_REPO` está vacía fuera de los pull requests, y es una URL `https://` desde
2022 (antes, `git://`), así que el hook la compara sin el esquema: pon tu repositorio en lugar de
`github.com/acme/shop.git`. Si no coincide, tus propios pull requests también fallan en estos
agentes, algo que el primero pondrá en evidencia. En los agentes que construyen forks, define
`PROBARA_ENABLED=false` en su hook `environment`: las pruebas del fork se ejecutan,
`npx playwright test` no envía nada, y `run create` y `run close` terminan con código 0 sin token.

Siguiente: [solución de problemas](https://docs.probara.net/es/developers/ci-integrations/playwright/troubleshooting/), o
conserva lo que un informe fallido no pudo enviar con un
[archivo de resultados](https://docs.probara.net/es/developers/ci-integrations/playwright/results-and-retries/#en-ci).
