Publicando um Add-on do Google Workspace com clasp e GitHub Actions

Equipe 8apps·

Um guia passo a passo para fazer deploy de add-ons do Apps Script direto de um git push — instale o clasp, configure o .clasp.json e deixe o GitHub Actions cuidar do resto.

Se você está construindo um Add-on do Google Workspace, o runtime mora num lugar meio estranho. O Apps Script é um servidor onde você não consegue dar SSH e uma UI para a qual você não consegue mandar arquivos via scp — toda alteração tem que passar pelo editor do Google ou pela API deles. A ponte entre o seu repositório e esse ambiente é o clasp (Command Line Apps Script), e quando você embrulha tudo isso em GitHub Actions, fazer deploy vira um simples git push.

Este post percorre a pipeline inteira de ponta a ponta: instalar o clasp, configurar o arquivo que liga seu repositório a um projeto específico do Apps Script e, no fim, um workflow do GitHub Actions que joga cada commit do main direto no Apps Script.


O Que é o clasp

O clasp é uma pequena CLI em Node criada pelo Google que conversa com a API do Apps Script. O modelo mental é simples:

  • Seu projeto do Apps Script vive numa URL como script.google.com/.../edit e é identificado por um scriptId.
  • clasp push faz upload dos arquivos .gs, .html e appsscript.json de um diretório local para esse projeto, substituindo a cópia no servidor.
  • clasp pull faz o inverso — útil quando alguém editou código pelo editor web do Apps Script e você quer trazer essas alterações de volta para o git.
  • clasp deploy corta uma deployment versionada e nomeada — é justamente essa que a loja de add-ons e seus usuários finais realmente executam. Sem ela, clasp push só atualiza a versão @HEAD, que ninguém além do desenvolvedor enxerga.

É isso. Sem build system, sem opiniões sobre o seu código — só um mecanismo de sincronização entre uma pasta no disco e um projeto de script na nuvem do Google.


Passo 1 — Instalar o clasp

O clasp é um pacote Node global. Garanta que você tem Node 20+ instalado e rode:

npm install -g @google/clasp
clasp --version

Antes de o clasp conseguir falar com a sua conta, você precisa habilitar a Apps Script API para o seu usuário Google. Vá em script.google.com/home/usersettings e ligue a Google Apps Script API. É um botão único por conta — fácil de esquecer, e o clasp aborta com um erro críptico se você pular essa etapa.

Agora faça login:

clasp login

Uma janela do navegador se abre e te leva pelo fluxo OAuth. Quando termina, o clasp grava suas credenciais em ~/.clasprc.json. Vamos voltar a esse arquivo quando configurarmos o CI.


Passo 2 — Pegar o scriptId

Todo projeto do Apps Script tem um scriptId único — é por ele que o clasp sabe para qual projeto fazer push. Existem duas formas de obter um.

Se o projeto ainda não existe, crie pela linha de comando:

mkdir my-addon && cd my-addon
clasp create --type standalone --title "My Add-on"

--type pode ser standalone, sheets, docs, slides, forms ou webapp. Escolha o que combina com o seu add-on. O clasp cria o projeto do lado do Google e gera um .clasp.json com o novo scriptId já preenchido.

Se o projeto já existe (você criou no editor do Apps Script ou alguém compartilhou com você), abra-o em script.google.com e olhe a URL:

https://script.google.com/d/1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp/edit
                              └────────────────────── scriptId ──────────────────────┘

O trecho longo de letras e números entre /d/ e /edit é o seu scriptId. Você também encontra ele dentro do editor do Apps Script em Configurações do projeto → IDs.


Passo 3 — Configurar o .clasp.json

O .clasp.json é o arquivo que prende seu diretório local a um projeto específico do Apps Script. Ele fica na raiz do repositório:

// .clasp.json
{
  "scriptId": "1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp",
  "rootDir": "./src"
}

Dois campos, ambos importantes:

  • scriptId — o projeto para onde o clasp deve fazer push. Cole o que você obteve no Passo 2.
  • rootDir — a pasta local que o clasp deve tratar como fonte do projeto. Tudo dentro dela é enviado, tudo fora é ignorado. Se você omite rootDir, o clasp usa o diretório atual, o que normalmente significa tentar enviar suas pastas node_modules e .git. Sempre defina explicitamente.

Alguns campos opcionais que você pode encontrar:

  • scriptExtensions e htmlExtensions permitem customizar quais extensões o clasp trata como código de servidor ou HTML.
  • filePushOrder força certos arquivos a serem enviados antes de outros — só relevante se você tiver dependências de ordem de carregamento entre arquivos .gs.

Para a maioria dos projetos, a versão de dois campos acima é suficiente.


Passo 4 — Organizar os Arquivos

O clasp não se importa como os arquivos chegaram em rootDir. Desde que a pasta contenha arquivos válidos do Apps Script, ele vai enviar. Um layout mínimo é assim:

my-addon/
  .clasp.json
  .claspignore          // opcional — arquivos a ignorar no push
  src/
    appsscript.json     // manifesto: scopes, runtime, configuração do add-on
    Code.gs             // suas funções do servidor
    Sidebar.html        // qualquer HTML servido via HtmlService

Três coisas para saber sobre os tipos de arquivo:

  • Arquivos .gs são código de servidor do Apps Script. O clasp converte de forma transparente para e a partir do formato nativo do editor.
  • Arquivos .html são templates servidos via HtmlService.createHtmlOutputFromFile().
  • appsscript.json é o manifesto do projeto. Declara escopos OAuth, a versão do runtime (V8), o fuso horário e — para add-ons — as entradas de menu e os triggers que o usuário vê. O clasp se recusa a fazer push sem ele.

