Skip to main content

Base Project

Esta na hora de partir para uma pipeline completa e para isso precisaremos de um código que possamos aplicar as várias steps de uma pipeline. Começaremos com o CI inicialmente e o CD podemos implementar no final utilizando GitOps.

Faça um fork desse repositório para a sua conta e vamos começar. Lembrando, esse código não é meu, mas podemos usar aplicar na prática as pipelines e usar os recurso do gitlab-ci. Lembre-se de fazer o fork para dentro do grupo que possui o runner que você criou se quiser usá-lo, caso contrário usará os runners shared do gitlab.

Ao clonar esse repositório podemos observar que é um projeto feito em node, ou seja, para rodar vamos precisar do nodejs.


~/Desktop/gitlab 
git clone [email protected]:puziol/learn-gitlab-app.git
cd learn-gitlab-app
# O que temos no projecto
❯ tree -L 1
.
├── e2e
├── eslint.config.js
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── playwright.config.cjs
├── public
├── README.md
├── src
├── tests
└── vite.config.js

Vamos fazer uma modificação para que tudo seja instalado automaticamente e de forma fácil.

Instale o DevBox e entenda como funciona, é importante pois acredito que mudará a sua vida daqui pra frente.

Já que é um projeto em nodejs precisamos instalar o Node para rodar. Isso é a primeira coisa que devemos saber, pois em uma pipeline vamos precisar no processo de build proporcionar o ambiente que possa buildar esse código.

  1. Instalar as dependências: Vamos precisar do npm para gerenciamento de pacote e isso vem com a instalação do nodejs.
  2. Buildar o projeto
  3. Testar

Na pasta do projeto vamos instalar inicializar o devbox.

# Inicializando o projeto com o devbox
❯ devbox init
# Adicionando o nodejs na versão que queremos
❯ devbox add [email protected]
# Ao iniciarmos o projeto dentro de um ambiente específico teremos tudo que precisamos sem instalar nada na máquina. Também podemos aproveitar isso para o pipeline futuramente.
❯ devbox shell
node --version
v23.11.0
npm --version
10.9.2

Irá observar que uma pasta .devbox aparecerá então é bom colocá-la no git-ignore para não subir para o repositório e também o devbox.lock

echo ".devbox" >> .gitignore
echo "devbox.lock" >> .gitignore

Agora que já estamos em um ambiente isolado, podemos instalar os as dependências antes de buildar o projeto e para isso podemos fazer.

npm install

added 371 packages, and audited 372 packages in 3s

123 packages are looking for funding
run `npm fund` for details

6 vulnerabilities (4 moderate, 2 critical)

To address all issues, run:
npm audit fix

Run `npm audit` for details.

Aqui já temos um ponto importante para a pipeline que vamos montar, conferir as vulnerabilidades de pacotes.

Vamos acertar isso fazendo o update dos pacotes.

npm update

added 11 packages, removed 2 packages, changed 85 packages, and audited 380 packages in 17s

130 packages are looking for funding
run `npm fund` for details

6 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
npm audit fix --force

Run `npm audit` for details.

####
npm audit fix --force
npm warn using --force Recommended protections disabled.
npm warn audit Updating vitest to 3.1.2, which is a SemVer major change.
npm warn audit Updating @vitest/ui to 3.1.2, which is a SemVer major change.

added 3 packages, removed 7 packages, changed 11 packages, and audited 376 packages in 2s

129 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities

Pronto agora não temos nenhuma vulnerabilidade e temos a pasta node_modules com as dependências necessárias (pacotes). Agora podemos buildar o projeto.

npm run build

> [email protected] build
> vite build

vite v6.3.2 building for production...
31 modules transformed.
build/index.html 0.47 kB │ gzip: 0.30 kB
build/assets/react-CHdo91hT.svg 4.13 kB │ gzip: 2.14 kB
build/assets/index-n_ryQ3BS.css 1.39 kB │ gzip: 0.72 kB
build/assets/index-BcKvuBhg.js 147.40 kB │ gzip: 47.58 kB
✓ built in 338ms

