Modelos de fluxo de trabalho


Este documento explica como configurar fluxos de trabalho de Integração Contínua (CI) para uma trilha de linguagem do Exercism usando o GitHub Actions (GHA). Ele traz boas práticas e exemplos que você pode usar para criar seus próprios fluxos de trabalho de CI rápidos, confiáveis e robustos. Os fluxos de trabalho do GHA nesta pasta podem ser adaptados para funcionar com qualquer CI, porque a estrutura básica continua a mesma.

Ele vai:

  • Esboçar o fluxo de trabalho de CI ideal
  • Discutir considerações e recomendações
  • Fornecer alguns modelos para você usar
  • Deixar um guia para migrar do Travis

Um exemplo de implementação desses arquivos de fluxo de trabalho pode ser encontrado em exercism/javascript.

SOCORRO: isso parece muito trabalho 😓

O restante do documento existe para explicar como os fluxos de trabalho funcionam. Se você está com pressa e só quer trocar o Travis ou o Circle pelo GHA sem otimizar os scripts de PR, dê uma olhada no nosso guia de ~10 minutos sobre Migrar do Travis.

Ações de CI da trilha

As ações recomendadas para verificar a integridade do conteúdo do seu repositório são as seguintes:

  1. lint do configlet para verificar o config.json
  2. verificar se há stubs
  3. verificar a documentação (v3 exige novos arquivos; isso pode passar para o configlet)
  4. rodar o lint dos exercícios usando uma configuração "maintainers"
  5. testar os exercícios usando os arquivos de exemplo/exemplar (pode incluir uma etapa de build)

Também pode haver ações específicas da trilha. Por exemplo:

  1. verificar a integridade das configurações dos exercícios
  2. verificar a formatação dos arquivos dos exercícios

E talvez você queira mais verificações de qualidade de vida, como:

  1. garantir que o CONTRIBUTING existe
  2. garantir que existe um lockfile razoável para as dependências
  3. garantir que os links dentro dos arquivos markdown são válidos
  4. ...

Recomendações

Com que frequência rodar as verificações

Para cada ação, pense em com que frequência ela deve rodar.

  • O lint do configlet é tão importante (uma trilha pode quebrar se o config.json quebrar) que provavelmente deve rodar sempre, mas só precisa rodar uma vez por commit.
  • A existência ou a integridade dos arquivos só precisa rodar uma vez por commit.
  • Se uma trilha deve rodar em várias versões de runtime ou de compilador, o build e o teste dos exercícios devem rodar em cada versão compatível.
  • Os PRs provavelmente só precisam rodar as ações nos arquivos adicionados ou alterados, mas como um arquivo pode influenciar um exercício, é mais seguro rodar as ações para o exercício quando um dos arquivos dele mudar.

Pode ser muito útil deixar as ações que devem rodar disponíveis também localmente. Assim, os scripts que fazem o trabalho de verdade também podem ser executados manualmente. Para conseguir isso, não coloque inline a ação dentro dos arquivos de fluxo de trabalho: crie um script independente. Por exemplo, a verificação de stubs pode ser feita inteiramente em bash dentro do arquivo de fluxo de trabalho, mas a recomendação aqui é criar um novo script executável, o scripts/ci-check.

"Mas o comando é bem curto, por exemplo eslint . --ext ts --ext tsx".

Quando esse comando precisar ser atualizado, ele vai ter que ser atualizado em todos os lugares: na documentação, nos arquivos de fluxo de trabalho e na cabeça dos mantenedores. Extrair isso para um script resolve tudo. Além disso, ler um arquivo de fluxo de trabalho pode ser muito assustador.

Verificações em PRs em que os exercícios mudam

Os scripts scripts/pr e scripts/pr-check (veja os modelos) são executados com vários argumentos, um para cada arquivo alterado ou adicionado neste PR. Por exemplo, se o two-fer foi atualizado, uma chamada pode ser assim:

scripts/pr exercises/two-fer/README.md exercises/two-fer/.meta/example.ext

É recomendado rodar as ações para o exercício alterado, e não para o arquivo alterado. Isso porque alterar um arquivo provavelmente provoca mudanças no exercício inteiro (pense em: configuração, pacotes).

Ainda não está pronto? / É complexo?

Antes de implementar essa otimização, você pode ignorá-la sem problema! O guia de migração sugere adicioná-la em uma etapa posterior. Se os argumentos de entrada forem ignorados, todas as verificações vão rodar em todos os exercícios. Isso não tem problema nenhum. Só vai demorar mais.

Verificações de integridade

