Comandos úteis de desenvolvimento
Este é o conjunto funcional de comandos que você usará no dia a dia: linting, os conjuntos de testes PHP e Vue, a construção do Webpack e os scripts de banco de dados que mantêm seu esquema local e dados iniciais honestos. Cada comando abaixo é reproduzido exatamente como você deve digitá-lo - os sinalizadores suportam carga, portanto, não os parafraseie.
A coisa mais importante a ser acertada antes de qualquer coisa é onde você executa cada comando. O desenvolvimento do omegaUp acontece através de um limite: algumas ferramentas são executadas em sua máquina host (precisam do soquete Docker, da instalação do Node ou de um navegador) e algumas são executadas dentro do contêiner frontend (precisam do tempo de execução do PHP, da conexão MySQL na porta 13306 e do código montado em /opt/omegaup). A execução de um comando no lado errado desse limite é o tropeço inicial mais comum, de modo que cada seção indica seu local de execução e vários scripts se recusam ativamente a executar no local errado, em vez de falharem de forma criptografada.
Para entrar no contêiner em primeiro lugar:
docker exec -it omegaup-frontend-1 /bin/bash
/opt/omegaup (o repositório, montado em ligação do seu host). O contêiner é denominado omegaup-frontend-1 no Docker Compose V2 (o esquema <project>-<service>-<n>, onde o nome do projeto é padronizado como seu diretório omegaup). Em instalações mais antigas do Compose V1, o mesmo contêiner é denominado omegaup_frontend_1 com sublinhados. Se docker exec reclamar que o contêiner não existe, execute docker compose ps para ver o nome exato que sua configuração produziu.
Como saber de que lado você está
Dentro do contêiner, seu prompt fica em /opt/omegaup; no host é onde você clonou o repositório (por exemplo, ~/dev/omegaup). Vários scripts explicam isso: git rev-parse --show-toplevel retornando /opt/omegaup é exatamente como lint.sh e runtests.sh detectam que estão dentro do contêiner.
Linting e validação
Execute todos os linters omegaUp
./stuff/lint.sh
omegaup/hook_tools:v1.0.9) para executar os linters em um ambiente reproduzível e fixado, por isso precisa de seu soquete Docker. Por causa disso, lint.sh se recusa explicitamente a ser executado dentro do contêiner: se git rev-parse --show-toplevel voltar como /opt/omegaup, ele imprime "Executar ./stuff/lint.sh dentro de um contêiner não é suportado" e sai, e se não conseguir encontrar um binário docker, ele informa para você instalar o Docker ou sair do contêiner. Ambas as mensagens são o script que protege você de uma execução que silenciosamente faria a coisa errada.
Sem argumentos, lint.sh não lint a árvore inteira - ele adivinha o conjunto de arquivos que você realmente alterou comparando com a base de mesclagem de sua ramificação e upstream/main (voltando para origin/main se você não adicionou o controle remoto upstream), e é por isso que uma primeira execução após a clonagem sem um upstream pode se comportar de maneira diferente do que você espera. Porém, você raramente precisa invocá-lo manualmente: ele está conectado ao gancho git pre-push, portanto, ele é executado automaticamente em cada git push e bloqueia o push se algo estiver sujo.
Validar estilo sem corrigir
./stuff/lint.sh validate
yapf, prettier, phpcbf e amigos dentro da imagem hook-tools); Em vez disso, o validate apenas verifica e relata, sem alterar nada no disco. Faça isso em situações semelhantes às de CI ou quando quiser ver o que há de errado antes de permitir que o autofixer reescreva seus arquivos.
Gere arquivos de tradução .lang
./stuff/lint.sh --linters=i18n fix --all
i18n e regenera os arquivos *.lang em todas as localidades a partir dos três arquivos de fonte da verdade es.lang, en.lang e pt.lang. Execute-o sempre que você adicionar ou alterar uma string voltada ao usuário para que os arquivos gerados por idioma permaneçam sincronizados - caso contrário, o linter i18n falhará no push. Ele também é executado fora do contêiner, na raiz do projeto.
Teste
Execute todos os testes e validações de PHP
./stuff/runtests.sh
stuff/db-migrate.py validate (confirma que suas migrações são consistentes), stuff/policy-tool.py validate e stuff/mysql_types.sh — que é a mais pesada, executando os controladores e emblemas PHPUnit suites mais a verificação de tipo de retorno do MySQL que verifica se seus métodos DAO realmente correspondem às formas que suas consultas retornam — e finalmente Psalm com --show-info=false.
runtests.sh reconhece localização: execute-o dentro do contêiner e ele invoca essas ferramentas diretamente; execute-o no host e ele será inserido de forma transparente no contêiner com docker compose exec -T frontend para cada etapa. De qualquer forma, quando a parte do contêiner termina, ele lembra você de executar as duas verificações no lado do host que não pode ser feita internamente - ./stuff/lint.sh e os testes Selenium/UI via python3 -m pytest ./frontend/tests/ui/ -s - porque eles precisam do Docker e de um navegador, respectivamente. Não pule esse lembrete; um runtests.sh verde por si só não é uma construção verde.
Execute testes de unidade PHP para um arquivo específico
./stuff/run-php-tests.sh frontend/tests/controllers/$MY_FILE.php
frontend/tests/). Ele conecta a configuração real do conjunto para você - --bootstrap frontend/tests/bootstrap.php, --configuration frontend/tests/phpunit.xml e cobertura gravada em coverage.xml - e depois passa quaisquer argumentos extras diretamente para phpunit. Essa passagem é a parte útil: para executar um único método de teste você pode anexar o próprio filtro do PHPUnit, por exemplo.
./stuff/run-php-tests.sh frontend/tests/controllers/UserRankTest.php --filter testUserRankingClassName
Execute testes ponta a ponta do Cypress (interativo)
npx cypress open
libasound2 e de outras dependências do X instaladas antes de ser iniciado). As próprias especificações residem no cypress/e2e/*.cy.ts - atualmente cerca de dez delas, abrangendo cursos, grupos, IDE, navegação, certificados, concursos e fluxos de criador/coleção de problemas.
Execute Cypress sem cabeça
yarn test:e2e
cypress run --browser chrome, executando todas as especificações sem cabeça e imprimindo os resultados no terminal. Isso é o que o CI usa e o que você deseja para uma passagem rápida "quebrei algum fluxo e2e", já que não espera que você clique em nada.
Execute testes de unidade Vue no modo de observação
yarn run test:watch
ts-jest) para o frontend Vue/TypeScript no modo de observação - nos bastidores, o cross-env TZ=UTC jest --watchAll --notify tem como escopo os arquivos correspondentes a frontend/www/js/.*test\.ts$. O modo Watch mantém o Jest residente e executa novamente os testes afetados sempre que você salva um componente ou seu teste, para que você obtenha um sinal vermelho/verde contínuo enquanto trabalha, em vez de reativar manualmente. O pino TZ=UTC é importante: ele força um fuso horário determinístico para que testes sensíveis à data não sejam aprovados em sua máquina e falhem no CI. Para uma execução única, use yarn test; para cobertura use yarn test:coverage.
Execute um arquivo de teste de unidade específico do Vue
./node_modules/.bin/jest frontend/www/js/omegaup/components/$MY_FILE.test.ts
frontend/www/js/omegaup/components/, assim como seus vizinhos .test.ts também. Este pode ser executado dentro ou fora do contêiner - é Node puro, sem dependência de MySQL.
Construindo o front-end
O site é um shell Twig 3 que envolve componentes de arquivo único Vue 2.7 + TypeScript, agrupados pelo Webpack 5. Durante o desenvolvimento, você quase sempre deseja que um observador reconstrua os pacotes conforme você edita, em vez de reconstruí-los manualmente.
yarn dev:watch
frontend no modo de desenvolvimento com --watch, portanto, cada salvamento agrupa novamente apenas os pontos de entrada do frontend. Scripts relacionados trocam escopo por velocidade - yarn dev é a mesma construção uma vez sem assistir; yarn dev-all / yarn dev-all:watch cria todas as configurações do Webpack (o frontend, mais o estilo e os pacotes secundários) quando uma alteração afeta mais do que o código do aplicativo.
Para um pacote entregável, yarn build executa Webpack em --mode=production (minificado, sem mapas de origem), enquanto yarn build-development produz uma construção de desenvolvimento não minificada. E para navegar pelos componentes isoladamente:
yarn storybook
6006 via storybook dev -p 6006, oferecendo uma sandbox para renderizar e cutucar componentes individuais do Vue sem inicializar o aplicativo inteiro. A cobertura da história é atualmente escassa – cerca de dez arquivos .stories contra mais de 250 componentes – portanto, nem todos os componentes têm uma entrada ainda.
O aplicativo da web não está mostrando minhas alterações
Se você editar um arquivo .vue ou .ts e a página parecer inalterada, a causa comum é que nenhum inspetor está em execução para reconstruir o pacote configurável. Certifique-se de que yarn dev:watch (ou yarn dev-all:watch) esteja em execução e, em seguida, recarregue a página em http://localhost:8001. As alterações do PHP, por outro lado, são obtidas diretamente da montagem de ligação, sem reconstrução.
Banco de dados
Redefinir o banco de dados para seu estado inicial
./stuff/bootstrap-environment.py --purge
--purge elimina e recria o banco de dados do zero; o script então reproduz uma série de solicitações reais de API para preenchê-lo, apresentando concursos, cursos, problemas e os usuários de teste necessários para testes manuais. A definição do que é criado reside no stuff/bootstrap.json, então se você quiser equipamentos extras, esse é o arquivo a ser editado. Sinta-se à vontade para executá-lo quantas vezes precisar - um novo bootstrap é a maneira mais rápida de sair de "meu banco de dados local está quebrado".
Aplicar migrações de banco de dados localmente
./stuff/db-migrate.py migrate --databases=omegaup,omegaup-test
.sql, isso aplica as alterações de esquema pendentes aos seus bancos de dados locais. Nomear ambos omegaup e omegaup-test é deliberado e importante: o segundo é o banco de dados no qual o conjunto PHPUnit é executado, portanto, se você migrar apenas omegaup, seu aplicativo funcionará, mas runtests.sh falhará em um esquema de teste obsoleto (e sua própria etapa db-migrate.py validate sinalizará a incompatibilidade). Execute-o dentro do contêiner.
Gere novamente o schema.sql e os DAOs da sua migração
./stuff/update-dao.sh
schema.sql e as classes DAO/VO geradas descrevem o formato atual do banco de dados e não se atualizam. Este script copia frontend/database/schema.sql para frontend/database/dao_schema.sql para acionar a regeneração e, em seguida, executa stuff/update-dao.py para reescrever as classes base DAO geradas automaticamente e objetos de valor para corresponder às suas novas colunas. Execute-o dentro do contêiner após adicionar uma migração - e observe o problema de ordenação: ele se regenera no esquema confirmado, portanto, ele faz seu trabalho assim que o arquivo de migração estiver em vigor.
Validação de tipo PHP
Execute o Psalm no código-fonte PHP
find frontend/ \
-name *.php \
-and -not -wholename 'frontend/server/libs/third_party/*' \
-and -not -wholename 'frontend/tests/badges/*' \
-and -not -wholename 'frontend/tests/controllers/*' \
-and -not -wholename 'frontend/tests/runfiles/*' \
-and -not -wholename 'frontend/www/preguntas/*' \
| xargs ./vendor/bin/psalm \
--long-progress \
--show-info=false
psalm.xml) sobre o PHP original, usando find para entregar todos os arquivos .php exceto os caminhos excluídos - bibliotecas de terceiros em frontend/server/libs/third_party/, vários diretórios de acessórios de teste e a árvore herdada frontend/www/preguntas/ - porque esses não são nossos para verificação de tipo ou afogariam a execução em ruído. --long-progress fornece uma barra de progresso ao vivo para o que é uma passagem lenta de árvore inteira, e --show-info=false suprime avisos informativos para que apenas erros de tipo genuínos apareçam. Execute-o dentro do contêiner. Se você deseja apenas a mesma verificação que o portão CI é executado, o runtests.sh já invoca o ./vendor/bin/psalm --show-info=false para você.
Docker
Inicie o ambiente de desenvolvimento
docker compose up --no-build
frontend (php-fpm por trás do nginx, servindo em http://localhost:8001), MySQL 8.0 na porta 13306, Redis e os serviços Go pré-construídos — gitserver, grader, broadcaster e runner — extraídos das imagens omegaup/*. --no-build pula a reconstrução das imagens e apenas executa o que você já tem, que é o que você deseja em um dia normal; solte-o (docker compose up) na primeira execução ou após as alterações da imagem, para que o Compose construa/puxe primeiro. O frontend PHP backend se comunica com o Go grader por HTTP em OMEGAUP_GRADER_URL (padrão https://localhost:21680), enquanto as mãos do avaliador trabalham com os executores internamente na porta 11302 - esses serviços residem nos repositórios omegaup/quark e omegaup/gitserver separados, não neste.
docker compose vs docker-compose
Docker Compose V2 é o plugin do formato docker compose (com espaço); configurações mais antigas possuem o binário docker-compose independente. Qualquer um deles funciona desde que sua instalação forneça um deles; os exemplos aqui usam o formulário V2.
Reinicie o serviço Docker
systemctl restart docker.service
docker exec começar a falhar com:
OCI runtime exec failed: exec failed: unable to start container process: open /dev/pts/0: operation not permitted: unknown
exec. Reiniciar o daemon docker.service o limpa, após o que docker exec -it omegaup-frontend-1 /bin/bash funciona novamente. (No macOS ou Windows, o equivalente é reiniciar o Docker Desktop.)
Referência rápida
Cada comando, com o lado do limite do contêiner ao qual pertence:
| Tarefa | Comando | Onde correr |
|---|---|---|
| Execute todos os linters (autofix) | ./stuff/lint.sh |
Host, raiz do projeto |
| Verifique o estilo sem consertar | ./stuff/lint.sh validate |
Host, raiz do projeto |
Gerar novamente arquivos .lang |
./stuff/lint.sh --linters=i18n fix --all |
Host, raiz do projeto |
| Teste PHP completo + portão de validação | ./stuff/runtests.sh |
Dentro do recipiente |
| Um arquivo de teste PHP | ./stuff/run-php-tests.sh frontend/tests/controllers/$MY_FILE.php |
Dentro do recipiente |
| GUI Cipreste | npx cypress open |
Anfitrião |
| Cipreste sem cabeça | yarn test:e2e |
Anfitrião |
| Testes de unidade Vue (assistir) | yarn run test:watch |
Qualquer lado |
| Um arquivo de teste Vue | ./node_modules/.bin/jest frontend/www/js/omegaup/components/$MY_FILE.test.ts |
Qualquer lado |
| Observador de construção de front-end | yarn dev:watch |
Anfitrião |
| Pacote de produção | yarn build |
Anfitrião |
| Caixa de areia de componentes | yarn storybook (porta 6006) |
Anfitrião |
| Redefinir e propagar o banco de dados | ./stuff/bootstrap-environment.py --purge |
Dentro do recipiente |
| Aplicar migrações | ./stuff/db-migrate.py migrate --databases=omegaup,omegaup-test |
Dentro do recipiente |
| Regenerar esquema + DAOs | ./stuff/update-dao.sh |
Dentro do recipiente |
| Abra um shell de contêiner | docker exec -it omegaup-frontend-1 /bin/bash |
Anfitrião |
| Inicie a pilha | docker compose up --no-build |
Anfitrião |
Documentação Relacionada
- Guia de teste — a imagem completa sobre PHPUnit, Jest e Cypress
- Diretrizes de codificação — os padrões que os linters impõem
- Configuração de desenvolvimento — colocar o ambiente em execução em primeiro lugar