E temos a pasta build que também será ignorada pelo .gitignore ao subir o código. É isso que precisamos ter no processo de build, nossa pasta build.

Vamos adicionar o pacote serve para rodar o projeto e verificar?

npm install serve
❯ npx serve ./build

┌────────────────────────────────────────┐
│ │
│ Serving!
│ │
│ - Local: http://localhost:3000 │
│ - Network: http://10.0.0.26:3000 │
│ │
│ Copied local address to clipboard!
│ │

E temos o projeto rodando no navegador.

alt text

Dois pontos importantes ao aproveitar o devbox. O npm install poderia fazer parte da inicialização quando o devbox subir o que acha?

Vamos editar o arquivo do devbox para quando ele inicializar já fazer npm install se existir o arquivo package.json. Podemos remover o test, pois não usaremos agora.

{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json",
"packages": ["[email protected]"],
"shell": {
"init_hook": [
"if [ -f package.json ]; then npm install; fi"
]
}
}

O código pronto está na branch devbox.

Quero deixar claro que poderíamos instalar o node na máquina e não precisaríamos do devbox, mas a limpeza e a facilidade que podemos ter no futuro com as pipelines usando o devbox é de outro mundo, veremos adiante.

Não para esse estudo, mas a pipeline podería começar localmente! Na verdade muitos erros que teremos com a pipeline no futuro poderiam ser resolvidos localmente antes de subir o código. Veja um pouco sobre o pre-commit mas não implemente para esse estudo.

Agora falando um pouco da pipeline, o runner tem que esta pronto para executar esse projeto e temos 3 opções.

1 - Instalar o node assim que o runner começar. Se vamos começar a partir da imagem "debian:bullseye-slim", saiba que ela não tem nodejs então seria necessário instalar através do gerenciador de pacotes apt desta imagem. 2 - Utilizar o mesmo processo que fizemos localmente para rodar, ou seja, instalar o devbox e deixar que ele prepare o ambiente completo. Seria a mesma coisa que o item 1, porém utilizariamos menos comandos. 3 - Utilizar uma imagem docker que já vem com o node instalado ao invés do "debian:bullseye-slim".

Todo o processo de instalação demanda tempo até que o runner fique pronto para fazer o que precisa ser feito. Cada job executará todo esse processo, de preparar o runner para que ele tenha capacidade de fazer o que precisa.

A melhor forma de fazer isso é utilizar o item 3, rodando uma imagem que já temos o que precisamos, porém nem sempre temos tudo que precisamos em uma imagem e as vezes uma imagem é tão específica e para ficar pequena tudo é removido. Por exemplo um imagem node pode não ter o gerenciador de pacote instalado para que instemos um Curl caso precisarmos.

A melhor forma é criar uma imagem com tudo o que precisamos, mas para isso é necessário conhecimento em Docker. Se você não tem essa expertise deveria ter, pois hojé é base para DevOps e desenvolvimento.

Dicas

Ao criar um projeto podemos definir algumas coisas no Settings. Podemos fazer isso em nível de grupo também para toda a organização. O que é bom fazer?

Em Settings > Merge request temos algumas opções.

Qual o tipo de método de merge?

alt text

A opção acima não cria um commit para o merge request mantendo o histório mais limpo.

alt text

Squashing commits é útil ao fazer o push. Se você fez várias modificações na branch, ao invés de mesclar todas as alterações individualmente feita na sua branch, ela irá criar um único commit na branch destino. É muito melhor para ler o histórico.

É interessante sempre que o pipeline tenha sucesso e todas as marcações de revisão tenha sido corrigidas.

alt text

Outra coisa que podemos fazer é criar branchs protegidas, para que ninguém possa fazer um push direto para uma branch como a main, sendo necessário um merge request e forçando a execução da pipeline. A brach main já é protegida, mas pessoas podem fazer push direto para ela. Podemos eliminar isso.

alt text