Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVSync

Sincronização bidirecional entre o conteúdo Gutenberg no banco de dados e arquivos versionados no repositório git (content/). O banco é a autoridade em tempo de edição; o repositório é a autoridade de transporte entre ambientes (spec: cvsync v1 + Apêndice A).

O que faz

  • Export (banco → arquivo): edições no admin marcam a entidade como dirty e o export acontece no shutdown do request, lendo o estado final do banco (debounce natural). Arquivos canônicos: frontmatter YAML + corpo de blocos, com placeholders no lugar de IDs internos ({{ref:slug}}, {{attachment:slug}}, {{attachment_url:slug}}, {{term:taxonomy:slug}}, {{home_url}}).
  • Apply (arquivo → banco): wp sync apply aplica o conteúdo do repositório no banco, com detecção de conflitos (3-way por hash), preservação do lado perdedor, snapshot pré-apply e audit log.
  • Entidades versionadas: páginas, padrões (wp_block), templates e template parts, navegações (wp_navigation), menus, global styles, branding (logo/ícone do site), anexos de mídia (sidecar + blob) e — opcional, desligado por default — termos de taxonomia (Apêndice B).
  • Ambientes: matriz normativa por ambiente (local/staging/homolog/prod) — em produção, apply e export automáticos ficam OFF (apply manual exige --force + TTY + CVSYNC_ALLOW_PROD_APPLY).

Instalação

  1. Copie plugins/cvsync/ para wp-content/plugins/ (ou monte como submódulo git).
  2. Opcional: composer install dentro do diretório do plugin (instala symfony/yaml e o autoloader otimizado). Sem vendor/, o plugin funciona com o autoloader próprio de fallback e o parser YAML interno.
  3. Ative o plugin. A ativação:
    • verifica a pré-condição dura: todo post type versionado precisa de suporte a revisions (exceção: attachment);
    • instala as tabelas wp_cvsync_state, wp_cvsync_conflicts, wp_cvsync_log;
    • executa a sonda PHP-off de uploads (.htaccess/sonda HTTP em CLI) — falha gera admin notice crítico, sem bloquear a ativação.
  4. Instale os git hooks: wp sync install-hooks.
  5. Defina o ambiente via WP_ENVIRONMENT_TYPE (core) e, quando necessário, CVSYNC_ENVIRONMENT (única porta para homolog).

Constantes CVSYNC_*

Precedência: constante em wp-config.php > variável de ambiente > default. Nenhuma flag vive no banco (options viajam com dumps). Valor inválido em qualquer constante → default fail-safe + admin notice (nunca silencioso).

Constante Valores Default Notas
CVSYNC_ENVIRONMENT local | staging | homolog | prod derivado de wp_get_environment_type(); desconhecido → prod (fail-closed) homolog só via constante explícita
CVSYNC_CONFLICT_WINNER db | file por ambiente (matriz §7.3) CI staging define file no job
CVSYNC_DEPLOY_GATE warn | halt warn halt = apply falha em conflito (exit 2)
CVSYNC_ALLOW_PROD_APPLY true ausente = negado pré-condição de --force em prod
CVSYNC_IMPORT_USER login ou ID primeiro administrador usuário técnico do import
CVSYNC_CONTENT_DIR path <repo-root>/content detecção: primeiro ancestral do plugin com .git; fallback dirname(ABSPATH). Nunca em tema/plugin/uploads
CVSYNC_FILE_MODE / CVSYNC_DIR_MODE octal 0664 / 0775 nunca depender de umask de request
CVSYNC_ATTACHMENT_MAX_BYTES bytes 10485760 (10 MB) teto único de anexo
CVSYNC_ATTACHMENT_MIME_TYPES lista CSV image/jpeg,image/png,image/webp,image/gif,application/pdf whitelist estática (interseção com get_allowed_mime_types())
CVSYNC_ATTACHMENT_ALLOW_SVG true | false false (default-deny) opt-in de SVG; exige sanitizador (§A.9.3)
CVSYNC_ATTACHMENT_SCOPE referenced | all referenced all exporta todo upload; typo NUNCA vira all silencioso
CVSYNC_SNAPSHOT_KEEP int 10 retenção de snapshots pré-apply
CVSYNC_SNAPSHOT_MAX_BYTES bytes 536870912 (512 MB) teto de disco com purge LRU
CVSYNC_TOMBSTONE_TTL_DAYS int 90 retenção de tombstones

