Configurar a Integração Contínua (CI) para o teu track é muito importante, porque ajuda a detetar erros.
Os repositórios do Exercism (incluindo os repositórios de tracks) usam o GitHub Actions para executar o CI. O GitHub Actions baseia-se em fluxos de trabalho, que definem scripts a executar automaticamente sempre que ocorre um evento específico (por exemplo, quando se faz push de um commit). Para mais informações sobre os fluxos de trabalho do GitHub Actions, consulta a documentação dos fluxos de trabalho.
Os tracks vêm com vários fluxos de trabalho pré-instalados, a maioria dos quais não deves modificar (são os chamados fluxos de trabalho partilhados). No entanto, há um fluxo de trabalho que deves alterar: o fluxo de trabalho test.yml.
O objetivo do fluxo de trabalho test.yml é verificar se os exercícios do track estão em condições. O fluxo de trabalho está configurado para ser executado automaticamente (na terminologia do GitHub Actions: é despoletado) quando se faz push para o ramo main ou para o ramo de um pull request.
O próprio fluxo de trabalho não deve fazer muito, exceto:
Como já foi referido, os exercícios são verificados através de um script, o script bin/verify-exercises (bash). Este script está quase pronto e faz o seguinte:
unskip_tests, na qual podes deixar de ignorar testes nos teus ficheiros de teste (opcional)run_tests, na qual deves executar os testes (obrigatório)As funções run_tests e unskip_tests são as únicas coisas que precisas de implementar.
Se o teu track suporta ignorar testes, temos de garantir que nenhum teste é ignorado ao verificar a solução de exemplo/exemplar de um exercício. Em geral, há duas formas de os tracks suportarem deixar de ignorar testes:
test.skip para test.SKIP_TESTS=false.Se ignorar testes for feito com base nos ficheiros (a primeira opção acima), edita a função unskip_tests para modificar os ficheiros de teste (o código existente já trata de percorrer os ficheiros de teste).
A função unskip_test é executada numa cópia do diretório de um exercício, por isso não hesites em modificar os ficheiros como entenderes.
O bin/verify-exercises file do track Arturo usa o sed para deixar de ignorar os testes dentro dos ficheiros de teste:
unskip_tests() {
jq -r '.files.test[]' .meta/config.json | while read -r test_file; do
sed -i 's/test.skip/test/g' "${test_file}"
done
}
Se deixar de ignorar testes exigir a definição de uma variável de ambiente, certifica-te de que ela é definida na função run_tests.
A função run_tests é responsável por executar os testes de um exercício. Quando a função é chamada, os ficheiros de exemplo/exemplar já foram copiados para os ficheiros de solução (stub), por isso só precisas de chamar o comando certo para executar os testes.
A função tem de devolver zero como código de saída se todos os testes passarem; caso contrário, tem de devolver um código de saída diferente de zero.
A função run_tests é executada numa cópia do diretório de um exercício, por isso não hesites em modificar os ficheiros como entenderes.
A opção predefinida do script de verificação dos exercícios é usar as ferramentas da linguagem (SDK/binário/etc.), que é o que a maioria dos tracks usa. Cada track tem a sua própria forma de executar os testes, mas normalmente é apenas um único comando.
O bin/verify-exercises file do track Arturo modifica a função run_tests para simplesmente chamar o comando arturo no ficheiro de teste:
run_tests() {
arturo tester.art
}
A segunda opção é verificar os exercícios executando o test runner do track. Isto depende, naturalmente, de o track ter um test runner funcional.
Se o teu track ainda não tem um test runner, podes:
É preciso fazer as seguintes alterações ao script bin/verify-exercises predefinido:
docker está disponíveldocker run para executar a imagem Docker do test runner em cada exercíciojq para verificar se o ficheiro results.json devolvido pelo contentor Docker indica que todos os testes passaramunskip_test e a chamada a essa funçãoA principal vantagem desta abordagem é que imita melhor a forma como os testes são executados em produção (no site). Com esta abordagem, é menos provável que algo falhe em produção depois de ter passado no CI. A desvantagem desta abordagem é que costuma ser mais lenta, por ser preciso descarregar a imagem Docker e devido à sobrecarga do Docker.
O bin/verify-exercises file do track Unison acrescenta a verificação de que o comando docker também está instalado:
required_tool docker
Em seguida, descarrega a imagem do test runner do track:
docker pull exercism/unison-test-runner
Depois, modifica a função run_tests para usar docker run e executar o test runner no exercício atual (que está no diretório de trabalho), seguido de um comando jq para verificar se o estado é o correto:
run_tests() {
local slug
slug="${1}"
docker run \
--rm \
--network none \
--mount type=bind,src="${PWD}",dst=/solution \
--mount type=bind,src="${PWD}",dst=/output \
--tmpfs /tmp:rw \
exercism/unison-test-runner "${slug}" "/solution" "/output"
jq -e '.status == "pass"' "${PWD}/results.json" >/dev/null 2>&1
}
Por fim, temos de alterar a forma como o comando run_tests é chamado, pois agora exige o slug:
run_tests "${slug}"
Agora que o script verify-exercises está terminado, é altura de finalizar o fluxo de trabalho test.yml. A forma de o fazer depende da opção escolhida para a implementação do script verify-exercises.
Se o script verify-exercises usar diretamente as ferramentas da linguagem, o fluxo de trabalho de testes terá de instalar:
Depois de o fazeres, o verify-exercises deve funcionar como esperado e tens o CI configurado com sucesso!
Para veres um exemplo, consulta o fluxo de trabalho test.yml do track Arturo:
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev libmpfr-dev
- name: Install Arturo
run: bin/install-arturo
env:
GH_TOKEN: ${{ github.token }}
- name: Verify all exercises
run: bin/verify-exercises
A segunda opção é verificar os exercícios executando o test runner do track. Esta opção exige duas condições:
verify-exercises usa a imagem Docker do test runner para executar os testes de um exercícioSe o teu track ainda não tem um test runner, podes:
Esta abordagem tem algumas vantagens:
A principal desvantagem é que provavelmente é mais lenta, por ser preciso descarregar a imagem Docker e devido à sobrecarga do Docker.
Há algumas formas de descarregar a imagem Docker do test runner:
verify-exercises.
É a abordagem adotada pelo track Unison.Então, que abordagem usar?
Recomendamos que implementes pelo menos a opção 1, para que o script verify-exercises seja autónomo. Se a tua imagem for particularmente grande, pode ser benéfico implementar também a opção 3, que guarda a imagem Docker criada na cache do GitHub Actions. As execuções seguintes podem então limitar-se a ler a imagem Docker da cache, em vez de a descarregar, o que pode ser melhor em termos de desempenho (mede, para teres a certeza).
Uma terceira opção, alternativa, é um híbrido das duas anteriores. Aqui, também usamos a imagem Docker do test runner, mas desta vez executamos o script verify-exercises dentro dessa imagem Docker. Para ativar esta opção, temos de definir o contentor do fluxo de trabalho como o test runner:
container:
image: exercism/vimscript-test-runner
Podemos então saltar os passos de instalação de dependências e ferramentas (uma vez que já estarão instaladas na imagem Docker do test runner) e passar à execução do script bin/verify-exercises.
O fluxo de trabalho test.yml do track vimscript usa esta opção:
name: Verify Exercises
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-24.04
container:
image: exercism/vimscript-test-runner
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Verify all exercises
run: bin/verify-exercises