Tema
Como publicar updates OTA pelo GitHub Actions
Atualizado em outubro de 2026.
Resposta curta: crie um token de deploy só para o CI, salve como segredo PIPANOAR_TOKEN no repositório e rode npx hot-updater deploy num workflow do GitHub Actions a cada push na main. Cada release fica ligada a um commit, com a mensagem dele, e o token sai das máquinas das pessoas. Comece com rollout baixo (-r 10) e aumente pelo painel depois de olhar os crashes.
Este artigo assume que o app já está configurado com o Pipa no Ar. Se ainda não está, siga o guia rápido ou rode npx @pipanoar/init.
Por que publicar pelo CI
- Rastreabilidade. A release nasce de um commit da
main, com a mensagem do commit. Ninguém publica do próprio computador um código que não passou por revisão. - Menos segredos espalhados. O token de deploy vive nos segredos do repositório, não no
.envde cada pessoa. - Repetível. O mesmo comando, com a mesma versão do Node e das dependências, todo dia.
1. Crie um token só para o CI
- No painel, abra a organização e vá em Tokens de deploy.
- Crie um token com escopo Deploy. Se o repositório é de um app só, limite o token a esse app.
- Copie o valor (começa com
pn_). Ele aparece uma vez só. - No GitHub, em Settings → Secrets and variables → Actions, crie o segredo
PIPANOAR_TOKENcom esse valor.
A CLI lê o token da variável PIPANOAR_TOKEN, então não é preciso mudar o hot-updater.config.ts. Mais sobre credenciais em Tokens e API keys.
2. O workflow
Este exemplo publica no canal production a cada push na main, para 10% dos aparelhos:
yaml
# .github/workflows/ota.yml
name: Update OTA
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Publicar iOS e Android
env:
PIPANOAR_TOKEN: ${{ secrets.PIPANOAR_TOKEN }}
run: |
npx hot-updater deploy -p ios -r 10
npx hot-updater deploy -p android -r 10A mensagem da release vem do último commit. Para usar outra, passe -m "texto". Se o projeto usa yarn, pnpm ou bun, troque o cache e o npm ci pelo equivalente.
3. Variações úteis
Publicar no beta primeiro
Uma branch beta que publica no canal beta:
yaml
on:
push:
branches: [beta]
# ...
run: |
npx hot-updater deploy -p ios -c beta
npx hot-updater deploy -p android -c betaQuando estiver bom, promova a mesma release para production pelo painel ou com npx hot-updater bundle promote <id> -t production. A release promovida é exatamente o bundle testado, sem gerar outro.
Disparar à mão, escolhendo o rollout
Com workflow_dispatch, o deploy roda pelo botão Run workflow do GitHub, com a porcentagem como entrada:
yaml
on:
workflow_dispatch:
inputs:
rollout:
description: "Porcentagem de aparelhos (1 a 100)"
default: "10"
# ...
run: |
npx hot-updater deploy -p ios -r ${{ inputs.rollout }}
npx hot-updater deploy -p android -r ${{ inputs.rollout }}Uma plataforma por job
Se o build de uma plataforma demora, separe em dois jobs com matrix, cada um com o seu -p. Assim uma falha no Android não segura o iOS.
yaml
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [ios, android]
steps:
# checkout, setup-node e npm ci como acima
- run: npx hot-updater deploy -p ${{ matrix.platform }} -r 10
env:
PIPANOAR_TOKEN: ${{ secrets.PIPANOAR_TOKEN }}4. Depois do deploy
- Olhe o Insights. Com o plugin
insights()no app, o painel mostra adoção e taxa de crash por release. - Aumente o rollout aos poucos, pelo painel ou com a automação Liberar aos poucos, que sobe os degraus e desativa a release se a taxa de crash passar do limite. Ver Rollout automático.
- Avise o time. As notificações da organização mandam cada deploy para um canal do Slack ou do Discord, ou para um webhook seu.
Rollout gradual e automação estão nos planos pagos, a partir do Starter. No Free, a release vai para 100% dos aparelhos do canal, então vale publicar no beta antes.
Cuidados
- Código nativo não vai pelo ar. Se o commit muda o iOS ou o Android (um módulo nativo novo, uma permissão), ele precisa de uma build nova na loja. O OTA leva só o JavaScript e os assets.
- Um token por pipeline. Se um token vazar, revogue só ele no painel. Para scripts que só consultam releases, use um token de escopo Leitura.
- Não coloque o token no app. O app usa a API key, que só lê updates. O token de deploy publica releases.
- Assinatura funciona igual no CI. Com
signing: trueno config, a CLI pede as assinaturas com o mesmo token, sem chave privada no runner. Ver Como assinar bundles OTA.
Uma action oficial
A action oficial pipanoar/deploy-action faz os mesmos passos numa linha: valida os inputs, instala o Node e as dependências (detecta Bun, pnpm, Yarn ou npm pelo lockfile), roda o deploy e escreve um resumo no job.
yaml
- uses: actions/checkout@v4
- uses: pipanoar/deploy-action@v1
with:
token: ${{ secrets.PIPANOAR_TOKEN }}
channel: production
rollout: 10O workflow manual acima continua valendo para quem quer controlar cada passo.
Perguntas frequentes
Preciso de runner macOS para publicar no iOS? O deploy OTA gera só o bundle JavaScript, sem compilar o app nativo, e o exemplo do guia roda em ubuntu-latest para as duas plataformas. A build nativa para a App Store continua precisando de macOS.
O CI pode desativar uma release? Pode, com npx hot-updater bundle disable <id>, usando um token de escopo Deploy. Na maioria dos casos, desativar pelo painel ou pela automação é mais rápido.
O guia de referência está em Deploy pelo CI, e todos os comandos e opções, em Comandos da CLI.