cvsync.json × constantes CVSYNC_*

São duas superfícies de configuração com papéis distintos (§A.13.10):

  • Constantes configuram o runtime (apply/export dentro do WordPress).
  • cvsync.json (na raiz do repo) configura o lint de CI (bin/cvsync-lint.php) — o CI não lê wp-config.php.

O apply loga warning quando a config do lint e as constantes divergirem. Mantenha as duas em sincronia (mesmos limites de tamanho/MIME).

Post types versionados

A estrutura de site versionada por default (posts de conteúdo comum não são versionados):

Post type Diretório em content/ Extensão
page pages/ .page.html
wp_block (padrões) patterns/ .pattern.html
wp_template templates/ .template.html
wp_template_part templates/parts/ .template-part.html
wp_navigation navigation/ .navigation.html

Adicionando CPTs — filtro cvsync/post_types

add_filter('cvsync/post_types', fn () => [
    'projeto',                                    // forma simples: defaults derivados
    'institucional' => [                          // forma associativa: sobrescreve campos
        'dir'   => 'site/institucional',
        'ext'   => '.inst.html',
        'stage' => 3,
        'meta'  => ['_thumbnail_id', '_wp_page_template', 'destaque'],
    ],
]);

Campos da forma associativa:

Campo Controla Default derivado
dir Diretório em content/ {type}s
ext Extensão do arquivo .{type}.html
stage Estágio de aplicação (deps: 1 blocos/navegação, 2 templates, 3 páginas/CPTs) 3
statuses Statuses versionados ['publish', 'draft', 'private']
meta Whitelist de meta no payload/hash ['_thumbnail_id']
identity_taxonomies Taxonomias cujos termos entram no payload do post []

Pré-condição dura: revisions (§3.2)

Todo post type versionado precisa de suporte a revisions — o plugin recusa operar sem isso (erro claro na ativação e no verify): registre o CPT com supports => ['title', 'editor', 'revisions', ...] ou, para CPT alheio já registrado, add_post_type_support('projeto', 'revisions').

Conteúdo existente

Post type adicionado em projeto com conteúdo já criado: os posts aparecem como untracked no verify até rodar wp sync export (a "adoção" gera o uuid e exporta os arquivos canônicos).

Meta

  • Por post type: campo meta da config (whitelist — só o que está na lista entra no payload e no hash);
  • Global: filtro cvsync/meta_whitelist (recebe a whitelist do tipo, pode ajustá-la);
  • Meta fora da Meta API (Pods/ACF table-based): filtro cvsync/meta_providers (§3.3) com callables fn (int $postId, string $type): array — o retorno é mesclado ao meta do post.

identity_taxonomies × taxonomias versionadas

São coisas diferentes: identity_taxonomies define termos que entram no payload/hash do post (associação — ex.: wp_pattern_category nos padrões); taxonomia versionada como entidade (definição do termo em content/terms/) é opt-in via cvsync/taxonomies — ver seção Termos de taxonomia (Apêndice B).

Attachments

Anexos de mídia não se configuram por este filtro: são entidade própria (Apêndice A, escopo referenced — ver CVSYNC_ATTACHMENT_* na tabela de constantes).

Painel de configuração (Ferramentas → CVSync → Configuração)

Tela admin (manage_options) para configurar escopo e comportamento de import — o que continua fora dela é decisão de deploy/CLI. Tudo persiste na option única cvsync_settings (taxonomies, post_types, lock_imports, auto_import).

  • Ambiente (read-only): box no topo mostra o ambiente efetivo (local/staging/homolog/prod) e a política resultante (apply/import e export: ON/OFF). Não é editável na tela por norma (§7.1/§10.1): ambiente é fail-closed via wp-config.php/env (WP_ENVIRONMENT_TYPE ou CVSYNC_ENVIRONMENT) — uma option viajaria num dump de banco; em prod o box é um aviso fail-closed explícito (apply manual só com triplo fator).
  • Bloquear importações neste ambiente (lock_imports): recusa comandos e handlers de import no ambiente. Só sabe restringir — se a option viajar num dump, o destino fica bloqueado, nunca liberado (fail-closed por direção). Em prod o toggle fica desabilitado (a matriz §7.3 já bloqueia).
  • Importação automática ao detectar mudanças no repositório (auto_import): habilita o check passivo de HEAD-hash + reconcile agendado. Em prod: desabilitado (matriz manda OFF; a option é inócua num dump).
  • Taxonomias sincronizadas: checkboxes das taxonomias públicas; a deny-list do Apêndice B (nav_menu, wp_theme, wp_pattern_category, wp_template_part_area, link_category, post_format) aparece desabilitada com o motivo. O filtro cvsync/taxonomies do código continua valendo (união com o marcado na tela).
  • Post types sincronizados: os defaults (estrutura de site) aparecem marcados e travados; os demais públicos são opcionais — sem suporte a revisions o checkbox fica desabilitado com o motivo (§3.2). União com o filtro cvsync/post_types. Attachments não se configuram aqui (Apêndice A).

