@codigodoleo/wp-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.cspell.json +104 -0
  2. package/.editorconfig +13 -0
  3. package/.eslintignore +3 -0
  4. package/.eslintrc.json +24 -0
  5. package/.github/workflows/publish-npm.yml +32 -0
  6. package/.github/workflows/release-please.yml +25 -0
  7. package/.gitkeep +0 -0
  8. package/.husky/_/post-merge +0 -0
  9. package/.prettierignore +4 -0
  10. package/.prettierrc +8 -0
  11. package/.vscode/settings.json +19 -0
  12. package/CHANGELOG.md +47 -0
  13. package/README.md +115 -0
  14. package/VSCODE_EXTENSIONS.md +11 -0
  15. package/bin/index.js +4 -0
  16. package/docs/HOOKS-SYSTEM.md +172 -0
  17. package/git-deploy.sh +74 -0
  18. package/index.php +17 -0
  19. package/lib/cli.js +15 -0
  20. package/lib/commands/init.js +132 -0
  21. package/lib/core/generator.js +261 -0
  22. package/lib/core/hook-manager.js +172 -0
  23. package/lib/core/infer-ci-capabilities.js +119 -0
  24. package/lib/prompts/index.js +105 -0
  25. package/lib/prompts/loadModulePrompts.js +27 -0
  26. package/lib/utils/generate-from-template.js +17 -0
  27. package/lib/utils/git.js +17 -0
  28. package/lib/utils/logger.js +28 -0
  29. package/modules/deploy/index.js +39 -0
  30. package/modules/deploy/prompts.js +27 -0
  31. package/modules/deploy/templates/.github/workflows/ci.yml.hbs +103 -0
  32. package/modules/deploy/templates/.gitlab/gitlab-ci.yml.hbs +154 -0
  33. package/modules/deploy/templates/bitbucket-pipelines.yml.hbs +97 -0
  34. package/modules/docs/index.js +3 -0
  35. package/modules/docs/prompts.js +8 -0
  36. package/modules/docs/templates/README.md.hbs +160 -0
  37. package/modules/docs/templates/docs/Arquitetura.md +399 -0
  38. package/modules/docs/templates/docs/Deploy-Pipeline.md +113 -0
  39. package/modules/docs/templates/docs/Desenvolvimento.md +1116 -0
  40. package/modules/docs/templates/docs/Getting-Started.md +493 -0
  41. package/modules/docs/templates/docs/Infraestrutura.md +211 -0
  42. package/modules/docs/templates/docs/Monitoramento.md +302 -0
  43. package/modules/docs/templates/docs/Sync-the-Production-DB-with-the-Staging-DB.md +8 -0
  44. package/modules/docs/templates/docs/Troubleshooting.md +3 -0
  45. package/modules/git/.commitlintrc.json +136 -0
  46. package/modules/git/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  47. package/modules/git/.gitlab/merge_request_templates/default.md +42 -0
  48. package/modules/git/.gitmessage +29 -0
  49. package/modules/git/.husky/commit-msg +4 -0
  50. package/modules/git/.husky/pre-commit +27 -0
  51. package/modules/git/.lintstagedrc.json +7 -0
  52. package/modules/git/.vscode/commit-instructions.md +59 -0
  53. package/modules/git/.vscode/conventional-commits.code-snippets +62 -0
  54. package/modules/git/.vscode/copilot.json +39 -0
  55. package/modules/git/docs/CONVENTIONAL-COMMITS.md +131 -0
  56. package/modules/git/index.js +137 -0
  57. package/modules/git/prompts.js +23 -0
  58. package/modules/git/templates/.lando.yml.hbs +13 -0
  59. package/modules/git/templates/package.json.hbs +15 -0
  60. package/modules/git/templates/workspace.json.hbs +114 -0
  61. package/modules/lint/.eslintignore +36 -0
  62. package/modules/lint/.eslintrc.json +8 -0
  63. package/modules/lint/.prettierignore +36 -0
  64. package/modules/lint/.prettierrc.json +29 -0
  65. package/modules/lint/.stylelintignore +19 -0
  66. package/modules/lint/.stylelintrc.json +9 -0
  67. package/modules/lint/index.js +15 -0
  68. package/modules/lint/pint.json +26 -0
  69. package/modules/lint/prompts.js +16 -0
  70. package/modules/lint/templates/.lando.yml.hbs +10 -0
  71. package/modules/lint/templates/package.json.hbs +16 -0
  72. package/modules/lint/templates/workspace.json.hbs +56 -0
  73. package/modules/php/index.js +3 -0
  74. package/modules/php/prompts.js +8 -0
  75. package/modules/php/scripts/php-wrapper.sh +38 -0
  76. package/modules/php/scripts/pint-wrapper.sh +44 -0
  77. package/modules/php/templates/.lando.yml.hbs +11 -0
  78. package/modules/php/templates/composer.json.hbs +6 -0
  79. package/modules/php/templates/workspace.json.hbs +74 -0
  80. package/modules/redis/prompts.js +8 -0
  81. package/modules/redis/templates/.lando.yml.hbs +8 -0
  82. package/modules/sage/index.js +20 -0
  83. package/modules/sage/prompts.js +16 -0
  84. package/modules/sage/templates/.lando.yml.hbs +64 -0
  85. package/modules/sage/templates/theme/composer.json.hbs +18 -0
  86. package/modules/sage/templates/theme/package.json.hbs +11 -0
  87. package/modules/sage/templates/theme/style.css.hbs +13 -0
  88. package/modules/sage/templates/theme/vite.config.js.hbs +53 -0
  89. package/modules/sage/templates/workspace.json.hbs +67 -0
  90. package/modules/test-directory/assets/module-file.txt +1 -0
  91. package/modules/test-directory/index.js +19 -0
  92. package/modules/test-directory/prompts.js +8 -0
  93. package/modules/test-directory/test-assets/file1.txt +1 -0
  94. package/modules/test-directory/test-assets/file2.txt +1 -0
  95. package/modules/test-directory/test-assets/subfolder/config.json +4 -0
  96. package/package.json +54 -0
  97. package/release-please-config.json +17 -0
  98. package/server/php/php.ini +48 -0
  99. package/server/www/rocket.conf +283 -0
  100. package/templates/.editorconfig.hbs +39 -0
  101. package/templates/.env.hbs +48 -0
  102. package/templates/.gitignore.hbs +86 -0
  103. package/templates/.lando.yml.hbs +44 -0
  104. package/templates/README.md.hbs +12 -0
  105. package/templates/composer.json.hbs +60 -0
  106. package/templates/package.json.hbs +47 -0
  107. package/templates/server/cmd/install-wp.sh.hbs +58 -0
  108. package/templates/server/www/vhosts.conf.hbs +71 -0
  109. package/templates/workspace.json.hbs +177 -0
  110. package/test-copy-directory.js +43 -0
  111. package/test-overwrite.js +45 -0
  112. package/wp-config.php +190 -0