Se você tem arquivos dentro de rootDir que não devem ser enviados (scripts de build, READMEs, qualquer coisa que não seja .gs/.html/appsscript.json), adicione um .claspignore ao lado do .clasp.json:

**/**
!appsscript.json
!**/*.gs
!**/*.html

Esse padrão diz: "ignore tudo, depois libere apenas os tipos de arquivo que o Apps Script realmente entende."

Com o layout pronto, você consegue fazer deploy local com dois comandos:

clasp push -f
clasp deploy --description "first version"

A flag -f pula a confirmação interativa de "manifesto alterado" — pode ficar ligada sempre, e mais tarde no CI ela vira obrigatória.


Passo 5 — Autenticar o clasp no CI

Os deploys locais funcionam porque o clasp login deixou credenciais em ~/.clasprc.json. Os runners do GitHub Actions não têm esse arquivo, e tampouco conseguem rodar um fluxo de navegador, então a gente entrega as credenciais direto via secret.

O arquivo se parece com isto:

{
  "token": {
    "access_token": "ya29....",
    "refresh_token": "1//0g....",
    "scope": "https://www.googleapis.com/auth/script.projects ...",
    "token_type": "Bearer",
    "expiry_date": 1736000000000
  },
  "oauth2ClientSettings": {
    "clientId": "xxxxxxxxxxxx.apps.googleusercontent.com",
    "clientSecret": "GOCSPX-xxxxxxxxxxxx",
    "redirectUri": "http://localhost"
  },
  "isLocalCreds": false
}

O refresh_token é a peça-chave — enquanto ninguém revogar a permissão, o clasp consegue gerar tokens de acesso novos por meses.

Para guardar no GitHub:

  1. Numa máquina, rode clasp login (pule se já fez no Passo 1).
  2. Rode cat ~/.clasprc.json e copie a saída inteira.
  3. No seu repo no GitHub: Settings → Secrets and variables → Actions → New repository secret.
  4. Name: CLASPRC_JSON. Value: o JSON completo que você acabou de copiar.

💡 Dica: Gere esse token a partir de uma conta Google dedicada que seja dona do projeto do Apps Script — não da sua conta pessoal. Se um desenvolvedor sair da equipe, você não precisa rotacionar nada.


Passo 6 — O Workflow do GitHub Actions

Agora a recompensa. Coloque isto em .github/workflows/deploy.yml:

name: Deploy Apps Script

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install clasp
        run: npm i -g @google/clasp

      - name: Restore clasp credentials
        run: echo '${{ secrets.CLASPRC_JSON }}' > ~/.clasprc.json

      - name: Push to Apps Script
        run: clasp push -f

      - name: Create a versioned deployment
        run: |
          DESC="ci-${GITHUB_SHA::7}-$(date -u +%Y%m%d%H%M)"
          clasp deploy --description "$DESC"

O que cada parte está fazendo:

  • on: push: branches: [main] — todo merge no main dispara um deploy. workflow_dispatch adiciona um botão "Run workflow" na aba Actions para reexecuções manuais.
  • environment: production — opt-in num GitHub Environment. Se você configurar reviewers obrigatórios nele, todo deploy espera a aprovação humana antes de prosseguir. Vale muito a pena para qualquer add-on com usuários reais.
  • Restore clasp credentials — escreve o secret de volta em ~/.clasprc.json para o clasp encontrar onde ele espera. Não use cat ou echo no secret em outro lugar; o GitHub só mascara automaticamente quando o secret é usado via ${{ secrets.* }}.
  • clasp push -f — envia tudo de rootDir para o projeto do Apps Script. O -f é obrigatório no CI; sem ele, o prompt de "manifesto alterado" trava o runner.
  • clasp deploy --description — corta uma nova deployment versionada. A descrição inclui o SHA curto e um timestamp para você rastrear qualquer deployment até o commit exato. Esse é o passo que a maioria esquece — sem ele, clasp push só atualiza o @HEAD, e os usuários instalados nunca veem a mudança.

Faça commit do workflow, dê push e veja o check verde. Daqui pra frente, fazer deploy é só git merge.


O Que Não Fazemos (e Por Quê)

Não comitamos o ~/.clasprc.json no repositório. Ele contém um refresh token que, na prática, é uma credencial de longa duração. Lugar dele é em GitHub Secrets, nunca no controle de versão.

Não compartilhamos uma única conta Google entre o time. O secret CLASPRC_JSON vem de uma conta dedicada que é dona do projeto do Apps Script. Contas pessoais mudam; a conta de deploy não.

Não rodamos testes nesse workflow. O runtime do Apps Script é diferente o suficiente do Node para tornar testes unitários significativos algo difícil. A gente roda testes de lógica num workflow separado, contra um port em Node do código compartilhado, e confia num smoke test manual depois de cada deploy.


A Recompensa

Antes desse setup, fazer deploy era: puxar o último, torcer pra o token do clasp não ter expirado, rodar clasp push, lembrar de rodar clasp deploy com uma descrição decente, torcer pra você não ter esquecido o -f. Cinco passos, cinco lugares para tropeçar.

Agora: merge no main, espera o check verde, abre o add-on. O Apps Script deixa de ser um caso especial — ele é só mais um destino de deploy atrás do mesmo workflow git que tudo o mais que você publica.

Se você mantém um Add-on do Workspace e ainda faz push do laptop, a migração é um trabalho de uma tarde. A parte mais difícil é encontrar o ~/.clasprc.json.


Tem um workflow personalizado em mente?
A gente constrói add-ons sob medida do Google Workspace adaptados aos seus processos de negócio. Escreva para support@8apps.co e vamos começar.