Files
2026-09-23 12:29:08 -03:00

5.5 KiB

name, description
name description
vitruvio-criar-patch Use when the user wants to create a new Liquibase database migration patch in a Vitruvio repository. Triggers: "create patch", "new patch", "criar patch", "novo patch", "database migration", "migração de banco", "changeset", "liquibase", or any request to scaffold oracle/postgresql patch XML files.

Create Vitruvio Patch

All messages shown to the user must be written in Portuguese.

You are creating a new Liquibase database migration patch inside a Vitruvio repository. Follow these steps in order.

Step 1 — Confirm you are inside a Vitruvio repo

ls vitruvio.json 2>/dev/null && echo "OK" || echo "NOT_A_VITRUVIO_REPO"

If NOT_A_VITRUVIO_REPO, stop and tell the user to cd into the correct repo.

Step 2 — Inspect existing patches

vitruvio new patch auto-detects the next changeset ID by scanning all existing XML files — you don't need to find it manually. For situational awareness you can check:

find patches/ -name "*.xml" | xargs grep -h 'id="[0-9]' 2>/dev/null | grep -oP 'id="\K[0-9]+' | sort -n | tail -1

Next ID = last found + 1. If no patches exist yet, starts at 1. The CLI also creates patches/oracle/ and patches/postgresql/ subdirectories if they don't exist yet.

Step 3 — Collect migration details

Ask the user (in a single message, only ask what is missing):

  • What this migration does — describe the change (e.g. "add column STATUS to table PEDIDO", "create table AUDIT_LOG", "insert config rows").
  • Author — Vitruvio username (e.g. joao.felix). Use git config user.name if unsure.
  • Module key — used in the filename (e.g. GO, checklist, faturamento). Default: the repo's metadata.key from vitruvio.json.

Step 4 — Create the patch files

Both oracle/ and postgresql/ files must always be created and kept in sync.

Filename convention: {YYYYMMDDHHmm}_{MODULE_KEY}.xml (e.g. 202506011430_checklist.xml).

Use vitruvio new patch to scaffold — it handles the filename, ID assignment, and directory creation automatically:

vitruvio new patch <module-key>

Find the created files, then replace the SQL placeholder in both with the actual migration for each DB dialect, and set author to the correct Vitruvio username:

ls -t patches/oracle/ | head -1

Absolute rules

  • Append-only. Never edit or delete existing <changeSet> entries — modifying a checksum that Liquibase already recorded breaks deployment.
  • Unique numeric IDs. Each <changeSet id="..."> must have a unique ID within the repo. Increment from the last found.
  • Always use <preConditions onFail="MARK_RAN"> — every changeset must be idempotent and safe to re-run on any DB state.
  • Oracle ≠ PostgreSQL. Write each file for its target DB — data types, sequences, and quoting differ. Never copy-paste blindly.
  • One logical change per changeset — don't batch unrelated changes into a single <changeSet>.

File skeleton

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
  xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
                      http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">

  <changeSet author="<author>" id="<next-id>" objectQuotingStrategy="LEGACY">
    <preConditions onError="WARN" onFail="MARK_RAN" onSqlOutput="IGNORE">
      <!-- guard appropriate for the operation — see examples below -->
    </preConditions>
    <sql endDelimiter=";" splitStatements="true" stripComments="false">
      -- SQL for this DB dialect
    </sql>
  </changeSet>

</databaseChangeLog>

preConditions reference

Operation Guard to use
CREATE TABLE <not><tableExists tableName="MY_TABLE"/></not>
ADD COLUMN <not><columnExists tableName="MY_TABLE" columnName="MY_COL"/></not>
CREATE INDEX <not><indexExists indexName="IDX_NAME"/></not>
ADD CONSTRAINT / FK <not><foreignKeyConstraintExists foreignKeyName="FK_NAME"/></not>
INSERT row (by PK) <sqlCheck expectedResult="0">SELECT COUNT(*) FROM MY_TABLE WHERE ID = 1</sqlCheck>
DROP TABLE <tableExists tableName="MY_TABLE"/>
DROP COLUMN <columnExists tableName="MY_TABLE" columnName="MY_COL"/>

Oracle vs PostgreSQL differences to watch

Oracle PostgreSQL
Auto-increment Separate CREATE SEQUENCE + trigger or DEFAULT seq.NEXTVAL SERIAL or GENERATED ALWAYS AS IDENTITY
String type VARCHAR2(n) VARCHAR(n)
Boolean NUMBER(1) BOOLEAN
Date/time DATE, TIMESTAMP DATE, TIMESTAMP
Current timestamp SYSDATE CURRENT_TIMESTAMP
Quoting LEGACY strategy (unquoted) Same

Step 5 — Check vitruvio.json patches registration

The patches directory only needs to be registered once. Check if it is already there:

grep -A2 '"patches"' vitruvio.json

If not registered, add to vitruvio.json:

"patches": "patches/"

Step 6 — Report

Tell the user:

  • Files created: patches/oracle/<filename>.xml and patches/postgresql/<filename>.xml
  • Changeset IDs used
  • Summary of what each changeset does
  • Reminder: never edit existing changesets once committed — add new ones instead