--- id: KB-PLUGIN-031 title: "Runbook — Workflow de desenvolvimento e deploy DEV de plugins GLPI" domain: plugin-dev tags: - runbook - workflow - dev - deploy - forgejo - scaffold - validation - console status: active severity: high created_at: 2026-06-11 updated_at: 2026-06-11 applies_to: - GLPI 11.x no ambiente dev (CT 100 docker, stack GLPI11) - qualquer plugin novo desenvolvido internamente related_records: - KB-INFRA-001 - KB-INFRA-002 - KB-PLUGIN-001 - KB-PLUGIN-004 - KB-PLUGIN-013 - KB-PLUGIN-018 - KB-PLUGIN-027 --- # Runbook — Workflow de desenvolvimento e deploy DEV de plugins GLPI Procedimento padrão do nascimento de um plugin até sua validação no GLPI de desenvolvimento. A **publicação em produção** (Mindplace/licenciamento) é outro processo — ver [KB-PLUGIN-013](KB-PLUGIN-013-mindplace-plugin-publication-runbook.md). Primeiro plugin a seguir este fluxo de ponta a ponta: `assetinherit` (2026-06-11). ## Mapa do ambiente | Componente | Onde | |---|---| | Servidor dev (docker) | CT 100 — `root@192.168.100.49` (SSH key do Mac já cadastrada) | | Diretório de plugins | `/opt/projects/GLPI11/docker/glpi/plugins/` (bind → `/var/www/glpi/plugins`, ver [KB-INFRA-001]) | | Container GLPI | `glpi11-app` (GLPI dev em `http://192.168.100.49:8081`) | | Git de dev | Forgejo local — `git@192.168.100.101:administrador/.git` (remote `origin`) | | Git de produção | Forgejo Mindtek — remote `production`, usado **só** na publicação | ## Fase 1 — Scaffold do plugin Estrutura mínima obrigatória (a chave/diretório do plugin define TUDO — funções, hooks, constantes): ``` / ├── setup.php # plugin_init_, plugin_version_ + 4 callbacks ├── hook.php # install/uninstall e demais hooks ├── logo.png # PNG 128x128 na raiz — obrigatório [KB-INFRA-002] ├── README.md # dor que resolve, como funciona, instalação, configuração ├── CHANGELOG.md # Keep a Changelog ├── LICENSE # GPL-3.0-or-later (compatível com o GLPI) └── .gitignore # padrão de plugins [KB-PLUGIN-013] ``` Checklist de armadilhas conhecidas: - [ ] `setup.php` com os **4 callbacks**: `check_prerequisites`, `check_config`, `install`, `uninstall` — sem eles a instalação falha genericamente ([KB-PLUGIN-001]). - [ ] Toda chave em `$PLUGIN_HOOKS[...]['']` é o **plugin key exato** (= nome do diretório). Variações falham em silêncio ([KB-PLUGIN-004]). - [ ] `logo.png` é PNG real (SVG renomeado não funciona) ([KB-INFRA-002]). - [ ] `version` no `setup.php` em SemVer — o release de produção lê de lá. ## Fase 2 — Repositório no Forgejo local Criar o repo via API (ou UI em `http://192.168.100.101:3000`): ```bash curl -s -u 'administrador:' -X POST \ http://192.168.100.101:3000/api/v1/user/repos \ -H 'Content-Type: application/json' \ -d '{"name":"","private":true,"default_branch":"main"}' ``` No diretório do plugin (na máquina de dev): ```bash git init && git branch -M main git add -A && git commit -m " 0.1.0: scaffold" git remote add origin git@192.168.100.101:administrador/.git git push -u origin main ``` Convenção de remotes: `origin` = Forgejo local (push contínuo de dev); `production` = Forgejo Mindtek (adicionado apenas na publicação, [KB-PLUGIN-013]). ## Fase 3 — Deploy no servidor dev ```bash ssh root@192.168.100.49 cd /opt/projects/GLPI11/docker/glpi/plugins git clone git@192.168.100.101:administrador/.git git config --global --add safe.directory \ /opt/projects/GLPI11/docker/glpi/plugins/ chown -R www-data:www-data ``` O bind mount entrega o plugin no container instantaneamente — **não** precisa recriar o container. ## Fase 4 — Instalação e ativação (sempre via console) ```bash docker exec glpi11-app sh -c ' php -l /var/www/glpi/plugins//setup.php && php -l /var/www/glpi/plugins//hook.php && php /var/www/glpi/bin/console plugin:install -n --username=glpi && php /var/www/glpi/bin/console plugin:activate -n && php /var/www/glpi/bin/console plugin:list | grep ' ``` Esperado: status **Habilitado**. O console dá erros legíveis; a UI só mostra falha genérica. ## Fase 5 — Validação funcional (teste E2E em CLI) ⚠️ **Gotcha do GLPI 11:** em CLI, `include 'inc/includes.php'` **não** carrega mais o core (classes como `RuleAsset` ficam indisponíveis). O bootstrap correto para scripts de teste é o do `bin/console`: ```php require '/var/www/glpi/vendor/autoload.php'; $kernel = new \Glpi\Kernel\Kernel(); $kernel->boot(); // carrega core + plugins ativos (plugin_init roda aqui) // sessão CLI mínima para CommonDBTM::add()/update() $_SESSION['glpiactiveentities'] = [0]; $_SESSION['glpiactive_entity'] = 0; $_SESSION['glpiactiveprofile']['interface'] = 'central'; ``` Padrão do teste: criar massa de dados de teste com prefixo `TEST` → exercitar os cenários → **deletar tudo com purge no final**. Executar: ```bash scp test_.php root@192.168.100.49:/tmp/ ssh root@192.168.100.49 'docker cp /tmp/test_.php glpi11-app:/tmp/ && docker exec glpi11-app php /tmp/test_.php' ``` Exemplo real completo: teste E2E do `assetinherit` (6 cenários, incluindo descoberta de comportamento que virou documentação — critério `PATTERN_EXISTS` não casa com `users_id = 0`). ## Fase 6 — Ciclo de iteração 1. IDE no Mac → Remote SSH em `root@192.168.100.49`, pasta do plugin. 2. Editar in-place — GLPI é PHP, refresh no browser e a mudança aparece. 3. `git add . && git commit && git push` → Forgejo local (`origin`). 4. Mudanças feitas no Mac: `git push origin` no Mac + `git pull` no CT 100 (lembrar `chown -R www-data:www-data` se criar arquivos novos como root). ## Fase 7 — Promoção para produção (fora deste runbook) Quando validado no dev: seguir [KB-PLUGIN-013] (kill switch de licença, release ZIP com wrapper directory [KB-PLUGIN-018], catálogo Mindplace, serial do cliente). ## Regra para agentes Ao criar/depurar plugin novo no ambiente dev, seguir este runbook na ordem. Antes de diagnosticar erro funcional, validar Fases 3-4 (mount, ownership, instalação via console). Para testes E2E em CLI, usar SEMPRE o bootstrap do Kernel (Fase 5), nunca `inc/includes.php`. ## Classificação - Tipo: Runbook operacional de desenvolvimento. - Reutilização: obrigatória para todo plugin novo.