Exportar / importar conteúdo (.zip)

Botões na mesma tela (handlers em admin-post.php, nonce cvsync_io):

  • Export: empacota o content/ atual para download. Liberado em qualquer ambiente (read-only). Use para capturar conteúdo de um ambiente sem git ou para transferência manual.
  • Import: upload de um zip com o content/ de outro ambiente — o zip é input de terceiro e atravessa a mesma fronteira de um PR, então a validação roda antes de qualquer byte tocar o content dir ativo: teto de 200 MB (físico e descompactado — zip bomb), varredura de path traversal/symlinks/executáveis, whitelist de subdirs/extensões, validação de conteúdo (frontmatter, anti-regressão §6.2, magic bytes dos blobs), teto de ~50 entidades, extração em tmp, backup do content/ atual e swap atômico (rename); falha pós-backup restaura o backup automaticamente. O resultado do apply (aplicados/ignorados/conflitos/erros) volta como notice na tela.
  • Quando usar CLI: ambientes com o content dir em FS imutável, lotes grandes que precisem de --batch, e qualquer operação fora da fronteira admin — a CLI é o caminho canônico (§8.3).

Ressalva operacional (import via web): o swap atômico usa rename no diretório pai do content dir — em ambientes docker com bind mount, o www-data precisa de permissão de escrita nesse pai (no projeto-base o compose alinha o uid via WWW_DATA_UID). Sem isso, o import falha com a mensagem acionável (via wp-cli/root funciona).

Termos de taxonomia (Apêndice B)

Versionamento opcional da definição editorial de termos (name, slug, description, parent por slug e meta da whitelist). Desligado por default: nada é versionado até o projeto optar via filtro cvsync/taxonomies (B.1.1):

add_filter('cvsync/taxonomies', fn () => [
    'category'    => ['dir' => 'categories'],
    'projeto_tag' => [], // item com valor simples: defaults derivados
]);
  • Item com valor simples → defaults: diretório {taxonomy}s e whitelist de meta ['thumbnail_id']; item associativo sobrescreve (dir, meta).
  • Deny-list (erro claro na ativação): nav_menu, wp_theme, wp_pattern_category, wp_template_part_area, link_category, post_format e taxonomias não-públicas.
  • Um arquivo por termo, layout plano (hierarquia é campo, não path): content/terms/{dir}/{slug}.term.yml:
# content/terms/categories/noticias.term.yml
uuid: 018f4b2e-7c3a-7d4e-9a1f-5e7c9b2d1e44  # identidade (termmeta _cvsync_uuid) — NUNCA no hash
taxonomy: category                            # hash: entra
slug: noticias                                # hash: entra
name: "Notícias"                              # hash: entra
description: "Conteúdo jornalístico"          # hash: entra
parent: null                                  # hash: entra — SLUG do pai, nunca term_id
meta:
  thumbnail_id: "{{attachment:logo}}"         # placeholderizado (§A.6)
hash: sha256:9f2c71ab…                        # derivado — última linha
  • A associação post↔termo continua no frontmatter do post (ortogonal à definição do termo — B.6.1); terms são aplicados no estágio 0, antes dos posts.
  • Export bulk: wp sync export --taxonomy=<tax> (sem flag = todas as taxonomias versionadas).
  • Erratas à spec v1: E2-bis (updates de count e edited_term_taxonomies ficam fora do dirty-marking — import não suja a fila) e E5-bis (delete de termo não tem trash — a rede de segurança é git + conflicts + tombstone + dirty-mark reverso).