@@ -0,0 +1,119 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+
4
+ function fileExists(filePath) {
5
+ try {
6
+ return fs.pathExistsSync(filePath);
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
11
+
12
+ function detectThemePaths(context, hasSage) {
13
+ const projectName = context.projectName;
14
+ const candidates = [
15
+ path.join(context.cwd, 'content', 'themes', projectName),
16
+ path.join(context.cwd, 'web', 'app', 'themes', projectName),
17
+ path.join(context.cwd, 'wp-content', 'themes', projectName)
18
+ ];
19
+
20
+ for (const abs of candidates) {
21
+ if (fileExists(abs)) {
22
+ const rel = path.relative(context.cwd, abs);
23
+ return {
24
+ themeRootAbs: abs,
25
+ themeRoot: rel,
26
+ packageJson: path.join(abs, 'package.json'),
27
+ composerJson: path.join(abs, 'composer.json'),
28
+ // Bud/Sage pode gerar em public/ ou dist/
29
+ distCandidates: [
30
+ path.join(rel, 'public'),
31
+ path.join(rel, 'dist')
32
+ ]
33
+ };
34
+ }
35
+ }
36
+
37
+ // Se Sage estiver habilitado, assumir caminho preferencial mesmo antes de existir
38
+ if (hasSage && projectName) {
39
+ const abs = path.join(context.cwd, 'content', 'themes', projectName);
40
+ const rel = path.relative(context.cwd, abs);
41
+ return {
42
+ themeRootAbs: abs,
43
+ themeRoot: rel,
44
+ packageJson: path.join(abs, 'package.json'),
45
+ composerJson: path.join(abs, 'composer.json'),
46
+ distCandidates: [
47
+ path.join(rel, 'public'),
48
+ path.join(rel, 'dist')
49
+ ]
50
+ };
51
+ }
52
+
53
+ return {
54
+ themeRootAbs: null,
55
+ themeRoot: null,
56
+ packageJson: null,
57
+ composerJson: null,
58
+ distCandidates: []
59
+ };
60
+ }
61
+
62
+ export function inferCiCapabilities(context) {
63
+ const hasSage = Boolean(context.enable_sage || context.useSage);
64
+ const theme = detectThemePaths(context, hasSage);
65
+
66
+ const rootComposer = path.join(context.cwd, 'composer.json');
67
+ const rootPackage = path.join(context.cwd, 'package.json');
68
+ const existsRootComposer = fileExists(rootComposer);
69
+ const existsThemeComposer = Boolean(theme.composerJson && fileExists(theme.composerJson));
70
+ const existsRootPackage = fileExists(rootPackage);
71
+ const existsThemePackage = Boolean(theme.packageJson && fileExists(theme.packageJson));
72
+
73
+ const hasComposer = Boolean(
74
+ existsRootComposer || existsThemeComposer || hasSage
75
+ );
76
+
77
+ const hasNode = Boolean(
78
+ existsRootPackage || existsThemePackage || hasSage
79
+ );
80
+
81
+ let nodeVersion = context.nodeVersion;
82
+ if (!nodeVersion) {
83
+ if (hasSage && context.sageVersion === '11') {
84
+ nodeVersion = '23';
85
+ } else {
86
+ nodeVersion = '18';
87
+ }
88
+ }
89
+
90
+ const ci = {
91
+ build: {
92
+ composer: hasComposer,
93
+ node: hasNode,
94
+ sage: hasSage
95
+ },
96
+ deploy: {
97
+ docker: context.deploy_strategy === 'docker'
98
+ },
99
+ nodeVersion,
100
+ theme: {
101
+ paths: theme
102
+ },
103
+ detect: {
104
+ existsRootComposer,
105
+ existsThemeComposer,
106
+ existsRootPackage,
107
+ existsThemePackage,
108
+ themeRootExists: Boolean(theme.themeRootAbs && fileExists(theme.themeRootAbs))
109
+ },
110
+ cache: {
111
+ packageGlobs: ['**/package.json'],
112
+ composerGlobs: ['**/composer.json']
113
+ }
114
+ };
115
+
116
+ return ci;
117
+ }
118
+
119
+
@@ -0,0 +1,105 @@
1
+ // lib/prompts/index.js
2
+ import inquirer from 'inquirer';
3
+ import { getGitUserDefaults } from '../utils/git.js';
4
+ import { loadModulePrompts } from './loadModulePrompts.js';
5
+ import { Generator } from '../core/generator.js';
6
+
7
+ export async function runPrompts({ defaults = false } = {}) {
8
+ const defaultsGit = getGitUserDefaults();
9
+
10
+ const corePrompts = [
11
+ {
12
+ type: 'input',
13
+ name: 'projectName',
14
+ message: 'Project name:',
15
+ default: 'wordpress-dev'
16
+ },
17
+ {
18
+ type: 'input',
19
+ name: 'projectDescription',
20
+ message: 'Project description:',
21
+ default: 'Generated with wp-devops'
22
+ },
23
+ {
24
+ type: 'input',
25
+ name: 'projectVersion',
26
+ message: 'Project version:',
27
+ default: '1.0.0'
28
+ },
29
+ {
30
+ type: 'input',
31
+ name: 'author',
32
+ message: 'Author:',
33
+ default: defaultsGit.author
34
+ },
35
+ {
36
+ type: 'input',
37
+ name: 'authorEmail',
38
+ message: 'Author email:',
39
+ default: defaultsGit.authorEmail
40
+ },
41
+ {
42
+ type: 'input',
43
+ name: 'gitRepository',
44
+ message: 'Repository URL:',
45
+ default: defaultsGit.gitRepository
46
+ },
47
+ {
48
+ type: 'list',
49
+ name: 'phpVersion',
50
+ message: 'PHP version:',
51
+ choices: ['8.3', '8.2', '8.1', '7.4'],
52
+ default: '8.3'
53
+ },
54
+ {
55
+ type: 'list',
56
+ name: 'nodeVersion',
57
+ message: 'Node.js version:',
58
+ choices: ['22', '21', '20', '18', '16'],
59
+ default: '22'
60
+ },
61
+ {
62
+ type: 'list',
63
+ name: 'wpCoreVersion',
64
+ message: 'WordPress core version:',
65
+ choices: ['6.8.1', '6.7', '6.6', '6.5', '6.0'],
66
+ default: '6.8.1'
67
+ },
68
+ {
69
+ type: 'confirm',
70
+ name: 'useRocket',
71
+ message: 'Use WP Rocket?',
72
+ default: true
73
+ },
74
+ {
75
+ type: 'confirm',
76
+ name: 'enableDebug',
77
+ message: 'Enable debug mode?',
78
+ default: false
79
+ }
80
+ ];
81
+
82
+ const modulePromptDefs = await loadModulePrompts();
83
+ const modulePrompts = Object.values(modulePromptDefs).flat();
84
+ const allPrompts = [...corePrompts, ...modulePrompts];
85
+
86
+ if (defaults) {
87
+ const defaultAnswers = { };
88
+ for (const prompt of allPrompts) {
89
+ if (prompt.when && !prompt.when(defaultAnswers)) continue;
90
+ const def = prompt.default;
91
+ defaultAnswers[prompt.name] = typeof def === 'function' ? def() : def;
92
+ }
93
+ const enabledModules = Object.keys(modulePromptDefs).filter(
94
+ (mod) => defaultAnswers[`enable_${mod}`] === true
95
+ );
96
+ return { ...defaultAnswers, enabledModules, projectDomain: `${defaultAnswers.projectName}.lndo.site`, salts: Generator.generateSalts() };
97
+ }
98
+
99
+ const answers = await inquirer.prompt(allPrompts);
100
+
101
+ const enabledModules = Object.keys(modulePromptDefs).filter(
102
+ (mod) => answers[`enable_${mod}`] === true
103
+ );
104
+ return { ...answers, enabledModules, projectDomain: `${answers.projectName}.lndo.site`, salts: Generator.generateSalts() };
105
+ }
@@ -0,0 +1,27 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export async function loadModulePrompts(modulesDir = 'modules') {
5
+ const modules = await fs.readdir(modulesDir);
6
+ const promptsMap = {};
7
+
8
+ for (const name of modules) {
9
+ const promptPath = path.join(modulesDir, name, 'prompts.js');
10
+ if (await fs.pathExists(promptPath)) {
11
+ const { default: prompts } = await import(path.resolve(promptPath));
12
+ promptsMap[name] = Array.isArray(prompts) ? prompts : await prompts();
13
+ } else {
14
+ // basic fallback: just ask if you want to enable the module
15
+ promptsMap[name] = [
16
+ {
17
+ type: 'confirm',
18
+ name: `enable_${name}`,
19
+ message: `Enable ${name} module?`,
20
+ default: false,
21
+ }
22
+ ];
23
+ }
24
+ }
25
+
26
+ return promptsMap;
27
+ }
@@ -0,0 +1,17 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { fileURLToPath } from 'url';
4
+ import handlebars from 'handlebars';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ export async function generateFromTemplate(templateName, outputPath, context) {
9
+ const templateDir = path.resolve(__dirname, '../../templates/base');
10
+ const templateFile = path.join(templateDir, `${templateName}.hbs`);
11
+
12
+ const raw = await fs.readFile(templateFile, 'utf-8');
13
+ const compiled = handlebars.compile(raw);
14
+ const content = compiled(context);
15
+
16
+ await fs.writeFile(outputPath, content, 'utf-8');
17
+ }
@@ -0,0 +1,17 @@
1
+ import { execSync } from 'child_process';
2
+
3
+ export function getGitUserDefaults() {
4
+ const exec = (cmd) => {
5
+ try {
6
+ return execSync(cmd).toString().trim();
7
+ } catch {
8
+ return '';
9
+ }
10
+ };
11
+
12
+ return {
13
+ author: exec('git config --get user.name') || 'Developer',
14
+ authorEmail: exec('git config --get user.email') || 'developer@example.com',
15
+ gitRepository: exec('git config --get remote.origin.url') || '',
16
+ };
17
+ }
@@ -0,0 +1,28 @@
1
+ import chalk from 'chalk';
2
+
3
+ export const color = {
4
+ blue: chalk.cyan,
5
+ green: chalk.green,
6
+ yellow: chalk.yellow,
7
+ red: chalk.red,
8
+ magenta: chalk.magenta,
9
+ orange: chalk.hex('#FFA500'),
10
+ gray: chalk.gray,
11
+ bold: chalk.bold,
12
+ underline: chalk.underline,
13
+ success: chalk.green,
14
+ error: chalk.red,
15
+ warning: chalk.yellow,
16
+ info: chalk.blue,
17
+ debug: chalk.hex('#FFA500'),
18
+ };
19
+
20
+ /**
21
+ * Prints a formatted message with prefix [wp-devops] and optional color
22
+ * @param {Function} colorFn - Chalk color function (e.g. color.green)
23
+ * @param {string} message - The message to print
24
+ */
25
+ export function log(colorFn, message) {
26
+ const prefix = chalk.bold.gray('[leo-wp]');
27
+ console.log(`${prefix} ${colorFn(message)}`);
28
+ }
@@ -0,0 +1,39 @@
1
+ import { log, color } from '../../lib/utils/logger.js';
2
+
3
+ export async function setupModule(context, generator) {
4
+ if (!context.enable_deploy) {
5
+ log(color.orange, '[deploy] Deploy desabilitado. Nenhuma ação será executada.');
6
+ return;
7
+ }
8
+
9
+ log(color.blue, '[deploy] Gerando pipeline de CI baseado em context.ci');
10
+
11
+ try {
12
+ if (context.gitProvider === 'gitlab') {
13
+ await generator.generateFile('.gitlab/gitlab-ci.yml', context, 'deploy', '.gitlab-ci.yml');
14
+ log(color.green, '[deploy] .gitlab-ci.yml gerado com sucesso.');
15
+ }
16
+ if (context.gitProvider === 'github') {
17
+ await generator.generateFile('.github/workflows/ci.yml', context, 'deploy', '.github/workflows/ci.yml');
18
+ log(color.green, '[deploy] GitHub Actions workflow gerado com sucesso.');
19
+ }
20
+ if (context.gitProvider === 'bitbucket') {
21
+ await generator.generateFile('bitbucket-pipelines.yml', context, 'deploy', 'bitbucket-pipelines.yml');
22
+ log(color.green, '[deploy] Bitbucket Pipelines gerado com sucesso.');
23
+ }
24
+ // Avisos inteligentes
25
+ if (context.ci) {
26
+ if (context.ci.build.composer && !context.ci.detect.existsRootComposer && !context.ci.detect.existsThemeComposer) {
27
+ log(color.orange, '[deploy] Aviso: Build de Composer habilitado, mas nenhum composer.json encontrado.');
28
+ }
29
+ if (context.ci.build.node && !context.ci.detect.existsRootPackage && !context.ci.detect.existsThemePackage) {
30
+ log(color.orange, '[deploy] Aviso: Build de Node habilitado, mas nenhum package.json encontrado.');
31
+ }
32
+ if (context.ci.build.sage && !context.ci.detect.themeRootExists) {
33
+ log(color.orange, '[deploy] Aviso: Sage habilitado, mas diretório do tema não foi encontrado.');
34
+ }
35
+ }
36
+ } catch (err) {
37
+ log(color.red, `[deploy] Falha ao gerar pipeline: ${err.message}`);
38
+ }
39
+ }
@@ -0,0 +1,27 @@
1
+ export default [
2
+ {
3
+ type: 'confirm',
4
+ name: 'enable_deploy',
5
+ message: 'Habilitar Pipelines de CI/CD?',
6
+ default: true
7
+ },
8
+ {
9
+ type: 'list',
10
+ name: 'deploy_strategy',
11
+ message: 'Qual estratégia de deploy você prefere?',
12
+ choices: [
13
+ {
14
+ name: 'Docker',
15
+ value: 'docker'
16
+ },
17
+ {
18
+ name: 'SSH',
19
+ value: 'ssh',
20
+ disabled: true,
21
+ description: 'Em breve'
22
+ }
23
+ ],
24
+ default: 'docker',
25
+ when: (answers) => answers.enable_deploy,
26
+ }
27
+ ];
@@ -0,0 +1,103 @@
1
+ # 🚀 WordPress CI (GitHub Actions)
2
+
3
+ name: CI
4
+
5
+ on:
6
+ push:
7
+ branches: [ main, develop, staging ]
8
+ pull_request:
9
+ branches: [ main, develop, staging ]
10
+
11
+ jobs:
12
+ build-basic:
13
+ name: Build basic
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+ - name: Setup Node
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: ${{ '{{' }} env.NODE_VERSION {{ '}}' }}
22
+ - name: Install deps (if present)
23
+ run: |
24
+ if [ -f package.json ]; then npm ci; fi
25
+
26
+ {{#if ci.build.composer}}
27
+ build-composer:
28
+ name: Build Composer
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - name: Checkout
32
+ uses: actions/checkout@v4
33
+ - name: Setup PHP
34
+ uses: shivammathur/setup-php@v2
35
+ with:
36
+ php-version: ${{ '{{' }} env.PHP_VERSION {{ '}}' }}
37
+ - name: Install Composer deps
38
+ run: |
39
+ if [ -f composer.json ]; then composer install --no-dev --optimize-autoloader; fi
40
+ {{/if}}
41
+
42
+ {{#if ci.build.sage}}
43
+ build-sage:
44
+ name: Build Sage Theme
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - name: Checkout
48
+ uses: actions/checkout@v4
49
+ - name: Setup Node
50
+ uses: actions/setup-node@v4
51
+ with:
52
+ node-version: ${{ '{{' }} env.NODE_VERSION {{ '}}' }}
53
+ - name: Build theme
54
+ run: |
55
+ THEME="{{ci.theme.paths.themeRoot}}"
56
+ if [ -d "$THEME" ]; then
57
+ cd "$THEME"
58
+ if [ -f package.json ]; then npm ci; fi
59
+ if [ -f yarn.lock ]; then yarn install --frozen-lockfile; fi
60
+ if [ -f package.json ]; then npm run build || yarn build; fi
61
+ else
62
+ echo "Tema não encontrado em $THEME — pulando build do tema"
63
+ fi
64
+ {{/if}}
65
+
66
+ test-basic:
67
+ name: Tests
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - name: Checkout
71
+ uses: actions/checkout@v4
72
+ - name: Setup Node
73
+ uses: actions/setup-node@v4
74
+ with:
75
+ node-version: ${{ '{{' }} env.NODE_VERSION {{ '}}' }}
76
+ - name: Run basic tests
77
+ run: echo "No tests yet"
78
+
79
+ {{#if ci.deploy.docker}}
80
+ deploy-docker:
81
+ if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging'
82
+ name: Deploy Docker
83
+ runs-on: ubuntu-latest
84
+ steps:
85
+ - name: Checkout
86
+ uses: actions/checkout@v4
87
+ - name: Set up Docker Buildx
88
+ uses: docker/setup-buildx-action@v3
89
+ - name: Login to GHCR
90
+ uses: docker/login-action@v3
91
+ with:
92
+ registry: ghcr.io
93
+ username: ${{ '{{' }} github.actor {{ '}}' }}
94
+ password: ${{ '{{' }} secrets.GITHUB_TOKEN {{ '}}' }}
95
+ - name: Build (placeholder)
96
+ run: echo "Deploy Docker"
97
+ {{/if}}
98
+
99
+ env:
100
+ PHP_VERSION: "{{phpVersion}}"
101
+ NODE_VERSION: "{{ci.nodeVersion}}"
102
+ WORDPRESS_VERSION: "{{wpCoreVersion}}"
103
+ PROJECT_NAME: "{{projectName}}"
@@ -0,0 +1,154 @@
1
+ # 🚀 WordPress CI/CD Pipeline (dinâmico)
2
+
3
+ variables:
4
+ PHP_VERSION: "{{phpVersion}}"
5
+ WORDPRESS_VERSION: "{{wpCoreVersion}}"
6
+ PROJECT_NAME: "{{projectName}}"
7
+ NODE_VERSION: "{{ci.nodeVersion}}"
8
+
9
+ workflow:
10
+ rules:
11
+ - if: $CI_COMMIT_BRANCH == "main"
12
+ variables:
13
+ ENVIRONMENT: "production"
14
+ when: always
15
+ - if: $CI_COMMIT_BRANCH == "staging"
16
+ variables:
17
+ ENVIRONMENT: "staging"
18
+ when: always
19
+ - if: $CI_COMMIT_BRANCH == "develop"
20
+ variables:
21
+ ENVIRONMENT: "development"
22
+ when: always
23
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
24
+ when: always
25
+ - when: never
26
+
27
+ stages:
28
+ - build
29
+ - test
30
+ - deploy
31
+
32
+ cache:
33
+ key:
34
+ files:
35
+ {{#each ci.cache.packageGlobs}}
36
+ - {{this}}
37
+ {{/each}}
38
+ {{#each ci.cache.composerGlobs}}
39
+ - {{this}}
40
+ {{/each}}
41
+ paths:
42
+ - **/node_modules/
43
+ - **/vendor/
44
+
45
+ default:
46
+ interruptible: true
47
+ retry:
48
+ max: 1
49
+ when:
50
+ - runner_system_failure
51
+ - stuck_or_timeout_failure
52
+
53
+ # ===== BUILD =====
54
+
55
+ build:basic:
56
+ stage: build
57
+ image: node:{{ci.nodeVersion}}-alpine
58
+ before_script:
59
+ - apk add --no-cache git
60
+ script:
61
+ - echo "🚀 Build básico"
62
+ - if [ -f package.json ]; then npm ci --cache .npm --prefer-offline; fi
63
+ artifacts:
64
+ paths:
65
+ - **/node_modules/
66
+ expire_in: 1 hour
67
+ rules:
68
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
69
+ - if: $CI_COMMIT_BRANCH == "main"
70
+ - if: $CI_COMMIT_BRANCH == "staging"
71
+ - if: $CI_COMMIT_BRANCH == "develop"
72
+
73
+ {{#if ci.build.composer}}
74
+ build:composer:
75
+ stage: build
76
+ image: composer:latest
77
+ before_script:
78
+ - apk add --no-cache git
79
+ script:
80
+ - echo "📦 Composer install"
81
+ - if [ -f composer.json ]; then composer install --no-dev --optimize-autoloader; fi
82
+ artifacts:
83
+ paths:
84
+ - **/vendor/
85
+ expire_in: 1 hour
86
+ rules:
87
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
88
+ - if: $CI_COMMIT_BRANCH == "main"
89
+ - if: $CI_COMMIT_BRANCH == "staging"
90
+ - if: $CI_COMMIT_BRANCH == "develop"
91
+ {{/if}}
92
+
93
+ {{#if ci.build.sage}}
94
+ build:sage:
95
+ stage: build
96
+ image: node:{{ci.nodeVersion}}-alpine
97
+ before_script:
98
+ - apk add --no-cache git
99
+ script:
100
+ - echo "🎨 Build do tema Sage"
101
+ - |
102
+ THEME="{{ci.theme.paths.themeRoot}}"
103
+ if [ -d "$THEME" ]; then
104
+ cd "$THEME"
105
+ if [ -f package.json ]; then npm ci --cache .npm --prefer-offline; fi
106
+ if [ -f yarn.lock ]; then yarn install --frozen-lockfile; fi
107
+ if [ -f package.json ]; then npm run build || yarn build; fi
108
+ else
109
+ echo "Tema não encontrado em $THEME — pulando build do tema"
110
+ fi
111
+ artifacts:
112
+ paths:
113
+ - {{ci.theme.paths.themeRoot}}/public/
114
+ - {{ci.theme.paths.themeRoot}}/dist/
115
+ when: always
116
+ expire_in: 1 day
117
+ rules:
118
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
119
+ - if: $CI_COMMIT_BRANCH == "main"
120
+ - if: $CI_COMMIT_BRANCH == "staging"
121
+ - if: $CI_COMMIT_BRANCH == "develop"
122
+ {{/if}}
123
+
124
+ # ===== TEST =====
125
+
126
+ test:basic:
127
+ stage: test
128
+ image: node:{{ci.nodeVersion}}-alpine
129
+ script:
130
+ - echo "🧪 Testes básicos"
131
+ rules:
132
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
133
+ - if: $CI_COMMIT_BRANCH == "main"
134
+ - if: $CI_COMMIT_BRANCH == "staging"
135
+ - if: $CI_COMMIT_BRANCH == "develop"
136
+
137
+ # ===== DEPLOY =====
138
+
139
+ {{#if ci.deploy.docker}}
140
+ deploy:docker:
141
+ stage: deploy
142
+ image: docker:latest
143
+ services:
144
+ - docker:dind
145
+ before_script:
146
+ - docker info
147
+ script:
148
+ - echo "🐳 Deploy Docker (placeholder)"
149
+ rules:
150
+ - if: $CI_COMMIT_BRANCH == "main"
151
+ - if: $CI_COMMIT_BRANCH == "staging"
152
+ {{/if}}
153
+
154
+