Depois de muito ler, tentar compreender, testar e apanhar da ferramenta, consegui fazer funcionar um processo simples de CI/CD entre desenvolvimento e produção. Consigo gerar releases da base de desenvolvimento que podem ser aplicados da mesma forma em outras bases de produção. Neste artigo, pretendo mostrar um pouco da minha abordagem.
Antes de iniciar, vamos alinhar as expectativas:
A. Nem tudo é perfeito
Se você espera um script perfeito, que vai fazer absolutamente tudo por você, já pode deixar essa expectativa de lado. SQLcl não é perfeito nem tão bem documentado. Você ainda vai precisar fazer alguns ajustes manuais.
Percebo que em cada versão existe um bug diferente, mas sempre é possível contornar de alguma forma;
B. Objetos java são ignorados
Objetos JAVA no banco de dados são esquecidos pela ferramenta. Você vai precisar encontrar uma forma de contornar isso, caso utilize.
C. Atenção se as duas bases rodam no mesmo PDB
Se você tem as bases de produção e desenvolvimento no mesmo PDB, sugiro fazer o CI/CD do APEX/ORDS num projeto separado, porque tem algumas particularidades que podem te trazer problemas.
D. Essa abordagem sugere que você está gerando os artefatos pela primeira vez
Estamos considerando aqui neste artigo que você está gerando os artefatos pela primeira vez para rodar numa base limpa. Se quiser rodar numa base que já está com os objetos atualizados, vai precisar rodar um comando para que elas se entendam. Vou dar a dica deste comando no final do artigo.
Requisitos:
Para seguir o passo a passo desse artigo você vai precisar de Oracle Database, é claro. Além disso, para replicar o tutorial você precisará de:
Windows (pode utilizar Linux, mas vai precisar adaptar alguns comandos/abordagens)
SQLcl (neste artigo utilizei a versão 25.2.1.195)
Java (neste artigo jdk-21.0.8)
Oracle Instant Client (neste caso 23.8)
GIT (qualquer versão recente. Precisa ser instalado, não vale o portátil.)
Depois de tudo isso instalado, vamos iniciar abrindo o CMD no windows e setar algumas variáveis manualmente para não ter risco de ele se perder. Abaixo temos apenas um exemplo, mas você vai precisar definer os paths conforme a sua instalação. Recomendo digitar linha por linha para ter certeza que o Windows entendeu o que foi passado. Abaixo, o meu exemplo:
rem O Comando CHCP 650001 vai fazer com que o seu CMD trate melhor caracteres como acentos, entre outros.
chcp 65001
rem Se houver estouro de memória pode setar manualmente a memória do Java.
rem set JAVA_TOOL_OPTIONS=-Xms512m -Xmx6G
rem Aqui iremos definir o diretório do seu Java Home, assim teremos certeza que ele irá buscar no local correto.
set "JAVA_HOME=C:\Oracle\jdk-21.0.8"
rem Vamos também definir o diretório do seu SQLcl
set "SQLCL_HOME=C:\Oracle\sqlcl-25.2.1.195.1751\sqlcl"
rem Caso necessário, temos aqui também o caminho do instant client
rem SET INSTANT_CLIENT_HOME=C:\Util\instantclient\instantclient_23_4
rem Com este comando, incluímos tudo isso junto com o PATH padrão.
set PATH=%SQLCL_HOME%\bin;%JAVA_HOME%\bin;%INSTANT_CLIENT_HOME%;%PATH%
rem Se quiser, pode chamar diretamente os dados do DB via TNSADMIN. O comando abaixo so se torna necessário se você fizer questão de usar o TNSADMIN
set TNS_ADMIN=C:\Oracle\instantclient_23_4\network\admin
Você configurou o ambiente para iniciar os próximos passos. Não feche esta janela pois nela foram passados todos os parâmetros que precisamos. O nome do meu projeto exemplo será PMT.
Pode deixar o CMD minimizado e criar uma pasta vazia para o seu projeto. No meu caso, a pasta será:
C:\Oracle\projetos\PMT. No CMD vamos navegar até a pasta criada
cd C:\Oracle\projetos\PMT
É importante garantir que você está na pasta certa. Agora podemos conectar o SQLcl:
CONECTANDO NO SQLCL
Para conectar no SQLcl, você tem mais de uma opção. Escolha apenas uma delas
- Conectar diretamente sem passar inicialmente a conexão com o banco, deixando para passar os dados da conexão após abrir o SQLcl.
sql -thin /nolog
conn PMT/pass@dbpessoal
- Conexão passando o caminho diretamente
sql -thin PMT/pass@//databasehostnameorip:1521/servicename
- Conexão via TNSNAMES.
sql -thin PMT/pass@dbpessoal
PREPARANDO SEU PRIMEIRO RELEASE
Depois de conectado no banco de dados via SQLcl, já na pasta do seu projeto, você vai precisar iniciar e definir algumas configurações do projeto. Isso só precisará ser feito uma única vez.
project init -name PMT -schemas PMT
Configurando o projeto
Assim que o projeto é iniciado, você pode simplesmente ignorar configurações adicionais ou personalizar de acordo com a sua preferência. Para verificar as configurações disponíveis, pode usar o comando abaixo.
project config -list -verbose
Abaixo, vou listar os comandos de minha preferência, que podem ser utilizados como exemplo ou não. Para entender o que cada um dos comandos faz, você pode rodar o comando acima, que está tudo bem explicado.
project config set -name export.format.enable -value false -verbose
project config set -name export.setTransform.emitSchema -value false -verbose
project config set -name export.apex.expComments -value true -verbose
project config set -name export.apex.expOriginalIds -value true -verbose
project config set -name export.apex.expSavedReports -value true -verbose
project config set -name export.apex.expPubReports -value true -verbose
Essa configurações ficam gravadas num arquivo dentro da pasta .dbtools.
Configurando filtros
Dentro da mesma pasta .dbtools, existe um subpasta de nome filters com um único arquivo project.filters. Se abrir o arquivo, verá outras configurações adicionais, como por exemplo, opções de ignorar objetos no projeto, exportar somente aplicações APEX específicas. Neste caso, não iremos fazer nenhuma mudança no arquivo. Vamos direto aos comandos GIT. De qualquer forma, recomendo que você analise os objetos APEX, ORDS e grants.
Considerando que você já tem o GIT instalado, iremos criar o main branch através deste comando. Como você ainda está dentro do SQLcl, teremos que adicionar um ! na frente dos comandos git. Isso vale para qualquer outro comando de sistema operacional dentro do SQLcl.
--com este comando você irá criar seu branch inicial e se posicionar nele. É importante colocar mesmo aqui que vem depois dos dois traços: -- nesse primeiro comando:
!git init --initial-branch=main
--com este comando iremos adicionar os arquivos no git
!git add .
--após adicionar precisamos fazer o commit e podemos cadastrar uma mensagem para identificar esse commit.
!git commit -m "Inicialização do projeto"
Agora vamos fazer nosso primeiro release, chamaremos de 1.0.
--esse comando vai criar o branch e nos colocar dentro dele
!git checkout -b release-1.0
Estamos dentro do branch 1.0, então é hora de exportar nosso banco de de dados. Para isso iremos rodar os comandos abaixo. Não deixe seus desenvolvedores fazerem modificações na sua base enquanto o export não termina.
-- Você pode escolher o número de threads utilizadas. Neste caso, escolhi 5 threads, que é o padrão.
project export -threads 5 -verbose
--adiciona e faz o commit no git.
!git add .
!git commit -m "release-1.0"
Apenas para conhecimento, todos os objetos exportados ficam na pasta /scr.
Depois disso, colocaremos o projeto em stage, que irá comparar o export atual com os branches anteriores. Abaixo, a lista de comandos.
--a primeira coisa a fazer é rodar o project stage, que irá compar os objetos exportados na versão atual com as versões anteriores.
project stage
--se você quiser adicionar uma lista de comandos dml, deve acrescentar com este comando, nessa etapa.
--project stage add-custom -file-name dml_file_name
--caso queira verificar se está tudo certo com o projeto pode rodar o project verify, mas não é obrigatório.
--project verify -verbose
--vamos informar a versão do release
project release -version 1.0 -verbose
--com o comando abaixo, iremos gerar o artefato. Um .zip com toda a instrução de deploy e todos os objetos, já listados na ordem em que devem ser executados.
project gen-artifact -version 1.0 -verbose
--adicionamos e commitamos.
!git add .
!git commit -m "Commit Version 1.0"
--depois de resultado de sucesso em todas as etapas acima precisamos voltar para o branch main e fazer um merge com o release atual.
!git checkout main
!git merge release-1.0
Nesta etapa você concluiu a geração do seu primeiro release e está pronto para aplica-lo em outras bases.
FAZENDO O DEPLOY DO SEU PRIMEIRO RELEASE NA BASE DE DESTINO
Depois que o seu release estiver pronto, você verá que o objeto .zip estará na sua pasta artifacts, dentro da pasta principal do seu projeto. Agora iremos repetir alguns comandos e acessar a base de destino. Lembrando que estamos considerando uma base de destino limpa, onde os objetos ainda não existem. Se a outra base já contiver os objetos isso não vai funcionar, precisa rodar primeiro um outro comando para isso, que será abordado no final desse artigo.
- Caso ainda esteja com o cmd aberto, basta rodar o comando quit para sair do SQLcl e reconectar na base que irá receber os objetos. Caso tenha fechado o cmd, basta rodar novamente os comandos de setar as variáveis de ambiente, voltar para a pasta do projeto e iniciar o SQLcl (dessa vez você irá conectar na base de destino, aquela que vai receber os objetos. Isso é muito importante.)
project deploy -file artifact/PMT-1.0.zip -verbose
Como escolhemos o modo verbose ele irá mostrar cada objeto que está sendo incluído no banco de dados de destino, até você receber a mensagem de sucesso. Além dos seus objetos, ele vai criar 3 tabelas na sua base de destino: DATABASECHANGELOG, DATABASECHANGELOG_ACTIONS e DATABASECHANGELOGLOCK, que são as tabelas de controle do liquibase.
PREPARANDO SEUS PRÓXIMOS RELEASES
Considerando que você já gerou seu primeiro release e agora precisa gerar outros, recomendo fazer um backup da pasta do projeto. Não tente usar o comando de compactar do windows, pq ele desconsidera tudo o que tem relação com o git naquela pasta. Você pode copiar a pasta ou gerar um .zip com o 7Zip.
Vamos ao trabalho. O primeiro passo é voltar para o SQLcl, na pasta do projeto e conectar na base de origem novamente. Para isso vamos executar:
--exportando o projeto novamente
project export -verbose
--criando novo branch
!git checkout -b release-1.1
!git add .
!git commit -m "Novos arquivos exportados da base de desenvolvimento na ver. 1.1"
-- colocando em stage para comparar nosso branch atual com o main
project stage -verbose
--criando o release
project release -version 1.1 -verbose
--gerando o novo artefato
project gen-artifact -version 1.1 -verbose
!git add .
!git commit -m "Commit dos novos arquivos da versão 1.1"
--fazendo o checkout e voltando para o main branch
!git checkout main
--fazendo o merge do último release na main
!git merge release-1.1
Tudo pronto. Você verá agora mais um artefato .zip incrementado com todos os objetos do release anterior + os objetos do release atual. Na hora de aplicar, ele irá confirmar no liquibase que todos os objetos do release anterior foram aplicados e logo irá começar a aplicar as mudanças do release atual. Caso você já tenha certeza que os anteriores estão aplicados com sucesso, pode descompactar o artefato e remover as referências dos releases anteriores do xml main.changelog que fica em /releases.
Após modificado precisará recompactar o arquivo com as alterações para poder fazer o deploy.
OUTRAS CONSIDERAÇÕES
A. Caso você esteja querendo iniciar quando sua base de dados de destino já contém os objetos:
Neste caso você irá criar os objetos normalmente, porém, antes de fazer o deploy do primeiro release na base de destino, precisará rodar o comando abaixo [na base de destino]:
liquibase changelog-sync -chf dist/releases/main.changelog.xml
Esse comando irá criar as tabelas do liquibase na sua base de destino e marcar os objetos como já aplicados. A partir daqui os próximos releases irão funcionar, visto que ele entenderá que o primeiro já foi aplicado.
B. Se estiver tentando aplicar tudo isso no mesmo PDB, porém em schemas diferentes:
Faça com que o ORDS e APEX sejam um processo a parte, porque ele pode acabar tentando substituir o que já existe. Para isso em .dbtools/filters marque para não exportar APEX nem ORDS, você pode fazer isso depois de forma separada.
OBSERVAÇÕES FINAIS:
Algumas observações pessoais sobre este processo:
Cada artefato de release novo carrega todos os releases antigos junto com ele. Ele sempre vai se comportar assim, porém, na hora de aplicar, para tudo funcionar você não deve mais por a mão na base de destino, principalmente no que diz respeito a criação de objetos e alterações de tabelas. Todo o processo deve ser feito somente através da ferramenta.
No windows, percebi que as permissões ficam bem vinculadas com o usuário, então se você tem um servidor TS e mais de uma pessoa vai mexer, recomendo criar um usuário devops.
As vezes a tela congela e você precisa apenas apertar ENTER para continuar. Em alguns casos a tela congela e não tem enter que resolva, só esperar. É normal.
Recomendo gerar os releases com certa frequência, não deixar acumular muitas mudanças para gerar o release. Digo isso, pois facilita bastante na hora de investigar o artefato em busca de erros.
Teste por sua conta e risco. Recomendo fazer backups do banco de dados antes de fazer os deploys.
Se tiver interesse em ver o tutorial adaptado para linux, basta comentar aqui, porque já comecei a trabalhar nisso.
Bugs que eu percebi em algumas versões do SQLcl
25.2.1 - Percebo que a versão ainda tem problemas para lidar com chaves primários tipo IDENTIFIED BY. Precisei trocar várias tabelas do banco de dados para o modelo normal (sequence + trigger) para não apresentar erro. Ainda tenho problema para o liquibase reconhecer objetos que foram dropados ou renomeados. Também pode apresentar problemas para conectar via TNSNAMES.
24.1 - As sequences já existentes são geradas toda vez e isso traz conflito.
Referências:
Top comments (0)