@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.
- package/.cspell.json +104 -0
- package/.editorconfig +13 -0
- package/.eslintignore +3 -0
- package/.eslintrc.json +24 -0
- package/.github/workflows/publish-npm.yml +32 -0
- package/.github/workflows/release-please.yml +25 -0
- package/.gitkeep +0 -0
- package/.husky/_/post-merge +0 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/.vscode/settings.json +19 -0
- package/CHANGELOG.md +47 -0
- package/README.md +115 -0
- package/VSCODE_EXTENSIONS.md +11 -0
- package/bin/index.js +4 -0
- package/docs/HOOKS-SYSTEM.md +172 -0
- package/git-deploy.sh +74 -0
- package/index.php +17 -0
- package/lib/cli.js +15 -0
- package/lib/commands/init.js +132 -0
- package/lib/core/generator.js +261 -0
- package/lib/core/hook-manager.js +172 -0
- package/lib/core/infer-ci-capabilities.js +119 -0
- package/lib/prompts/index.js +105 -0
- package/lib/prompts/loadModulePrompts.js +27 -0
- package/lib/utils/generate-from-template.js +17 -0
- package/lib/utils/git.js +17 -0
- package/lib/utils/logger.js +28 -0
- package/modules/deploy/index.js +39 -0
- package/modules/deploy/prompts.js +27 -0
- package/modules/deploy/templates/.github/workflows/ci.yml.hbs +103 -0
- package/modules/deploy/templates/.gitlab/gitlab-ci.yml.hbs +154 -0
- package/modules/deploy/templates/bitbucket-pipelines.yml.hbs +97 -0
- package/modules/docs/index.js +3 -0
- package/modules/docs/prompts.js +8 -0
- package/modules/docs/templates/README.md.hbs +160 -0
- package/modules/docs/templates/docs/Arquitetura.md +399 -0
- package/modules/docs/templates/docs/Deploy-Pipeline.md +113 -0
- package/modules/docs/templates/docs/Desenvolvimento.md +1116 -0
- package/modules/docs/templates/docs/Getting-Started.md +493 -0
- package/modules/docs/templates/docs/Infraestrutura.md +211 -0
- package/modules/docs/templates/docs/Monitoramento.md +302 -0
- package/modules/docs/templates/docs/Sync-the-Production-DB-with-the-Staging-DB.md +8 -0
- package/modules/docs/templates/docs/Troubleshooting.md +3 -0
- package/modules/git/.commitlintrc.json +136 -0
- package/modules/git/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/modules/git/.gitlab/merge_request_templates/default.md +42 -0
- package/modules/git/.gitmessage +29 -0
- package/modules/git/.husky/commit-msg +4 -0
- package/modules/git/.husky/pre-commit +27 -0
- package/modules/git/.lintstagedrc.json +7 -0
- package/modules/git/.vscode/commit-instructions.md +59 -0
- package/modules/git/.vscode/conventional-commits.code-snippets +62 -0
- package/modules/git/.vscode/copilot.json +39 -0
- package/modules/git/docs/CONVENTIONAL-COMMITS.md +131 -0
- package/modules/git/index.js +137 -0
- package/modules/git/prompts.js +23 -0
- package/modules/git/templates/.lando.yml.hbs +13 -0
- package/modules/git/templates/package.json.hbs +15 -0
- package/modules/git/templates/workspace.json.hbs +114 -0
- package/modules/lint/.eslintignore +36 -0
- package/modules/lint/.eslintrc.json +8 -0
- package/modules/lint/.prettierignore +36 -0
- package/modules/lint/.prettierrc.json +29 -0
- package/modules/lint/.stylelintignore +19 -0
- package/modules/lint/.stylelintrc.json +9 -0
- package/modules/lint/index.js +15 -0
- package/modules/lint/pint.json +26 -0
- package/modules/lint/prompts.js +16 -0
- package/modules/lint/templates/.lando.yml.hbs +10 -0
- package/modules/lint/templates/package.json.hbs +16 -0
- package/modules/lint/templates/workspace.json.hbs +56 -0
- package/modules/php/index.js +3 -0
- package/modules/php/prompts.js +8 -0
- package/modules/php/scripts/php-wrapper.sh +38 -0
- package/modules/php/scripts/pint-wrapper.sh +44 -0
- package/modules/php/templates/.lando.yml.hbs +11 -0
- package/modules/php/templates/composer.json.hbs +6 -0
- package/modules/php/templates/workspace.json.hbs +74 -0
- package/modules/redis/prompts.js +8 -0
- package/modules/redis/templates/.lando.yml.hbs +8 -0
- package/modules/sage/index.js +20 -0
- package/modules/sage/prompts.js +16 -0
- package/modules/sage/templates/.lando.yml.hbs +64 -0
- package/modules/sage/templates/theme/composer.json.hbs +18 -0
- package/modules/sage/templates/theme/package.json.hbs +11 -0
- package/modules/sage/templates/theme/style.css.hbs +13 -0
- package/modules/sage/templates/theme/vite.config.js.hbs +53 -0
- package/modules/sage/templates/workspace.json.hbs +67 -0
- package/modules/test-directory/assets/module-file.txt +1 -0
- package/modules/test-directory/index.js +19 -0
- package/modules/test-directory/prompts.js +8 -0
- package/modules/test-directory/test-assets/file1.txt +1 -0
- package/modules/test-directory/test-assets/file2.txt +1 -0
- package/modules/test-directory/test-assets/subfolder/config.json +4 -0
- package/package.json +54 -0
- package/release-please-config.json +17 -0
- package/server/php/php.ini +48 -0
- package/server/www/rocket.conf +283 -0
- package/templates/.editorconfig.hbs +39 -0
- package/templates/.env.hbs +48 -0
- package/templates/.gitignore.hbs +86 -0
- package/templates/.lando.yml.hbs +44 -0
- package/templates/README.md.hbs +12 -0
- package/templates/composer.json.hbs +60 -0
- package/templates/package.json.hbs +47 -0
- package/templates/server/cmd/install-wp.sh.hbs +58 -0
- package/templates/server/www/vhosts.conf.hbs +71 -0
- package/templates/workspace.json.hbs +177 -0
- package/test-copy-directory.js +43 -0
- package/test-overwrite.js +45 -0
- 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
|
+
}
|
package/lib/utils/git.js
ADDED
|
@@ -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
|
+
|