Regras de ouro

  • content/** é artefato gerado que é versionado: nunca editar à mão. Mudanças manuais serão perdidas no próximo export (§12.2).
  • O plugin nunca roda git no runtime web, nunca commita, nunca escreve em .git.
  • Commit de conteúdo é decisão humana: edite no admin → export automático → git add content/... && git commit → PR com review humano do diff.
  • Um worktree ↔ um banco/ambiente WP.
  • Nunca force-push em branch compartilhada de conteúdo.

CLI (contrato §8.3)

Todos os comandos vivem no namespace wp sync. Neste projeto, rode dentro do container:

docker compose exec -T wordpress wp sync <comando>

Convenções gerais (de CommandBase, aplicam-se a quase todos):

  • --format=json emite saída estruturada (uma linha JSON por item + resumo);
  • constantes CVSYNC_* com valor inválido geram warning no início de qualquer comando (nunca passam silenciosas);
  • comandos de mutação (apply, bootstrap, resolve, restore) respeitam a matriz de ambientes: em local/staging/homolog são livres via CLI; em prod exigem o triplo fator (--force + TTY interativo + CVSYNC_ALLOW_PROD_APPLY=true) — stdin não-TTY é recusado;
  • export, plan, verify, status, log, blame, conflicts são read-only no banco e livres em qualquer ambiente (inclusive prod).

Tabela-resumo

Comando O que faz Mutação? Exit codes
apply Reconcilia arquivos → banco sim 0 ok · 1 falha/recusa · 2 deploy_gate=halt com conflito · 3 migration pendente
plan Dry-run do plano completo não 0 ok · 1 erro de plano · 3 migration pendente
export Exporta banco → arquivos (bulk/filtros) não (banco) 0 ok · 1 erro ou diff no --check · 3 migration pendente
bootstrap Seed inicial da state table sim 0 ok · 1 falhas · 3 migration pendente
verify Recalcula hashes dos dois lados × state não 0 convergente · ≠0 divergência
status Visão geral do sync no ambiente não 0 sempre
log Audit trail recente não 0 sempre
blame "Por que esta entidade mudou?" não 0 sempre
conflicts Lista conflitos pendentes / prune não / prune 0 ok · 1 erro
conflict show Despeja o payload do lado perdedor não 0 ok · 1 id inexistente
resolve Resolução manual de conflito sim 0 ok · 1 erro/sem pendente
rebase Re-alinha state sem aplicar mudanças state apenas 0 ok · 1 erros
restore Re-aplica snapshot pré-apply sim 0 ok · 1 snapshot inexistente
install-hooks Aponta git para .githooks/ git config 0 ok · 1 sem git/.githooks
purge-revisions Remove revisions antigas (com retenção) sim (seguro) 0 sempre
attachments gc GC de blobs do repo / arquivos de uploads dry-run default 0 sempre

Reconciliação

wp sync apply

Aplica o conteúdo do repositório no banco (arquivo → banco). Detecta conflitos 3-way por hash, preserva o lado perdedor na tabela de conflitos, tira snapshot pré-apply e registra tudo no audit log. Entidades com editor lock ativo são puladas (skipped-locked — conta como falha para o exit code; o retry é natural no próximo checkpoint).

Flag Descrição Default
--dry-run Simula sem escrever (equivale ao plan, com gates de ambiente desligados) off
--force 1º fator do apply em prod off
--force-locks Sobrescreve entidades com editor lock — só com TTY interativo off
--delete / --force-delete Autoriza deleções pendentes (respeitam a política do ambiente: trash em local/staging; homolog é trash-only e recusa --force-delete; prod nunca deleta) off
--format=json Saída estruturada off

Exit codes: 0 sucesso (conflitos auto-resolvidos não sobem exit code) · 1 houve falhas ou recusa de ambiente/lock · 2 CVSYNC_DEPLOY_GATE=halt e houve conflito auto-resolvido no lote · 3 migration de schema pendente (fail-closed §5.9 — recusa imediata com ação prescritiva, sem resumo; reative o plugin ou rode a migration no pipeline).

docker compose exec -T wordpress wp sync apply --dry-run   # ensaio
docker compose exec -T wordpress wp sync apply             # aplica de verdade (local)

wp sync plan

Mostra o plano completo sem aplicar nada: o que seria importado, exportado, os conflitos, deleções pendentes e purges de tombstone. Ideal para review de PR e pipeline. Exit 0/1 (1 = erro de plano) · 3 migration pendente (recusa imediata com ação prescritiva).

docker compose exec -T wordpress wp sync plan

wp sync export

Exporta o banco para os arquivos (bulk, recuperação ou captura inicial). Livre em prod (read-only no banco) — é a porta para trazer conteúdo do cliente de volta ao repo.

Flag Descrição Default
--post-type=<type> Restringe a um post type (inclui attachment, nav_menu, wp_global_styles, branding) todos
--taxonomy=<tax> Restringe a uma taxonomia versionada (Apêndice B) todas as versionadas
--scope=referenced|all Escopo de attachments: só referenciados ou biblioteca inteira referenced
--batch=<n> Tamanho do lote (chunking retomável por idempotência) 50
--out=<dir> Destino alternativo (ex.: captura de prod em dir temporário — não toca o FS do deploy) content dir real
--check Modo CI: falha (exit 1) se o export geraria diff — gate de idempotência off
--format=json Saída estruturada off
docker compose exec -T wordpress wp sync export --check    # CI: repo está em sincronia?
docker compose exec -T wordpress wp sync export --post-type=attachment --scope=all

wp sync bootstrap

Seed inicial da state table — a ausência de state nunca é inferida, este comando é a porta explícita. Comando de mutação (prod: triplo fator).

Flag Descrição Default
--from=files Repo é a autoridade: importa o que falta no banco, recria linhas convergentes silenciosamente, marca divergências como conflict (nunca adivinha) default
--from=db Banco é a autoridade: exporta cada entidade do escopo
--force 1º fator em prod off
docker compose exec -T wordpress wp sync bootstrap           # ambiente novo, repo cheio
docker compose exec -T wordpress wp sync bootstrap --from=db # banco legado, repo vazio

Inspeção e diagnóstico

wp sync status

Visão geral: ambiente efetivo, política da matriz, versão do schema, contagens por status na state table, HEAD do repo × último HEAD aplicado. Exit 0 sempre (observação pura).

docker compose exec -T wordpress wp sync status

wp sync verify

Recalcula os hashes dos dois lados e compara com a state table. Relatório por entidade (ok, drift-db, drift-file, orphan, pending_ref, conflict, missing_binary, oversized-untracked) + seções agregadas (tree-hash por tipo, drift externo de otimizadores, sonda PHP-off de uploads). É o comando de monitoramento em prod e o gate de CI/pós-deploy.

Flag Descrição Default
--deep Re-hash dos blobs binários (única varredura de disco em massa — uso sob demanda explícita) off
--format=json Saída estruturada off

Exit: ≠ 0 em qualquer divergência (apto para CI). Sonda PHP-off: FAIL → exit ≠ 0; INDETERMINATE → warning, exit 0 (nunca trava operação por não-verificabilidade).

docker compose exec -T wordpress wp sync verify

wp sync log [--last=50]

Audit trail recente: entidade, direção, gatilho, actor, resultado, arquivo, hash antes/depois. Exit 0 sempre.

docker compose exec -T wordpress wp sync log --last=20

wp sync blame <entidade> [--last=20]

Responde "por que esta página mudou?": últimas aplicações da entidade, com gatilho, arquivo e hashes. <entidade> = post_type:slug | kind:post_type:key | uuid. Exit 0 sempre.

docker compose exec -T wordpress wp sync blame page:home

Conflitos

wp sync conflicts

Lista os conflitos pendentes (entidade, lado perdedor, vencedor, gatilho, actor, HEAD do git). Exit 0.

wp sync conflict show <id> [--out=<path>]

Despeja o payload preservado do lado perdedor de um conflito — na tela ou em arquivo (--out). Exit 1 se o id não existir.

wp sync resolve <entidade> --keep=db|file [--force]

Resolução manual: aplica o vencedor escolhido e fecha administrativamente os conflitos pendentes da entidade. --keep=db re-exporta a partir do banco (lossless; o working tree diverge do HEAD — commit depois); --keep=file importa o arquivo (sempre cria revisions). Mutação: prod exige triplo fator.

docker compose exec -T wordpress wp sync conflicts
docker compose exec -T wordpress wp sync conflict show 3
docker compose exec -T wordpress wp sync resolve page:home --keep=db

wp sync conflicts prune [--older-than=90d] [--all-resolved]

Housekeeping da tabela de conflitos: remove registros já resolvidos mais antigos que o cutoff (90d default; --all-resolved remove todos os resolvidos). Exit 0.

Manutenção

wp sync rebase --from=db|files

Recalcula a state table sem aplicar mudanças (não importa nem exporta) — re-alinha os hashes observados do lado escolhido à realidade. Caso de uso: após rename de tema (o global styles namespaced pelo stylesheet antigo vira órfão). Divergências resultantes aparecem no plan/verify seguintes. Exit 0/1.

wp sync restore <timestamp> [--force]

Re-aplica um snapshot pré-apply (rede de segurança): reimporta o estado preservado em uploads/cvsync-backups/<ts>/ e re-materializa binários ausentes (aditivo — nunca sobrescreve byte alheio). Sem argumento, lista os snapshots disponíveis. Mutação: prod exige triplo fator. Exit 1 se o snapshot não existir.

docker compose exec -T wordpress wp sync restore 20260804-133000

wp sync purge-revisions [--older-than=90d]

Contenção de volume de revisions (o import sempre cria revisions; a contenção é purge documentado, nunca supressão). Nunca remove a revision mais recente de cada post nem toca posts que não são revisions. Exit 0 sempre (falhas individuais são warnings).

wp sync attachments gc (--blobs|--files) [--execute] [--older-than=90d]

Os dois coletores de lixo de mídia, dry-run por default (--execute aplica):

  • --blobs — GC do repo: blob sem sidecar referenciando e sem linha não-tombstone na state. A remoção efetiva é commit humano em PR próprio (chore(media): gc) — o plugin lista, nunca commita;
  • --files — GC físico de uploads: arquivo sem _wp_attached_file correspondente (o guard cruzado inclui thumbnails e originais -scaled via _wp_attachment_metadata; nunca varre uploads/cvsync-backups/**).

Em prod, recomenda-se --older-than=180d. Exit 0.

docker compose exec -T wordpress wp sync attachments gc --files             # dry-run
docker compose exec -T wordpress wp sync attachments gc --files --execute --older-than=180d

Setup

wp sync install-hooks

Aponta o git para os hooks versionados (git config core.hooksPath .githooks). É o único comando que invoca o binário git (permitido em SAPI CLI; o runtime web nunca roda git). Exit 1 se não houver .git (artefato deployado) ou .githooks/.

docker compose exec -T wordpress wp sync install-hooks

Fluxos comuns

1. Primeiro uso (repo já tem conteúdo versionado):

docker compose exec -T wordpress wp sync install-hooks
docker compose exec -T wordpress wp sync bootstrap        # importa o repo, cria a state
docker compose exec -T wordpress wp sync status           # confere o resultado

2. Puxei código do colega (git pull trouxe content/** novo):

# O hook post-merge já tenta o apply automaticamente. Para conferir/reenviar:
docker compose exec -T wordpress wp sync plan
docker compose exec -T wordpress wp sync apply

3. Apareceu conflito, e agora?

docker compose exec -T wordpress wp sync conflicts                 # o que está pendente
docker compose exec -T wordpress wp sync conflict show <id>        # vê o lado perdedor
docker compose exec -T wordpress wp sync resolve page:home --keep=db   # escolhe o vencedor
# --keep=db: re-exporta do banco → git add content/... && git commit (o tree diverge do HEAD)

4. Capturar mídia de produção para o repo (FS de prod é imutável):

# No servidor de prod (export é livre, read-only no banco):
wp sync export --post-type=attachment --scope=all --out=/tmp/cvsync-capture
# Copia /tmp/cvsync-capture para a estação, merge no content/ do repo, PR com review.

5. Verify em CI / pós-deploy:

# CI: o repo deve estar em sincronia com o banco de homolog
wp sync verify --format=json          # exit ≠ 0 falha o pipeline
# Gate de idempotência: export não pode gerar diff
wp sync export --check                # exit 1 se geraria diff

Observabilidade

  • Audit log (wp_cvsync_log), conflitos (wp_cvsync_conflicts) e estado (wp_cvsync_state).
  • Admin: metabox de origem na tela de edição, notices (drift em prod, conflitos em homolog, sonda PHP-off, constantes inválidas) e Ferramentas > CVSync (log + conflitos).
  • Hooks para notificação: cvsync_applied, cvsync_failed, cvsync_conflict_registered, cvsync_files_materialized.

About

Sincronização bidirecional entre o conteúdo Gutenberg no banco de dados e arquivos versionáveis

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages