Modelos de fluxo de trabalho


Este documento explica como configurar fluxos de trabalho de Integração Contínua (CI) para um percurso de linguagem do Exercism usando o GitHub Actions (GHA). Fornece boas práticas e exemplos que podes usar para criar os teus próprios fluxos de trabalho de CI rápidos, fiáveis e robustos. Os fluxos de trabalho do GHA nesta pasta podem ser adaptados para funcionar com qualquer CI, porque a estrutura de base mantém-se igual.

Vai:

  • Descrever o fluxo de trabalho de CI ideal
  • Abordar considerações e recomendações
  • Dar-te alguns modelos para usares
  • Deixar-te um guia para migrares do Travis

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

AJUDA: isto parece dar muito trabalho 😓

O resto do documento foi pensado para explicar como funcionam os fluxos de trabalho. Se estás com pressa e só queres passar do Travis ou do Circle para o GHA sem otimizar os scripts de PR, vê o nosso guia de ~10 minutos sobre Migrar do Travis.

Ações de CI do percurso

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

  1. fazer lint com o configlet para verificar o config.json
  2. verificar se há stubs
  3. verificar a documentação (o v3 exige novos ficheiros; isto pode passar para o configlet)
  4. fazer lint dos exercícios com uma configuração "maintainers"
  5. testar os exercícios com os ficheiros de exemplo/exemplar (pode incluir um passo de compilação)

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

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

E talvez queiras 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 ficheiros markdown são válidos
  4. ...

Recomendações

Frequência de execução das verificações

Para cada ação, pensa na frequência com que deve correr.

  • O lint com o configlet é tão importante (porque um percurso pode quebrar se o config.json quebrar) que provavelmente deve correr sempre, mas só precisa de correr uma vez por commit.
  • A existência ou integridade dos ficheiros só precisa de correr uma vez por commit.
  • Se um percurso deve correr em várias versões de runtime ou do compilador, a compilação/teste dos exercícios deve correr para cada versão suportada
  • Os PRs provavelmente só precisam de correr ações nos ficheiros adicionados ou alterados, mas como um ficheiro pode influenciar um exercício, é mais seguro correr as ações para o exercício, se um dos seus ficheiros mudar.

Pode ser muito útil tornar também as ações que devem correr disponíveis localmente. Isto significa que os scripts que fazem o trabalho de facto também podem ser executados manualmente. Para isso, não coloques a ação inline dentro dos ficheiros de fluxo de trabalho, mas cria um script autónomo. Por exemplo, a verificação de stubs pode ser feita de forma improvisada dentro do ficheiro de fluxo de trabalho, mas a recomendação aqui é criar, em vez disso, um novo script executável scripts/ci-check.

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

Quando este comando precisa de ser atualizado, passa a ter de ser atualizado em todos os sítios: na documentação, nos ficheiros de fluxo de trabalho e nas mentes dos responsáveis. Extrair isto para um script resolve tudo isso. Ler um ficheiro de fluxo de trabalho também pode ser muito intimidante.

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

Os scripts scripts/pr e scripts/pr-check (vê os modelos) são executados com vários argumentos, um por cada ficheiro alterado ou adicionado neste PR. Por exemplo, se o two-fer tiver sido atualizado, uma chamada pode ter este aspeto:

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

Recomenda-se correr as ações contra o exercício alterado, e não contra o ficheiro alterado. Isto porque alterar um ficheiro provavelmente desencadeia mudanças em todo o exercício (pensa: configuração, pacotes).

Ainda não está pronto? / Complicado?

Antes de implementares esta otimização, podes ignorá-la sem problema! O guia de migração sugere adicioná-la numa fase posterior. Se os argumentos de entrada forem ignorados, todas as verificações correm em todos os exercícios. Isso é perfeitamente aceitável. Só demora mais tempo.

Verificações de integridade

Se o percurso tiver um único ficheiro de dependências de "nível superior" e/ou outros ficheiros de configuração, acrescenta um passo de integridade (que existe a par de um scripts/sync ou bin/sync, que copiaria todos os ficheiros de configuração para todos os exercícios), que garante que os ficheiros de nível superior/base são iguais aos copiados para os diretórios dos exercícios. Assim as dependências podem ser atualizadas, sincronizadas por todo o repositório, e podemos garantir que todos os exercícios têm a mesma configuração.

Uma forma comum de conseguir isto é usar um checksum. O Ubuntu (e várias outras distribuições Linux) vem com uma ferramenta chamada sha1sum, mas usar qualquer método para aplicar hash ou reduzir o ficheiro de configuração (md5, sha1, crc32) a um valor de checksum funcionaria:

$ sha1sum README.md
cd58091c5043bf21f00d39ff1740d8b2976deeff *README.md

Verificações de segurança

Se o percurso usar 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 a um commit específico. Consulta 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 as ferramentas tiverem lockfiles para a gestão de dependências, considera adicioná-los ao repositório e usar um "lockfile congelado" dentro dos ficheiros de fluxo de trabalho. Por exemplo: npm ci, yarn install --frozen-lockfile e bundle install --frozen. Isto garante que o lockfile está atualizado quando mudas as dependências e impede a entrada de pacotes maliciosos.

Modelos

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

  • configlet.yml: Este fluxo de trabalho vai buscar o binário mais recente do configlet e faz lint a este repositório. Corre em cada commit. Nos PRs, corre no commit real e numa árvore "após merge".
  • ci.yml: Este fluxo de trabalho só corre no ramo main, uma vez por cada commit.
    1. Corre um comando de 'pre-check' (verificar stubs, lint, docs, etc.) para todos os exercícios
    2. Corre um comando 'ci' (compilar e testar) para várias versões, para todos os exercícios
  • pr.ci.yml: Este fluxo de trabalho só corre em PRs, uma vez por cada commit.
    1. Corre um comando de 'pre-check' (verificar stubs, lint, docs, etc.) para os ficheiros alterados
    2. Corre um comando 'ci' (compilar e testar) 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 através de workflow_dispatch.

Cada ficheiro tem indicado no topo que "scripts" devem estar disponíveis. Se quiseres que sejam binários, substitui scripts/xxx por bin/xxx. Algumas ferramentas vão exigir que os binários estejam dentro de uma pasta bin.

  • scripts/ci: um script que deve compilar e testar todos os exercícios, usando as soluções de exemplo, contra os testes
  • scripts/ci-check: um script que deve fazer lint a todos os exercícios e, opcionalmente, verificar stubs, a integridade da configuração e mais
  • scripts/pr: igual ao scripts/ci, mas só deve correr nos exercícios obtidos a partir dos caminhos dados como entrada
  • scripts/pr-check: igual ao scripts/ci-check, mas só deve correr para os ficheiros ou exercícios obtidos a partir dos caminhos dados como entrada

Resolução de problemas

Se tiveres algum problema ou quiseres que alguém reveja os teus fluxos de trabalho, avisa a equipa @exercism/github-actions.

Alteraste um ficheiro de nível superior que devia desencadear uma execução de CI em todos os exercícios

No momento em que escrevo isto, o pr.ci.yml só permite testes por "extensão". O ideal seria atualizá-lo para ser acionado sempre que certos ficheiros mudam (por exemplo, o binário para correr os testes). No entanto, estas mudanças são muitas vezes pouco frequentes e feitas pelos responsáveis, por isso o facto de o ci.yml correr no main, sempre, para tudo, é provavelmente suficientemente seguro.

Criaste um ficheiro scripts/xxx no Windows e agora não funciona em {other OS}

Por predefinição, os ficheiros criados no Windows não têm metadados incorporados no índice do git sobre a sua executabilidade, porque o modelo de permissões no Windows é diferente. Por predefinição, o Git usa os metadados do índice do git para determinar se o ficheiro deve ser executável em sistemas baseados em POSIX, e por isso torna o ficheiro scripts/xxx NÃO executável.

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