Se a trilha tem um único arquivo de dependências "de nível superior" e/ou outros arquivos de configuração, adicione uma etapa de integridade (que fica junto de um scripts/sync ou bin/sync, que copiaria todos os arquivos de configuração para todos os exercícios) que garanta que os arquivos de nível superior/base sejam iguais aos copiados para os diretórios dos exercícios. Assim, dá para atualizar as dependências, sincronizá-las em todo o repositório e garantir que todos os exercícios tenham a mesma configuração.

Uma forma comum de fazer isso é usar uma soma de verificação. O Ubuntu (e várias outras distribuições Linux) vem com uma ferramenta chamada sha1sum, mas qualquer método de hash ou de redução do arquivo de configuração (md5, sha1, crc32) a um valor de soma de verificação funcionaria:

$ sha1sum README.md
cd58091c5043bf21f00d39ff1740d8b2976deeff *README.md

Verificações de segurança

Se a trilha usa fluxos de trabalho adicionais que precisam de acesso ao token do GitHub ou a outros segredos, a boa prática é fixar todas as ações usadas no fluxo de trabalho em um commit específico. Veja o guia de reforço de segurança do GitHub para mais detalhes.

Por exemplo:

- uses: julia-actions/setup-julia@v1
+ uses: julia-actions/setup-julia@d26d1111976eae5f00db04f0515ab744ec9cd79e # 1.3.1

Se o ferramental tem lockfiles para gerenciar dependências, considere adicioná-los ao repositório e usar um "lockfile congelado" dentro dos arquivos de fluxo de trabalho. Por exemplo: npm ci, yarn install --frozen-lockfile e bundle install --frozen. Isso garante que o lockfile esteja atualizado ao mudar dependências e impede a entrada de pacotes maliciosos.

Modelos

Neste diretório há, no mínimo, os seguintes modelos:

  • configlet.yml: este fluxo de trabalho baixa o binário mais recente do configlet e faz o lint deste repositório. Roda a cada commit. Para PRs, roda no commit em questão e na árvore "após o merge".
  • ci.yml: este fluxo de trabalho roda só na branch main, uma vez a cada commit.
    1. Executa um comando de 'pré-verificação' (verificação de stubs, lint, docs, etc.) para todos os exercícios
    2. Executa um comando de 'ci' (build e teste) para várias versões, para todos os exercícios
  • pr.ci.yml: este fluxo de trabalho roda só em PRs, uma vez a cada commit.
    1. Executa um comando de 'pré-verificação' (verificação de stubs, lint, docs, etc.) para os arquivos alterados
    2. Executa um comando de 'ci' (build e teste) para várias versões, para os exercícios alterados

Os fluxos de trabalho que não são de PR também podem ser acionados via workflow_dispatch.

Cada arquivo lista no topo quais "scripts" devem estar disponíveis. Se você quiser que sejam binários, troque scripts/xxx por bin/xxx. Algumas ferramentas vão exigir que os binários fiquem dentro de uma pasta bin.

  • scripts/ci: um script que deve fazer o build e o teste de todos os exercícios, usando as soluções de exemplo contra os testes
  • scripts/ci-check: um script que deve rodar o lint de todos os exercícios e, opcionalmente, verificar stubs, a integridade da configuração e mais
  • scripts/pr: o mesmo que scripts/ci, mas deve rodar apenas os exercícios resolvidos a partir dos caminhos passados como entrada
  • scripts/pr-check: o mesmo que scripts/ci-check, mas deve rodar apenas para os arquivos ou exercícios resolvidos a partir dos caminhos passados como entrada

Solução de problemas

Se você tiver algum problema ou quiser que alguém revise seus fluxos de trabalho, chame a equipe @exercism/github-actions.

Mudei um arquivo de nível superior que deveria disparar uma execução de CI em todos os exercícios

No momento em que escrevemos isto, o pr.ci.yml só permite testar por "extensão". O ideal seria atualizá-lo para disparar sempre que certos arquivos mudarem (por exemplo, o binário que roda os testes). No entanto, essas mudanças costumam ser pouco frequentes e feitas por mantenedores, então o fato de o ci.yml rodar na main, sempre, para tudo, provavelmente é seguro o suficiente.

Criei um arquivo scripts/xxx no Windows e agora ele não funciona em {outro SO}

Por padrão, os arquivos criados no Windows não têm, no git-index, metadados sobre sua executabilidade, porque o modelo de permissões do Windows é diferente. Por padrão, o Git usa os metadados do git-index para determinar se o arquivo deve ser executável em sistemas baseados em POSIX, e assim deixa o arquivo scripts/xxx NÃO executável.

git update-index --chmod=+x scripts/xxx
git commit -m "Make scripts/xxx executable"