feat: add templates, CLI dirs, docs, and Gitea-first platform config #1
@@ -1,6 +1,24 @@
|
||||
# MokoStandards Enterprise API
|
||||
|
||||
PHP implementation of MokoStandards — enterprise standards and automation framework.
|
||||
PHP implementation of MokoStandards — enterprise standards, automation framework, workflow templates, and bulk sync tooling.
|
||||
|
||||
> **Primary platform**: [Gitea — git.mokoconsulting.tech](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API)
|
||||
> **Backup mirror**: [GitHub](https://github.com/mokoconsulting-tech/MokoStandards-API) *(read-only mirror)*
|
||||
|
||||
## What Lives Here
|
||||
|
||||
| Directory | Purpose |
|
||||
|-----------|---------|
|
||||
| `lib/Enterprise/` | 38 PHP enterprise library classes (platform adapters, sync, validation, plugins) |
|
||||
| `cli/` | CLI scripts (archive, create, release, sync rulesets, version management) |
|
||||
| `automation/` | Bulk sync, push files, repo cleanup, Gitea migration |
|
||||
| `validate/` | 18 validation scripts (health, structure, secrets, syntax, drift) |
|
||||
| `templates/` | **Workflow templates** and config templates synced to governed repos |
|
||||
| `definitions/` | Repository structure definitions (`.tf` format) |
|
||||
| `deploy/` | Deployment scripts (SFTP, Joomla) |
|
||||
| `maintenance/` | Labels, inventory, SHA pinning, version sync |
|
||||
| `docs/` | API documentation, workflow guides, automation docs |
|
||||
| `tests/` | PHPUnit test suite |
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -36,6 +54,16 @@ vendor/bin/moko sync
|
||||
vendor/bin/moko inventory -- --path .
|
||||
```
|
||||
|
||||
## Platform Configuration
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `GIT_PLATFORM` | `gitea` (default) or `github` |
|
||||
| `GA_TOKEN` | Gitea API / Gitea Actions token |
|
||||
| `GH_TOKEN` | GitHub API token (for mirror sync) |
|
||||
| `GITEA_URL` | Gitea instance URL (default: `https://git.mokoconsulting.tech`) |
|
||||
| `GITEA_ORG` | Gitea organization (default: `mokoconsulting-tech`) |
|
||||
|
||||
## License
|
||||
|
||||
GPL-3.0-or-later — See [LICENSE.md](LICENSE.md)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Automation
|
||||
* INGROUP: MokoStandards.Scripts
|
||||
* PATH: /api/automation/bulk_joomla_template.php
|
||||
* PATH: /automation/bulk_joomla_template.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Bulk scaffold and sync Joomla template repositories
|
||||
*
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Automation
|
||||
* INGROUP: MokoStandards.Scripts
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/automation/bulk_sync.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /automation/bulk_sync.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise-grade bulk repository synchronization
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Automation
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/automation/migrate_to_gitea.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /automation/migrate_to_gitea.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Migrate repositories from GitHub to self-hosted Gitea instance
|
||||
*
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Automation
|
||||
* INGROUP: MokoStandards.Scripts
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/automation/push_files.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /automation/push_files.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Push one or more specific files to one or more remote repositories
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Automation
|
||||
* INGROUP: MokoStandards.Scripts
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/automation/repo_cleanup.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /automation/repo_cleanup.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise repository cleanup — branches, PRs, issues, workflows, labels, logs
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Build Index: /api/build
|
||||
|
||||
## Purpose
|
||||
|
||||
This folder contains build system management and compilation scripts.
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [README](./README.md) - Build scripts documentation
|
||||
|
||||
## Scripts
|
||||
|
||||
- [moko-make](./moko-make) - Build system wrapper
|
||||
- [resolve_makefile.py](./resolve_makefile.py) - Makefile resolution
|
||||
|
||||
## Metadata
|
||||
|
||||
- **Document Type:** index
|
||||
- **Auto-generated:** This file is manually maintained for ignored directory
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# Moko Build Wrapper
|
||||
# Automatically finds and uses appropriate Makefile from MokoStandards
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
COLOR_RESET="\033[0m"
|
||||
COLOR_GREEN="\033[32m"
|
||||
COLOR_BLUE="\033[34m"
|
||||
COLOR_RED="\033[31m"
|
||||
|
||||
# Find MokoStandards root
|
||||
find_mokostandards() {
|
||||
# Check environment variable
|
||||
if [ -n "$MOKOSTANDARDS_ROOT" ] && [ -d "$MOKOSTANDARDS_ROOT/templates/build" ]; then
|
||||
echo "$MOKOSTANDARDS_ROOT"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check adjacent directories
|
||||
if [ -d "../MokoStandards/templates/build" ]; then
|
||||
echo "$(cd ../MokoStandards && pwd)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -d "../../MokoStandards/templates/build" ]; then
|
||||
echo "$(cd ../../MokoStandards && pwd)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check home directory
|
||||
if [ -d "$HOME/.mokostandards/templates/build" ]; then
|
||||
echo "$HOME/.mokostandards"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check system location
|
||||
if [ -d "/opt/mokostandards/templates/build" ]; then
|
||||
echo "/opt/mokostandards"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Find appropriate Makefile
|
||||
find_makefile() {
|
||||
# Check for local Makefile
|
||||
if [ -f "Makefile" ]; then
|
||||
echo "Makefile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check for .moko/Makefile
|
||||
if [ -f ".moko/Makefile" ]; then
|
||||
echo ".moko/Makefile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Find MokoStandards
|
||||
MOKO_ROOT=$(find_mokostandards)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${COLOR_RED}✗${COLOR_RESET} MokoStandards repository not found" >&2
|
||||
echo -e "${COLOR_BLUE}Hint:${COLOR_RESET} Set MOKOSTANDARDS_ROOT or clone adjacent" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect project type
|
||||
if [ -d "core/modules" ] && ls core/modules/mod*.class.php >/dev/null 2>&1; then
|
||||
echo "$MOKO_ROOT/templates/build/dolibarr/Makefile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check for Joomla XML files
|
||||
shopt -s nullglob # Prevent glob expansion if no matches
|
||||
for xml in *.xml; do
|
||||
if [ -f "$xml" ]; then
|
||||
if grep -q 'type="component"' "$xml" 2>/dev/null; then
|
||||
echo "$MOKO_ROOT/templates/build/joomla/Makefile.component"
|
||||
return 0
|
||||
elif grep -q 'type="module"' "$xml" 2>/dev/null; then
|
||||
echo "$MOKO_ROOT/templates/build/joomla/Makefile.module"
|
||||
return 0
|
||||
elif grep -q 'type="plugin"' "$xml" 2>/dev/null; then
|
||||
echo "$MOKO_ROOT/templates/build/joomla/Makefile.plugin"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
||||
echo -e "${COLOR_RED}✗${COLOR_RESET} Could not detect project type" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
MAKEFILE=$(find_makefile)
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show which Makefile we're using
|
||||
if [[ "$MAKEFILE" == *"MokoStandards"* ]] || [[ "$MAKEFILE" == *".mokostandards"* ]]; then
|
||||
echo -e "${COLOR_BLUE}ℹ${COLOR_RESET} Using MokoStandards template"
|
||||
fi
|
||||
|
||||
# Run make with the found Makefile
|
||||
exec make -f "$MAKEFILE" "$@"
|
||||
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* This file is part of a Moko Consulting project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/archive_repo.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Gracefully retire a governed repository — archive, close issues/PRs, remove sync def
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/archive_repo.php --repo MokoOldModule
|
||||
* php api/cli/archive_repo.php --repo MokoOldModule --dry-run
|
||||
* php api/cli/archive_repo.php --repo MokoOldModule --skip-close # Archive only, keep issues open
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use MokoEnterprise\Config;
|
||||
use MokoEnterprise\PlatformAdapterFactory;
|
||||
|
||||
$dryRun = in_array('--dry-run', $argv);
|
||||
$skipClose = in_array('--skip-close', $argv);
|
||||
|
||||
$repoName = null;
|
||||
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--repo' && isset($argv[$i + 1])) { $repoName = $argv[$i + 1]; }
|
||||
}
|
||||
|
||||
if (!$repoName) {
|
||||
fwrite(STDERR, "Usage: php archive_repo.php --repo <RepoName> [--skip-close] [--dry-run]\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$config = Config::load();
|
||||
$adapter = PlatformAdapterFactory::create($config);
|
||||
$org = $config->getString(
|
||||
$adapter->getPlatformName() . '.organization',
|
||||
'mokoconsulting-tech'
|
||||
);
|
||||
|
||||
$repoRoot = dirname(__DIR__, 2);
|
||||
$platformName = $adapter->getPlatformName();
|
||||
|
||||
echo "Archiving repository: {$org}/{$repoName} (on {$platformName})\n\n";
|
||||
|
||||
// ── Step 1: Verify repo exists ──────────────────────────────────────────
|
||||
echo "Step 1: Verifying repository...\n";
|
||||
try {
|
||||
$repoData = $adapter->getRepo($org, $repoName);
|
||||
} catch (\Exception $e) {
|
||||
fwrite(STDERR, " Repository {$org}/{$repoName} not found: " . $e->getMessage() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
if ($repoData['archived'] ?? false) {
|
||||
echo " Already archived — nothing to do\n";
|
||||
exit(0);
|
||||
}
|
||||
echo " Found: " . ($repoData['html_url'] ?? "{$org}/{$repoName}") . "\n";
|
||||
|
||||
// ── Step 2: Close all open PRs ──────────────────────────────────────────
|
||||
if (!$skipClose) {
|
||||
echo "Step 2: Closing open pull requests...\n";
|
||||
$prs = $adapter->listPullRequests($org, $repoName, ['state' => 'open']);
|
||||
$prCount = count($prs);
|
||||
echo " Found {$prCount} open PRs\n";
|
||||
|
||||
foreach ($prs as $pr) {
|
||||
$num = $pr['number'];
|
||||
if (!$dryRun) {
|
||||
$adapter->updatePullRequest($org, $repoName, $num, ['state' => 'closed']);
|
||||
$adapter->addIssueComment($org, $repoName, $num,
|
||||
"Closed as part of repository archival. This repository is being retired.\n\n*Auto-closed by `archive_repo.php`*"
|
||||
);
|
||||
}
|
||||
echo " Closed PR #{$num}: {$pr['title']}\n";
|
||||
}
|
||||
|
||||
// ── Step 3: Close all open issues ───────────────────────────────────
|
||||
echo "Step 3: Closing open issues...\n";
|
||||
$issues = $adapter->listIssues($org, $repoName, ['state' => 'open']);
|
||||
$issues = array_filter($issues, fn($i) => !isset($i['pull_request']));
|
||||
$issueCount = count($issues);
|
||||
echo " Found {$issueCount} open issues\n";
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
$num = $issue['number'];
|
||||
if (!$dryRun) {
|
||||
$adapter->closeIssue($org, $repoName, $num);
|
||||
$adapter->addIssueComment($org, $repoName, $num,
|
||||
"Closed as part of repository archival.\n\n*Auto-closed by `archive_repo.php`*"
|
||||
);
|
||||
}
|
||||
echo " Closed issue #{$num}: {$issue['title']}\n";
|
||||
}
|
||||
} else {
|
||||
echo "Step 2-3: Skipping issue/PR closure (--skip-close)\n";
|
||||
}
|
||||
|
||||
// ── Step 4: Archive the repository ──────────────────────────────────────
|
||||
echo "Step 4: Archiving repository...\n";
|
||||
if (!$dryRun) {
|
||||
try {
|
||||
$adapter->archiveRepo($org, $repoName);
|
||||
echo " Repository archived\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " Failed to archive: " . $e->getMessage() . "\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would archive {$org}/{$repoName}\n";
|
||||
}
|
||||
|
||||
// ── Step 5: Remove sync definition ──────────────────────────────────────
|
||||
echo "Step 5: Removing sync definition...\n";
|
||||
$defFile = "{$repoRoot}/definitions/sync/{$repoName}.def.tf";
|
||||
if (file_exists($defFile)) {
|
||||
if (!$dryRun) {
|
||||
unlink($defFile);
|
||||
echo " Removed: {$defFile}\n";
|
||||
} else {
|
||||
echo " (dry-run) would remove {$defFile}\n";
|
||||
}
|
||||
} else {
|
||||
echo " No sync definition found\n";
|
||||
}
|
||||
|
||||
// ── Step 6: Create archival record ──────────────────────────────────────
|
||||
echo "Step 6: Creating archival record...\n";
|
||||
if (!$dryRun) {
|
||||
$now = gmdate('Y-m-d H:i:s') . ' UTC';
|
||||
try {
|
||||
$issue = $adapter->createIssue($org, 'MokoStandards',
|
||||
"chore: archived repository {$repoName}",
|
||||
"## Repository Archived\n\n**Repository:** `{$org}/{$repoName}`\n**Archived:** {$now}\n**Platform:** {$platformName}\n**Sync definition removed:** yes\n\n---\n*Auto-created by `archive_repo.php`*\n",
|
||||
[
|
||||
'labels' => ['type: chore', 'automation', 'archived'],
|
||||
'assignees' => ['jmiller-moko'],
|
||||
]
|
||||
);
|
||||
if (isset($issue['number'])) { echo " Archival record: MokoStandards#{$issue['number']}\n"; }
|
||||
} catch (\Exception $e) {
|
||||
echo " Warning: could not create archival record: " . $e->getMessage() . "\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would create archival record issue\n";
|
||||
}
|
||||
|
||||
echo "\n" . str_repeat('-', 50) . "\n";
|
||||
echo "Repository {$org}/{$repoName} archived successfully\n";
|
||||
@@ -0,0 +1,477 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* This file is part of a Moko Consulting project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/create_project.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Create baseline GitHub Projects for repositories with standard fields and views
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/create_project.php --repo MokoCRM # Auto-detect type, create project
|
||||
* php api/cli/create_project.php --repo MokoCRM --type dolibarr # Force type
|
||||
* php api/cli/create_project.php --org mokoconsulting-tech --all # All repos without projects
|
||||
* php api/cli/create_project.php --repo MokoCRM --dry-run # Preview without changes
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$dryRun = in_array('--dry-run', $argv);
|
||||
$allMode = in_array('--all', $argv);
|
||||
|
||||
$org = 'mokoconsulting-tech';
|
||||
$repoName = null;
|
||||
$typeOverride = null;
|
||||
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--repo' && isset($argv[$i + 1])) {
|
||||
$repoName = $argv[$i + 1];
|
||||
}
|
||||
if ($arg === '--org' && isset($argv[$i + 1])) {
|
||||
$org = $argv[$i + 1];
|
||||
}
|
||||
if ($arg === '--type' && isset($argv[$i + 1])) {
|
||||
$typeOverride = $argv[$i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$repoName && !$allMode) {
|
||||
fwrite(STDERR, "Usage: php create_project.php --repo <name> [--type <type>] [--dry-run]\n");
|
||||
fwrite(STDERR, " php create_project.php --all [--org <org>] [--dry-run]\n");
|
||||
fwrite(STDERR, "\nTypes: generic, dolibarr, joomla, nodejs, terraform, python, wordpress, mobile-app, api, documentation\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN');
|
||||
if (empty($token)) {
|
||||
fwrite(STDERR, "GH_TOKEN or GITHUB_TOKEN not set\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$repoRoot = dirname(__DIR__, 2);
|
||||
$templatesDir = "{$repoRoot}/templates/projects";
|
||||
|
||||
// ── Always-exclude list (no project needed) ─────────────────────────────
|
||||
$ALWAYS_EXCLUDE = ['MokoStandards', '.github-private'];
|
||||
|
||||
// ── Platform type map ───────────────────────────────────────────────────
|
||||
$PLATFORM_TO_TYPE = [
|
||||
'crm-module' => 'dolibarr',
|
||||
'crm-platform' => 'dolibarr',
|
||||
'waas-component' => 'joomla',
|
||||
'waas-library' => 'joomla',
|
||||
'waas-plugin' => 'joomla',
|
||||
'waas-package' => 'joomla',
|
||||
'nodejs' => 'nodejs',
|
||||
'terraform' => 'terraform',
|
||||
'python' => 'python',
|
||||
'wordpress' => 'wordpress',
|
||||
'mobile' => 'mobile-app',
|
||||
'api' => 'api',
|
||||
'documentation' => 'documentation',
|
||||
];
|
||||
|
||||
// ── Template file map ───────────────────────────────────────────────────
|
||||
$TYPE_TO_TEMPLATE = [
|
||||
'generic' => 'generic-project-definition.tf',
|
||||
'dolibarr' => 'dolibarr-project-definition.tf',
|
||||
'joomla' => 'joomla-project-definition.tf',
|
||||
'nodejs' => 'nodejs-project-definition.tf',
|
||||
'terraform' => 'terraform-project-definition.tf',
|
||||
'python' => 'python-project-definition.tf',
|
||||
'wordpress' => 'wordpress-project-definition.tf',
|
||||
'mobile-app' => 'mobile-app-project-definition.tf',
|
||||
'api' => 'api-project-definition.tf',
|
||||
'documentation' => 'documentation-project-definition.tf',
|
||||
];
|
||||
|
||||
/**
|
||||
* Execute a GitHub GraphQL query.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function graphql(string $query, array $variables, string $token): array
|
||||
{
|
||||
$payload = json_encode(['query' => $query, 'variables' => $variables]);
|
||||
$ch = curl_init('https://api.github.com/graphql');
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $payload,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: bearer ' . $token,
|
||||
'Content-Type: application/json',
|
||||
'User-Agent: MokoStandards-CreateProject',
|
||||
],
|
||||
]);
|
||||
$body = (string) curl_exec($ch);
|
||||
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($status !== 200) {
|
||||
fwrite(STDERR, "GraphQL request failed (HTTP {$status}): {$body}\n");
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode($body, true) ?? [];
|
||||
if (!empty($data['errors'])) {
|
||||
foreach ($data['errors'] as $err) {
|
||||
fwrite(STDERR, " GraphQL error: " . ($err['message'] ?? 'unknown') . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return $data['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a GitHub REST API GET call.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function restGet(string $path, string $token): array
|
||||
{
|
||||
$ch = curl_init("https://api.github.com/{$path}");
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: token ' . $token,
|
||||
'User-Agent: MokoStandards-CreateProject',
|
||||
'Accept: application/vnd.github.v3+json',
|
||||
],
|
||||
]);
|
||||
$body = (string) curl_exec($ch);
|
||||
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return $status === 200 ? (json_decode($body, true) ?? []) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect platform type from .mokostandards file in the repo.
|
||||
*/
|
||||
function detectPlatform(string $org, string $repo, string $token): string
|
||||
{
|
||||
// Try .github/.mokostandards first, then root
|
||||
foreach (['.github/.mokostandards', '.mokostandards'] as $path) {
|
||||
$data = restGet("repos/{$org}/{$repo}/contents/{$path}", $token);
|
||||
if (!empty($data['content'])) {
|
||||
$content = base64_decode($data['content']);
|
||||
if (preg_match('/^platform:\s*(.+)/m', $content, $m)) {
|
||||
return trim($m[1], " \t\n\r\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GitHub node ID for a repository.
|
||||
*/
|
||||
function getRepoNodeId(string $org, string $repo, string $token): string
|
||||
{
|
||||
$data = graphql(
|
||||
'query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { id } }',
|
||||
['owner' => $org, 'name' => $repo],
|
||||
$token
|
||||
);
|
||||
return $data['repository']['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GitHub node ID for the organization owner.
|
||||
*/
|
||||
function getOrgNodeId(string $org, string $token): string
|
||||
{
|
||||
$data = graphql(
|
||||
'query($login: String!) { organization(login: $login) { id } }',
|
||||
['login' => $org],
|
||||
$token
|
||||
);
|
||||
return $data['organization']['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a repo already has a GitHub Project linked.
|
||||
*
|
||||
* @return array{bool, string} [hasProject, projectTitle]
|
||||
*/
|
||||
function repoHasProject(string $org, string $repo, string $token): array
|
||||
{
|
||||
$data = graphql(
|
||||
'query($owner: String!, $name: String!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
projectsV2(first: 1) { nodes { id title } totalCount }
|
||||
}
|
||||
}',
|
||||
['owner' => $org, 'name' => $repo],
|
||||
$token
|
||||
);
|
||||
|
||||
$count = $data['repository']['projectsV2']['totalCount'] ?? 0;
|
||||
$title = $data['repository']['projectsV2']['nodes'][0]['title'] ?? '';
|
||||
return [$count > 0, $title];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a .tf template file to extract custom fields.
|
||||
*
|
||||
* @return array{name: string, fields: array, views: array}
|
||||
*/
|
||||
function parseTemplate(string $filePath): array
|
||||
{
|
||||
if (!file_exists($filePath)) {
|
||||
return ['name' => 'Development Board', 'fields' => [], 'views' => []];
|
||||
}
|
||||
|
||||
$content = file_get_contents($filePath);
|
||||
$result = ['name' => 'Development Board', 'fields' => [], 'views' => []];
|
||||
|
||||
// Extract project name
|
||||
if (preg_match('/name\s*=\s*"([^"]+)"/', $content, $m)) {
|
||||
$result['name'] = $m[1];
|
||||
}
|
||||
|
||||
// Extract custom fields
|
||||
if (preg_match_all('/\{\s*name\s*=\s*"([^"]+)"\s*type\s*=\s*"([^"]+)"\s*description\s*=\s*"([^"]+)"(?:\s*options\s*=\s*\[([^\]]*)\])?\s*\}/s', $content, $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$field = [
|
||||
'name' => $match[1],
|
||||
'type' => $match[2],
|
||||
'description' => $match[3],
|
||||
];
|
||||
if (!empty($match[4])) {
|
||||
$field['options'] = array_map(
|
||||
fn($o) => trim($o, " \t\n\r\"'"),
|
||||
explode(',', $match[4])
|
||||
);
|
||||
$field['options'] = array_filter($field['options']);
|
||||
}
|
||||
$result['fields'][] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GitHub Project V2 for a repository.
|
||||
*/
|
||||
function createProject(
|
||||
string $org,
|
||||
string $repo,
|
||||
string $ownerId,
|
||||
string $repoId,
|
||||
array $template,
|
||||
string $token,
|
||||
bool $dryRun
|
||||
): bool {
|
||||
$title = "{$repo} — {$template['name']}";
|
||||
|
||||
if ($dryRun) {
|
||||
echo " (dry-run) would create project: {$title}\n";
|
||||
echo " (dry-run) fields: " . count($template['fields']) . "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 1: Create the project
|
||||
echo " Creating project: {$title}\n";
|
||||
$data = graphql(
|
||||
'mutation($ownerId: ID!, $title: String!) {
|
||||
createProjectV2(input: { ownerId: $ownerId, title: $title }) {
|
||||
projectV2 { id number url }
|
||||
}
|
||||
}',
|
||||
['ownerId' => $ownerId, 'title' => $title],
|
||||
$token
|
||||
);
|
||||
|
||||
$projectId = $data['createProjectV2']['projectV2']['id'] ?? '';
|
||||
$projectUrl = $data['createProjectV2']['projectV2']['url'] ?? '';
|
||||
|
||||
if (empty($projectId)) {
|
||||
fwrite(STDERR, " Failed to create project for {$repo}\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
echo " Project created: {$projectUrl}\n";
|
||||
|
||||
// Step 2: Link the project to the repository
|
||||
graphql(
|
||||
'mutation($projectId: ID!, $repositoryId: ID!) {
|
||||
linkProjectV2ToRepository(input: { projectId: $projectId, repositoryId: $repositoryId }) {
|
||||
repository { id }
|
||||
}
|
||||
}',
|
||||
['projectId' => $projectId, 'repositoryId' => $repoId],
|
||||
$token
|
||||
);
|
||||
echo " Linked to {$org}/{$repo}\n";
|
||||
|
||||
// Step 3: Create custom fields
|
||||
$fieldCount = 0;
|
||||
foreach ($template['fields'] as $field) {
|
||||
$fieldType = match ($field['type']) {
|
||||
'single_select' => 'SINGLE_SELECT',
|
||||
'text' => 'TEXT',
|
||||
'number' => 'NUMBER',
|
||||
'date' => 'DATE',
|
||||
'iteration' => 'ITERATION',
|
||||
default => 'TEXT',
|
||||
};
|
||||
|
||||
$vars = [
|
||||
'projectId' => $projectId,
|
||||
'name' => $field['name'],
|
||||
'dataType' => $fieldType,
|
||||
];
|
||||
|
||||
// Single select fields need options created with the field
|
||||
if ($fieldType === 'SINGLE_SELECT' && !empty($field['options'])) {
|
||||
$optionInputs = array_map(
|
||||
fn($o) => ['name' => $o, 'description' => '', 'color' => 'GRAY'],
|
||||
$field['options']
|
||||
);
|
||||
$vars['singleSelectOptions'] = $optionInputs;
|
||||
|
||||
graphql(
|
||||
'mutation($projectId: ID!, $name: String!, $dataType: ProjectV2CustomFieldType!, $singleSelectOptions: [ProjectV2SingleSelectFieldOptionInput!]) {
|
||||
createProjectV2Field(input: {
|
||||
projectId: $projectId,
|
||||
dataType: $dataType,
|
||||
name: $name,
|
||||
singleSelectOptions: $singleSelectOptions
|
||||
}) {
|
||||
projectV2Field { ... on ProjectV2SingleSelectField { id name } }
|
||||
}
|
||||
}',
|
||||
$vars,
|
||||
$token
|
||||
);
|
||||
} else {
|
||||
graphql(
|
||||
'mutation($projectId: ID!, $name: String!, $dataType: ProjectV2CustomFieldType!) {
|
||||
createProjectV2Field(input: {
|
||||
projectId: $projectId,
|
||||
dataType: $dataType,
|
||||
name: $name
|
||||
}) {
|
||||
projectV2Field { ... on ProjectV2Field { id name } }
|
||||
}
|
||||
}',
|
||||
$vars,
|
||||
$token
|
||||
);
|
||||
}
|
||||
|
||||
$fieldCount++;
|
||||
}
|
||||
|
||||
echo " Created {$fieldCount} custom fields\n";
|
||||
|
||||
// Step 4: Update project description and README
|
||||
graphql(
|
||||
'mutation($projectId: ID!, $shortDescription: String!) {
|
||||
updateProjectV2(input: {
|
||||
projectId: $projectId,
|
||||
shortDescription: $shortDescription,
|
||||
readme: "Managed by MokoStandards. Run `php api/cli/create_project.php` to regenerate."
|
||||
}) {
|
||||
projectV2 { id }
|
||||
}
|
||||
}',
|
||||
[
|
||||
'projectId' => $projectId,
|
||||
'shortDescription' => "Standard project board for {$repo}. Auto-created by MokoStandards.",
|
||||
],
|
||||
$token
|
||||
);
|
||||
|
||||
echo " Project setup complete\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── Main ────────────────────────────────────────────────────────────────
|
||||
|
||||
$repos = [];
|
||||
|
||||
if ($allMode) {
|
||||
echo "Fetching repositories from {$org}...\n";
|
||||
$page = 1;
|
||||
do {
|
||||
$batch = restGet("orgs/{$org}/repos?per_page=100&page={$page}&type=all", $token);
|
||||
foreach ($batch as $r) {
|
||||
if (!$r['archived'] && !in_array($r['name'], $ALWAYS_EXCLUDE, true)) {
|
||||
$repos[] = $r['name'];
|
||||
}
|
||||
}
|
||||
$page++;
|
||||
} while (count($batch) === 100);
|
||||
|
||||
sort($repos);
|
||||
echo "Found " . count($repos) . " repositories\n\n";
|
||||
} else {
|
||||
$repos = [$repoName];
|
||||
}
|
||||
|
||||
$ownerId = getOrgNodeId($org, $token);
|
||||
if (empty($ownerId)) {
|
||||
fwrite(STDERR, "Could not resolve org node ID for {$org}\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$created = 0;
|
||||
$skipped = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ($repos as $repo) {
|
||||
echo "Processing {$repo}...\n";
|
||||
|
||||
// Check if project already exists
|
||||
[$hasProject, $existingTitle] = repoHasProject($org, $repo, $token);
|
||||
if ($hasProject) {
|
||||
echo " Already has project: {$existingTitle} — skipping\n";
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Detect project type
|
||||
$type = $typeOverride;
|
||||
if (!$type) {
|
||||
$platform = detectPlatform($org, $repo, $token);
|
||||
$type = $PLATFORM_TO_TYPE[$platform] ?? 'generic';
|
||||
echo " Platform: {$platform} → type: {$type}\n";
|
||||
}
|
||||
|
||||
// Load template
|
||||
$templateFile = $TYPE_TO_TEMPLATE[$type] ?? $TYPE_TO_TEMPLATE['generic'];
|
||||
$template = parseTemplate("{$templatesDir}/{$templateFile}");
|
||||
|
||||
// Get repo node ID
|
||||
$repoId = getRepoNodeId($org, $repo, $token);
|
||||
if (empty($repoId)) {
|
||||
fwrite(STDERR, " Could not resolve repo node ID for {$repo}\n");
|
||||
$failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the project
|
||||
$ok = createProject($org, $repo, $ownerId, $repoId, $template, $token, $dryRun);
|
||||
if ($ok) {
|
||||
$created++;
|
||||
} else {
|
||||
$failed++;
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo str_repeat('-', 50) . "\n";
|
||||
echo "Done: {$created} created, {$skipped} skipped, {$failed} failed\n";
|
||||
exit($failed > 0 ? 1 : 0);
|
||||
@@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* This file is part of a Moko Consulting project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/create_repo.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Scaffold a new governed repository with full MokoStandards baseline
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/create_repo.php --name MokoNewModule --type dolibarr --description "My new module"
|
||||
* php api/cli/create_repo.php --name MokoNewModule --type joomla --private
|
||||
* php api/cli/create_repo.php --name MokoNewModule --type generic --dry-run
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use MokoEnterprise\Config;
|
||||
use MokoEnterprise\PlatformAdapterFactory;
|
||||
|
||||
$dryRun = in_array('--dry-run', $argv);
|
||||
$private = in_array('--private', $argv);
|
||||
|
||||
$name = null;
|
||||
$type = null;
|
||||
$description = '';
|
||||
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--name' && isset($argv[$i + 1])) { $name = $argv[$i + 1]; }
|
||||
if ($arg === '--type' && isset($argv[$i + 1])) { $type = $argv[$i + 1]; }
|
||||
if ($arg === '--description' && isset($argv[$i + 1])) { $description = $argv[$i + 1]; }
|
||||
}
|
||||
|
||||
if (!$name || !$type) {
|
||||
fwrite(STDERR, "Usage: php create_repo.php --name <RepoName> --type <type> [--description \"...\"] [--private] [--dry-run]\n");
|
||||
fwrite(STDERR, "\nTypes: generic, dolibarr, dolibarr-platform, joomla, nodejs, terraform, python, wordpress\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$config = Config::load();
|
||||
$adapter = PlatformAdapterFactory::create($config);
|
||||
$org = $config->getString(
|
||||
$adapter->getPlatformName() . '.organization',
|
||||
'mokoconsulting-tech'
|
||||
);
|
||||
|
||||
$repoRoot = dirname(__DIR__, 2);
|
||||
|
||||
$TYPE_TO_PLATFORM = [
|
||||
'dolibarr' => 'crm-module',
|
||||
'dolibarr-platform' => 'crm-platform',
|
||||
'joomla' => 'waas-component',
|
||||
'nodejs' => 'nodejs',
|
||||
'terraform' => 'terraform',
|
||||
'python' => 'python',
|
||||
'wordpress' => 'wordpress',
|
||||
'generic' => 'generic',
|
||||
];
|
||||
|
||||
$TYPE_TO_TOPICS = [
|
||||
'dolibarr' => ['dolibarr', 'erp', 'crm', 'php', 'mokostandards'],
|
||||
'joomla' => ['joomla', 'cms', 'php', 'mokostandards'],
|
||||
'nodejs' => ['nodejs', 'javascript', 'typescript', 'mokostandards'],
|
||||
'terraform' => ['terraform', 'infrastructure', 'iac', 'mokostandards'],
|
||||
'python' => ['python', 'mokostandards'],
|
||||
'wordpress' => ['wordpress', 'php', 'cms', 'mokostandards'],
|
||||
'generic' => ['mokostandards'],
|
||||
];
|
||||
|
||||
$platform = $TYPE_TO_PLATFORM[$type] ?? 'generic';
|
||||
$topics = $TYPE_TO_TOPICS[$type] ?? ['mokostandards'];
|
||||
$platformName = $adapter->getPlatformName();
|
||||
|
||||
echo "Scaffolding new repository: {$org}/{$name} (on {$platformName})\n";
|
||||
echo " Type: {$type} (platform: {$platform})\n";
|
||||
echo " Visibility: " . ($private ? 'private' : 'public') . "\n";
|
||||
if ($description) { echo " Description: {$description}\n"; }
|
||||
echo "\n";
|
||||
|
||||
// ── Step 1: Create the repository ───────────────────────────────────────
|
||||
echo "Step 1: Creating repository...\n";
|
||||
if (!$dryRun) {
|
||||
try {
|
||||
$data = $adapter->createOrgRepo($org, $name, [
|
||||
'description' => $description ?: "Managed by MokoStandards ({$type})",
|
||||
'private' => $private,
|
||||
'has_issues' => true,
|
||||
'has_projects' => true,
|
||||
'has_wiki' => false,
|
||||
'auto_init' => true,
|
||||
'delete_branch_on_merge' => true,
|
||||
'allow_squash_merge' => true,
|
||||
'allow_merge_commit' => false,
|
||||
'allow_rebase_merge' => false,
|
||||
]);
|
||||
echo " Created: " . ($data['html_url'] ?? "{$org}/{$name}") . "\n";
|
||||
} catch (\Exception $e) {
|
||||
if (str_contains($e->getMessage(), '422') || str_contains($e->getMessage(), 'already exists')) {
|
||||
echo " Repository already exists — continuing with setup\n";
|
||||
} else {
|
||||
fwrite(STDERR, " Failed to create repo: " . $e->getMessage() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would create {$org}/{$name}\n";
|
||||
}
|
||||
|
||||
// ── Step 2: Set topics ──────────────────────────────────────────────────
|
||||
echo "Step 2: Setting topics...\n";
|
||||
if (!$dryRun) {
|
||||
$adapter->setRepoTopics($org, $name, $topics);
|
||||
echo " Topics: " . implode(', ', $topics) . "\n";
|
||||
} else {
|
||||
echo " (dry-run) would set topics: " . implode(', ', $topics) . "\n";
|
||||
}
|
||||
|
||||
// ── Step 3: Create .mokostandards file ──────────────────────────────────
|
||||
echo "Step 3: Creating .github/.mokostandards...\n";
|
||||
$mokoContent = "platform: {$platform}\nversion: 04.02.30\nmanaged: true\n";
|
||||
if (!$dryRun) {
|
||||
try {
|
||||
$adapter->createOrUpdateFile(
|
||||
$org, $name, '.github/.mokostandards', $mokoContent,
|
||||
'chore: add .mokostandards platform config [skip ci]'
|
||||
);
|
||||
echo " .mokostandards created\n";
|
||||
} catch (\Exception $e) {
|
||||
echo " Warning: " . $e->getMessage() . "\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would create .github/.mokostandards\n";
|
||||
}
|
||||
|
||||
// ── Step 4: Create initial README.md ────────────────────────────────────
|
||||
echo "Step 4: Creating README.md...\n";
|
||||
|
||||
// Determine the repo base URL based on platform
|
||||
$baseUrl = $platformName === 'gitea'
|
||||
? $config->getString('gitea.url', 'https://git.mokoconsulting.tech')
|
||||
: 'https://github.com';
|
||||
$repoUrl = "{$baseUrl}/{$org}/{$name}";
|
||||
$standardsUrl = "{$baseUrl}/{$org}/MokoStandards";
|
||||
|
||||
$readmeContent = <<<MD
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: {$name}
|
||||
INGROUP: MokoStandards
|
||||
REPO: {$repoUrl}
|
||||
PATH: /README.md
|
||||
VERSION: 01.00.00
|
||||
BRIEF: {$description}
|
||||
-->
|
||||
|
||||
# {$name}
|
||||
|
||||
[]({$standardsUrl})
|
||||
[]({$repoUrl})
|
||||
|
||||
{$description}
|
||||
|
||||
## Getting Started
|
||||
|
||||
This repository is governed by [MokoStandards]({$standardsUrl}).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the GPL-3.0-or-later license. See [LICENSE](LICENSE) for details.
|
||||
|
||||
---
|
||||
|
||||
*This file is part of the Moko Consulting ecosystem. All rights reserved.*
|
||||
*This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.*
|
||||
MD;
|
||||
|
||||
if (!$dryRun) {
|
||||
// Get existing README sha (auto_init creates one)
|
||||
$sha = null;
|
||||
try {
|
||||
$existing = $adapter->getFileContents($org, $name, 'README.md');
|
||||
$sha = $existing['sha'] ?? null;
|
||||
} catch (\Exception $e) {
|
||||
$adapter->getApiClient()->resetCircuitBreaker();
|
||||
}
|
||||
|
||||
$adapter->createOrUpdateFile(
|
||||
$org, $name, 'README.md', $readmeContent,
|
||||
'docs: initialize README with MokoStandards header [skip ci]',
|
||||
$sha
|
||||
);
|
||||
echo " README.md created\n";
|
||||
} else {
|
||||
echo " (dry-run) would create README.md\n";
|
||||
}
|
||||
|
||||
// ── Step 5: Provision labels ────────────────────────────────────────────
|
||||
echo "Step 5: Provisioning labels...\n";
|
||||
if (!$dryRun) {
|
||||
$labelScript = "{$repoRoot}/api/maintenance/setup_labels.php";
|
||||
if (file_exists($labelScript)) {
|
||||
$exitCode = 0;
|
||||
passthru("php " . escapeshellarg($labelScript) . " --org " . escapeshellarg($org) . " --repo " . escapeshellarg($name), $exitCode);
|
||||
echo $exitCode === 0 ? " Labels provisioned\n" : " Label provisioning had issues\n";
|
||||
} else {
|
||||
echo " Labels will be provisioned on next sync\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would provision standard labels\n";
|
||||
}
|
||||
|
||||
// ── Step 6: Run first sync ──────────────────────────────────────────────
|
||||
echo "Step 6: Running initial sync...\n";
|
||||
if (!$dryRun) {
|
||||
$syncScript = "{$repoRoot}/api/automation/bulk_sync.php";
|
||||
if (file_exists($syncScript)) {
|
||||
passthru("php " . escapeshellarg($syncScript) . " --repos " . escapeshellarg($name) . " --force --yes");
|
||||
} else {
|
||||
echo " Run manually: php api/automation/bulk_sync.php --repos {$name} --force --yes\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would run initial sync\n";
|
||||
}
|
||||
|
||||
// ── Step 7: Create Project ──────────────────────────────────────────────
|
||||
echo "Step 7: Creating Project...\n";
|
||||
if (!$dryRun) {
|
||||
$projectScript = "{$repoRoot}/api/cli/create_project.php";
|
||||
if (file_exists($projectScript)) {
|
||||
passthru("php " . escapeshellarg($projectScript) . " --repo " . escapeshellarg($name) . " --type " . escapeshellarg($type));
|
||||
} else {
|
||||
echo " Run manually: php api/cli/create_project.php --repo {$name} --type {$type}\n";
|
||||
}
|
||||
} else {
|
||||
echo " (dry-run) would create Project\n";
|
||||
}
|
||||
|
||||
echo "\n" . str_repeat('-', 50) . "\n";
|
||||
echo "Repository {$org}/{$name} scaffolded successfully\n";
|
||||
echo " URL: {$repoUrl}\n";
|
||||
echo " Platform: {$platform} ({$platformName})\n";
|
||||
echo " Next: verify the sync and merge any PRs\n";
|
||||
@@ -0,0 +1,394 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* This file is part of a Moko Consulting project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/joomla_release.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Joomla release pipeline — build ZIP+tar.gz, upload to GitHub Release, update updates.xml
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/joomla_release.php --repo MokoCassiopeia --stability stable
|
||||
* php api/cli/joomla_release.php --repo MokoCassiopeia --stability development
|
||||
* php api/cli/joomla_release.php --repo MokoCassiopeia --stability rc --dry-run
|
||||
* php api/cli/joomla_release.php --path /local/repo --stability stable
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use MokoEnterprise\{ApiClient, AuditLogger, CLIApp};
|
||||
|
||||
class JoomlaRelease extends CLIApp
|
||||
{
|
||||
private const VERSION = '04.06.00';
|
||||
private const ORG = 'mokoconsulting-tech';
|
||||
|
||||
private const STABILITY_TAGS = [
|
||||
'development' => 'development',
|
||||
'alpha' => 'alpha',
|
||||
'beta' => 'beta',
|
||||
'rc' => 'release-candidate',
|
||||
'stable' => null,
|
||||
];
|
||||
|
||||
private const SUFFIXES = [
|
||||
'development' => '-dev',
|
||||
'alpha' => '-alpha',
|
||||
'beta' => '-beta',
|
||||
'rc' => '-rc',
|
||||
'stable' => '',
|
||||
];
|
||||
|
||||
private ApiClient $api;
|
||||
private AuditLogger $logger;
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription('Joomla release pipeline — build packages, upload, update updates.xml');
|
||||
$this->addArgument('--repo', 'Repository name (e.g., MokoCassiopeia)', '');
|
||||
$this->addArgument('--path', 'Local repo path (alternative to --repo)', '.');
|
||||
$this->addArgument('--stability', 'Stability level: development|alpha|beta|rc|stable', 'stable');
|
||||
$this->addArgument('--dry-run', 'Preview without making changes', false);
|
||||
$this->addArgument('--verbose', 'Show detailed output', false);
|
||||
}
|
||||
|
||||
protected function run(): int
|
||||
{
|
||||
$repo = (string) $this->getArgument('--repo');
|
||||
$path = (string) $this->getArgument('--path');
|
||||
$stability = (string) $this->getArgument('--stability');
|
||||
$dryRun = (bool) $this->getArgument('--dry-run');
|
||||
|
||||
if (!isset(self::STABILITY_TAGS[$stability])) {
|
||||
$this->log('ERROR', "Invalid stability: {$stability}. Use: " . implode(', ', array_keys(self::STABILITY_TAGS)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->api = new ApiClient();
|
||||
$this->logger = new AuditLogger('joomla_release');
|
||||
|
||||
if ($repo !== '') {
|
||||
$path = $this->cloneRepo($repo);
|
||||
if ($path === null) { return 1; }
|
||||
}
|
||||
$path = rtrim($path, '/\\');
|
||||
|
||||
$this->log('INFO', "Joomla Release Pipeline v" . self::VERSION);
|
||||
$this->log('INFO', "Path: {$path} | Stability: {$stability} | Dry run: " . ($dryRun ? 'yes' : 'no'));
|
||||
|
||||
// ── Step 1: Parse manifest ────────────────────────────────────
|
||||
$manifest = $this->findManifest($path);
|
||||
if ($manifest === null) {
|
||||
$this->log('ERROR', 'No Joomla XML manifest found');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$meta = $this->parseManifest($manifest);
|
||||
$this->log('INFO', "Extension: {$meta['name']} ({$meta['type']}) — element: {$meta['element']}");
|
||||
|
||||
// ── Step 2: Read version ──────────────────────────────────────
|
||||
$version = $this->readVersion($path) ?? $meta['version'];
|
||||
if ($version === '') {
|
||||
$this->log('ERROR', 'No version found in README.md or manifest');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$suffix = self::SUFFIXES[$stability];
|
||||
$displayVersion = $version . $suffix;
|
||||
$major = explode('.', $version)[0];
|
||||
$releaseTag = self::STABILITY_TAGS[$stability] ?? "v{$major}";
|
||||
|
||||
$this->log('INFO', "Version: {$displayVersion} | Release tag: {$releaseTag}");
|
||||
|
||||
// ── Step 3: Build packages ────────────────────────────────────
|
||||
$srcDir = is_dir("{$path}/src") ? "{$path}/src" : (is_dir("{$path}/htdocs") ? "{$path}/htdocs" : null);
|
||||
if ($srcDir === null) {
|
||||
$this->log('ERROR', 'No src/ or htdocs/ directory');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$zipName = "{$meta['element']}-{$displayVersion}.zip";
|
||||
$tarName = "{$meta['element']}-{$displayVersion}.tar.gz";
|
||||
$zipPath = sys_get_temp_dir() . "/{$zipName}";
|
||||
$tarPath = sys_get_temp_dir() . "/{$tarName}";
|
||||
|
||||
$sha256 = 'dry-run';
|
||||
if (!$dryRun) {
|
||||
$this->buildZip($srcDir, $zipPath);
|
||||
$this->buildTarGz($srcDir, $tarPath);
|
||||
$sha256 = hash_file('sha256', $zipPath);
|
||||
$this->log('SUCCESS', "ZIP: {$zipName} (" . filesize($zipPath) . " bytes)");
|
||||
$this->log('SUCCESS', "tar.gz: {$tarName} (" . filesize($tarPath) . " bytes)");
|
||||
$this->log('SUCCESS', "SHA-256: {$sha256}");
|
||||
} else {
|
||||
$this->log('INFO', "[DRY-RUN] Would build: {$zipName} + {$tarName}");
|
||||
}
|
||||
|
||||
// ── Step 4: Upload to GitHub Release ──────────────────────────
|
||||
$repoFullName = self::ORG . '/' . ($repo ?: basename($path));
|
||||
|
||||
if (!$dryRun) {
|
||||
$this->ensureRelease($repoFullName, $releaseTag, $displayVersion, $stability);
|
||||
$this->uploadAsset($repoFullName, $releaseTag, $zipPath, $zipName);
|
||||
$this->uploadAsset($repoFullName, $releaseTag, $tarPath, $tarName);
|
||||
$this->log('SUCCESS', "Uploaded to release: {$releaseTag}");
|
||||
} else {
|
||||
$this->log('INFO', "[DRY-RUN] Would upload to {$releaseTag}");
|
||||
}
|
||||
|
||||
// ── Step 5: Update updates.xml ────────────────────────────────
|
||||
$updatesXml = "{$path}/updates.xml";
|
||||
$zipUrl = "https://github.com/{$repoFullName}/releases/download/{$releaseTag}/{$zipName}";
|
||||
$tarUrl = "https://github.com/{$repoFullName}/releases/download/{$releaseTag}/{$tarName}";
|
||||
|
||||
$entry = $this->buildUpdateEntry($meta, $displayVersion, $stability, $zipUrl, $tarUrl, $sha256);
|
||||
|
||||
if (!$dryRun) {
|
||||
$this->mergeUpdateEntry($updatesXml, $stability, $entry);
|
||||
$this->log('SUCCESS', "updates.xml updated ({$stability}: {$displayVersion})");
|
||||
} else {
|
||||
$this->log('INFO', "[DRY-RUN] Would update updates.xml");
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
$this->log('SUCCESS', "Release complete: {$displayVersion} → {$releaseTag}");
|
||||
|
||||
if (!$dryRun) {
|
||||
@unlink($zipPath);
|
||||
@unlink($tarPath);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ── Manifest ─────────────────────────────────────────────────────
|
||||
|
||||
private function findManifest(string $path): ?string
|
||||
{
|
||||
foreach ([$path, "{$path}/src", "{$path}/htdocs"] as $dir) {
|
||||
if (!is_dir($dir)) { continue; }
|
||||
foreach (glob("{$dir}/*.xml") as $file) {
|
||||
if (str_contains((string) file_get_contents($file), '<extension')) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function parseManifest(string $file): array
|
||||
{
|
||||
$xml = simplexml_load_file($file);
|
||||
$name = (string) ($xml->name ?? '');
|
||||
$type = (string) ($xml->attributes()->type ?? 'component');
|
||||
$element = (string) ($xml->element ?? '');
|
||||
$client = (string) ($xml->attributes()->client ?? '');
|
||||
$group = (string) ($xml->attributes()->group ?? '');
|
||||
$version = (string) ($xml->version ?? '');
|
||||
$phpMin = (string) ($xml->php_minimum ?? '');
|
||||
|
||||
// Templates don't have <element> — derive from <name>
|
||||
if ($element === '') {
|
||||
$element = strtolower(str_replace(' ', '', $name));
|
||||
}
|
||||
|
||||
$tp = '';
|
||||
if (isset($xml->targetplatform)) {
|
||||
$tpNode = $xml->targetplatform;
|
||||
$tp = '<targetplatform name="' . ($tpNode->attributes()->name ?? 'joomla')
|
||||
. '" version="' . ($tpNode->attributes()->version ?? '5.*') . '" />';
|
||||
}
|
||||
if ($tp === '') {
|
||||
$tp = '<targetplatform name="joomla" version="5.*" />';
|
||||
}
|
||||
|
||||
return compact('name', 'type', 'element', 'client', 'group', 'version', 'tp', 'phpMin');
|
||||
}
|
||||
|
||||
private function readVersion(string $path): ?string
|
||||
{
|
||||
$readme = "{$path}/README.md";
|
||||
if (!is_file($readme)) { return null; }
|
||||
if (preg_match('/VERSION:\s*(\d{2}\.\d{2}\.\d{2})/', file_get_contents($readme), $m)) {
|
||||
return $m[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ── Package building ─────────────────────────────────────────────
|
||||
|
||||
private function buildZip(string $srcDir, string $outPath): void
|
||||
{
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($outPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$iter = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($srcDir, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
foreach ($iter as $file) {
|
||||
$local = str_replace('\\', '/', str_replace($srcDir . DIRECTORY_SEPARATOR, '', $file->getPathname()));
|
||||
if ($this->isExcluded(basename($local))) { continue; }
|
||||
$file->isDir() ? $zip->addEmptyDir($local) : $zip->addFile($file->getPathname(), $local);
|
||||
}
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
private function buildTarGz(string $srcDir, string $outPath): void
|
||||
{
|
||||
$tarPath = preg_replace('/\.gz$/', '', $outPath);
|
||||
$phar = new \PharData($tarPath);
|
||||
$phar->buildFromDirectory($srcDir);
|
||||
$phar->compress(\Phar::GZ);
|
||||
@unlink($tarPath);
|
||||
}
|
||||
|
||||
private function isExcluded(string $name): bool
|
||||
{
|
||||
if ($name === '.ftpignore') { return true; }
|
||||
if (str_starts_with($name, 'sftp-config')) { return true; }
|
||||
if (str_starts_with($name, '.env')) { return true; }
|
||||
$ext = pathinfo($name, PATHINFO_EXTENSION);
|
||||
return in_array($ext, ['ppk', 'pem', 'key'], true);
|
||||
}
|
||||
|
||||
// ── GitHub Release ───────────────────────────────────────────────
|
||||
|
||||
private function ensureRelease(string $repo, string $tag, string $version, string $stability): void
|
||||
{
|
||||
try {
|
||||
$this->api->get("/repos/{$repo}/releases/tags/{$tag}");
|
||||
} catch (\Exception $e) {
|
||||
$this->api->post("/repos/{$repo}/releases", [
|
||||
'tag_name' => $tag,
|
||||
'name' => ($stability === 'stable') ? "v" . explode('.', $version)[0] . " (latest: {$version})" : "{$tag} ({$version})",
|
||||
'body' => "## {$version}\n\nCreated by MokoStandards release pipeline.",
|
||||
'prerelease' => ($stability !== 'stable'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function uploadAsset(string $repo, string $tag, string $filePath, string $fileName): void
|
||||
{
|
||||
$release = $this->api->get("/repos/{$repo}/releases/tags/{$tag}");
|
||||
$uploadUrl = str_replace('{?name,label}', '', $release['upload_url']);
|
||||
|
||||
foreach ($release['assets'] ?? [] as $asset) {
|
||||
if ($asset['name'] === $fileName) {
|
||||
$this->api->delete("/repos/{$repo}/releases/assets/{$asset['id']}");
|
||||
}
|
||||
}
|
||||
|
||||
$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN');
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => "{$uploadUrl}?name=" . urlencode($fileName),
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => file_get_contents($filePath),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
"Authorization: token {$token}",
|
||||
'Content-Type: application/octet-stream',
|
||||
'Accept: application/vnd.github+json',
|
||||
],
|
||||
]);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
// ── updates.xml ──────────────────────────────────────────────────
|
||||
|
||||
private function buildUpdateEntry(array $meta, string $version, string $stability, string $zipUrl, string $tarUrl, string $sha256): string
|
||||
{
|
||||
$lines = [' <update>'];
|
||||
$lines[] = " <name>{$meta['name']}</name>";
|
||||
$lines[] = " <description>{$meta['name']} ({$stability})</description>";
|
||||
$lines[] = " <element>{$meta['element']}</element>";
|
||||
$lines[] = " <type>{$meta['type']}</type>";
|
||||
$lines[] = " <version>{$version}</version>";
|
||||
|
||||
if ($meta['client'] !== '') {
|
||||
$lines[] = " <client>{$meta['client']}</client>";
|
||||
} elseif (in_array($meta['type'], ['module', 'plugin'])) {
|
||||
$lines[] = ' <client>site</client>';
|
||||
}
|
||||
if ($meta['group'] !== '' && $meta['type'] === 'plugin') {
|
||||
$lines[] = " <folder>{$meta['group']}</folder>";
|
||||
}
|
||||
|
||||
$lines[] = ' <tags>';
|
||||
$lines[] = " <tag>{$stability}</tag>";
|
||||
$lines[] = ' </tags>';
|
||||
$lines[] = " <infourl title=\"{$meta['name']}\">https://github.com/" . self::ORG . "</infourl>";
|
||||
$lines[] = ' <downloads>';
|
||||
$lines[] = " <downloadurl type=\"full\" format=\"zip\">{$zipUrl}</downloadurl>";
|
||||
$lines[] = " <downloadurl type=\"full\" format=\"tar.gz\">{$tarUrl}</downloadurl>";
|
||||
$lines[] = ' </downloads>';
|
||||
|
||||
if ($sha256 !== '' && $sha256 !== 'dry-run') {
|
||||
$lines[] = " <sha256>sha256:{$sha256}</sha256>";
|
||||
}
|
||||
|
||||
$lines[] = " {$meta['tp']}";
|
||||
if ($meta['phpMin'] !== '') {
|
||||
$lines[] = " <php_minimum>{$meta['phpMin']}</php_minimum>";
|
||||
}
|
||||
$lines[] = ' <maintainer>Moko Consulting</maintainer>';
|
||||
$lines[] = ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>';
|
||||
$lines[] = ' </update>';
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
private function mergeUpdateEntry(string $xmlPath, string $stability, string $newEntry): void
|
||||
{
|
||||
if (!is_file($xmlPath)) {
|
||||
file_put_contents($xmlPath, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<updates>\n{$newEntry}\n</updates>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
$content = file_get_contents($xmlPath);
|
||||
$pattern = '#\s*<update>.*?<tag>' . preg_quote($stability, '#') . '</tag>.*?</update>#s';
|
||||
$content = preg_replace($pattern, '', $content);
|
||||
$content = str_replace('</updates>', "{$newEntry}\n</updates>", $content);
|
||||
$content = preg_replace('/\n{3,}/', "\n\n", $content);
|
||||
file_put_contents($xmlPath, $content);
|
||||
}
|
||||
|
||||
private function cloneRepo(string $repo): ?string
|
||||
{
|
||||
$tmpDir = sys_get_temp_dir() . "/joomla_release_{$repo}";
|
||||
if (is_dir($tmpDir)) {
|
||||
$this->rmdir($tmpDir);
|
||||
}
|
||||
$token = getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN');
|
||||
$url = "https://x-access-token:{$token}@github.com/" . self::ORG . "/{$repo}.git";
|
||||
$cmd = ['git', 'clone', '--depth', '1', '--quiet', $url, $tmpDir];
|
||||
$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
|
||||
proc_close($proc);
|
||||
return is_dir($tmpDir) ? $tmpDir : null;
|
||||
}
|
||||
|
||||
private function rmdir(string $dir): void
|
||||
{
|
||||
$iter = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
foreach ($iter as $file) {
|
||||
$file->isDir() ? rmdir($file->getPathname()) : unlink($file->getPathname());
|
||||
}
|
||||
rmdir($dir);
|
||||
}
|
||||
}
|
||||
|
||||
$script = new JoomlaRelease('joomla_release', 'Joomla release pipeline');
|
||||
exit($script->execute());
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/platform_detect.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Detect platform from .mokostandards file — outputs platform string
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$path = '.';
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
||||
}
|
||||
|
||||
$root = realpath($path) ?: $path;
|
||||
// Check .github/.mokostandards first, fallback to root
|
||||
$file = "{$root}/.github/.mokostandards";
|
||||
if (!file_exists($file)) {
|
||||
$file = "{$root}/.mokostandards";
|
||||
}
|
||||
if (!file_exists($file)) {
|
||||
echo "unknown\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
if (preg_match('/^platform:\s*(.+)/m', $content, $m)) {
|
||||
echo trim($m[1], " \t\n\r\"'") . "\n";
|
||||
} else {
|
||||
echo "unknown\n";
|
||||
}
|
||||
|
||||
exit(0);
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/release.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Automate the MokoStandards version branch release flow
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/release.php # Release current version
|
||||
* php api/cli/release.php --bump minor # Bump minor, then release
|
||||
* php api/cli/release.php --bump major # Bump major, then release
|
||||
* php api/cli/release.php --dry-run # Preview without changes
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$dryRun = in_array('--dry-run', $argv);
|
||||
$bumpType = null;
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--bump' && isset($argv[$i + 1])) {
|
||||
$bumpType = $argv[$i + 1]; // patch | minor | major
|
||||
}
|
||||
}
|
||||
|
||||
$repoRoot = dirname(__DIR__, 2);
|
||||
$syncFile = "{$repoRoot}/api/lib/Enterprise/RepositorySynchronizer.php";
|
||||
// Check both workflow directories for the bulk-repo-sync workflow
|
||||
$bulkSyncFile = file_exists("{$repoRoot}/.gitea/workflows/bulk-repo-sync.yml")
|
||||
? "{$repoRoot}/.gitea/workflows/bulk-repo-sync.yml"
|
||||
: "{$repoRoot}/.github/workflows/bulk-repo-sync.yml";
|
||||
$cleanupFile = "{$repoRoot}/templates/workflows/shared/repository-cleanup.yml.template";
|
||||
|
||||
// ── Step 1: Read current version ────────────────────────────────────────
|
||||
$readme = "{$repoRoot}/README.md";
|
||||
$content = file_get_contents($readme);
|
||||
if (!preg_match('/^\s*VERSION:\s*(\d{2})\.(\d{2})\.(\d{2})/m', $content, $m)) {
|
||||
fwrite(STDERR, "No VERSION found in README.md\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$major = (int)$m[1];
|
||||
$minor = (int)$m[2];
|
||||
$patch = (int)$m[3];
|
||||
$currentVersion = sprintf('%02d.%02d.%02d', $major, $minor, $patch);
|
||||
|
||||
// ── Step 2: Bump version if requested ───────────────────────────────────
|
||||
if ($bumpType) {
|
||||
switch ($bumpType) {
|
||||
case 'major': $major++; $minor = 0; $patch = 0; break;
|
||||
case 'minor': $minor++; $patch = 0; break;
|
||||
case 'patch': $patch++; break;
|
||||
default:
|
||||
fwrite(STDERR, "Invalid bump type: {$bumpType} (use patch/minor/major)\n");
|
||||
exit(1);
|
||||
}
|
||||
$newVersion = sprintf('%02d.%02d.%02d', $major, $minor, $patch);
|
||||
echo "Bumping: {$currentVersion} → {$newVersion}\n";
|
||||
|
||||
if (!$dryRun) {
|
||||
// Update README.md
|
||||
$content = preg_replace(
|
||||
'/^(\s*VERSION:\s*)\d{2}\.\d{2}\.\d{2}/m',
|
||||
'${1}' . $newVersion,
|
||||
$content,
|
||||
1
|
||||
);
|
||||
file_put_contents($readme, $content);
|
||||
|
||||
// Propagate to all files
|
||||
echo "Propagating version to all files...\n";
|
||||
passthru("php {$repoRoot}/api/maintenance/update_version_from_readme.php --path {$repoRoot}");
|
||||
}
|
||||
$currentVersion = $newVersion;
|
||||
} else {
|
||||
echo "Version: {$currentVersion}\n";
|
||||
}
|
||||
|
||||
// Derive major.minor for branch naming (patches update existing branch)
|
||||
$versionParts = explode('.', $currentVersion);
|
||||
$minorVersion = $versionParts[0] . '.' . $versionParts[1];
|
||||
$branch = "version/{$minorVersion}";
|
||||
|
||||
// ── Step 3: Update STANDARDS_VERSION + STANDARDS_MINOR constants ────────
|
||||
echo "Updating STANDARDS_VERSION → {$currentVersion}\n";
|
||||
echo "Updating STANDARDS_MINOR → {$minorVersion}\n";
|
||||
if (!$dryRun) {
|
||||
$syncContent = file_get_contents($syncFile);
|
||||
$syncContent = preg_replace(
|
||||
"/STANDARDS_VERSION\s*=\s*'[^']+'/",
|
||||
"STANDARDS_VERSION = '{$currentVersion}'",
|
||||
$syncContent
|
||||
);
|
||||
$syncContent = preg_replace(
|
||||
"/STANDARDS_MINOR\s*=\s*'[^']+'/",
|
||||
"STANDARDS_MINOR = '{$minorVersion}'",
|
||||
$syncContent
|
||||
);
|
||||
file_put_contents($syncFile, $syncContent);
|
||||
}
|
||||
|
||||
// ── Step 4: Update bulk-repo-sync.yml checkout ref ──────────────────────
|
||||
echo "Updating bulk-repo-sync.yml → {$branch}\n";
|
||||
if (!$dryRun) {
|
||||
$bulkContent = file_get_contents($bulkSyncFile);
|
||||
$bulkContent = preg_replace(
|
||||
'/ref:\s*version\/[\d.]+/',
|
||||
"ref: {$branch}",
|
||||
$bulkContent
|
||||
);
|
||||
file_put_contents($bulkSyncFile, $bulkContent);
|
||||
}
|
||||
|
||||
// ── Step 5: Update repository-cleanup.yml current branch ────────────────
|
||||
echo "Updating repository-cleanup.yml → chore/sync-mokostandards-v{$minorVersion}\n";
|
||||
if (!$dryRun) {
|
||||
$cleanupContent = file_get_contents($cleanupFile);
|
||||
$cleanupContent = preg_replace(
|
||||
'/CURRENT="chore\/sync-mokostandards-v[^"]*"/',
|
||||
"CURRENT=\"chore/sync-mokostandards-v{$minorVersion}\"",
|
||||
$cleanupContent
|
||||
);
|
||||
file_put_contents($cleanupFile, $cleanupContent);
|
||||
}
|
||||
|
||||
// ── Step 6: Commit changes ──────────────────────────────────────────────
|
||||
if (!$dryRun) {
|
||||
echo "Committing...\n";
|
||||
passthru("cd {$repoRoot} && git add -A && git commit -m \"chore(release): prepare {$currentVersion} release [skip ci]\"");
|
||||
passthru("cd {$repoRoot} && git pull --rebase 2>/dev/null; git push");
|
||||
}
|
||||
|
||||
// ── Step 7: Create or update version branch ─────────────────────────────
|
||||
$isPatch = ($versionParts[2] ?? '00') !== '00';
|
||||
if ($isPatch) {
|
||||
echo "Updating version branch: {$branch} (patch update)\n";
|
||||
if (!$dryRun) {
|
||||
passthru("cd " . escapeshellarg($repoRoot) . " && git push origin main:{$branch} --force 2>&1");
|
||||
}
|
||||
} else {
|
||||
echo "Creating version branch: {$branch} (minor release)\n";
|
||||
if (!$dryRun) {
|
||||
$exitCode = 0;
|
||||
passthru("cd " . escapeshellarg($repoRoot) . " && git push origin main:{$branch} 2>&1", $exitCode);
|
||||
if ($exitCode !== 0) {
|
||||
echo "Branch {$branch} already exists — force updating\n";
|
||||
passthru("cd " . escapeshellarg($repoRoot) . " && git push origin main:{$branch} --force 2>&1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Step 8: Create git tag (never overwrite existing) ───────────────────
|
||||
$tag = "v{$currentVersion}";
|
||||
echo "Creating tag {$tag}\n";
|
||||
if (!$dryRun) {
|
||||
$exitCode = 0;
|
||||
passthru("cd {$repoRoot} && git tag {$tag} 2>/dev/null && git push origin {$tag} 2>/dev/null", $exitCode);
|
||||
if ($exitCode !== 0) {
|
||||
echo "⚠️ Tag {$tag} already exists — skipping\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n✅ Release {$currentVersion} complete\n";
|
||||
echo " Branch: {$branch}\n";
|
||||
echo " Tag: {$tag}\n";
|
||||
echo " Next: run bulk sync to push to all repos\n";
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/release_notes.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Extract release notes from CHANGELOG.md for a given version
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$path = '.';
|
||||
$version = null;
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
||||
if ($arg === '--version' && isset($argv[$i + 1])) $version = $argv[$i + 1];
|
||||
}
|
||||
|
||||
if ($version === null) {
|
||||
// Read from README.md
|
||||
$readme = realpath($path) . '/README.md';
|
||||
if (file_exists($readme)) {
|
||||
$content = file_get_contents($readme);
|
||||
if (preg_match('/^\s*VERSION:\s*(\d{2}\.\d{2}\.\d{2})/m', $content, $m)) {
|
||||
$version = $m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($version === null) {
|
||||
fwrite(STDERR, "Usage: release_notes.php --path . --version XX.YY.ZZ\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$changelog = realpath($path) . '/CHANGELOG.md';
|
||||
if (!file_exists($changelog)) {
|
||||
echo "Release {$version}\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$lines = file($changelog, FILE_IGNORE_NEW_LINES);
|
||||
$notes = [];
|
||||
$capturing = false;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^##\s.*' . preg_quote($version, '/') . '/', $line)) {
|
||||
$capturing = true;
|
||||
continue;
|
||||
}
|
||||
if ($capturing && preg_match('/^## /', $line)) {
|
||||
break; // Next version heading — stop
|
||||
}
|
||||
if ($capturing) {
|
||||
$notes[] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
$result = trim(implode("\n", $notes));
|
||||
echo $result ?: "Release {$version}";
|
||||
echo "\n";
|
||||
exit(0);
|
||||
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* This file is part of a Moko Consulting project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/sync_rulesets.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Apply branch protection rules to all repos via platform adapter
|
||||
*
|
||||
* USAGE
|
||||
* php api/cli/sync_rulesets.php # Apply to all repos
|
||||
* php api/cli/sync_rulesets.php --repo MokoCRM # Single repo
|
||||
* php api/cli/sync_rulesets.php --dry-run # Preview only
|
||||
* php api/cli/sync_rulesets.php --delete # Remove then re-apply
|
||||
*
|
||||
* NOTE: On GitHub, this creates rulesets via the rulesets API.
|
||||
* On Gitea, this creates branch_protections via the branch protection API.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use MokoEnterprise\Config;
|
||||
use MokoEnterprise\PlatformAdapterFactory;
|
||||
|
||||
$dryRun = in_array('--dry-run', $argv);
|
||||
$deleteOld = in_array('--delete', $argv);
|
||||
|
||||
$repoName = null;
|
||||
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--repo' && isset($argv[$i + 1])) { $repoName = $argv[$i + 1]; }
|
||||
}
|
||||
|
||||
$config = Config::load();
|
||||
$adapter = PlatformAdapterFactory::create($config);
|
||||
$org = $config->getString(
|
||||
$adapter->getPlatformName() . '.organization',
|
||||
'mokoconsulting-tech'
|
||||
);
|
||||
|
||||
$platformName = $adapter->getPlatformName();
|
||||
$ALWAYS_EXCLUDE = ['MokoStandards', '.github-private'];
|
||||
|
||||
// ── Protection rules (platform-agnostic format) ─────────────────────────
|
||||
// On GitHub → rulesets API. On Gitea → branch_protections API.
|
||||
$PROTECTIONS = [
|
||||
[
|
||||
'name' => 'MAIN — protect default branch',
|
||||
'branch' => 'main',
|
||||
'rules' => [
|
||||
'required_reviews' => 1,
|
||||
'dismiss_stale' => true,
|
||||
'enforce_admins' => true,
|
||||
'block_on_rejected' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'VERSION — immutable snapshots',
|
||||
'branch' => 'version/*',
|
||||
'rules' => [
|
||||
'required_reviews' => 0,
|
||||
'enforce_admins' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'DEV — prevent branch deletion',
|
||||
'branch' => 'dev/*',
|
||||
'rules' => [
|
||||
'required_reviews' => 0,
|
||||
'enforce_admins' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'RC — prevent branch deletion',
|
||||
'branch' => 'rc/*',
|
||||
'rules' => [
|
||||
'required_reviews' => 0,
|
||||
'enforce_admins' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// ── Build repo list ─────────────────────────────────────────────────────
|
||||
$repos = [];
|
||||
if ($repoName) {
|
||||
$repos = [$repoName];
|
||||
} else {
|
||||
echo "Fetching repositories from {$org} ({$platformName})...\n";
|
||||
$allRepos = $adapter->listOrgRepos($org, true); // skip archived
|
||||
foreach ($allRepos as $r) {
|
||||
if (!in_array($r['name'], $ALWAYS_EXCLUDE, true)) {
|
||||
$repos[] = $r['name'];
|
||||
}
|
||||
}
|
||||
sort($repos);
|
||||
echo "Found " . count($repos) . " repositories\n\n";
|
||||
}
|
||||
|
||||
$created = 0;
|
||||
$skipped = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ($repos as $repo) {
|
||||
echo "Processing {$repo}...\n";
|
||||
|
||||
// Check existing protections
|
||||
$existing = $adapter->listBranchProtections($org, $repo);
|
||||
$existingNames = [];
|
||||
if (is_array($existing)) {
|
||||
foreach ($existing as $bp) {
|
||||
$bpName = $bp['name'] ?? $bp['branch_name'] ?? $bp['rule_name'] ?? '';
|
||||
$bpId = $bp['id'] ?? null;
|
||||
if ($bpName !== '') {
|
||||
$existingNames[$bpName] = $bpId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($PROTECTIONS as $protection) {
|
||||
$pName = $protection['name'];
|
||||
|
||||
if ($deleteOld && isset($existingNames[$pName])) {
|
||||
if (!$dryRun) {
|
||||
try {
|
||||
// Platform-specific deletion via raw API
|
||||
$adapter->getApiClient()->delete(
|
||||
"/repos/{$org}/{$repo}/" .
|
||||
($platformName === 'github' ? 'rulesets' : 'branch_protections') .
|
||||
"/{$existingNames[$pName]}"
|
||||
);
|
||||
} catch (\Exception $e) { /* ignore delete errors */ }
|
||||
}
|
||||
echo " Deleted: {$pName}\n";
|
||||
unset($existingNames[$pName]);
|
||||
}
|
||||
|
||||
if (isset($existingNames[$pName])) {
|
||||
echo " Exists: {$pName}\n";
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($dryRun) {
|
||||
echo " (dry-run) would create: {$pName}\n";
|
||||
$created++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$adapter->setBranchProtection($org, $repo, $protection['branch'], $protection['rules']);
|
||||
echo " Created: {$pName}\n";
|
||||
$created++;
|
||||
} catch (\Exception $e) {
|
||||
$msg = $e->getMessage();
|
||||
if (str_contains($msg, '403')) {
|
||||
echo " Skipped (needs Pro/paid plan): {$pName}\n";
|
||||
$skipped++;
|
||||
} else {
|
||||
echo " Failed: {$pName} — {$msg}\n";
|
||||
$failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo str_repeat('-', 50) . "\n";
|
||||
echo "Done: {$created} created, {$skipped} skipped, {$failed} failed\n";
|
||||
exit($failed > 0 ? 1 : 0);
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/version_bump.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Auto-increment patch version in README.md — outputs old → new
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$path = '.';
|
||||
$type = 'patch'; // patch | minor | major
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
||||
if ($arg === '--minor') $type = 'minor';
|
||||
if ($arg === '--major') $type = 'major';
|
||||
}
|
||||
|
||||
$readme = realpath($path) . '/README.md';
|
||||
if (!file_exists($readme)) {
|
||||
fwrite(STDERR, "No README.md found at {$path}\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$content = file_get_contents($readme);
|
||||
if (!preg_match('/^(\s*VERSION:\s*)(\d{2})\.(\d{2})\.(\d{2})/m', $content, $m)) {
|
||||
fwrite(STDERR, "No VERSION field found in README.md\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$major = (int)$m[2];
|
||||
$minor = (int)$m[3];
|
||||
$patch = (int)$m[4];
|
||||
$old = sprintf('%02d.%02d.%02d', $major, $minor, $patch);
|
||||
|
||||
switch ($type) {
|
||||
case 'major': $major++; $minor = 0; $patch = 0; break;
|
||||
case 'minor': $minor++; $patch = 0; break;
|
||||
default:
|
||||
$patch++;
|
||||
if ($patch > 99) { $minor++; $patch = 0; }
|
||||
if ($minor > 99) { $major++; $minor = 0; }
|
||||
break;
|
||||
}
|
||||
|
||||
$new = sprintf('%02d.%02d.%02d', $major, $minor, $patch);
|
||||
$updated = preg_replace(
|
||||
'/^(\s*VERSION:\s*)\d{2}\.\d{2}\.\d{2}/m',
|
||||
'${1}' . $new,
|
||||
$content,
|
||||
1
|
||||
);
|
||||
|
||||
file_put_contents($readme, $updated);
|
||||
echo "{$old} → {$new}\n";
|
||||
exit(0);
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/version_read.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Read VERSION from README.md — outputs just the version string
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$path = '.';
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--path' && isset($argv[$i + 1])) {
|
||||
$path = $argv[$i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
$readme = realpath($path) . '/README.md';
|
||||
if (!file_exists($readme)) {
|
||||
fwrite(STDERR, "No README.md found at {$path}\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$content = file_get_contents($readme);
|
||||
if (preg_match('/^\s*VERSION:\s*(\d{2}\.\d{2}\.\d{2})/m', $content, $m)) {
|
||||
echo $m[1] . "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fwrite(STDERR, "No VERSION field found in README.md\n");
|
||||
exit(1);
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.CLI
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /cli/version_set_platform.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Set version in platform-specific files (Dolibarr $this->version, Joomla <version>)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$path = '.';
|
||||
$version = null;
|
||||
$branch = null;
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
|
||||
if ($arg === '--version' && isset($argv[$i + 1])) $version = $argv[$i + 1];
|
||||
if ($arg === '--branch' && isset($argv[$i + 1])) $branch = $argv[$i + 1];
|
||||
}
|
||||
|
||||
// Auto-detect branch from git or GitHub env
|
||||
if ($branch === null) {
|
||||
$branch = trim((string) @shell_exec('git rev-parse --abbrev-ref HEAD 2>/dev/null'));
|
||||
if (empty($branch) || $branch === 'HEAD') {
|
||||
$branch = getenv('GITHUB_REF_NAME') ?: 'main';
|
||||
}
|
||||
}
|
||||
|
||||
if ($version === null) {
|
||||
fwrite(STDERR, "Usage: version_set_platform.php --path . --version development\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$root = realpath($path) ?: $path;
|
||||
|
||||
// Detect platform
|
||||
$platform = '';
|
||||
$mokoStandards = "{$root}/.github/.mokostandards";
|
||||
if (!file_exists($mokoStandards)) {
|
||||
$mokoStandards = "{$root}/.mokostandards";
|
||||
}
|
||||
if (file_exists($mokoStandards)) {
|
||||
$content = file_get_contents($mokoStandards);
|
||||
if (preg_match('/^platform:\s*(.+)/m', $content, $m)) {
|
||||
$platform = trim($m[1], " \t\n\r\"'");
|
||||
}
|
||||
}
|
||||
|
||||
$changed = 0;
|
||||
|
||||
// Dolibarr: $this->version + $this->url_last_version in mod*.class.php
|
||||
if ($platform === 'crm-module') {
|
||||
$pattern = "{$root}/src/core/modules/mod*.class.php";
|
||||
foreach (glob($pattern) ?: [] as $file) {
|
||||
$content = file_get_contents($file);
|
||||
|
||||
// Set $this->version
|
||||
$updated = preg_replace(
|
||||
'/(\$this->version\s*=\s*)[\'"][^\'"]*[\'"]/',
|
||||
"\${1}'{$version}'",
|
||||
$content
|
||||
);
|
||||
|
||||
// Rewrite $this->url_last_version to point to current branch
|
||||
if (preg_match('/\$this->url_last_version\s*=\s*[\'"]([^\'"]+)[\'"]/', $updated, $urlMatch)) {
|
||||
$oldUrl = $urlMatch[1];
|
||||
// Replace the branch segment: .../BRANCH/update.txt
|
||||
$newUrl = preg_replace(
|
||||
'#(raw\.githubusercontent\.com/[^/]+/[^/]+/)[^/]+(/update\.json)#',
|
||||
"\${1}{$branch}\${2}",
|
||||
$oldUrl
|
||||
);
|
||||
if ($newUrl !== $oldUrl) {
|
||||
$updated = str_replace($oldUrl, $newUrl, $updated);
|
||||
echo "Dolibarr: url_last_version → {$branch}/update.txt\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated !== $content) {
|
||||
file_put_contents($file, $updated);
|
||||
echo "Dolibarr: " . basename($file) . " → version={$version}, branch={$branch}\n";
|
||||
$changed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Joomla: <version> in XML manifests
|
||||
if ($platform === 'waas-component') {
|
||||
foreach (glob("{$root}/src/*.xml") ?: glob("{$root}/*.xml") ?: [] as $file) {
|
||||
$content = file_get_contents($file);
|
||||
if (!str_contains($content, '<extension')) continue;
|
||||
$updated = preg_replace(
|
||||
'|<version>[^<]*</version>|',
|
||||
"<version>{$version}</version>",
|
||||
$content
|
||||
);
|
||||
if ($updated !== $content) {
|
||||
file_put_contents($file, $updated);
|
||||
echo "Joomla: " . basename($file) . " → {$version}\n";
|
||||
$changed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($changed === 0) {
|
||||
if (empty($platform)) {
|
||||
echo "No .mokostandards file — skipping platform version set\n";
|
||||
} else {
|
||||
echo "No platform-specific version files found for {$platform}\n";
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Deploy
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/deploy/deploy-joomla.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /deploy/deploy-joomla.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Smart Joomla deploy — routes files to correct Joomla directories based on XML manifest
|
||||
*
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Deploy
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/deploy/deploy-sftp.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /deploy/deploy-sftp.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Deploy a repository src/ directory to a remote web server via SFTP
|
||||
*/
|
||||
|
||||
@@ -204,7 +204,7 @@ All files must include:
|
||||
# FILE INFORMATION
|
||||
# DEFGROUP: [Group]
|
||||
# INGROUP: [Parent Group]
|
||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
# PATH: [Relative path from repo root]
|
||||
# VERSION: [X.Y.Z] # Version is dynamically read from README.md title line
|
||||
# BRIEF: [One-line description]
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Analysis Tools
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains documentation for analysis tools in `/api/analysis/`.
|
||||
|
||||
Analysis tools provide code quality, dependency analysis, and other analytical capabilities.
|
||||
|
||||
## Contents
|
||||
|
||||
_To be documented_
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Overview](../index.md)
|
||||
- [Validation Tools](../validate/index.md)
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/analysis/`
|
||||
**Mirrors**: `/api/analysis/`
|
||||
**Last Updated**: 2026-03-03
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,138 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/automation/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for automation scripts in api/automation/
|
||||
-->
|
||||
|
||||
# Automation Scripts
|
||||
|
||||
Scripts in `api/automation/` orchestrate large-scale operations across multiple
|
||||
repositories. They require a GitHub PAT (`GH_TOKEN`) with appropriate scopes.
|
||||
|
||||
---
|
||||
|
||||
## bulk_sync.php
|
||||
|
||||
Enterprise-grade bulk synchronization. Reads repository definitions from
|
||||
`api/definitions/sync/`, applies template files to governed repositories,
|
||||
and opens Pull Requests with the changes.
|
||||
|
||||
**Base class:** `CLIApp`
|
||||
|
||||
```bash
|
||||
# Dry-run sync for the entire org
|
||||
php api/automation/bulk_sync.php --org mokoconsulting-tech --dry-run
|
||||
|
||||
# Sync specific repositories
|
||||
php api/automation/bulk_sync.php --org mokoconsulting-tech --repos "repo-a,repo-b"
|
||||
|
||||
# Exclude repos and skip archived
|
||||
php api/automation/bulk_sync.php --org mokoconsulting-tech --exclude "legacy-repo" --skip-archived
|
||||
|
||||
# Auto-approve PRs (non-interactive)
|
||||
php api/automation/bulk_sync.php --org mokoconsulting-tech --yes
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--org <name>` | GitHub organization to sync |
|
||||
| `--repos <list>` | Comma-separated list of specific repositories |
|
||||
| `--exclude <list>` | Repositories to skip |
|
||||
| `--skip-archived` | Skip archived repositories |
|
||||
| `--yes` | Approve all PRs without prompting |
|
||||
| `--dry-run` | Preview changes without creating PRs |
|
||||
| `--verbose` / `-v` | Verbose output |
|
||||
| `--help` / `-h` | Show help and exit |
|
||||
|
||||
**Related:** See [Bulk Repo Sync](../../bulk-repo-sync-override-files.md) for
|
||||
override file conventions.
|
||||
|
||||
---
|
||||
|
||||
## push_files.php
|
||||
|
||||
Targeted file push tool. Pushes one or more specific files from MokoStandards
|
||||
templates to remote repositories without running a full sync. Supports both
|
||||
definition-based lookup and arbitrary `source:destination` pairs.
|
||||
|
||||
```bash
|
||||
# Push a single file to one repo
|
||||
php api/automation/push_files.php --files=.github/ISSUE_TEMPLATE/config.yml --repos=MokoCRM
|
||||
|
||||
# Push multiple files to multiple repos
|
||||
php api/automation/push_files.php --files=".github/workflows/ci.yml,.github/workflows/codeql-analysis.yml" --repos=MokoCRM,WaasComponent
|
||||
|
||||
# Push directly to a branch (no PR)
|
||||
php api/automation/push_files.php --files=templates/foo.txt:docs/foo.txt --repos=MyRepo --direct --branch=main
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--org <name>` | GitHub organization (default: mokoconsulting-tech) |
|
||||
| `--repos <list>` | Target repositories — comma-separated (required) |
|
||||
| `--files <list>` | Files to push — destination paths or `source:dest` pairs (required) |
|
||||
| `--message <msg>` | Custom commit message |
|
||||
| `--branch <name>` | Target branch for `--direct` pushes |
|
||||
| `--direct` | Push directly instead of creating a PR |
|
||||
| `--yes` | Auto-confirm without prompting |
|
||||
| `--no-issue` | Skip creating a tracking issue |
|
||||
|
||||
---
|
||||
|
||||
## repo_cleanup.php
|
||||
|
||||
Enterprise repository cleanup. Comprehensive maintenance for governed repos:
|
||||
delete stale sync branches, close superseded PRs, close resolved tracking
|
||||
issues, delete retired workflows, clean workflow logs, verify labels, and
|
||||
detect version drift.
|
||||
|
||||
```bash
|
||||
# Preview all cleanup operations
|
||||
php api/automation/repo_cleanup.php --all --dry-run
|
||||
|
||||
# Run all operations on specific repos
|
||||
php api/automation/repo_cleanup.php --repos "MokoCRM MokoWaas" --all --yes
|
||||
|
||||
# Delete retired workflow files only
|
||||
php api/automation/repo_cleanup.php --delete-retired --yes
|
||||
|
||||
# Close resolved issues and clean old logs
|
||||
php api/automation/repo_cleanup.php --close-issues --clean-logs --log-days=14 --yes
|
||||
|
||||
# Check version drift across all repos
|
||||
php api/automation/repo_cleanup.php --check-drift --json
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--org <name>` | GitHub organization |
|
||||
| `--repos <list>` | Specific repositories (space-separated) |
|
||||
| `--skip-archived` | Skip archived repositories |
|
||||
| `--close-issues` | Close resolved tracking issues |
|
||||
| `--lock-old-issues` | Lock issues closed >30 days |
|
||||
| `--clean-workflows` | Delete cancelled/stale workflow runs |
|
||||
| `--clean-logs` | Delete workflow run logs older than `--log-days` |
|
||||
| `--log-days <n>` | Days to keep logs (default: 30) |
|
||||
| `--delete-retired` | Delete retired workflow files from repos |
|
||||
| `--check-labels` | Verify mokostandards label exists |
|
||||
| `--check-drift` | Check for version drift against README.md |
|
||||
| `--all` | Run all cleanup operations |
|
||||
| `--yes` | Auto-confirm prompts |
|
||||
| `--dry-run` | Preview changes without making them |
|
||||
| `--json` | Output results as JSON |
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/automation/`
|
||||
**Mirrors:** `api/automation/`
|
||||
**Last Updated:** 2026-04-04
|
||||
@@ -0,0 +1,212 @@
|
||||
# Default Repository Definitions
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains base platform-specific definition files that serve as templates for repository validation and structure. These definitions are used as the foundation for generating repository-specific definitions during bulk sync operations.
|
||||
|
||||
## Definition Files
|
||||
|
||||
| File | Platform | Description |
|
||||
|------|----------|-------------|
|
||||
| **crm-module.tf** | Dolibarr | Structure for Dolibarr/CRM modules with core/modules structure, language files, SQL tables |
|
||||
| **default-repository.json** | Generic | JSON format of default repository structure (legacy format) |
|
||||
| **default-repository.tf** | Generic | Standard structure for generic repositories, libraries, and multi-language projects |
|
||||
| **generic-repository.tf** | Generic | Alternative generic repository structure with minimal requirements |
|
||||
| **standards-repository.tf** | Standards | Structure for MokoStandards organizational repository with api/, templates/, docs/, logs/ |
|
||||
| **waas-component.tf** | Joomla | Structure for Joomla/WaaS components, modules, plugins with manifest validation |
|
||||
|
||||
## File Format
|
||||
|
||||
All definition files use Terraform HCL (HashiCorp Configuration Language) format with `.tf` extension:
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
repository_structure = {
|
||||
metadata = {
|
||||
name = "Repository Type Name"
|
||||
description = "Detailed description"
|
||||
repository_type = "type-identifier"
|
||||
platform = "platform-name"
|
||||
last_updated = "ISO8601-timestamp"
|
||||
maintainer = "Maintainer Name"
|
||||
version = "1.0"
|
||||
schema_version = "1.0"
|
||||
}
|
||||
|
||||
root_files = [
|
||||
{
|
||||
name = "filename.ext"
|
||||
extension = "ext"
|
||||
description = "File description"
|
||||
required = true
|
||||
audience = "general"
|
||||
}
|
||||
]
|
||||
|
||||
directories = [
|
||||
{
|
||||
name = "dirname"
|
||||
path = "path/to/dir"
|
||||
description = "Directory description"
|
||||
required = true
|
||||
purpose = "Purpose description"
|
||||
|
||||
files = [ /* nested files */ ]
|
||||
subdirectories = [ /* nested directories */ ]
|
||||
}
|
||||
]
|
||||
|
||||
repository_requirements = {
|
||||
secrets = [ /* required secrets */ ]
|
||||
variables = [ /* required variables */ ]
|
||||
branch_protections = { /* protection rules */ }
|
||||
repository_settings = { /* settings */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Platform Detection
|
||||
|
||||
These definitions are automatically selected during platform detection:
|
||||
|
||||
```bash
|
||||
# Auto-detect platform and load appropriate definition
|
||||
php api/validate/auto_detect_platform.php \
|
||||
--repo-path /path/to/repository \
|
||||
--schema-dir api/definitions/default
|
||||
```
|
||||
|
||||
The detection script will:
|
||||
1. Analyze repository structure and content
|
||||
2. Score each platform based on indicators
|
||||
3. Select the best-matching definition
|
||||
4. Validate repository against the definition
|
||||
|
||||
### Manual Selection
|
||||
|
||||
You can manually specify which definition to use:
|
||||
|
||||
```bash
|
||||
# Use specific definition
|
||||
php api/validate/auto_detect_platform.php \
|
||||
--repo-path /path/to/repository \
|
||||
--platform dolibarr
|
||||
```
|
||||
|
||||
This will load `api/definitions/default/crm-module.tf`.
|
||||
|
||||
### During Bulk Sync
|
||||
|
||||
When bulk sync runs, it:
|
||||
1. Detects the repository platform
|
||||
2. Loads the corresponding base definition from this directory
|
||||
3. Customizes it with repository-specific metadata
|
||||
4. Saves to `api/definitions/sync/{repo}.def.tf`
|
||||
|
||||
## Platform Mapping
|
||||
|
||||
The auto-detection script maps platforms to definition files:
|
||||
|
||||
| Platform | Definition File |
|
||||
|----------|----------------|
|
||||
| `joomla` | waas-component.tf |
|
||||
| `dolibarr` | crm-module.tf |
|
||||
| `nodejs` | nodejs-repository.tf (future) |
|
||||
| `python` | python-repository.tf (future) |
|
||||
| `terraform` | terraform-repository.tf (future) |
|
||||
| `standards` | standards-repository.tf |
|
||||
| `generic` | default-repository.tf |
|
||||
|
||||
## Creating New Definitions
|
||||
|
||||
To create a new platform definition:
|
||||
|
||||
1. **Copy an existing definition as template:**
|
||||
```bash
|
||||
cp api/definitions/default/default-repository.tf \
|
||||
api/definitions/default/myplatform-repository.tf
|
||||
```
|
||||
|
||||
2. **Update metadata:**
|
||||
- Change `name`, `description`, `repository_type`, `platform`
|
||||
- Update `last_updated` timestamp
|
||||
- Set appropriate `version` and `schema_version`
|
||||
|
||||
3. **Define structure:**
|
||||
- Update `root_files` array with platform-specific files
|
||||
- Define `directories` with nested structure
|
||||
- Add platform-specific validation rules
|
||||
- Specify repository requirements (secrets, variables, etc.)
|
||||
|
||||
4. **Update platform detection:**
|
||||
Add mapping in `api/validate/auto_detect_platform.php`:
|
||||
```php
|
||||
'myplatform' => 'myplatform-repository.tf',
|
||||
```
|
||||
|
||||
5. **Add detection logic:**
|
||||
Update detection scoring to recognize your platform based on:
|
||||
- File patterns (e.g., `composer.json`, `package.json`)
|
||||
- Directory structure
|
||||
- Repository topics
|
||||
- Naming conventions
|
||||
|
||||
6. **Validate syntax:**
|
||||
```bash
|
||||
# Using Terraform (if installed)
|
||||
terraform fmt -check api/definitions/default/myplatform-repository.tf
|
||||
```
|
||||
|
||||
7. **Test definition:**
|
||||
```bash
|
||||
php api/validate/auto_detect_platform.php \
|
||||
--repo-path /test/repository \
|
||||
--platform myplatform
|
||||
```
|
||||
|
||||
## Validation Levels
|
||||
|
||||
Definitions support multiple requirement levels:
|
||||
|
||||
| Level | Meaning | Impact |
|
||||
|-------|---------|--------|
|
||||
| **required** | MUST be present | Blocks deployment if missing |
|
||||
| **suggested** | SHOULD be present | Warning if missing, reduces health score |
|
||||
| **optional** | MAY be present | No validation, informational only |
|
||||
| **not-allowed** | MUST NOT be present | Error if present (e.g., node_modules) |
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating Definitions
|
||||
|
||||
1. Edit the definition file
|
||||
2. Update `last_updated` timestamp
|
||||
3. Increment `version` if breaking changes
|
||||
4. Test with validation script
|
||||
5. Update CHANGELOG.md
|
||||
6. Commit changes
|
||||
|
||||
### Version Control
|
||||
|
||||
- Definition files are versioned through git
|
||||
- Breaking changes require major version bump
|
||||
- Schema version tracked in definition metadata
|
||||
- Maintain backward compatibility when possible
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Synced Definitions](../sync/index.md) - Auto-generated repository definitions
|
||||
- [Schema Guide](../../../docs/schemas/repohealth/schema-guide.md) - Complete schema specification
|
||||
- [Validation Guide](../../../docs/guide/validation/auto-detection.md) - Platform detection and validation
|
||||
- [Main Definitions README](../README.md) - Overview of definitions structure
|
||||
|
||||
---
|
||||
|
||||
**Location**: `api/definitions/default/`
|
||||
**Purpose**: Base platform-specific repository definitions
|
||||
**Used By**: Auto-detection, validation, bulk sync
|
||||
**Last Updated**: 2026-03-03
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,224 @@
|
||||
# Synced Repository Definitions
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains auto-generated repository structure definitions created during bulk synchronization operations. Each synced repository gets its own definition file that captures its detected platform, structure, and configuration.
|
||||
|
||||
## Purpose
|
||||
|
||||
When the bulk sync process runs, it:
|
||||
|
||||
1. **Detects the repository platform** (Joomla, Dolibarr, Node.js, etc.)
|
||||
2. **Generates a repository-specific definition** based on the detected platform
|
||||
3. **Saves the definition** in this directory as `{repo}.def.tf`
|
||||
4. **Uses the definition** for validation and health checks
|
||||
|
||||
This replaces the previous approach of creating `.github/override.tf` files in remote repositories.
|
||||
|
||||
## File Naming Convention
|
||||
|
||||
Files are named using the pattern: `{repository}.def.tf`
|
||||
|
||||
The `.def.tf` extension follows Terraform conventions where:
|
||||
- `.tf` indicates Terraform HCL format
|
||||
- `.def` indicates this is a definition/configuration file
|
||||
- Follows Terraform protocol standards for module and configuration naming
|
||||
|
||||
**Examples:**
|
||||
- `MokoDoliCGAdClaude.def.tf` - Dolibarr CRM module
|
||||
- `joomla-component-example.def.tf` - Joomla component
|
||||
- `nodejs-api.def.tf` - Node.js API project
|
||||
|
||||
## File Format
|
||||
|
||||
Each definition file uses Terraform HCL format (`.tf` extension) with the same structure as files in `api/definitions/default/`:
|
||||
|
||||
```hcl
|
||||
/**
|
||||
* Repository Definition: {org}/{repo}
|
||||
* Auto-generated during bulk sync on {date}
|
||||
* Platform: {platform}
|
||||
* Repository Type: {type}
|
||||
*/
|
||||
|
||||
locals {
|
||||
repository_structure = {
|
||||
metadata = {
|
||||
name = "{Repository Name}"
|
||||
description = "Repository structure for {org}/{repo}"
|
||||
repository_type = "{type}"
|
||||
platform = "{platform}"
|
||||
last_updated = "{ISO8601 timestamp}"
|
||||
maintainer = "{org}"
|
||||
version = "1.0"
|
||||
schema_version = "1.0"
|
||||
|
||||
# Sync metadata
|
||||
sync_generated = true
|
||||
sync_date = "{ISO8601 timestamp}"
|
||||
source_repo = "{org}/{repo}"
|
||||
detected_platform = "{platform}"
|
||||
}
|
||||
|
||||
# Root files, directories, etc. inherited from platform definition
|
||||
# with repository-specific customizations
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generation Process
|
||||
|
||||
During bulk sync:
|
||||
|
||||
1. **Platform Detection**: Auto-detect repository platform using `auto_detect_platform.php`
|
||||
2. **Load Base Definition**: Load the appropriate base definition from `api/definitions/default/`
|
||||
3. **Customize Metadata**: Add repository-specific metadata (org, repo name, sync date)
|
||||
4. **Save Definition**: Write to `api/definitions/sync/{org}-{repo}.tf`
|
||||
5. **Skip Remote Override**: Do NOT create `.github/override.tf` in the remote repository
|
||||
|
||||
## Benefits
|
||||
|
||||
### Centralized Management
|
||||
- All repository definitions stored in MokoStandards repository
|
||||
- Easy to track changes and history through git
|
||||
- No scattered override files across multiple repositories
|
||||
|
||||
### Audit Trail
|
||||
- Complete history of when repositories were synced
|
||||
- Platform detection results preserved
|
||||
- Changes to repository structure tracked in version control
|
||||
|
||||
### Validation & Health Checks
|
||||
- Health check scripts can reference these definitions
|
||||
- Validation scripts can compare actual vs. expected structure
|
||||
- Automated compliance monitoring across all repositories
|
||||
|
||||
### Clean Remote Repositories
|
||||
- No `.github/override.tf` files cluttering remote repos
|
||||
- Remote repositories only receive templates and workflows
|
||||
- Cleaner git history in remote repositories
|
||||
|
||||
## Usage
|
||||
|
||||
### Validation Scripts
|
||||
|
||||
Validation scripts automatically check both locations:
|
||||
|
||||
```bash
|
||||
# Auto-detect platform and validate using synced definition if available
|
||||
php api/validate/auto_detect_platform.php \
|
||||
--repo-path /path/to/repository \
|
||||
--repo repository-name
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Check for synced definition in `api/definitions/sync/{repo}.def.tf`
|
||||
2. Fall back to platform-based definition in `api/definitions/default/` if not found
|
||||
3. Validate repository structure against the definition
|
||||
|
||||
### Health Checks
|
||||
|
||||
```bash
|
||||
# Run health check using synced definition
|
||||
php api/validate/check_repo_health.php \
|
||||
--repo-path /path/to/repository \
|
||||
--repo repository-name
|
||||
```
|
||||
|
||||
### Manual Review
|
||||
|
||||
To review a synced repository's definition:
|
||||
|
||||
```bash
|
||||
# View the definition
|
||||
cat api/definitions/sync/MyRepo.def.tf
|
||||
|
||||
# Compare with base definition
|
||||
diff api/definitions/default/default-repository.tf \
|
||||
api/definitions/sync/MyRepo.def.tf
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Cleaning Stale Definitions
|
||||
|
||||
Periodically review and remove definitions for repositories that:
|
||||
- Have been deleted
|
||||
- Have been archived
|
||||
- Are no longer being synced
|
||||
|
||||
```bash
|
||||
# Find definitions for archived repositories
|
||||
php api/maintenance/clean_stale_definitions.php --dry-run
|
||||
```
|
||||
|
||||
### Updating Definitions
|
||||
|
||||
Definitions are automatically regenerated on each bulk sync. To manually regenerate:
|
||||
|
||||
```bash
|
||||
# Regenerate definition for a specific repository
|
||||
php api/automation/bulk_sync.php \
|
||||
--repos mokoconsulting-tech/MyRepo \
|
||||
--regenerate-definitions
|
||||
```
|
||||
|
||||
## Git Tracking
|
||||
|
||||
All files in this directory are **tracked in git** for complete audit trail and version control:
|
||||
|
||||
```
|
||||
api/definitions/sync/
|
||||
├── .gitignore # Git configuration
|
||||
├── README.md # This documentation
|
||||
└── *.def.tf # All synced repository definitions (TRACKED)
|
||||
```
|
||||
|
||||
This approach:
|
||||
- ✅ Preserves complete history of all synced repositories
|
||||
- ✅ Provides audit trail of definition changes over time
|
||||
- ✅ Enables diff/review of repository structure changes
|
||||
- ✅ Allows rollback to previous definition versions
|
||||
- ✅ Documents which repositories are actively synced
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### From Previous Approach
|
||||
|
||||
Previously, bulk sync created `.github/override.tf` files in each remote repository. This has been replaced with:
|
||||
|
||||
**Old Approach:**
|
||||
```
|
||||
Remote Repo: .github/override.tf (created by bulk sync)
|
||||
MokoStandards: templates/github/override.tf.template
|
||||
```
|
||||
|
||||
**New Approach:**
|
||||
```
|
||||
Remote Repo: (no override file)
|
||||
MokoStandards: api/definitions/sync/{repo}.def.tf (auto-generated)
|
||||
```
|
||||
|
||||
### Existing Override Files
|
||||
|
||||
For repositories that already have `.github/override.tf` files:
|
||||
- They will continue to work (not deleted)
|
||||
- New syncs will not update them
|
||||
- Health checks will prefer synced definitions in MokoStandards
|
||||
- Manual cleanup of old override files can be done separately
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Default Definitions](../default/README.md) - Base platform definitions
|
||||
- [Schema Guide](../../../docs/schemas/repohealth/schema-guide.md) - Definition schema specification
|
||||
- [Bulk Sync Documentation](../../../docs/automation/bulk-repo-sync.md) - Bulk sync process
|
||||
- [Validation Guide](../../../docs/guide/validation/auto-detection.md) - Platform detection and validation
|
||||
|
||||
---
|
||||
|
||||
**Location**: `api/definitions/sync/`
|
||||
**Purpose**: Auto-generated synced repository definitions
|
||||
**Generated By**: Bulk sync automation
|
||||
**Last Updated**: 2026-03-03
|
||||
**Maintained By**: MokoStandards automation (do not edit manually)
|
||||
@@ -0,0 +1,162 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/deploy/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for deployment scripts in api/deploy/
|
||||
-->
|
||||
|
||||
# Deploy Scripts
|
||||
|
||||
Scripts in `api/deploy/` upload repository source files to remote web servers via SFTP.
|
||||
|
||||
---
|
||||
|
||||
## deploy-sftp.php
|
||||
|
||||
**Path:** `api/deploy/deploy-sftp.php`
|
||||
**Base class:** `MokoEnterprise\CliFramework`
|
||||
|
||||
Reads connection details from a `sftp-config.json` file and recursively uploads
|
||||
a repository's `src/` directory to the configured remote path.
|
||||
Supports PuTTY `.ppk` keys and OpenSSH PEM keys via phpseclib. Strips `//`
|
||||
line comments from the config file so the Sublime Text SFTP plugin format works
|
||||
without modification.
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
php api/deploy/deploy-sftp.php [OPTIONS]
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path <dir>` | `.` | Repository root to deploy |
|
||||
| `--src-dir <dir>` | `src` | Sub-directory inside the repo to upload |
|
||||
| `--env <dev\|demo>` | — | Target environment; selects named config file (see below) |
|
||||
| `--config <file>` | — | Explicit config path — overrides `--env` and auto-lookup |
|
||||
| `--key-passphrase <pw>` | _(none)_ | Passphrase for encrypted SSH key |
|
||||
| `--dry-run` | off | Preview uploads without connecting |
|
||||
| `--verbose` / `-v` | off | Show per-file transfer details |
|
||||
| `--quiet` / `-q` | off | Suppress all output except errors |
|
||||
| `--help` / `-h` | — | Show help and exit |
|
||||
|
||||
### Config File Resolution
|
||||
|
||||
`--env` controls which config file is loaded from `{path}/scripts/sftp-config/`:
|
||||
|
||||
| `--env` | Config file |
|
||||
|---------|-------------|
|
||||
| `dev` | `scripts/sftp-config/sftp-config.dev.json` |
|
||||
| `demo` | `scripts/sftp-config/sftp-config.demo.json` |
|
||||
| _(none)_ | `scripts/sftp-config/sftp-config.json` (generic fallback) |
|
||||
|
||||
> **Note:** The `rs` environment has been retired. RS deployment is via the release pipeline only.
|
||||
|
||||
`--config <file>` always takes precedence over `--env`.
|
||||
|
||||
### Directory Layout
|
||||
|
||||
Both directories are **gitignored** — create them locally and never commit their contents:
|
||||
|
||||
```
|
||||
{repo_root}/
|
||||
scripts/
|
||||
sftp-config/ ← gitignored; copy templates from templates/scripts/deploy/
|
||||
sftp-config.dev.json ← copy of sftp-config.dev.json.example, filled in
|
||||
sftp-config.demo.json ← copy of sftp-config.demo.json.example, filled in
|
||||
keys/ ← gitignored; place your .ppk / PEM key file here
|
||||
```
|
||||
|
||||
> **IMPORTANT:** `sftp-config.json` files are for local development only. In CI/CD, all credentials must come from GitHub variables and secrets. Never commit sftp-config files.
|
||||
|
||||
See `templates/scripts/sftp-config/README.md` for step-by-step setup instructions.
|
||||
|
||||
### Key Resolution
|
||||
|
||||
`ssh_key_file` in `sftp-config.json` may be an absolute path or a bare filename.
|
||||
When not absolute, the script looks for the key under `{path}/scripts/keys/` first,
|
||||
then falls back to the value as a path relative to CWD.
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Preview what would be uploaded (no connection)
|
||||
php api/deploy/deploy-sftp.php --env dev --dry-run --verbose
|
||||
|
||||
# Deploy src/ to dev server
|
||||
php api/deploy/deploy-sftp.php --path /repos/mymodule --env dev
|
||||
|
||||
# Deploy src/ to demo server
|
||||
php api/deploy/deploy-sftp.php --path /repos/mymodule --env demo
|
||||
|
||||
# Use a different source directory
|
||||
php api/deploy/deploy-sftp.php --path /repos/mymodule --env dev --src-dir htdocs
|
||||
|
||||
# Deploy with explicit config and encrypted key
|
||||
php api/deploy/deploy-sftp.php \
|
||||
--path /repos/mymodule \
|
||||
--config /repos/mymodule/scripts/sftp-config/sftp-config.demo.json \
|
||||
--key-passphrase "my passphrase"
|
||||
```
|
||||
|
||||
### Config Format
|
||||
|
||||
Copy a template from `templates/scripts/deploy/` to `scripts/sftp-config/` and fill in your values:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "sftp",
|
||||
"host": "iad1-shared-b7-01.dreamhost.com",
|
||||
"user": "mokoconsulting_dev",
|
||||
"ssh_key_file": "jmiller_private.ppk",
|
||||
"port": "22",
|
||||
"remote_path": "/home/mokoconsulting_dev/crm.dev.mokoconsulting.tech/htdocs/custom/mymodule/",
|
||||
"ignore_regexes": [
|
||||
"\\.git*",
|
||||
"sftp-config(-alt\\d?)?\\.json",
|
||||
"\\.DS_Store",
|
||||
"Thumbs\\.db"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`ssh_key_file` may be a bare filename (resolved from `scripts/keys/`) or an
|
||||
absolute path (e.g. `J:/My Drive/Keys/jmiller_private.ppk`).
|
||||
|
||||
### Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `0` | All files uploaded successfully |
|
||||
| `1` | Connection failed or one or more files could not be uploaded |
|
||||
| `2` | Invalid arguments or config file error |
|
||||
|
||||
### Called by Workflows
|
||||
|
||||
| Workflow | Trigger | Target | Secrets prefix |
|
||||
|----------|---------|--------|----------------|
|
||||
| `deploy-dev.yml` | `workflow_call`, `workflow_dispatch` | Dev server | `DEV_FTP_` |
|
||||
| `deploy-demo.yml` | `workflow_call`, `workflow_dispatch` | Demo server | `DEMO_FTP_` |
|
||||
|
||||
> **Note:** The former `deploy-rs.yml` workflow (RS server, `RS_FTP_` prefix) has been retired. RS deployment is now handled via the release pipeline (`auto-release.yml`).
|
||||
|
||||
See [Deploy Workflows](../../workflows/dev-deployment.md) for workflow usage.
|
||||
|
||||
### GitHub Secrets and Variables Reference
|
||||
|
||||
When called from CI, the script reads credentials from environment variables set by the workflow. See the [SFTP Deployment Guide](../../deployment/sftp.md#github-secrets-and-variables) for the full secrets/variables tables for `DEV_FTP_*` and `DEMO_FTP_*` environments, including types (Secret vs. Variable) and scopes (Org vs. Repo).
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/deploy/`
|
||||
**Mirrors:** `api/deploy/`
|
||||
**Last Updated:** 2026-04-07
|
||||
@@ -0,0 +1,114 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/fix/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for automated fix scripts in api/fix/
|
||||
-->
|
||||
|
||||
# Fix Scripts
|
||||
|
||||
Scripts in `api/fix/` make automated corrections to source files. All scripts:
|
||||
|
||||
- Extend `CliBase`
|
||||
- Support `--dry-run` (preview changes without writing)
|
||||
- Support `--help` for usage information
|
||||
- Operate on tracked files only (respects `.gitignore`)
|
||||
|
||||
Always run with `--dry-run` first to review changes before applying them.
|
||||
|
||||
```bash
|
||||
php api/fix/<script>.php --path /path/to/repo --dry-run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## fix_line_endings.php
|
||||
|
||||
Converts CRLF (`\r\n`) line endings to LF (`\n`) in all tracked text files.
|
||||
Prevents spurious diff noise on Windows development machines.
|
||||
|
||||
```bash
|
||||
php api/fix/fix_line_endings.php --path .
|
||||
php api/fix/fix_line_endings.php --path . --dry-run
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--dry-run` | off | Show files that would be changed |
|
||||
| `--help` | — | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## fix_permissions.php
|
||||
|
||||
Sets correct file permissions across the repository:
|
||||
|
||||
- Directories: `755`
|
||||
- Regular files: `644`
|
||||
- Executable scripts (`*.php`, `*.sh`): `755`
|
||||
|
||||
```bash
|
||||
php api/fix/fix_permissions.php --path .
|
||||
php api/fix/fix_permissions.php --path . --dry-run
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--dry-run` | off | Show permission changes without applying |
|
||||
| `--help` | — | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## fix_tabs.php
|
||||
|
||||
Converts leading tabs to spaces (or vice versa) in tracked source files
|
||||
according to `.editorconfig` rules.
|
||||
|
||||
```bash
|
||||
php api/fix/fix_tabs.php --path .
|
||||
php api/fix/fix_tabs.php --path . --type yaml
|
||||
php api/fix/fix_tabs.php --path . --dry-run
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--type <ext>` | all | Limit fixes to files of this type (`yaml`, `php`, etc.) |
|
||||
| `--dry-run` | off | Show files that would be changed |
|
||||
| `--help` | — | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## fix_trailing_spaces.php
|
||||
|
||||
Removes trailing whitespace from every line in tracked source files.
|
||||
|
||||
```bash
|
||||
php api/fix/fix_trailing_spaces.php --path .
|
||||
php api/fix/fix_trailing_spaces.php --path . --type php
|
||||
php api/fix/fix_trailing_spaces.php --path . --dry-run
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--type <ext>` | all | Limit fixes to files of this type |
|
||||
| `--dry-run` | off | Show files that would be changed |
|
||||
| `--help` | — | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/fix/`
|
||||
**Mirrors:** `api/fix/`
|
||||
**Last Updated:** 2026-03-13
|
||||
@@ -0,0 +1,322 @@
|
||||
# API Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains documentation for the MokoStandards API structure. The documentation mirrors the actual API directory structure found in `/api/`.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
docs/api/
|
||||
├── index.md # This file - API documentation overview
|
||||
├── analysis/ # Analysis tools documentation
|
||||
├── automation/ # Automation scripts (bulk_sync.php)
|
||||
├── build/ # Build tools documentation
|
||||
├── definitions/ # Repository definitions documentation
|
||||
│ ├── default/ # Default platform definitions documentation
|
||||
│ └── sync/ # Synced repository definitions documentation
|
||||
├── cli/ # Repo lifecycle & release scripts
|
||||
├── deploy/ # Deploy scripts (deploy-sftp.php, deploy-joomla.php)
|
||||
├── fix/ # Fix utilities (fix_*.php)
|
||||
├── lib/ # Library documentation
|
||||
│ ├── Enterprise/ # Enterprise libraries
|
||||
│ └── plugins/ # Plugin system
|
||||
├── maintenance/ # Maintenance scripts documentation
|
||||
├── plugin/ # Plugin runner scripts (plugin_*.php)
|
||||
├── release/ # Release tools documentation
|
||||
├── tests/ # Testing documentation
|
||||
├── validate/ # Validation scripts (check_*.php)
|
||||
└── wrappers/ # Wrapper scripts documentation
|
||||
```
|
||||
|
||||
## Purpose
|
||||
|
||||
The API directory (`/api/`) contains all core functionality for:
|
||||
|
||||
- **Repository validation** - Scripts to validate repository structure and compliance
|
||||
- **Automation** - Bulk sync and automated repository management
|
||||
- **Definitions** - Repository structure definitions for different platforms
|
||||
- **Enterprise libraries** - Reusable PHP libraries for GitHub API, logging, metrics
|
||||
- **Build and release** - Tools for building and releasing projects
|
||||
- **Analysis** - Code analysis and quality tools
|
||||
- **Testing** - Test infrastructure and utilities
|
||||
|
||||
## Documentation Conventions
|
||||
|
||||
### File Organization
|
||||
|
||||
- Each API directory has corresponding documentation in `docs/api/`
|
||||
- Documentation files use `.md` (Markdown) format
|
||||
- Index files (`index.md`) provide directory overview
|
||||
- Individual scripts/tools have dedicated documentation files
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
Documentation files follow these patterns:
|
||||
|
||||
- `index.md` - Directory overview and contents listing
|
||||
- `{script-name}.md` - Documentation for specific script
|
||||
- `{library-name}.md` - Documentation for specific library
|
||||
- `overview.md` - Conceptual overview for complex subsystems
|
||||
|
||||
### Documentation Structure
|
||||
|
||||
Each documentation file should include:
|
||||
|
||||
1. **Title and Purpose** - What the component does
|
||||
2. **Usage** - How to use it (command-line examples, API calls)
|
||||
3. **Parameters/Options** - Detailed parameter documentation
|
||||
4. **Examples** - Real-world usage examples
|
||||
5. **Output** - What to expect from the command/function
|
||||
6. **Related** - Links to related documentation
|
||||
|
||||
## API Directories
|
||||
|
||||
### automation/
|
||||
|
||||
Automation scripts for bulk repository operations:
|
||||
|
||||
- **bulk_sync.php** - Bulk synchronization across multiple repositories
|
||||
- Repository definition generation
|
||||
- Automated PR creation and management
|
||||
|
||||
[View automation documentation →](./automation/index.md)
|
||||
|
||||
### definitions/
|
||||
|
||||
Repository structure definitions:
|
||||
|
||||
- **default/** - Platform-specific base definitions
|
||||
- **sync/** - Auto-generated repository-specific definitions
|
||||
|
||||
[View definitions documentation →](./definitions/default/index.md)
|
||||
|
||||
### validate/
|
||||
|
||||
Validation and compliance checking:
|
||||
|
||||
- **auto_detect_platform.php** - Platform detection and validation
|
||||
- **check_repo_health.php** - Repository health scoring
|
||||
- **check_enterprise_readiness.php** - Enterprise readiness validation
|
||||
|
||||
[View validation documentation →](./validate/index.md)
|
||||
|
||||
### lib/
|
||||
|
||||
Reusable library components:
|
||||
|
||||
- **Enterprise/** - GitHub API client, logging, metrics, synchronization
|
||||
- **plugins/** - Plugin system for platform-specific operations
|
||||
|
||||
[View library documentation →](./lib/index.md)
|
||||
|
||||
### build/
|
||||
|
||||
Build tools and utilities:
|
||||
|
||||
- Build automation scripts
|
||||
- Dependency management
|
||||
- Asset compilation
|
||||
|
||||
[View build documentation →](./build/index.md)
|
||||
|
||||
### release/
|
||||
|
||||
Release management tools:
|
||||
|
||||
- Package generation scripts
|
||||
- Platform-specific packaging (Joomla, Dolibarr)
|
||||
- Version management
|
||||
|
||||
[View release documentation →](./release/index.md)
|
||||
|
||||
### tests/
|
||||
|
||||
Testing infrastructure:
|
||||
|
||||
- Unit tests
|
||||
- Integration tests
|
||||
- Test utilities and helpers
|
||||
|
||||
[View testing documentation →](./tests/index.md)
|
||||
|
||||
### cli/
|
||||
|
||||
Repository lifecycle and release management scripts:
|
||||
|
||||
- **create_repo.php** — Scaffold new governed repositories (7-step wizard: create, topics, .mokostandards, README, labels, sync, project)
|
||||
- **archive_repo.php** — Graceful retirement: close PRs/issues, archive on GitHub, remove sync definition
|
||||
- **release.php** — Create version releases and version branches (`version/XX`)
|
||||
- **sync_rulesets.php** — Apply org rulesets (MAIN, DEV, VERSION, RC, WORKFLOWS) to repos
|
||||
- **platform_detect.php** — Detect repo platform type (crm-module, waas-component, crm-platform, generic)
|
||||
- **version_bump.php** — Bump version numbers across all files
|
||||
- **version_read.php** — Read current version from repo
|
||||
- **create_project.php** — Create GitHub Project for a repo
|
||||
|
||||
### deploy/
|
||||
|
||||
SFTP deployment scripts:
|
||||
|
||||
- **deploy-sftp.php** — Upload a repo's `src/` or `htdocs/` to a remote server via SFTP
|
||||
- **deploy-joomla.php** — Smart Joomla deploy: parses XML manifest, routes files to correct Joomla directories
|
||||
- Supports PuTTY `.ppk` and OpenSSH PEM keys
|
||||
- Called by `deploy-dev.yml` and `deploy-demo.yml` workflows (`deploy-rs.yml` retired)
|
||||
|
||||
[View deploy documentation →](./deploy/index.md)
|
||||
|
||||
### plugin/
|
||||
|
||||
Plugin-system runner scripts (entry points for governed repos):
|
||||
|
||||
- **plugin_validate.php** — Validate project structure and standards
|
||||
- **plugin_health_check.php** — Run health checks and score
|
||||
- **plugin_readiness.php** — Check release readiness
|
||||
- **plugin_metrics.php** — Collect project metrics
|
||||
- **plugin_list.php** — List all registered project-type plugins
|
||||
|
||||
[View plugin script documentation →](./plugin/index.md)
|
||||
|
||||
### maintenance/
|
||||
|
||||
Maintenance and housekeeping scripts:
|
||||
|
||||
- **pin_action_shas.php** — Pin GitHub Actions to immutable SHAs
|
||||
- **setup_labels.php** — Deploy 67 required GitHub labels (12 groups)
|
||||
- **sync_dolibarr_readmes.php** — Keep root and src READMEs in sync
|
||||
- **update_sha_hashes.php** — Regenerate script registry hashes
|
||||
- **update_version_from_readme.php** — Propagate version from README
|
||||
- **rotate_secrets.php** — Audit FTP secrets/variables across repos
|
||||
- **repo_inventory.php** — Live inventory dashboard as GitHub issue
|
||||
|
||||
[View maintenance documentation →](./maintenance/index.md)
|
||||
|
||||
### analysis/
|
||||
|
||||
Code analysis tools:
|
||||
|
||||
- Static analysis
|
||||
- Quality metrics
|
||||
- Dependency analysis
|
||||
|
||||
[View analysis documentation →](./analysis/index.md)
|
||||
|
||||
### wrappers/
|
||||
|
||||
Shell wrappers for cross-platform compatibility:
|
||||
|
||||
- **bash/** - Bash wrapper scripts
|
||||
|
||||
[View wrappers documentation →](./wrappers/index.md)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Repository Validation
|
||||
|
||||
```bash
|
||||
# Auto-detect platform and validate repository
|
||||
php api/validate/auto_detect_platform.php --path /path/to/repo
|
||||
|
||||
# Check repository health score
|
||||
php api/validate/check_repo_health.php --path /path/to/repo
|
||||
|
||||
# Check all validation scripts at once
|
||||
php api/validate/check_repo_health.php --path . --json
|
||||
```
|
||||
|
||||
### Plugin System
|
||||
|
||||
```bash
|
||||
# Validate a project
|
||||
php api/plugin_validate.php --project-path /path/to/project
|
||||
|
||||
# Check release readiness
|
||||
php api/plugin_readiness.php --project-path /path/to/project
|
||||
|
||||
# Run health check
|
||||
php api/plugin_health_check.php --project-path /path/to/project
|
||||
|
||||
# List all registered plugins
|
||||
php api/plugin_list.php
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
```bash
|
||||
# Preview SFTP upload (dry-run)
|
||||
php api/deploy/deploy-sftp.php --path /path/to/project --dry-run --verbose
|
||||
|
||||
# Deploy src/ to remote server
|
||||
php api/deploy/deploy-sftp.php --path /path/to/project
|
||||
```
|
||||
|
||||
### Bulk Sync
|
||||
|
||||
```bash
|
||||
# Sync templates to multiple repositories
|
||||
php api/automation/bulk_sync.php \
|
||||
--org mokoconsulting-tech \
|
||||
--repos "repo1,repo2,repo3"
|
||||
```
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
When developing new API components:
|
||||
|
||||
1. **Follow existing patterns** - Use established conventions
|
||||
2. **Add documentation** - Create corresponding docs/api/ documentation
|
||||
3. **Include examples** - Provide real-world usage examples
|
||||
4. **Handle errors** - Implement proper error handling and logging
|
||||
5. **Write tests** - Add test coverage for new functionality
|
||||
6. **Use type hints** - Declare strict types in PHP code
|
||||
7. **Log operations** - Use AuditLogger for important operations
|
||||
|
||||
## Architecture
|
||||
|
||||
### Plugin System
|
||||
|
||||
The API uses a plugin architecture for platform-specific operations:
|
||||
|
||||
```php
|
||||
// Auto-detect platform and create plugin
|
||||
$detector = new ProjectTypeDetector($repoPath);
|
||||
$projectType = $detector->detect();
|
||||
$plugin = PluginFactory::createForProject($repoPath);
|
||||
|
||||
// Use plugin for platform-specific operations
|
||||
$health = $plugin->healthCheck();
|
||||
$metrics = $plugin->collectMetrics();
|
||||
```
|
||||
|
||||
### Enterprise Libraries
|
||||
|
||||
Core enterprise libraries provide:
|
||||
|
||||
- **ApiClient** - GitHub API client with rate limiting and circuit breaker
|
||||
- **AuditLogger** - Structured logging with transaction support
|
||||
- **MetricsCollector** - Metrics collection and reporting
|
||||
- **RepositorySynchronizer** - Repository synchronization logic
|
||||
|
||||
### Validation Pipeline
|
||||
|
||||
Repository validation follows this pipeline:
|
||||
|
||||
1. **Platform Detection** - Identify repository type
|
||||
2. **Definition Loading** - Load appropriate structure definition
|
||||
3. **Structure Validation** - Validate against definition
|
||||
4. **Health Scoring** - Calculate health score (0-100+)
|
||||
5. **Report Generation** - Generate validation report
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Validation Guide](../guide/validation/) - Complete validation documentation
|
||||
- [Automation Guide](../automation/) - Automation workflows and processes
|
||||
- [Schema Guide](../schemas/repohealth/) - Repository structure schemas
|
||||
- [Development Guide](../development/) - Development guidelines and standards
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/`
|
||||
**Purpose**: Documentation for MokoStandards API
|
||||
**Mirrors**: `/api/` directory structure
|
||||
**Last Updated**: 2026-04-04
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,20 @@
|
||||
# Lib Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains documentation for tools in `/api/lib/`.
|
||||
|
||||
## Contents
|
||||
|
||||
_To be documented_
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Overview](../index.md)
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/lib/`
|
||||
**Mirrors**: `/api/lib/`
|
||||
**Last Updated**: 2026-03-03
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,180 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/maintenance/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for housekeeping and maintenance scripts in api/maintenance/
|
||||
-->
|
||||
|
||||
# Maintenance Scripts
|
||||
|
||||
Scripts in `api/maintenance/` perform housekeeping tasks: pinning action SHAs,
|
||||
syncing README files, propagating version numbers, and managing GitHub labels.
|
||||
|
||||
---
|
||||
|
||||
## pin_action_shas.php
|
||||
|
||||
Pins all `uses:` references in `.github/workflows/` to immutable SHA digests,
|
||||
replacing floating tags (e.g. `v4`) to prevent supply-chain attacks.
|
||||
|
||||
```bash
|
||||
php api/maintenance/pin_action_shas.php --dry-run
|
||||
php api/maintenance/pin_action_shas.php --verbose
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--dry-run` | Show changes without writing files |
|
||||
| `--verbose` / `-v` | Print each file processed |
|
||||
| `--help` / `-h` | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## setup_labels.php
|
||||
|
||||
Deploys the full set of GitHub issue and PR labels to all governed
|
||||
repositories. Idempotent — creates missing labels and updates colour/description
|
||||
of existing ones via `gh label create --force`.
|
||||
|
||||
**Label groups (67 total):**
|
||||
|
||||
| Group | Count | Examples |
|
||||
|-------|-------|---------|
|
||||
| Project Type | 3 | `joomla`, `dolibarr`, `generic` |
|
||||
| Language | 6 | `php`, `javascript`, `css` |
|
||||
| Component | 8 | `documentation`, `ci-cd`, `security`, `tests` |
|
||||
| Workflow | 5 | `automation`, `mokostandards`, `breaking-change` |
|
||||
| Priority | 4 | `priority: critical` … `priority: low` |
|
||||
| Type | 5 | `type: bug`, `type: feature`, `type: chore` |
|
||||
| Status | 5 | `status: pending`, `status: in-progress`, `status: blocked` |
|
||||
| Size | 6 | `size/xs` … `size/xxl` |
|
||||
| Health | 4 | `health: excellent` … `health: poor` |
|
||||
| Sync/Automation | 11 | `standards-update`, `deploy-failure`, `version-drift` |
|
||||
| Testing | 4 | `type: test`, `needs-testing`, `test-failure`, `regression` |
|
||||
| Version/Release | 6 | `type: release`, `release-candidate`, `minor-release`, `patch-release` |
|
||||
|
||||
```bash
|
||||
php api/maintenance/setup_labels.php
|
||||
php api/maintenance/setup_labels.php --dry-run
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--dry-run` | Preview label changes without applying them |
|
||||
| `--help` / `-h` | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## sync_dolibarr_readmes.php
|
||||
|
||||
Keeps the root `README.md` and `src/README.md` in sync for Dolibarr module
|
||||
repositories. Copies the canonical root README into `src/` to satisfy the
|
||||
module store requirement.
|
||||
|
||||
```bash
|
||||
php api/maintenance/sync_dolibarr_readmes.php --path /path/to/module
|
||||
php api/maintenance/sync_dolibarr_readmes.php --path /path/to/module --dry-run
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--dry-run` | off | Show what would be synced without writing |
|
||||
|
||||
---
|
||||
|
||||
## update_sha_hashes.php
|
||||
|
||||
Regenerates SHA-256 hashes in the script registry (`api/definitions/`) to
|
||||
reflect current file contents after scripts are modified.
|
||||
|
||||
```bash
|
||||
php api/maintenance/update_sha_hashes.php --dry-run
|
||||
php api/maintenance/update_sha_hashes.php --verbose
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--dry-run` | Show hash differences without updating |
|
||||
| `--verbose` / `-v` | Print each file processed |
|
||||
| `--help` / `-h` | Show help and exit |
|
||||
|
||||
---
|
||||
|
||||
## update_version_from_readme.php
|
||||
|
||||
Reads the canonical version from the `VERSION` field in `README.md`'s FILE
|
||||
INFORMATION block and propagates it to all badges, headers, and other VERSION
|
||||
fields throughout the repository. Run this after bumping the version in
|
||||
`README.md` instead of manually updating every file.
|
||||
|
||||
```bash
|
||||
php api/maintenance/update_version_from_readme.php --path .
|
||||
php api/maintenance/update_version_from_readme.php --path . --dry-run
|
||||
php api/maintenance/update_version_from_readme.php --path . --create-issue --repo owner/repo
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--path` | `.` | Repository root |
|
||||
| `--dry-run` | off | Show changes without writing |
|
||||
| `--create-issue` | off | Create a GitHub issue listing updated files |
|
||||
| `--repo <owner/repo>` | — | Repository for issue creation |
|
||||
|
||||
---
|
||||
|
||||
## rotate_secrets.php
|
||||
|
||||
Audits FTP secrets and variables (DEV/DEMO/RS) across all governed repositories.
|
||||
Reports missing auth keys, incomplete environment configs, and optionally posts
|
||||
results as a GitHub issue in MokoStandards.
|
||||
|
||||
```bash
|
||||
php api/maintenance/rotate_secrets.php --all
|
||||
php api/maintenance/rotate_secrets.php --repo MokoCRM
|
||||
php api/maintenance/rotate_secrets.php --all --create-issue
|
||||
php api/maintenance/rotate_secrets.php --all --json
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--all` | Audit all governed repos |
|
||||
| `--repo <name>` | Audit a single repo |
|
||||
| `--json` | Machine-readable JSON output |
|
||||
| `--create-issue` | Post/update audit results as a GitHub issue |
|
||||
| `--org <name>` | GitHub organization (default: `mokoconsulting-tech`) |
|
||||
|
||||
---
|
||||
|
||||
## repo_inventory.php
|
||||
|
||||
Generates a live inventory dashboard of all governed repos and posts it as a
|
||||
GitHub issue in MokoStandards. Shows platform, version, rulesets status,
|
||||
project linkage, and open issue count per repo. Auto-updates on each run.
|
||||
|
||||
```bash
|
||||
php api/maintenance/repo_inventory.php
|
||||
php api/maintenance/repo_inventory.php --dry-run
|
||||
php api/maintenance/repo_inventory.php --json
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--dry-run` | Preview without posting issue |
|
||||
| `--json` | JSON output to stdout |
|
||||
| `--org <name>` | GitHub organization (default: `mokoconsulting-tech`) |
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/maintenance/`
|
||||
**Mirrors:** `api/maintenance/`
|
||||
**Last Updated:** 2026-03-30
|
||||
@@ -0,0 +1,176 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/plugin/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for plugin runner scripts in api/plugin_*.php
|
||||
-->
|
||||
|
||||
# Plugin Scripts
|
||||
|
||||
Scripts at `api/plugin_*.php` are the primary CLI entry points for the
|
||||
MokoStandards plugin system. Each script auto-detects the project type
|
||||
(Joomla, Dolibarr, Node.js, Python, WordPress, Terraform, mobile, API,
|
||||
generic, documentation) or accepts `--project-type` to override.
|
||||
|
||||
All scripts share a common set of flags and exit-code conventions.
|
||||
|
||||
---
|
||||
|
||||
## Common Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--project-path <dir>` | **(required)** Path to the project directory |
|
||||
| `--project-type <type>` | Override auto-detection. Valid: `joomla`, `dolibarr`, `wordpress`, `nodejs`, `python`, `terraform`, `mobile`, `api`, `documentation`, `generic` |
|
||||
| `--config <file>` | Path to a project-specific configuration file |
|
||||
| `--json` | Output results in machine-readable JSON |
|
||||
| `--verbose` | Enable verbose logging |
|
||||
| `--help` / `-h` | Show help and exit |
|
||||
|
||||
## Common Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `0` | Success (check/collection passed) |
|
||||
| `1` | Completed with failures or warnings |
|
||||
| `2` | Script error (invalid arguments, plugin not found, etc.) |
|
||||
|
||||
---
|
||||
|
||||
## plugin_validate.php
|
||||
|
||||
**Path:** `api/plugin_validate.php`
|
||||
|
||||
Validates a project's structure, required files, and standards compliance.
|
||||
|
||||
```bash
|
||||
# Auto-detect project type and validate
|
||||
php api/plugin_validate.php --project-path /path/to/project
|
||||
|
||||
# Validate a specific type
|
||||
php api/plugin_validate.php --project-path /path/to/project --project-type dolibarr
|
||||
|
||||
# Machine-readable output
|
||||
php api/plugin_validate.php --project-path /path/to/project --json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## plugin_health_check.php
|
||||
|
||||
**Path:** `api/plugin_health_check.php`
|
||||
|
||||
Runs health checks on a project and returns a health score (0–100).
|
||||
|
||||
Additional options:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--json` | Output as JSON (default) |
|
||||
|
||||
```bash
|
||||
# Run health check
|
||||
php api/plugin_health_check.php --project-path /path/to/project
|
||||
|
||||
# Explicit type, human-readable output
|
||||
php api/plugin_health_check.php --project-path /path/to/project --project-type joomla --verbose
|
||||
```
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` — Healthy
|
||||
- `1` — Unhealthy
|
||||
- `2` — Script error
|
||||
|
||||
---
|
||||
|
||||
## plugin_readiness.php
|
||||
|
||||
**Path:** `api/plugin_readiness.php`
|
||||
|
||||
Checks whether a project is ready for release or deployment by evaluating
|
||||
blockers vs. warnings.
|
||||
|
||||
```bash
|
||||
# Check release readiness
|
||||
php api/plugin_readiness.php --project-path /path/to/project
|
||||
|
||||
# Pipe JSON output to jq
|
||||
php api/plugin_readiness.php --project-path /path/to/project --json | jq '.ready'
|
||||
```
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` — Ready for release (no blockers)
|
||||
- `1` — Not ready (has blockers)
|
||||
- `2` — Script error
|
||||
|
||||
---
|
||||
|
||||
## plugin_metrics.php
|
||||
|
||||
**Path:** `api/plugin_metrics.php`
|
||||
|
||||
Collects project metrics (file counts, code coverage, complexity indicators,
|
||||
dependency counts, etc.) as reported by the plugin.
|
||||
|
||||
Additional options:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--format <fmt>` | Output format: `json` (default), `table`, `csv` |
|
||||
|
||||
```bash
|
||||
# JSON metrics (default)
|
||||
php api/plugin_metrics.php --project-path /path/to/project
|
||||
|
||||
# Table output
|
||||
php api/plugin_metrics.php --project-path /path/to/project --format table
|
||||
|
||||
# CSV for spreadsheet import
|
||||
php api/plugin_metrics.php --project-path /path/to/project --format csv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## plugin_list.php
|
||||
|
||||
**Path:** `api/plugin_list.php`
|
||||
|
||||
Lists all registered project-type plugins and their capabilities. Does not
|
||||
require `--project-path`.
|
||||
|
||||
Additional options:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--format <fmt>` | Output format: `table` (default), `json`, `simple` |
|
||||
| `--type <type>` | Show details for one specific plugin type |
|
||||
| `--details` | Include required files, features, and commands in output |
|
||||
|
||||
```bash
|
||||
# List all plugins (table)
|
||||
php api/plugin_list.php
|
||||
|
||||
# JSON output of all plugins
|
||||
php api/plugin_list.php --format json
|
||||
|
||||
# Details for a specific plugin
|
||||
php api/plugin_list.php --type dolibarr --details
|
||||
|
||||
# Simple list of plugin type names only
|
||||
php api/plugin_list.php --format simple
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/plugin/`
|
||||
**Mirrors:** `api/plugin_*.php`
|
||||
**Last Updated:** 2026-03-13
|
||||
@@ -0,0 +1,62 @@
|
||||
# Tests Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
Documentation for the test suite in `/api/tests/` of the `mokoconsulting/mokostandards` package.
|
||||
|
||||
## Test Files
|
||||
|
||||
### test_circuit_breaker_handling.php
|
||||
|
||||
Verifies that `CircuitBreakerOpen` and `RateLimitExceeded` exceptions are throwable and
|
||||
catchable, and that `ApiClient` trips its circuit breaker after repeated failures.
|
||||
|
||||
**Run:**
|
||||
```bash
|
||||
php api/tests/test_circuit_breaker_handling.php
|
||||
```
|
||||
|
||||
### test_enterprise_libraries.php
|
||||
|
||||
Smoke-tests all Enterprise library classes:
|
||||
`MetricsCollector`, `SecurityValidator`, `TransactionManager`, `UnifiedValidator`,
|
||||
`CLIApp` (`CliFramework`).
|
||||
|
||||
**Run:**
|
||||
```bash
|
||||
php api/tests/test_enterprise_libraries.php
|
||||
```
|
||||
|
||||
## Sample Fixture
|
||||
|
||||
`tests/sample/` (at the repository root) is a minimal generic repository used to exercise
|
||||
validators (`check_repo_health.php`, `auto_detect_platform.php`) against a local path without
|
||||
requiring network access or a real GitHub repository.
|
||||
|
||||
This directory is committed to version control. It contains:
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `README.md` | Substantial README (satisfies health-check threshold) |
|
||||
| `LICENSE` | GPL-3.0-or-later |
|
||||
| `.gitignore` | Basic ignore rules |
|
||||
| `CHANGELOG.md` | Keep-a-Changelog stub |
|
||||
| `CODE_OF_CONDUCT.md` | Contributor Covenant stub |
|
||||
| `SECURITY.md` | Vulnerability reporting policy |
|
||||
| `composer.json` | PHP project manifest (`mokoconsulting/sample-repo`) |
|
||||
| `docs/` | Minimal docs directory |
|
||||
| `.github/workflows/ci.yml` | Sample CI workflow |
|
||||
| `.github/dependabot.yml` | Dependabot configuration |
|
||||
|
||||
See [`docs/api/tests/sample/index.md`](./sample/index.md) for details.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Overview](../index.md)
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/tests/`
|
||||
**Mirrors**: `/api/tests/`
|
||||
**Last Updated**: 2026-03-04
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,56 @@
|
||||
# Sample Fixture Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
`tests/sample/` (at the repository root) is a minimal generic repository fixture used by
|
||||
MokoStandards API tests. This directory is committed to version control as part of the
|
||||
repository.
|
||||
|
||||
## Purpose
|
||||
|
||||
Test scripts pass `tests/sample/` as the `--path` argument to validation scripts so
|
||||
that validators can be exercised locally without network access or a real GitHub repository.
|
||||
|
||||
## Fixture Contents
|
||||
|
||||
| Path | Health-check satisfied |
|
||||
|---|---|
|
||||
| `README.md` | README.md exists + substantial content |
|
||||
| `LICENSE` | LICENSE file exists |
|
||||
| `.gitignore` | .gitignore exists |
|
||||
| `CHANGELOG.md` | CHANGELOG.md exists |
|
||||
| `CODE_OF_CONDUCT.md` | CODE_OF_CONDUCT.md exists |
|
||||
| `SECURITY.md` | SECURITY.md exists |
|
||||
| `composer.json` | PHP project manifest |
|
||||
| `docs/` | docs/ directory exists |
|
||||
| `.github/workflows/ci.yml` | Workflows directory exists |
|
||||
| `.github/dependabot.yml` | dependabot configured |
|
||||
|
||||
## Example Usage
|
||||
|
||||
```php
|
||||
// From a test script at api/tests/test_*.php, __DIR__ = api/tests/
|
||||
// Two levels up from api/tests/ reaches the repo root
|
||||
$samplePath = __DIR__ . '/../../tests/sample';
|
||||
|
||||
// Platform detection
|
||||
$detector = new AutoDetectPlatform();
|
||||
$platform = $detector->detect($samplePath); // returns 'generic'
|
||||
|
||||
// Health check
|
||||
$checker = new RepositoryHealthChecker($samplePath);
|
||||
$score = $checker->run(); // should reach passing threshold
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Tests Documentation](../index.md)
|
||||
- [Validation Scripts](../../validate/index.md)
|
||||
- [API Overview](../../index.md)
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/tests/sample/`
|
||||
**Mirrors**: `/tests/sample/`
|
||||
**Last Updated**: 2026-03-04
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,276 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation.API
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/api/validate/index.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: API reference for all validation scripts in api/validate/
|
||||
-->
|
||||
|
||||
# Validation Scripts
|
||||
|
||||
Scripts in `api/validate/` check a repository or project for standards compliance.
|
||||
All scripts extend `CliFramework` and support `--help`, `--dry-run`, `--verbose`,
|
||||
`--quiet`, and `--json` unless noted otherwise.
|
||||
|
||||
The typical invocation pattern is:
|
||||
|
||||
```bash
|
||||
php api/validate/<script>.php --path /path/to/repo [OPTIONS]
|
||||
```
|
||||
|
||||
Run all validations at once via:
|
||||
|
||||
```bash
|
||||
php api/validate/check_repo_health.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## auto_detect_platform.php
|
||||
|
||||
Auto-detects the repository platform (Joomla, Dolibarr, Node.js, etc.) and
|
||||
validates its structure against the detected schema.
|
||||
|
||||
```bash
|
||||
php api/validate/auto_detect_platform.php --path .
|
||||
php api/validate/auto_detect_platform.php --repo-path /path/to/repo --schema-dir api/definitions/
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--repo-path` | Repository path (default: `.`) |
|
||||
| `--schema-dir` | Directory containing schema `.tf` definition files |
|
||||
| `--output-dir` | Directory to write detection report |
|
||||
|
||||
---
|
||||
|
||||
## check_changelog.php
|
||||
|
||||
Validates `CHANGELOG.md` structure: presence of `## [Unreleased]` section,
|
||||
semantic version headings, and Keep-a-Changelog format.
|
||||
|
||||
```bash
|
||||
php api/validate/check_changelog.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_dolibarr_module.php
|
||||
|
||||
Validates the directory structure of a Dolibarr ERP module: required files,
|
||||
descriptor, language keys, and SQL install scripts.
|
||||
|
||||
```bash
|
||||
php api/validate/check_dolibarr_module.php --path /path/to/module
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_enterprise_readiness.php
|
||||
|
||||
Comprehensive enterprise-readiness check: copyright headers, PSR-12 markers,
|
||||
strict types, forbidden functions, and documentation completeness.
|
||||
|
||||
```bash
|
||||
php api/validate/check_enterprise_readiness.php --path .
|
||||
php api/validate/check_enterprise_readiness.php --path . --strict
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--strict` | Fail on warnings as well as errors |
|
||||
|
||||
---
|
||||
|
||||
## check_joomla_manifest.php
|
||||
|
||||
Validates the Joomla XML manifest (`*.xml`): required elements, version format,
|
||||
namespace declarations, and file list accuracy.
|
||||
|
||||
```bash
|
||||
php api/validate/check_joomla_manifest.php --path /path/to/extension
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_language_structure.php
|
||||
|
||||
Validates Joomla/Dolibarr language `.ini` files: `KEY=value` format, no BOM,
|
||||
consistent line endings, and no duplicate keys.
|
||||
|
||||
```bash
|
||||
php api/validate/check_language_structure.php --path /path/to/extension
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_license_headers.php
|
||||
|
||||
Advisory check: ensures source files contain a valid SPDX-License-Identifier
|
||||
comment. Reports files that are missing headers without blocking.
|
||||
|
||||
```bash
|
||||
php api/validate/check_license_headers.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_no_secrets.php
|
||||
|
||||
Advisory check: scans committed files for patterns that resemble secrets
|
||||
(API keys, passwords, private keys). Uses heuristic regex patterns.
|
||||
|
||||
```bash
|
||||
php api/validate/check_no_secrets.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_paths.php
|
||||
|
||||
Advisory check: ensures all path strings in source files use forward slashes
|
||||
(`/`) rather than backslashes for cross-platform compatibility.
|
||||
|
||||
```bash
|
||||
php api/validate/check_paths.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_php_syntax.php
|
||||
|
||||
Runs `php -l` against every tracked `.php` file and reports syntax errors.
|
||||
|
||||
```bash
|
||||
php api/validate/check_php_syntax.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_repo_health.php
|
||||
|
||||
Master health-check script: aggregates results from multiple validators and
|
||||
produces a score (0–100). Optionally creates a GitHub issue with the report.
|
||||
|
||||
```bash
|
||||
# Basic health check
|
||||
php api/validate/check_repo_health.php --path .
|
||||
|
||||
# With JSON output
|
||||
php api/validate/check_repo_health.php --path . --json
|
||||
|
||||
# Fail below threshold (default 70)
|
||||
php api/validate/check_repo_health.php --path . --threshold 80
|
||||
|
||||
# Create a GitHub issue with results
|
||||
php api/validate/check_repo_health.php --path . --create-issue --repo owner/repo
|
||||
```
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--threshold <n>` | `70` | Minimum passing score (0–100) |
|
||||
| `--json` | off | Machine-readable output |
|
||||
| `--create-issue` | off | Post results as a GitHub issue |
|
||||
| `--repo <owner/repo>` | — | Repository for issue creation |
|
||||
|
||||
---
|
||||
|
||||
## check_structure.php
|
||||
|
||||
Validates that required directories and files exist in the repository root.
|
||||
|
||||
```bash
|
||||
php api/validate/check_structure.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_tabs.php
|
||||
|
||||
Checks that no literal tab characters exist in source files (files that should
|
||||
use spaces per `.editorconfig`). Note: PHP and Markdown files are expected to
|
||||
use tabs — this check targets YAML files.
|
||||
|
||||
```bash
|
||||
php api/validate/check_tabs.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_version_consistency.php
|
||||
|
||||
Compares version numbers across `README.md`, `CHANGELOG.md`, `composer.json`,
|
||||
and FILE INFORMATION headers to detect drift.
|
||||
|
||||
```bash
|
||||
php api/validate/check_version_consistency.php
|
||||
php api/validate/check_version_consistency.php --verbose
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## check_xml_wellformed.php
|
||||
|
||||
Validates all tracked `.xml` files are well-formed (parse without errors).
|
||||
|
||||
```bash
|
||||
php api/validate/check_xml_wellformed.php --path .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## scan_drift.php
|
||||
|
||||
Scans multiple repositories in a GitHub organization for divergence from
|
||||
MokoStandards templates. Can create GitHub issues in drifted repos.
|
||||
|
||||
```bash
|
||||
php api/validate/scan_drift.php --org mokoconsulting-tech
|
||||
php api/validate/scan_drift.php --org mokoconsulting-tech --type dolibarr --json
|
||||
php api/validate/scan_drift.php --org mokoconsulting-tech --create-issues --threshold 20
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--org <name>` | GitHub organization to scan |
|
||||
| `--repos <list>` | Comma-separated list of specific repos |
|
||||
| `--type <type>` | Filter by project type |
|
||||
| `--create-issues` | Open drift issues in affected repos |
|
||||
| `--threshold <n>` | Minimum drift % to flag (default: `10`) |
|
||||
| `--json` | Machine-readable output |
|
||||
|
||||
---
|
||||
|
||||
## check_composer_deps.php
|
||||
|
||||
Validates `composer.json` across all governed repos: checks the enterprise
|
||||
dependency (`mokoconsulting-tech/enterprise`) is present and pinned to the
|
||||
correct version branch, detects stale `dev-main` references, and verifies
|
||||
`composer.lock` exists.
|
||||
|
||||
```bash
|
||||
php api/validate/check_composer_deps.php --repo MokoCRM
|
||||
php api/validate/check_composer_deps.php --all
|
||||
php api/validate/check_composer_deps.php --all --json
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--repo <name>` | Check a single repository |
|
||||
| `--all` | Check all governed repos |
|
||||
| `--json` | Machine-readable JSON output |
|
||||
| `--org <name>` | GitHub organization (default: `mokoconsulting-tech`) |
|
||||
|
||||
---
|
||||
|
||||
**Location:** `docs/api/validate/`
|
||||
**Mirrors:** `api/validate/`
|
||||
**Last Updated:** 2026-03-30
|
||||
@@ -0,0 +1,20 @@
|
||||
# Wrappers Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains documentation for tools in `/api/wrappers/`.
|
||||
|
||||
## Contents
|
||||
|
||||
_To be documented_
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Overview](../index.md)
|
||||
|
||||
---
|
||||
|
||||
**Location**: `docs/api/wrappers/`
|
||||
**Mirrors**: `/api/wrappers/`
|
||||
**Last Updated**: 2026-03-03
|
||||
**Maintained By**: MokoStandards Team
|
||||
@@ -0,0 +1,136 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Automation Documentation
|
||||
|
||||
Documentation for all automation systems deployed across MokoStandards organization repositories.
|
||||
|
||||
## Available Documentation
|
||||
|
||||
### Automation Scripts
|
||||
For details on available automation scripts, see:
|
||||
- [Automation Scripts](../../api/automation/index.md) - Bulk repository updates
|
||||
- [Maintenance Scripts](../../api/maintenance/index.md) - Repository maintenance utilities
|
||||
- [Release Scripts](../../api/release/index.md) - Release automation utilities
|
||||
|
||||
### CLI Tools (`api/cli/`)
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `create_repo.php` | Scaffold new governed repo (7-step: create, topics, .mokostandards, README, labels, sync, project) |
|
||||
| `archive_repo.php` | Retire repo (close PRs/issues, archive on GitHub, remove sync def, create record) |
|
||||
| `create_project.php` | Provision GitHub Projects V2 from 10 platform templates |
|
||||
| `sync_rulesets.php` | Apply MAIN/VERSION/DEV rulesets to all repos via GitHub API |
|
||||
| `release.php` | Full release flow (bump, propagate, version branch, tag) |
|
||||
| `version_bump.php` | Bump version (major/minor/patch) |
|
||||
| `version_read.php` | Read current version from README |
|
||||
| `version_set_platform.php` | Set platform-specific version (Dolibarr/Joomla) |
|
||||
| `platform_detect.php` | Detect platform type from repo |
|
||||
| `release_notes.php` | Generate release notes from CHANGELOG |
|
||||
|
||||
### Validation (`api/validate/`)
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `check_repo_health.php` | 118-point health score (9 categories incl. rulesets) |
|
||||
| `check_composer_deps.php` | Validate enterprise dependency version across all repos |
|
||||
| `scan_drift.php` | Detect file/config drift from standards |
|
||||
|
||||
### Maintenance (`api/maintenance/`)
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `rotate_secrets.php` | Audit DEV/DEMO/RS FTP secrets and variables |
|
||||
| `repo_inventory.php` | Live inventory dashboard posted as GitHub issue |
|
||||
| `repo_cleanup.php` | 8 cleanup operations (branches, PRs, retired workflows, etc.) |
|
||||
| `update_version_from_readme.php` | Propagate version across all file headers and badges |
|
||||
| `setup_labels.php` | Deploy 58-label standard set |
|
||||
|
||||
## CI/CD Pipeline Overview
|
||||
|
||||
The complete automation pipeline runs on every push and pull request.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Code Push/PR] --> B[GitHub Actions Trigger]
|
||||
|
||||
B --> C[Standards Compliance Check]
|
||||
B --> D[Security Scanning]
|
||||
B --> E[Code Quality Analysis]
|
||||
|
||||
C --> C1[File Headers]
|
||||
C --> C2[Tabs/Spaces Policy]
|
||||
C --> C3[File Encoding]
|
||||
C --> C4[Trailing Spaces]
|
||||
C --> C5[CHANGELOG Format]
|
||||
|
||||
D --> D1[Secret Scanning]
|
||||
D --> D2[CodeQL Analysis]
|
||||
D --> D3[Dependency Review]
|
||||
|
||||
E --> E1[PHP Syntax Check]
|
||||
E --> E2[Shell Script Validation]
|
||||
E --> E4[Markdown Links]
|
||||
|
||||
C1 --> F{All Checks Pass?}
|
||||
C2 --> F
|
||||
C3 --> F
|
||||
C4 --> F
|
||||
C5 --> F
|
||||
D1 --> F
|
||||
D2 --> F
|
||||
D3 --> F
|
||||
E1 --> F
|
||||
E2 --> F
|
||||
E4 --> F
|
||||
|
||||
F -->|Yes| G[✓ Build Passes]
|
||||
F -->|No| H[✗ Build Fails]
|
||||
|
||||
G --> I{Is Main Branch?}
|
||||
I -->|Yes| J[Trigger Auto-Release]
|
||||
I -->|No| K[Ready for Merge]
|
||||
|
||||
style A fill:#e1f5ff
|
||||
style G fill:#c8e6c9
|
||||
style H fill:#ffccbc
|
||||
```
|
||||
|
||||
> Full diagram set: [docs/visual/cicd-pipeline.md](../visual/cicd-pipeline.md)
|
||||
|
||||
## Bulk Sync Workflow
|
||||
|
||||
`bulk_sync.php` synchronizes standards across all organization repositories with checkpoint recovery.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[bulk_sync.php] --> B{--dry-run?}
|
||||
B -->|Yes| C[Simulate all operations\nNo API writes\nNo checkpoints written]
|
||||
B -->|No| D[Execute real sync\nWrite to GitHub API\nCheckpoint after each repo]
|
||||
|
||||
style C fill:#fff9c4
|
||||
style D fill:#e1f5ff
|
||||
```
|
||||
|
||||
> Full diagram: [docs/visual/bulk-sync-workflow.md](../visual/bulk-sync-workflow.md)
|
||||
|
||||
## Related Documentation
|
||||
|
||||
### Scripts Documentation
|
||||
- [Maintenance Scripts](../../api/maintenance/index.md)
|
||||
- [Release Scripts](../../api/release/index.md)
|
||||
- [Automation Scripts](../../api/automation/index.md)
|
||||
|
||||
### Policy & Strategy
|
||||
- [Branching Strategy](../policy/branching-strategy.md)
|
||||
- [Release Management](../policy/governance/release-management.md)
|
||||
|
||||
## Support
|
||||
|
||||
For automation-related issues:
|
||||
1. Review script documentation in [api/automation/](../../api/automation/)
|
||||
2. Contact MokoStandards maintainers
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-26
|
||||
**Status**: Production Ready
|
||||
@@ -0,0 +1,337 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
> **⚠️ DEPRECATED DOCUMENTATION**
|
||||
> **Status**: REMOVED — This Python-based automation system has been replaced by PHP scripts. See api/automation/.
|
||||
> **Last Updated**: 2026-02-10
|
||||
> **Current Status**: MokoStandards uses PHP-based automation (see [Automation Scripts](../../api/automation/index.md))
|
||||
|
||||
# Branch and Version Automation - Comprehensive Guide
|
||||
|
||||
**Document Version**: 1.0.0
|
||||
**Last Updated**: 2026-02-10
|
||||
**Status**: Production Ready
|
||||
**Audience**: Developers, DevOps Engineers, Repository Maintainers
|
||||
|
||||
## Overview
|
||||
|
||||
This guide provides comprehensive documentation for the branch and version automation systems deployed across all MokoStandards organization repositories via Terraform.
|
||||
|
||||
### Quick Links
|
||||
|
||||
- [Version Automation](#version-automation)
|
||||
- [Branch Management](#branch-management)
|
||||
- [Release Automation](#release-automation)
|
||||
- [Terraform Distribution](#terraform-distribution)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Required Scripts (9 Total)
|
||||
|
||||
All organization repositories automatically receive these scripts:
|
||||
|
||||
| Script | Category | Purpose | Auto-Sync |
|
||||
|--------|----------|---------|-----------|
|
||||
| `version_bump_detector.py` | Core Library | Semantic version detection | ✅ |
|
||||
| `detect_version_bump.py` | Automation | Version bump CLI | ✅ |
|
||||
| `common.py` | Core Library | Shared utilities | ⚠️ |
|
||||
| `clean_old_branches.py` | Maintenance | Branch cleanup | ✅ |
|
||||
| `release_version.py` | Maintenance | Release management | ✅ |
|
||||
| `unified_release.py` | Release | Release orchestration | ✅ |
|
||||
| `detect_platform.py` | Release | Platform detection | ✅ |
|
||||
| `package_extension.py` | Release | Extension packaging | ✅ |
|
||||
| `test_version_bump_detector.py` | Testing | Unit tests | ✅ |
|
||||
|
||||
## Version Automation
|
||||
|
||||
### Semantic Version Bump Rules
|
||||
|
||||
```
|
||||
Breaking change → MAJOR (X.y.z)
|
||||
New feature → MINOR (x.Y.z)
|
||||
Bug fix → PATCH (x.y.Z)
|
||||
Documentation update → PATCH (x.y.Z)
|
||||
Performance improvement → PATCH (x.y.Z)
|
||||
Code refactoring → PATCH (x.y.Z)
|
||||
Dependency update → PATCH (x.y.Z)
|
||||
Security fix → PATCH (x.y.Z)
|
||||
```
|
||||
|
||||
### Quick Start
|
||||
|
||||
**Detect version bump:**
|
||||
```bash
|
||||
./api/automation/detect_version_bump.py --file pr_template.md
|
||||
```
|
||||
|
||||
**Apply version bump:**
|
||||
```bash
|
||||
./api/automation/detect_version_bump.py \
|
||||
--text "New feature" \
|
||||
--apply \
|
||||
--stats
|
||||
```
|
||||
|
||||
### Enterprise Features
|
||||
|
||||
- ✅ **Audit Logging**: Complete operation trail in JSON format
|
||||
- ✅ **Backup/Rollback**: Automatic backup before modifications
|
||||
- ✅ **SHA-256 Integrity**: File integrity validation
|
||||
- ✅ **Performance Metrics**: Detailed statistics
|
||||
- ✅ **Dry-Run Mode**: Preview changes safely
|
||||
|
||||
**Audit Log Location**: `logs/automation/version_bump_*.json`
|
||||
|
||||
### CLI Reference
|
||||
|
||||
```bash
|
||||
./api/automation/detect_version_bump.py [OPTIONS]
|
||||
|
||||
Input Sources:
|
||||
--file FILE Read from file
|
||||
--stdin Read from stdin
|
||||
--text TEXT Analyze text
|
||||
--checkboxes TEXT Analyze checkboxes
|
||||
|
||||
Actions:
|
||||
--apply Apply version bump
|
||||
--dry-run Preview only
|
||||
|
||||
Options:
|
||||
--bump-type {major,minor,patch} Override detection
|
||||
--backup / --no-backup Toggle backup
|
||||
--audit-log / --no-audit-log Toggle logging
|
||||
--verbose, -v Verbose output
|
||||
--json JSON output
|
||||
--stats Performance stats
|
||||
```
|
||||
|
||||
## Branch Management
|
||||
|
||||
### Automated Branch Cleanup
|
||||
|
||||
**List old branches:**
|
||||
```bash
|
||||
./api/maintenance/clean_old_branches.py --days 90 --list
|
||||
```
|
||||
|
||||
**Delete with dry-run:**
|
||||
```bash
|
||||
./api/maintenance/clean_old_branches.py --days 90 --delete --dry-run
|
||||
```
|
||||
|
||||
**Actually delete:**
|
||||
```bash
|
||||
./api/maintenance/clean_old_branches.py --days 90 --delete --yes
|
||||
```
|
||||
|
||||
**Protected Branches** (never deleted):
|
||||
- `main`, `master`, `dev`, `staging`, `production`
|
||||
|
||||
### Release Version Management
|
||||
|
||||
**Create release:**
|
||||
```bash
|
||||
./api/maintenance/release_version.py --version 1.3.0 --yes
|
||||
```
|
||||
|
||||
**Update CHANGELOG only:**
|
||||
```bash
|
||||
./api/maintenance/release_version.py --version 1.3.0 --changelog-only
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
1. Moves UNRELEASED to versioned section
|
||||
2. Updates VERSION in headers
|
||||
3. Creates git tags (optional)
|
||||
4. Triggers GitHub releases (optional)
|
||||
|
||||
## Release Automation
|
||||
|
||||
### Unified Release
|
||||
|
||||
**Create stable release:**
|
||||
```bash
|
||||
./scripts/release/unified_release.py --version 1.3.0 --release-type stable
|
||||
```
|
||||
|
||||
**Release candidate:**
|
||||
```bash
|
||||
./scripts/release/unified_release.py --version 1.3.0-rc1 --release-type rc
|
||||
```
|
||||
|
||||
### Release Types
|
||||
|
||||
| Type | Example | Use Case |
|
||||
|------|---------|----------|
|
||||
| `stable` | 1.3.0 | Production |
|
||||
| `rc` | 1.3.0-rc1 | Release candidate |
|
||||
| `beta` | 1.3.0-beta1 | Beta testing |
|
||||
| `alpha` | 1.3.0-alpha1 | Early testing |
|
||||
|
||||
### Platform Detection
|
||||
|
||||
```bash
|
||||
./scripts/release/detect_platform.py
|
||||
```
|
||||
|
||||
**Supported:** Joomla, Dolibarr, WordPress, Python, Node.js, Generic
|
||||
|
||||
### Extension Packaging
|
||||
|
||||
```bash
|
||||
./scripts/release/package_extension.py --version 1.3.0
|
||||
```
|
||||
|
||||
**Output:** `release/ProjectName-1.3.0.zip` + checksums
|
||||
|
||||
## Terraform Distribution
|
||||
|
||||
### Deployment
|
||||
|
||||
**Automatic:**
|
||||
```bash
|
||||
./api/automation/bulk_update_repos.php --yes --set-standards
|
||||
```
|
||||
|
||||
**Manual:**
|
||||
```bash
|
||||
cd infrastructure/terraform/repository-management
|
||||
terraform apply -var="github_token=$GH_TOKEN"
|
||||
```
|
||||
|
||||
### Configuration Files
|
||||
|
||||
- `infrastructure/terraform/repository-types/default-repository.tf` - Structure definition
|
||||
- `infrastructure/terraform/repository-management/main.tf` - Distribution config
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Version Not Found
|
||||
|
||||
**Error:** `Version not found in README.md`
|
||||
|
||||
**Fix:** Ensure format is `# README - ProjectName (VERSION: 04.06.00)`
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
chmod -R 755 scripts/
|
||||
chmod 644 scripts/**/*.py
|
||||
```
|
||||
|
||||
### Failed Mid-Operation
|
||||
|
||||
```bash
|
||||
# Check backup
|
||||
ls -la .version_bump_backup/
|
||||
|
||||
# Rollback
|
||||
cp -r .version_bump_backup/* ./
|
||||
|
||||
# Retry
|
||||
./api/automation/detect_version_bump.py --text "Fix" --apply
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```bash
|
||||
# Verbose output
|
||||
./api/automation/detect_version_bump.py --verbose --text "..."
|
||||
|
||||
# Check logs
|
||||
cat logs/automation/version_bump_*.json | jq '.'
|
||||
```
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
name: Auto Version Bump
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
version-bump:
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Apply Version Bump
|
||||
run: |
|
||||
./api/automation/detect_version_bump.py \
|
||||
--text "${{ github.event.pull_request.body }}" \
|
||||
--apply \
|
||||
--stats
|
||||
```
|
||||
|
||||
### Pre-commit Hook
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
|
||||
if git diff --cached --name-only | grep -qE '(\.py|\.md)$'; then
|
||||
./api/automation/detect_version_bump.py --validate || {
|
||||
echo "❌ Version inconsistency"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Version Management
|
||||
|
||||
1. Always run dry-run first
|
||||
2. Review audit logs regularly
|
||||
3. Keep backups for 30+ days
|
||||
4. Use semantic versioning consistently
|
||||
|
||||
### Branch Management
|
||||
|
||||
1. Run cleanup monthly
|
||||
2. Always dry-run before delete
|
||||
3. Maintain protected branch list
|
||||
4. Document exceptions
|
||||
|
||||
### Release Automation
|
||||
|
||||
1. Detect platform before release
|
||||
2. Test packaging in non-prod
|
||||
3. Verify checksums
|
||||
4. Maintain release notes
|
||||
|
||||
## Reference
|
||||
|
||||
### Related Documentation
|
||||
|
||||
- [Terraform Distribution Guide](../../infrastructure/terraform/repository-management/VERSION_BUMP_DISTRIBUTION.md)
|
||||
- [Maintenance Scripts](../../api/maintenance/index.md)
|
||||
- [Release Scripts](../../api/release/index.md)
|
||||
- [Branching Strategy](../policy/branching-strategy.md)
|
||||
|
||||
### External Resources
|
||||
|
||||
- [Semantic Versioning](https://semver.org/)
|
||||
- [Keep a Changelog](https://keepachangelog.com/)
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
|
||||
## Support
|
||||
|
||||
**Getting Help:**
|
||||
1. Check this documentation
|
||||
2. Review troubleshooting section
|
||||
3. Check audit logs: `logs/automation/*.json`
|
||||
4. Contact MokoStandards maintainers
|
||||
|
||||
**Reporting Issues:**
|
||||
Include: script name, command, error message, audit log, context
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0.0
|
||||
**Next Review**: 2026-03-10
|
||||
**Maintainer**: MokoStandards Team
|
||||
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/automation/push-files.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for push_files.php — push specific files to selected repositories
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Push Files
|
||||
|
||||
Push specific files from MokoStandards to selected repositories. Unlike `bulk_sync.php` which syncs all defined files, `push_files.php` pushes only the files you specify.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Push a file to a single repo (creates a PR)
|
||||
php api/automation/push_files.php --repos MokoCRM --files "src/config.php" --yes
|
||||
|
||||
# Push to multiple repos
|
||||
php api/automation/push_files.php --repos "MokoCRM MokoDoliHRM" --files "LICENSE GOVERNANCE.md" --yes
|
||||
|
||||
# Direct commit (no PR) — pushes straight to main
|
||||
php api/automation/push_files.php --repos MokoCRM --files "LICENSE" --direct --yes
|
||||
|
||||
# Skip tracking issue creation
|
||||
php api/automation/push_files.php --repos MokoCRM --files "LICENSE" --yes --no-issue
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--org` | GitHub organization (default: mokoconsulting-tech) |
|
||||
| `--repos` | Target repositories (space-separated, required) |
|
||||
| `--files` | Files to push (space-separated, required) |
|
||||
| `--direct` | Push directly to main (no PR) |
|
||||
| `--no-issue` | Skip creating a tracking issue |
|
||||
| `--dry-run` | Preview without making changes |
|
||||
| `--yes` | Auto-confirm prompts |
|
||||
|
||||
## Behaviour
|
||||
|
||||
- Creates a PR with the pushed files (unless `--direct` is used)
|
||||
- Creates/updates a tracking issue in each target repo
|
||||
- Cross-links the tracking issue to the PR in the Development sidebar
|
||||
- Assigns `jmiller-moko` to both PR and issue
|
||||
- Applies standard labels: `standards-update`, `mokostandards`, `type: chore`, `automation`
|
||||
@@ -0,0 +1,114 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/automation/repo-cleanup.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for repo_cleanup.php and the repository-cleanup.yml recurring maintenance workflow
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Repository Cleanup
|
||||
|
||||
Two tools for cleaning up governed repositories: a PHP CLI script for bulk operations and a GitHub Actions workflow for recurring per-repo maintenance.
|
||||
|
||||
## Workflow: `repository-cleanup.yml`
|
||||
|
||||
Recurring maintenance workflow synced to all governed repos. Runs automatically on the **1st and 15th of each month** at 6:00 AM UTC (1:00 AM CDT), and on manual dispatch.
|
||||
|
||||
### Schedule vs Manual
|
||||
|
||||
| Task | Schedule (1st + 15th) | Manual Dispatch |
|
||||
|------|----------------------|-----------------|
|
||||
| **Delete retired workflows** | Always | Always |
|
||||
| **Version drift detection** | Always | Always |
|
||||
| **Create custom workflow dir** | Always | Always |
|
||||
| **Label reset** | Off (safe default) | Toggle (default: off) |
|
||||
| **Branch cleanup** | On | Toggle (default: on) |
|
||||
| **Workflow run cleanup** | On | Toggle (default: on) |
|
||||
| **Log cleanup (>30 days)** | On | Toggle (default: on) |
|
||||
| **Issue template fix** | On | Toggle (default: on) |
|
||||
| **Doc index rebuild** | On | Toggle (default: on) |
|
||||
|
||||
### What Each Task Does
|
||||
|
||||
**Delete retired workflows** — Hardwired, always runs. Removes 25 workflow files that have been superseded or retired from MokoStandards. Prevents old workflows from running.
|
||||
|
||||
**Version drift detection** — Scans all `.php`, `.md`, and `.yml` files for `VERSION:` fields and compares against the README.md version. Reports any mismatches in the step summary.
|
||||
|
||||
**Create custom workflow directory** — Creates `.github/workflows/custom/` with a README if it doesn't exist. Custom workflows in this directory are never overwritten or deleted by sync.
|
||||
|
||||
**Label reset** — Deletes ALL existing labels and recreates the standard 58-label set. Only runs when explicitly toggled on manual dispatch (never on schedule).
|
||||
|
||||
**Branch cleanup** — Deletes old `chore/sync-mokostandards-*` branches (keeps only the current versioned branch). Closes any open PRs on deleted branches.
|
||||
|
||||
**Workflow run cleanup** — Deletes cancelled and stale workflow runs from the Actions tab.
|
||||
|
||||
**Log cleanup** — Deletes workflow run logs older than 30 days.
|
||||
|
||||
**Issue template fix** — Strips `<!-- copyright -->` comment blocks from issue templates that GitHub renders in the issue form.
|
||||
|
||||
**Doc index rebuild** — Generates `index.md` for each `docs/` subdirectory listing all markdown files.
|
||||
|
||||
### Custom Workflows
|
||||
|
||||
Repos can have their own workflows that won't be touched by MokoStandards sync or cleanup:
|
||||
|
||||
```
|
||||
.github/
|
||||
├── workflows/
|
||||
│ ├── deploy-dev.yml ← Synced from MokoStandards (overwritten on sync)
|
||||
│ ├── auto-release.yml ← Synced from MokoStandards (overwritten on sync)
|
||||
│ ├── repository-cleanup.yml ← Synced from MokoStandards (overwritten on sync)
|
||||
│ └── custom/ ← SAFE — never touched by sync or cleanup
|
||||
│ ├── README.md
|
||||
│ ├── my-custom-ci.yml
|
||||
│ └── slack-notify.yml
|
||||
```
|
||||
|
||||
The `custom/` directory is auto-created by the cleanup workflow if it doesn't exist.
|
||||
|
||||
### Authorization
|
||||
|
||||
- **Schedule:** Always authorized (runs as github-actions[bot])
|
||||
- **Manual dispatch:** `jmiller-moko` and `github-actions[bot]` always authorized; others need admin/maintain role
|
||||
|
||||
---
|
||||
|
||||
## CLI Script: `repo_cleanup.php`
|
||||
|
||||
Scans governed repositories and deletes stale sync branches, closes superseded PRs, and optionally closes resolved tracking issues.
|
||||
|
||||
```bash
|
||||
# Preview cleanup (dry run)
|
||||
php api/automation/repo_cleanup.php --dry-run
|
||||
|
||||
# Clean up all repos
|
||||
php api/automation/repo_cleanup.php --yes
|
||||
|
||||
# Also close tracking issues where the linked PR is merged
|
||||
php api/automation/repo_cleanup.php --yes --close-issues
|
||||
|
||||
# Clean a specific repo
|
||||
php api/automation/repo_cleanup.php --repos MokoCRM --yes
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--org` | GitHub organization (default: mokoconsulting-tech) |
|
||||
| `--repos` | Specific repos to clean (space-separated) |
|
||||
| `--close-issues` | Close tracking issues where the linked PR has been merged |
|
||||
| `--skip-archived` | Skip archived repositories |
|
||||
| `--dry-run` | Preview without making changes |
|
||||
| `--yes` | Auto-confirm prompts |
|
||||
| `--json` | Output results as JSON |
|
||||
@@ -0,0 +1,598 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# GitHub Workflow Templates Documentation
|
||||
|
||||
**Status**: Active | **Version**: 04.00.04 | **Effective**: 2026-01-07
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides comprehensive documentation for MokoStandards workflow templates. These templates provide standardized CI/CD configurations that ensure consistency, security, and compliance across all Moko Consulting repositories.
|
||||
|
||||
### Workflow Documentation
|
||||
|
||||
- [Workflow Architecture](./workflow-architecture.md) - Workflow hierarchy and design patterns
|
||||
- [Workflow Inventory](./workflow-inventory.md) - Complete inventory of workflows
|
||||
- [Reusable Workflows](./reusable-workflows.md) - Documentation for reusable GitHub Actions workflows
|
||||
- [Standards Compliance](./standards-compliance.md) - **NEW**: Comprehensive standards validation workflow
|
||||
- [Bulk Repository Sync](./bulk-repo-sync.md) - Automated standards deployment across organization repositories
|
||||
- [Release System](./release-system.md) - Unified release system documentation
|
||||
- [Changelog Management](./changelog-management.md) - Changelog management workflows and scripts
|
||||
- [Dev Branch Tracking and Issue Coordination](./dev-branch-tracking.md) - Automated dev branch and PR tracking system
|
||||
- [Dev Deployment](./dev-deployment.md) - Development deployment workflows
|
||||
- [Reserve Dolibarr Module ID](./reserve-dolibarr-module-id.md) - Automated Dolibarr module ID reservation workflow
|
||||
|
||||
### Workflow Template Locations
|
||||
|
||||
MokoStandards provides workflow templates in two locations:
|
||||
|
||||
1. **`templates/workflows/`** - **Public workflow templates** for community adoption
|
||||
- `build.yml.template` - Universal build workflow with automatic project detection
|
||||
- `release-cycle.yml.template` - Automated release management workflow (v2.0 with auto-detect & manual modes)
|
||||
- `generic/codeql-analysis.yml` - Security scanning with CodeQL
|
||||
- `generic/dependency-review.yml.template` - Dependency vulnerability scanning
|
||||
- `standards-compliance.yml.template` - MokoStandards compliance validation
|
||||
- `flush-actions-cache.yml.template` - GitHub Actions cache management workflow
|
||||
|
||||
2. **`templates/workflows/`** - Platform-specific workflow examples
|
||||
- `joomla/` - Joomla extension workflows
|
||||
- `dolibarr/` - Dolibarr module workflows
|
||||
- `generic/` - Generic project workflows
|
||||
|
||||
### Quick Start
|
||||
|
||||
To adopt MokoStandards workflows in your repository:
|
||||
|
||||
```bash
|
||||
# Copy universal build workflow
|
||||
cp templates/workflows/build.yml.template .github/workflows/build.yml
|
||||
|
||||
# Copy release management workflow
|
||||
cp templates/workflows/release-cycle.yml.template .github/workflows/release.yml
|
||||
|
||||
# Copy security scanning workflows
|
||||
cp templates/workflows/generic/codeql-analysis.yml .github/workflows/
|
||||
cp templates/workflows/generic/dependency-review.yml.template .github/workflows/dependency-review.yml
|
||||
|
||||
# Copy standards compliance workflow
|
||||
cp templates/workflows/standards-compliance.yml.template .github/workflows/standards-compliance.yml
|
||||
|
||||
# Optional: Copy cache management workflow
|
||||
cp templates/workflows/flush-actions-cache.yml.template .github/workflows/flush-actions-cache.yml
|
||||
```
|
||||
|
||||
Then customize the workflows for your project as needed.
|
||||
|
||||
## Public Workflow Templates (`templates/workflows/`)
|
||||
|
||||
### 1. Build Universal (`build.yml.template`)
|
||||
|
||||
**Location**: `templates/workflows/build.yml.template`
|
||||
|
||||
Universal build workflow with automatic project type detection and Makefile precedence system.
|
||||
|
||||
**Features**:
|
||||
- **Automatic project detection** - Detects Joomla, Dolibarr, or Generic projects
|
||||
- **Makefile precedence system** - Repository Makefile → MokoStandards Makefile → Default builds
|
||||
- **Multi-language support** - PHP, Node.js, and mixed projects
|
||||
- **Build artifacts** - Automatic artifact upload
|
||||
- **Customizable** - Extensive inline documentation for customization
|
||||
|
||||
**Trigger Patterns**:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev/**, rc/**, version/**]
|
||||
pull_request:
|
||||
branches: [main, dev/**, rc/**]
|
||||
workflow_dispatch:
|
||||
```
|
||||
|
||||
**Usage**: Copy to `.github/workflows/build.yml` and customize as needed.
|
||||
|
||||
See [Build System Documentation](../build-system/README.md) for details on the Makefile precedence system.
|
||||
|
||||
### 2. Release Cycle (`release-cycle.yml.template`)
|
||||
|
||||
**Location**: `templates/workflows/release-cycle.yml.template`
|
||||
|
||||
**Version 02.00.00** - Merged unified-release and release-cycle workflows with auto-detection and manual dispatch modes
|
||||
|
||||
Automated release management workflow implementing the MokoStandards release cycle: main → dev → rc → version → main.
|
||||
|
||||
**Features**:
|
||||
- **Auto-detection** - Detects version changes from CITATION.cff, pyproject.toml, package.json, CHANGELOG.md
|
||||
- **Manual dispatch** - Full control over release actions
|
||||
- **Semantic versioning** - Automatic validation of version format
|
||||
- **Branch management** - Automated branch creation and merging
|
||||
- **Release actions** - start-release, create-rc, finalize-release, hotfix, simple-release
|
||||
- **Release notes** - Automated generation from commits
|
||||
- **GitHub releases** - Automatic creation with artifacts
|
||||
|
||||
**Actions**:
|
||||
- `start-release` - Create development branch and update version
|
||||
- `create-rc` - Create release candidate from dev branch
|
||||
- `finalize-release` - Create version branch, merge to main, create release
|
||||
- `hotfix` - Create hotfix branch for emergency fixes
|
||||
|
||||
**Trigger Pattern**:
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
action:
|
||||
type: choice
|
||||
options: [start-release, create-rc, finalize-release, hotfix]
|
||||
version:
|
||||
type: string
|
||||
required: true
|
||||
```
|
||||
|
||||
**Usage**: Copy to `.github/workflows/release.yml` for automated release management.
|
||||
|
||||
See [Release Management Documentation](../release-management/README.md) for complete release procedures.
|
||||
|
||||
### 3. Dependency Review (`dependency-review.yml.template`)
|
||||
|
||||
**Location**: `templates/workflows/generic/dependency-review.yml.template`
|
||||
|
||||
Comprehensive dependency vulnerability scanning for pull requests.
|
||||
|
||||
**Features**:
|
||||
- **GitHub Dependency Review** - Scans dependencies in PRs
|
||||
- **npm audit** - Node.js dependency security checks
|
||||
- **Composer audit** - PHP dependency security checks
|
||||
- **Python Safety** - Python dependency vulnerability scanning
|
||||
- **License compliance** - Validates dependency licenses
|
||||
|
||||
**Trigger Pattern**:
|
||||
```yaml
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, dev/**, rc/**]
|
||||
```
|
||||
|
||||
**Usage**: Copy to `.github/workflows/dependency-review.yml` to enable dependency scanning on PRs.
|
||||
|
||||
### 4. Standards Compliance (`standards-compliance.yml.template`)
|
||||
|
||||
**Location**: `templates/workflows/standards-compliance.yml.template`
|
||||
|
||||
MokoStandards compliance validation workflow.
|
||||
|
||||
**Features**:
|
||||
- **Repository structure** - Validates required directories and files
|
||||
- **Documentation quality** - Checks README, CHANGELOG, and other docs
|
||||
- **Coding standards** - Tab detection, encoding, line endings
|
||||
- **License compliance** - SPDX header validation
|
||||
- **Git hygiene** - .gitignore, large files, etc.
|
||||
- **Workflow validation** - YAML syntax and required workflows
|
||||
|
||||
**Trigger Pattern**:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev/**, rc/**]
|
||||
pull_request:
|
||||
branches: [main, dev/**, rc/**]
|
||||
workflow_dispatch:
|
||||
```
|
||||
|
||||
**Usage**: Copy to `.github/workflows/standards-compliance.yml` to enable compliance checks.
|
||||
|
||||
### 5. Flush Actions Cache (`flush-actions-cache.yml.template`)
|
||||
|
||||
**Location**: `templates/workflows/flush-actions-cache.yml.template`
|
||||
|
||||
Cache management workflow for flushing GitHub Actions caches on demand.
|
||||
|
||||
**Features**:
|
||||
- **Manual trigger** - Run from Actions tab when needed
|
||||
- **Filter by branch** - Target specific branch caches
|
||||
- **Filter by key pattern** - Target specific dependency caches (composer, node)
|
||||
- **Dry-run mode** - Preview deletions before executing
|
||||
- **Comprehensive reporting** - Shows cache details before deletion
|
||||
- **Automatic script download** - Downloads latest flush script from MokoStandards
|
||||
|
||||
**Trigger Pattern**:
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to filter caches (leave empty for all branches)'
|
||||
key-pattern:
|
||||
description: 'Key pattern to filter caches (e.g., composer, node)'
|
||||
dry-run:
|
||||
description: 'Dry run mode (show what would be deleted without deleting)'
|
||||
type: boolean
|
||||
```
|
||||
|
||||
**Common Use Cases**:
|
||||
- Clear all caches when corrupted
|
||||
- Clear branch-specific caches after branch deletion
|
||||
- Clear dependency caches after major updates (Composer, npm)
|
||||
- Preview cache usage with dry-run mode
|
||||
|
||||
**Usage**: Copy to `.github/workflows/flush-actions-cache.yml` to enable cache management.
|
||||
|
||||
See [flush_actions_cache.py documentation](/docs/api/maintenance/flush-actions-cache-py.md) for detailed script usage.
|
||||
|
||||
### 6. CodeQL Analysis (`codeql-analysis.yml`)
|
||||
|
||||
**Location**: `templates/workflows/generic/codeql-analysis.yml`
|
||||
|
||||
Security scanning with GitHub's CodeQL engine (also available in `.github/workflows/`).
|
||||
|
||||
See section below for complete details.
|
||||
|
||||
## Platform-Specific Workflow Templates (`templates/workflows/`)
|
||||
|
||||
The following templates are organized by platform in `templates/workflows/`.
|
||||
|
||||
### 1. CI Template (`ci.yml`)
|
||||
|
||||
**Location**: `.github/workflows/ci.yml` (MokoStandards root)
|
||||
|
||||
Continuous Integration workflow that enforces repository standards through automated validation.
|
||||
|
||||
**Features**:
|
||||
- **Manifest validation** - Validates project manifests (Joomla XML, Dolibarr descriptors)
|
||||
- **XML well-formedness** - Ensures all XML files are properly formatted
|
||||
- **PHP syntax validation** - Checks PHP code across multiple versions
|
||||
- **CHANGELOG structure** - Validates changelog formatting and completeness
|
||||
- **License headers** - Verifies SPDX headers in all source files
|
||||
- **Version alignment** - Ensures version numbers are consistent across files
|
||||
- **Path separator checks** - Validates file paths
|
||||
- **Tab detection** - Enforces space-over-tabs policy
|
||||
- **Secret scanning** - Prevents accidental secret commits
|
||||
|
||||
**Trigger Patterns**:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev/**, rc/**, version/**]
|
||||
pull_request:
|
||||
branches: [main, dev/**, rc/**, version/**]
|
||||
```
|
||||
|
||||
**Usage**: Copy from MokoStandards `.github/workflows/ci.yml` to your repository.
|
||||
|
||||
### 2. CodeQL Analysis Template (`codeql-analysis.yml`)
|
||||
|
||||
**Location**: `.github/workflows/codeql-analysis.yml` (MokoStandards root)
|
||||
|
||||
Security scanning workflow using GitHub's CodeQL engine for vulnerability detection.
|
||||
|
||||
**Features**:
|
||||
- **Multi-language support** - Analyzes Python, JavaScript, PHP, Go, etc.
|
||||
- **Security-extended queries** - Uses comprehensive security query packs
|
||||
- **Quality analysis** - Includes code quality checks
|
||||
- **Scheduled scans** - Weekly automated security scans (Monday 6:00 AM UTC)
|
||||
- **PR integration** - Scans all pull requests automatically
|
||||
|
||||
**Trigger Patterns**:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev/**, rc/**]
|
||||
pull_request:
|
||||
branches: [main, dev/**, rc/**]
|
||||
schedule:
|
||||
- cron: '0 6 * * 1' # Weekly Monday 6:00 AM UTC
|
||||
workflow_dispatch:
|
||||
```
|
||||
|
||||
**Usage**: Copy from MokoStandards `.github/workflows/codeql-analysis.yml` to your repository.
|
||||
|
||||
### 3. Dependency Review
|
||||
|
||||
**Purpose**: Automated dependency vulnerability scanning
|
||||
|
||||
Dependency scanning in MokoStandards repositories is handled through:
|
||||
- **Dependabot configuration** - `.github/dependabot.yml` (configure for your project)
|
||||
- **CodeQL analysis** - Includes dependency checks
|
||||
- **Generic code quality workflow** - `templates/workflows/generic/code-quality.yml`
|
||||
|
||||
**Recommended Approach**:
|
||||
1. Enable Dependabot in repository settings
|
||||
2. Create `.github/dependabot.yml` configuration
|
||||
3. Use CodeQL for comprehensive security analysis
|
||||
|
||||
### 4. Standards Compliance Template (`repo_health.yml`)
|
||||
|
||||
**Location**: `templates/workflows/generic/repo_health.yml`
|
||||
|
||||
Repository health and governance validation workflow that enforces MokoStandards compliance.
|
||||
|
||||
**Features**:
|
||||
- **Admin-only execution** - Requires admin permissions
|
||||
- **Release configuration checks** - Validates SFTP deployment variables
|
||||
- **SFTP connectivity testing** - Tests remote server access
|
||||
- **Scripts governance** - Validates script directory structure
|
||||
- **Repository artifacts** - Checks required files (README, LICENSE, CONTRIBUTING, etc.)
|
||||
- **Content heuristics** - Validates document content and structure
|
||||
- **Extended checks** (optional):
|
||||
- CODEOWNERS presence
|
||||
- Workflow action version pinning
|
||||
- Documentation link integrity
|
||||
- ShellCheck validation
|
||||
- SPDX header compliance
|
||||
- Git hygiene (stale branches)
|
||||
|
||||
**Profiles**:
|
||||
- `all` - Run all checks (default)
|
||||
- `release` - Release configuration only
|
||||
- `scripts` - Scripts governance only
|
||||
- `repo` - Repository health only
|
||||
|
||||
**Trigger Pattern**:
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
profile:
|
||||
type: choice
|
||||
options: [all, release, scripts, repo]
|
||||
```
|
||||
|
||||
**Usage**: Copy from `templates/workflows/generic/repo_health.yml` and customize for your project.
|
||||
|
||||
### 5. Platform-Specific Workflows
|
||||
|
||||
#### Joomla Workflows (`templates/workflows/joomla/`)
|
||||
|
||||
**ci.yml** - Joomla extension CI workflow:
|
||||
- Joomla manifest validation
|
||||
- Extension structure checks
|
||||
- PHP 7.4-8.2 compatibility
|
||||
- XML schema validation
|
||||
|
||||
**test.yml** - Comprehensive Joomla testing:
|
||||
- PHPUnit tests with Joomla framework
|
||||
- Code quality (PHPCS, PHPStan, Psalm)
|
||||
- Matrix testing: PHP 7.4-8.2, Joomla 4.4-5.0
|
||||
- Code coverage with Codecov
|
||||
|
||||
**release.yml** - Automated Joomla package creation:
|
||||
- Version bumping in manifests
|
||||
- ZIP package creation with proper structure
|
||||
- Checksum generation (SHA256, MD5)
|
||||
- GitHub release creation with changelog
|
||||
- Release artifact upload
|
||||
|
||||
#### Dolibarr Workflows (`templates/workflows/dolibarr/`)
|
||||
|
||||
**ci.yml** - Dolibarr module CI workflow:
|
||||
- Module structure validation
|
||||
- PHP syntax checking (7.4-8.2)
|
||||
- Dolibarr API usage validation (16.0-18.0)
|
||||
- Database schema validation
|
||||
- Security scanning (SQL injection, XSS, credentials)
|
||||
|
||||
**test.yml** - Dolibarr module testing:
|
||||
- PHPUnit tests with Dolibarr environment
|
||||
- Automatic Dolibarr installation
|
||||
- MySQL database integration
|
||||
- Module linking and installation
|
||||
- Code coverage reporting
|
||||
|
||||
#### Generic Workflows (`templates/workflows/generic/`)
|
||||
|
||||
**ci.yml** - Multi-language CI with auto-detection:
|
||||
- Supports: Node.js, Python, PHP, Go, Ruby, Rust
|
||||
- Automatic language detection
|
||||
- Parallel testing across language matrices
|
||||
- Language-specific linting
|
||||
- Security scanning with Trivy
|
||||
|
||||
**test.yml** - Comprehensive testing framework:
|
||||
- Unit tests with coverage
|
||||
- Integration tests (PostgreSQL, Redis)
|
||||
- End-to-end tests with Playwright
|
||||
- Codecov integration
|
||||
- Test result summaries
|
||||
|
||||
**deploy.yml** - Multi-environment deployment:
|
||||
- Automatic environment detection
|
||||
- Multi-language build support
|
||||
- Staging and production deployment jobs
|
||||
- Smoke tests after deployment
|
||||
- Automatic rollback on failure
|
||||
- Deployment notifications
|
||||
|
||||
**code-quality.yml** - Advanced code analysis:
|
||||
- Multi-language linting (ESLint, Flake8, PHPCS, golangci-lint, clippy)
|
||||
- Code formatting validation
|
||||
- Static analysis (CodeQL, PHPStan, Pylint)
|
||||
- Dependency security (Snyk, npm audit, pip safety)
|
||||
- Code complexity analysis
|
||||
|
||||
## Platform Detection
|
||||
|
||||
Workflows use automatic project type detection based on file presence. See [Project Type Detection](../reference/project-types.md) for complete details.
|
||||
|
||||
### Quick Reference
|
||||
|
||||
- **Joomla**: Detected by `joomla.xml` manifest file
|
||||
- **Dolibarr**: Detected by `htdocs/` directory or `core/modules/` structure
|
||||
- **Generic**: Fallback for all other projects
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
### For New Projects
|
||||
|
||||
1. **Choose appropriate templates**:
|
||||
- Joomla → `templates/workflows/joomla/`
|
||||
- Dolibarr → `templates/workflows/dolibarr/`
|
||||
- Other → `templates/workflows/generic/`
|
||||
|
||||
2. **Copy workflow files**:
|
||||
```bash
|
||||
mkdir -p .github/workflows
|
||||
cp /path/to/MokoStandards/templates/workflows/joomla/ci.yml .github/workflows/
|
||||
```
|
||||
|
||||
3. **Customize for your project**:
|
||||
- Update FILE INFORMATION headers with correct paths
|
||||
- Adjust branch patterns if needed
|
||||
- Configure environment-specific settings
|
||||
- Add/remove validation scripts as appropriate
|
||||
|
||||
4. **Commit and enable**:
|
||||
```bash
|
||||
git add .github/workflows/
|
||||
git commit -m "Add MokoStandards workflows"
|
||||
git push
|
||||
```
|
||||
|
||||
### For Existing Projects
|
||||
|
||||
1. Review current workflows against templates
|
||||
2. Identify gaps or outdated patterns
|
||||
3. Update workflows incrementally
|
||||
4. Test on feature branch before merging to main
|
||||
|
||||
## Required Workflows
|
||||
|
||||
All MokoStandards-governed repositories **MUST** implement:
|
||||
|
||||
1. **CI workflow** - For build validation and testing
|
||||
2. **Security scanning** - CodeQL or equivalent
|
||||
|
||||
Recommended workflows:
|
||||
- Repository health workflow
|
||||
- Platform-specific test workflows
|
||||
- Automated release workflows (for libraries/extensions)
|
||||
- Deployment workflows (for applications)
|
||||
- Code quality workflows
|
||||
|
||||
## Workflow Dependencies
|
||||
|
||||
### Common Requirements (All Workflows)
|
||||
|
||||
- Git repository with proper branching structure
|
||||
- Python 3.x for validation scripts
|
||||
- Proper permissions configured in repository settings
|
||||
|
||||
### CI Workflows Require
|
||||
|
||||
**For Joomla**:
|
||||
- `api/validate/manifest.sh`
|
||||
- `api/validate/xml_wellformed.sh`
|
||||
- Joomla XML manifest file
|
||||
|
||||
**For Dolibarr**:
|
||||
- Module descriptor (`core/modules/modMyModule.class.php`)
|
||||
- Proper Dolibarr directory structure
|
||||
|
||||
**For Generic**:
|
||||
- Language-specific package managers (npm, pip, composer, etc.)
|
||||
- Test configurations
|
||||
|
||||
### Test Workflows Require
|
||||
|
||||
- Test framework configuration (Jest, pytest, PHPUnit, etc.)
|
||||
- Optional: Database services (configured in workflow)
|
||||
- Optional: Browser testing tools (Playwright)
|
||||
|
||||
### Deployment Workflows Require
|
||||
|
||||
- Environment secrets in GitHub repository settings
|
||||
- Deployment target configuration
|
||||
- For SFTP deployments: See [SFTP Deployment Guide](../deployment/sftp.md)
|
||||
|
||||
## Standards Compliance
|
||||
|
||||
All workflows follow MokoStandards requirements:
|
||||
|
||||
- ✅ SPDX license headers (GPL-3.0-or-later)
|
||||
- ✅ Proper error handling and reporting
|
||||
- ✅ Step summaries for GitHub Actions UI
|
||||
- ✅ Audit trail generation
|
||||
- ✅ Secure secret handling
|
||||
- ✅ Versioned action dependencies
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Pin action versions** - Use `@v4` not `@main`
|
||||
2. **Test in feature branches** - Never merge untested workflows
|
||||
3. **Use workflow concurrency** - Prevent duplicate runs
|
||||
4. **Set appropriate timeouts** - Avoid hanging workflows
|
||||
5. **Configure secrets properly** - Use GitHub repository secrets
|
||||
6. **Monitor costs** - Track GitHub Actions minutes usage
|
||||
7. **Document customizations** - Add comments for deviations
|
||||
8. **Review step summaries** - Check GitHub Actions UI after runs
|
||||
9. **Use matrix strategies** - Test across multiple versions
|
||||
10. **Keep workflows DRY** - Use reusable workflows when possible
|
||||
|
||||
## Integration with Health Scoring
|
||||
|
||||
These workflows contribute to the [Health Scoring System](../policy/health-scoring.md):
|
||||
|
||||
- **CI/CD Status**: 15 points - CI workflow passing
|
||||
- **Workflows**: 10 points - Required workflows present
|
||||
- **Security**: 15 points - CodeQL and dependency scanning enabled
|
||||
|
||||
## Support and Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Workflow fails to find scripts**:
|
||||
- Ensure scripts exist in expected locations
|
||||
- Verify script permissions (`chmod +x`)
|
||||
- Check FILE INFORMATION paths match actual structure
|
||||
|
||||
**SFTP connectivity fails**:
|
||||
- Verify all required secrets are configured
|
||||
- Test credentials manually
|
||||
- Check firewall/network access
|
||||
- See [SFTP Deployment Guide](../deployment/sftp.md)
|
||||
|
||||
**CodeQL fails**:
|
||||
- Ensure language matrix includes project languages
|
||||
- Remove languages with no code to analyze
|
||||
- Review CodeQL queries configuration
|
||||
|
||||
### Getting Help
|
||||
|
||||
1. Review workflow logs in GitHub Actions UI
|
||||
2. Check step summaries for detailed errors
|
||||
3. Validate scripts locally before CI
|
||||
4. Refer to [Project Types Documentation](../reference/project-types.md)
|
||||
5. Consult [SFTP Deployment Guide](../deployment/sftp.md)
|
||||
|
||||
For issues with templates:
|
||||
- Open issue in MokoStandards repository
|
||||
- Tag with `workflow-template` label
|
||||
- Include workflow name and error details
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Document | Workflow Templates Documentation |
|
||||
| Path | /docs/workflows/README.md |
|
||||
| Repository | https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards |
|
||||
| Owner | Moko Consulting |
|
||||
| Status | Active |
|
||||
| Version | 04.00.04 |
|
||||
| Effective | 2026-01-07 |
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---|---|---|
|
||||
| 04.00.04 | 2026-02-08 | Consolidated workflow templates: removed duplicate build-universal (use build.yml.template), removed superseded release-cycle-simple (use release-cycle v2.0) |
|
||||
| 04.00.04 | 2026-01-07 | Added public workflow templates documentation (build-universal, release-cycle, dependency-review, standards-compliance) |
|
||||
| 01.00.00 | 2026-01-07 | Initial comprehensive workflow documentation |
|
||||
|
||||
## See Also
|
||||
|
||||
- [Build System Documentation](../build-system/README.md)
|
||||
- [Release Management Documentation](../release-management/README.md)
|
||||
- [Health Scoring System](../policy/health-scoring.md)
|
||||
- [SFTP Deployment Guide](../deployment/sftp.md)
|
||||
- [Project Type Detection](../reference/project-types.md)
|
||||
- [Repository Structure Schema](../guide/repository-structure-schema.md)
|
||||
- [Workflow Templates (Technical)](../../templates/workflows/README.md)
|
||||
- [Public Workflow Templates](../../templates/workflows/)
|
||||
@@ -0,0 +1,103 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/auto-release.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for the auto-release workflow — creates GitHub Releases on merge to main
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Auto Release
|
||||
|
||||
Creates or updates a GitHub Release on every push to main. Uses **major-only tags** (`vXX`) — one release per major version, with all minor+patch versions appending notes and assets to the same release.
|
||||
|
||||
## Platform-Specific Pipelines
|
||||
|
||||
### Generic Repos
|
||||
|
||||
1. Reads `VERSION:` from README.md FILE INFORMATION block (e.g., `04.06.00`)
|
||||
2. Extracts major version (e.g., `04`)
|
||||
3. Creates or updates the `v04` tag on the release commit
|
||||
4. Creates or updates the `v04` GitHub Release, appending changelog notes for this version
|
||||
5. Auto-bumps patch version with `[skip ci]` commit
|
||||
6. Auto-creates `version/XX` archive branch
|
||||
|
||||
### Joomla Repos (waas-component)
|
||||
|
||||
Joomla repos do **not** use FTP deploy. Distribution is via GitHub Release ZIPs.
|
||||
|
||||
1. Reads `VERSION:` from README.md FILE INFORMATION block
|
||||
2. Builds installable ZIP from `src/` directory
|
||||
3. Computes SHA-256 hash of the ZIP
|
||||
4. Uploads ZIP as an asset to the `vXX` GitHub Release (e.g., `com_myextension-01.02.03.zip`)
|
||||
5. Updates `updates.xml` with the stable entry: version, download URL, and SHA-256 hash
|
||||
6. Creates or updates the `vXX` tag and release, appending changelog notes
|
||||
7. Auto-bumps patch version with `[skip ci]` commit
|
||||
8. Auto-creates `version/XX` archive branch
|
||||
|
||||
### Dolibarr Repos (crm-module, crm-platform)
|
||||
|
||||
1. Reads `VERSION:` from README.md FILE INFORMATION block
|
||||
2. Updates `$this->version` in `mod*.class.php` to the real version
|
||||
3. Updates `update.txt` with the stable version string
|
||||
4. Creates or updates the `vXX` tag and release, appending changelog notes
|
||||
5. Auto-bumps patch version with `[skip ci]` commit
|
||||
6. Auto-creates `version/XX` archive branch
|
||||
|
||||
## Triggers
|
||||
|
||||
- Push to `main` or `master`
|
||||
- Skips commits by `github-actions[bot]` and commits with `[skip ci]`
|
||||
|
||||
## Version Lifecycle
|
||||
|
||||
| Phase | Branch | Module Version | Release? |
|
||||
|-------|--------|---------------|----------|
|
||||
| Development | `dev/**` | `XX.YY.00` (patch 00 = dev) | No |
|
||||
| Alpha (optional) | `alpha/**` | `XX.YY.ZZ` | `alpha` tag release |
|
||||
| Beta (optional) | `beta/**` | `XX.YY.ZZ` | `beta` tag release |
|
||||
| Release Candidate | `rc/**` | `XX.YY.ZZ` (patch >= 01) | `release-candidate` tag (draft release created on RC branch creation) |
|
||||
| Merge to main | `main` | Real version (e.g., `01.02.01`) | Yes — `vXX` tag + release |
|
||||
| Auto-bump | `main` | Auto-incremented patch | No (skipped by `[skip ci]`) |
|
||||
|
||||
**Note**: Alpha and beta stages are optional. Dev can go directly to rc when not needed.
|
||||
|
||||
## Release Tags
|
||||
|
||||
Each stability level has its own GitHub Release tag:
|
||||
|
||||
| Tag | Stability | Source |
|
||||
|-----|-----------|--------|
|
||||
| `development` | Development | `dev/**` branches |
|
||||
| `alpha` | Alpha | `alpha/**` branches |
|
||||
| `beta` | Beta | `beta/**` branches |
|
||||
| `release-candidate` | RC | `rc/**` branches |
|
||||
| `vXX` | Stable production | `main` (major only, e.g., `v04`) |
|
||||
|
||||
- The `vXX` production tag is **major only** — one GitHub Release per major version
|
||||
- All minor+patch versions append release notes and ZIP assets to the same `vXX` release
|
||||
- No minor or patch production tags are created
|
||||
- Pre-release tags are updated in-place per stability level
|
||||
|
||||
## Requirements
|
||||
|
||||
- `secrets.GH_TOKEN` with `contents: write` permission
|
||||
- `VERSION:` field in README.md FILE INFORMATION block
|
||||
- `.mokostandards` file with `platform:` field (`joomla`, `dolibarr`, or `generic`)
|
||||
|
||||
## Changelog Extraction
|
||||
|
||||
The workflow extracts release notes from `CHANGELOG.md` by finding the section header that matches the version number. If no match is found, it uses `"Release {VERSION}"` as the fallback.
|
||||
|
||||
## Draft Release (RC Branches)
|
||||
|
||||
When an `rc/**` branch is created, the branch tracking system auto-creates a **draft** GitHub Release for the `vXX` major version. This draft is later published by `auto-release.yml` when the RC merges to main. See [Dev Branch Tracking](./dev-branch-tracking.md) for details.
|
||||
@@ -0,0 +1,87 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/build-release.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Build & Release pipeline — unified workflow for version branches, tags, and GitHub Releases
|
||||
-->
|
||||
|
||||
# Build & Release Pipeline
|
||||
|
||||
Every governed repo has an `auto-release.yml` workflow that runs a 7-step build and release pipeline on every push to main.
|
||||
|
||||
## Pipeline Steps
|
||||
|
||||
```
|
||||
Push to main
|
||||
│
|
||||
├─ 1. Read VERSION from README.md
|
||||
│
|
||||
├─ 2. Create version/XX branch (snapshot)
|
||||
│
|
||||
├─ 3. Set platform version
|
||||
│ ├─ Dolibarr: $this->version in mod*.class.php
|
||||
│ └─ Joomla: <version> in XML manifest
|
||||
│
|
||||
├─ 4. Update [VERSION: XX.YY.ZZ] badges in markdown files
|
||||
│
|
||||
├─ 5. Write update.txt (Dolibarr only — plain text version for checkForUpdate)
|
||||
│
|
||||
├─ 6. Create git tag vXX.YY.ZZ
|
||||
│
|
||||
└─ 7. Create GitHub Release with changelog notes
|
||||
```
|
||||
|
||||
## Triggers
|
||||
|
||||
- Push to `main` or `master`
|
||||
- Skips commits by `github-actions[bot]` and commits with `[skip ci]`
|
||||
- Skips if tag + branch already exist (idempotent)
|
||||
|
||||
## What Each Step Does
|
||||
|
||||
### Step 1: Read version
|
||||
Reads `VERSION:` from the README.md FILE INFORMATION block using `version_read.php`.
|
||||
|
||||
### Step 2: Create version branch
|
||||
Creates `version/XX` as a frozen snapshot of main at release time. If the branch already exists, this step is skipped.
|
||||
|
||||
### Step 3: Set platform version
|
||||
- **Dolibarr**: sets `$this->version` in `src/core/modules/mod*.class.php` to the real version AND rewrites `$this->url_last_version` to point to the main branch
|
||||
- **Joomla**: sets `<version>` in XML manifest files
|
||||
|
||||
### Step 4: Update version badges
|
||||
Finds all `[VERSION: XX.YY.ZZ]` badges in markdown files and updates them to the current version.
|
||||
|
||||
### Step 5: Write update.txt
|
||||
For Dolibarr repos only: writes the version number as plain text to `update.txt`. Dolibarr's `checkForUpdate()` expects raw text < 30 chars from `$this->url_last_version`.
|
||||
|
||||
### Step 6: Create git tag
|
||||
Creates `vXX.YY.ZZ` tag and pushes to remote.
|
||||
|
||||
### Step 7: Create GitHub Release
|
||||
Extracts release notes from CHANGELOG.md (section matching the version heading) and creates a GitHub Release targeting the version branch.
|
||||
|
||||
## Version Lifecycle
|
||||
|
||||
| Phase | Branch | Module Version | Badge | Release? |
|
||||
|-------|--------|---------------|-------|----------|
|
||||
| Development | `dev/**` | `"development"` | Dev version | No |
|
||||
| Merge to main | `main` | Real version | Updated | Yes |
|
||||
| Version bump | `main` | Auto-incremented | Updated | Next push |
|
||||
|
||||
## Related Workflows
|
||||
|
||||
| Workflow | Role |
|
||||
|----------|------|
|
||||
| `sync-version-on-merge.yml` | Auto-bumps patch version in README on push to main |
|
||||
| `auto-release.yml` | This pipeline — builds, branches, tags, releases |
|
||||
| `deploy-dev.yml` | Deploys to dev server with version="development" |
|
||||
| `deploy-demo.yml` | Deploys to demo with real version |
|
||||
| `repository-cleanup.yml` | Deletes old version branches on schedule |
|
||||
@@ -0,0 +1,775 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Workflow
|
||||
INGROUP: MokoStandards.Documentation
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/bulk-repo-sync.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Comprehensive documentation for the bulk repository sync workflow
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||

|
||||

|
||||
|
||||
# Bulk Repository Sync Workflow
|
||||
|
||||
**Status**: ✅ Active | **Version**: 2.0.0 | **Enterprise Ready**: ✅ Certified | **Last Updated**: 2026-02-26
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Enterprise Features](#enterprise-features)
|
||||
- [How It Works](#how-it-works)
|
||||
- [Workflow Triggers](#workflow-triggers)
|
||||
- [Configuration](#configuration)
|
||||
- [Usage Scenarios](#usage-scenarios)
|
||||
- [Sync Behavior](#sync-behavior)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Security Considerations](#security-considerations)
|
||||
- [Related Documentation](#related-documentation)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The **Bulk Repository Sync** workflow is MokoStandards' automated system for deploying and maintaining organizational standards across all repositories in the mokoconsulting-tech organization.
|
||||
|
||||
**Version 2.0 Updates**: Enhanced with enterprise libraries for audit logging, metrics collection, API rate limiting, and error recovery.
|
||||
|
||||
### Purpose
|
||||
|
||||
- **Consistency**: Ensure all repositories follow MokoStandards conventions
|
||||
- **Automation**: Deploy workflows, scripts, and configurations automatically
|
||||
- **Maintenance**: Keep repositories up-to-date with latest standards
|
||||
- **Compliance**: Enforce organizational coding standards across projects
|
||||
- **Observability**: Track operations with audit logs and metrics
|
||||
|
||||
### Key Features
|
||||
|
||||
✅ **Organization-Scoped**: Works only within mokoconsulting-tech organization
|
||||
✅ **Monthly Automation**: Automatically syncs on 1st of each month
|
||||
✅ **Manual Control**: Trigger sync for specific repos or use dry-run mode
|
||||
✅ **Override Support**: Respects repository-specific configurations
|
||||
✅ **Platform Detection**: Automatically detects terraform, dolibarr, joomla, generic projects
|
||||
✅ **Safe PR Creation**: Creates pull requests instead of direct commits
|
||||
✅ **Enterprise Audit Logging**: All operations logged for compliance
|
||||
✅ **API Rate Limiting**: Intelligent GitHub API usage with circuit breaker
|
||||
✅ **Error Recovery**: Automatic retry with checkpointing
|
||||
✅ **Metrics Collection**: Performance and success metrics tracked
|
||||
✅ **Security Validation**: Pre-sync vulnerability scanning
|
||||
✅ **Dry-Run Mode**: Test changes without applying them
|
||||
✅ **Enterprise Ready**: Certified with full enterprise library integration
|
||||
|
||||
### Workflow Location
|
||||
|
||||
- **File**: `.github/workflows/bulk-repo-sync.yml`
|
||||
- **Script**: `api/automation/bulk_sync.php`
|
||||
- **Version**: 5.0 (Rebuilt using Enterprise library)
|
||||
- **Status**: ✅ **ENTERPRISE READY** - Fully integrated with enterprise security, audit logging, and metrics
|
||||
|
||||
---
|
||||
|
||||
## Enterprise Features
|
||||
|
||||
### Integrated Enterprise Libraries
|
||||
|
||||
The bulk_sync.php script is **ENTERPRISE READY** with full integration of:
|
||||
|
||||
1. **RepositorySynchronizer** (Primary Component)
|
||||
- Core synchronization logic
|
||||
- Repository listing and filtering
|
||||
- Per-repository processing with checkpoints
|
||||
- Progress tracking and reporting
|
||||
|
||||
2. **ApiClient**
|
||||
- Rate limiting (5000 requests/hour default)
|
||||
- Exponential backoff retry logic
|
||||
- Circuit breaker protection
|
||||
- Response caching for performance
|
||||
|
||||
3. **AuditLogger**
|
||||
- Transaction tracking for each repository sync
|
||||
- Per-file operation logging with timestamps
|
||||
- Security event logging
|
||||
- Compliance reports for audit trails
|
||||
|
||||
4. **MetricsCollector**
|
||||
- Success/failure rate tracking
|
||||
- Sync duration measurements
|
||||
- File count metrics (processed, synced, skipped)
|
||||
- Performance indicators for monitoring
|
||||
|
||||
5. **CheckpointManager**
|
||||
- Automatic checkpoint saving during sync
|
||||
- Resume capability after failures
|
||||
- State persistence for long-running operations
|
||||
|
||||
6. **SecurityValidator**
|
||||
- Pre-sync vulnerability scanning
|
||||
- Detection of hardcoded credentials and API keys
|
||||
- Insecure pattern detection
|
||||
- Security issues logged in audit trail
|
||||
|
||||
### Monitoring Workflows
|
||||
|
||||
New enterprise monitoring workflows are available:
|
||||
- `audit-log-archival.yml` - Weekly audit log processing
|
||||
- `metrics-collection.yml` - Daily metrics aggregation
|
||||
- `health-check.yml` - Hourly health monitoring
|
||||
- `security-scan.yml` - Enhanced security scanning
|
||||
- `integration-tests.yml` - Enterprise library testing
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Running a Test Sync (Dry Run)
|
||||
|
||||
1. Go to **Actions** → **Bulk Repository Sync** in GitHub
|
||||
2. Click **Run workflow**
|
||||
3. Check **Dry run** box
|
||||
4. Leave **Repositories** blank (tests all repos)
|
||||
5. Click **Run workflow**
|
||||
|
||||
This previews changes without applying them.
|
||||
|
||||
### Syncing Specific Repositories
|
||||
|
||||
1. Go to **Actions** → **Bulk Repository Sync**
|
||||
2. Click **Run workflow**
|
||||
3. Enter repository names: `MokoApp MokoWeb` (space-separated)
|
||||
4. Leave **Dry run** unchecked
|
||||
5. Click **Run workflow**
|
||||
|
||||
This creates PRs in the specified repositories.
|
||||
|
||||
### Syncing All Repositories (Scheduled Behavior)
|
||||
|
||||
The workflow automatically runs on the 1st of each month at 00:00 UTC, syncing all non-archived repositories except MokoStandards itself.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
### Workflow Flow Diagram
|
||||
|
||||
```
|
||||
TRIGGER: Monthly Schedule (1st @ 00:00 UTC) or Manual Dispatch
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Parse Terraform │
|
||||
│ Override Config │───┐ Read override.config.tf
|
||||
└──────────────────┘ │ Extract exclusions & configs
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────┐ │
|
||||
│ List All Org │◀──┘
|
||||
│ Repositories │
|
||||
└──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Filter Repos │───┐ Apply exclusions
|
||||
│ Apply Exclusions │ │ Skip archived/disabled
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
╔══════════════════╗ │
|
||||
║ FOR EACH REPO: ║◀──┘
|
||||
╚══════════════════╝
|
||||
│
|
||||
├────────────────┬────────────────┬────────────────┐
|
||||
▼ ▼ ▼ ▼
|
||||
┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐
|
||||
│ Sync │ │ Sync │ │ Sync │ │ Create │
|
||||
│Workflows│ │ Scripts │ │ Configs │ │ PR │
|
||||
└─────────┘ └──────────┘ └─────────┘ └──────────┘
|
||||
│ │ │ │
|
||||
└────────────────┴────────────────┴────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ OUTPUTS: │
|
||||
│ • Sync Report │
|
||||
│ • PR Links │
|
||||
│ • Error Summary │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Sync Process Steps
|
||||
|
||||
1. **Clone Target Repository**: Clone each repository to temporary directory
|
||||
2. **Load Override Configuration**: Check for `override.config.tf` in target repo
|
||||
3. **Determine Platform Type**: Use override or auto-detect (infrastructure/terraform/dolibarr/joomla/generic)
|
||||
4. **Select Files to Sync**: Based on platform type and override exclusions
|
||||
5. **Create Branch**: Create `chore/sync-mokostandards-updates` branch
|
||||
6. **Sync Files**: Copy workflows, scripts, and configurations
|
||||
7. **Commit Changes**: Commit with descriptive message
|
||||
8. **Create Pull Request**: Open PR for review (never direct push)
|
||||
|
||||
---
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
### 1. Scheduled Trigger (Monthly)
|
||||
|
||||
**Schedule**: 1st of every month at 00:00 UTC
|
||||
|
||||
```yaml
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- Syncs to ALL non-archived repositories
|
||||
- Automatically excludes: `MokoStandards`, `MokoStandards-Private`
|
||||
- Creates PRs for review
|
||||
- No manual intervention required
|
||||
|
||||
**Use Cases**:
|
||||
- Regular maintenance of organizational standards
|
||||
- Deploy new workflow updates monthly
|
||||
- Keep repositories in sync with latest templates
|
||||
|
||||
### 2. Manual Trigger (workflow_dispatch)
|
||||
|
||||
Trigger manually from GitHub Actions UI.
|
||||
|
||||
**Inputs**:
|
||||
|
||||
| Input | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `repos` | string | No | (all) | Space-separated list of repositories to sync |
|
||||
| `exclude` | string | No | (none) | Space-separated list of repositories to exclude |
|
||||
| `dry_run` | boolean | No | false | Preview changes without creating PRs |
|
||||
|
||||
**Use Cases**:
|
||||
- Test sync on specific repository before monthly run
|
||||
- Emergency sync after critical workflow update
|
||||
- Sync to newly created repositories
|
||||
- Troubleshoot sync issues with dry-run mode
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Secrets
|
||||
|
||||
The workflow requires the following GitHub secret:
|
||||
|
||||
#### `GH_TOKEN`
|
||||
|
||||
**Type**: Personal Access Token (PAT) or GitHub App token
|
||||
|
||||
**Required Permissions**:
|
||||
- `repo` (full control)
|
||||
- `workflow` (update GitHub Actions workflows)
|
||||
- `admin:org` (read org repositories)
|
||||
|
||||
**Setup**:
|
||||
1. Generate PAT with required permissions
|
||||
2. Add to organization secrets as `GH_TOKEN` (GitHub organization Settings → Secrets and variables → Actions)
|
||||
3. Workflow will automatically use it
|
||||
|
||||
**Security Note**: As an organization secret, `GH_TOKEN` is available to all workflow runs across all repositories in the `mokoconsulting-tech` organization.
|
||||
|
||||
### Repository Override Configuration
|
||||
|
||||
Repositories can control sync behavior using `override.config.tf` file.
|
||||
|
||||
**Example Override File**:
|
||||
|
||||
```hcl
|
||||
# override.config.tf
|
||||
locals {
|
||||
override_metadata = {
|
||||
repository_type = "terraform" # Skip auto-detection
|
||||
}
|
||||
|
||||
sync_config = {
|
||||
enabled = true
|
||||
cleanup_mode = "conservative"
|
||||
}
|
||||
|
||||
exclude_files = [
|
||||
{
|
||||
path = ".github/workflows/custom-ci.yml"
|
||||
reason = "Custom CI workflow with special requirements"
|
||||
}
|
||||
]
|
||||
|
||||
protected_files = [
|
||||
{
|
||||
path = ".gitignore"
|
||||
reason = "Repository-specific ignore patterns"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**For complete override documentation**, see: [Terraform Override Files Guide](../guide/terraform-override-files.md)
|
||||
|
||||
---
|
||||
|
||||
## Usage Scenarios
|
||||
|
||||
### Scenario 1: Test Sync on Single Repository
|
||||
|
||||
**Situation**: You updated a workflow template and want to test before monthly sync.
|
||||
|
||||
**Steps**:
|
||||
1. Navigate to **Actions** → **Bulk Repository Sync**
|
||||
2. Click **Run workflow**
|
||||
3. **Inputs**:
|
||||
- `repos`: `moko-test-project`
|
||||
- `dry_run`: `true`
|
||||
4. Review workflow output for proposed changes
|
||||
5. If looks good, re-run with `dry_run`: `false`
|
||||
|
||||
**Expected Outcome**: Workflow shows what files would be synced without creating PR.
|
||||
|
||||
### Scenario 2: Emergency Workflow Update
|
||||
|
||||
**Situation**: Security fix needed in all repositories immediately.
|
||||
|
||||
**Steps**:
|
||||
1. Update workflow template in MokoStandards
|
||||
2. Commit and push changes
|
||||
3. Navigate to **Actions** → **Bulk Repository Sync**
|
||||
4. Click **Run workflow**
|
||||
5. **Inputs**:
|
||||
- `repos`: (leave empty for all)
|
||||
- `exclude`: `archived-repo deprecated-project`
|
||||
- `dry_run`: `false`
|
||||
6. Monitor workflow progress
|
||||
7. Review and merge PRs in target repositories
|
||||
|
||||
**Expected Outcome**: PRs created in all active repositories with updated workflow.
|
||||
|
||||
### Scenario 3: Sync to Newly Created Repository
|
||||
|
||||
**Situation**: New repository created, needs standards applied.
|
||||
|
||||
**Steps**:
|
||||
1. Create repository in mokoconsulting-tech organization
|
||||
2. Navigate to **Actions** → **Bulk Repository Sync**
|
||||
3. Click **Run workflow**
|
||||
4. **Inputs**:
|
||||
- `repos`: `new-repository-name`
|
||||
- `dry_run`: `false`
|
||||
5. Review and merge the PR in new repository
|
||||
|
||||
**Expected Outcome**: New repository receives all standard workflows and configurations.
|
||||
|
||||
### Scenario 4: Exclude Specific Repositories
|
||||
|
||||
**Situation**: Some repositories should not receive updates (archived, experimental, etc.)
|
||||
|
||||
**Steps**:
|
||||
1. Navigate to **Actions** → **Bulk Repository Sync**
|
||||
2. Click **Run workflow**
|
||||
3. **Inputs**:
|
||||
- `repos`: (leave empty)
|
||||
- `exclude`: `old-project experimental-repo archived-module`
|
||||
- `dry_run`: `false`
|
||||
|
||||
**Expected Outcome**: All repositories except specified ones receive updates.
|
||||
|
||||
### Scenario 5: Troubleshooting Sync Failures
|
||||
|
||||
**Situation**: Sync failed for a repository, need to diagnose.
|
||||
|
||||
**Steps**:
|
||||
1. Check workflow logs for error messages
|
||||
2. Re-run with `dry_run`: `true` for that repository
|
||||
3. Review proposed changes
|
||||
4. Check if repository has `override.config.tf` with conflicts
|
||||
5. Verify `GH_TOKEN` has correct permissions
|
||||
6. Check if repository is archived or private with restricted access
|
||||
|
||||
---
|
||||
|
||||
## Sync Behavior
|
||||
|
||||
### What Gets Synced
|
||||
|
||||
The bulk sync workflow synchronizes the following file types:
|
||||
|
||||
#### 1. **Core Configuration Files** (All Repositories)
|
||||
|
||||
- `.github/dependabot.yml` - Dependabot configuration
|
||||
- `.github/copilot.yml` - GitHub Copilot configuration
|
||||
|
||||
#### 2. **Universal Workflows** (All Repositories)
|
||||
|
||||
- `.github/workflows/build.yml` - Build workflow
|
||||
- `.github/workflows/ci.yml` - CI validation workflow
|
||||
|
||||
#### 3. **Platform-Specific Workflows**
|
||||
|
||||
**Terraform Repositories**:
|
||||
- `.github/workflows/terraform-ci.yml` - Terraform CI
|
||||
- `.github/workflows/terraform-deploy.yml` - Terraform deployment
|
||||
- `.github/workflows/terraform-drift.yml` - Drift detection
|
||||
|
||||
**Dolibarr Repositories**:
|
||||
- `.github/workflows/release.yml` - Dolibarr release workflow
|
||||
- `.github/workflows/sync-changelogs.yml` - Changelog sync
|
||||
|
||||
**Joomla Repositories**:
|
||||
- `.github/workflows/release.yml` - Joomla release workflow
|
||||
- `.github/workflows/repo-health.yml` - Repository health checks
|
||||
|
||||
**Generic Repositories**:
|
||||
- `.github/workflows/code-quality.yml` - Code quality checks
|
||||
- `.github/workflows/codeql-analysis.yml` - Security scanning
|
||||
- `.github/workflows/repo-health.yml` - Health checks
|
||||
|
||||
#### 4. **Reusable Workflows** (All Repositories)
|
||||
|
||||
- `.github/workflows/reusable-build.yml` - Reusable build workflow
|
||||
- `.github/workflows/reusable-release.yml` - Reusable release workflow
|
||||
- `.github/workflows/reusable-project-detector.yml` - Project detection
|
||||
- Additional reusable workflows based on platform
|
||||
|
||||
#### 5. **Validation Scripts** (All Repositories)
|
||||
|
||||
- `api/validate/auto_detect_platform.php` - Platform detection
|
||||
- Schema definition files (required by validators)
|
||||
|
||||
### What DOESN'T Get Synced
|
||||
|
||||
The following are never synced (always excluded):
|
||||
|
||||
❌ Repository-specific files (by default):
|
||||
- `.gitignore`
|
||||
- `.editorconfig`
|
||||
- `README.md`
|
||||
- `LICENSE`
|
||||
|
||||
❌ Custom files in override's `protected_files` list
|
||||
|
||||
❌ Files in override's `exclude_files` list
|
||||
|
||||
❌ Repository-specific override file itself (`override.config.tf`)
|
||||
|
||||
### Platform Detection Logic
|
||||
|
||||
The sync tool determines platform type in this order:
|
||||
|
||||
1. **Check Override First**: If `override.config.tf` specifies `repository_type`, use it
|
||||
2. **Auto-Detection**: If no override, run `auto_detect_platform.php`:
|
||||
- Checks for Terraform files (`.tf`, `infrastructure/terraform/`)
|
||||
- Checks for Dolibarr structure (`htdocs/`, module XML)
|
||||
- Checks for Joomla structure (`manifest.xml`, Joomla patterns)
|
||||
- Falls back to "generic" if none detected
|
||||
3. **Default**: Use "generic" if detection fails
|
||||
|
||||
**Performance**: Override-based detection is ~2-3 seconds faster per repository.
|
||||
|
||||
### File Cleanup Behavior
|
||||
|
||||
The sync tool has three cleanup modes (configured in override):
|
||||
|
||||
**1. `none`** - No cleanup
|
||||
- Only adds or updates files
|
||||
- Never removes files
|
||||
- **Use for**: Initial sync, testing
|
||||
|
||||
**2. `conservative`** (Default)
|
||||
- Removes obsolete `.yml` and `.py` files from managed directories
|
||||
- Only touches files that were previously synced
|
||||
- **Use for**: Regular maintenance, most repositories
|
||||
|
||||
**3. `aggressive`**
|
||||
- Removes ALL files in managed directories not in sync list
|
||||
- Can remove custom files if not protected
|
||||
- **Use for**: Advanced users, strict compliance requirements
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Issue 1: Sync Fails with "Authentication Required"
|
||||
|
||||
**Symptoms**:
|
||||
- Workflow fails at git operations
|
||||
- Error mentions authentication or permissions
|
||||
|
||||
**Solutions**:
|
||||
1. Verify `GH_TOKEN` secret exists
|
||||
2. Check token hasn't expired
|
||||
3. Verify token has `repo`, `workflow`, and `admin:org` permissions
|
||||
4. Re-generate token if needed
|
||||
|
||||
#### Issue 2: Repository Not Being Synced
|
||||
|
||||
**Symptoms**:
|
||||
- Repository missing from sync report
|
||||
- No PR created in expected repository
|
||||
|
||||
**Solutions**:
|
||||
1. Check if repository is archived (archived repos skipped)
|
||||
2. Verify repository name spelling
|
||||
3. Check if repository is in exclude list
|
||||
4. Review workflow logs for skip messages
|
||||
|
||||
#### Issue 3: Files Not Syncing Despite No Override
|
||||
|
||||
**Symptoms**:
|
||||
- Expected files not appearing in PR
|
||||
- Sync completes but files missing
|
||||
|
||||
**Solutions**:
|
||||
1. Check if files exist in MokoStandards templates
|
||||
2. Verify platform detection is correct
|
||||
3. Look for parse errors in workflow logs
|
||||
4. Check if files are in default exclusion list
|
||||
|
||||
#### Issue 4: Platform Detection Wrong
|
||||
|
||||
**Symptoms**:
|
||||
- Wrong workflows being synced (e.g., terraform workflows in PHP project)
|
||||
- Platform shows as "generic" when should be specific
|
||||
|
||||
**Solutions**:
|
||||
1. Add `override.config.tf` with explicit `repository_type`
|
||||
2. Verify repository structure matches expected patterns
|
||||
3. Check auto-detection script works: `php api/validate/auto_detect_platform.php`
|
||||
|
||||
#### Issue 5: Dry Run Shows No Changes
|
||||
|
||||
**Symptoms**:
|
||||
- Dry run reports no files to sync
|
||||
- Repository clearly out of date
|
||||
|
||||
**Solutions**:
|
||||
1. Check if all files are in override's `exclude_files`
|
||||
2. Verify cleanup mode isn't "none"
|
||||
3. Check if repository already has latest files
|
||||
4. Review sync configuration in override file
|
||||
|
||||
### Getting Help
|
||||
|
||||
If issues persist:
|
||||
|
||||
1. **Review Logs**: Check workflow run logs for detailed error messages
|
||||
2. **Check Override**: Verify `override.config.tf` syntax
|
||||
3. **Dry Run**: Test with single repository in dry-run mode
|
||||
4. **Open Issue**: Create issue in MokoStandards repository with:
|
||||
- Repository name
|
||||
- Workflow run URL
|
||||
- Error messages
|
||||
- Override file content (if applicable)
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Test with Dry Run First
|
||||
|
||||
Before syncing to multiple repositories:
|
||||
|
||||
```
|
||||
✓ DO: Test on one repo with dry_run: true
|
||||
✓ DO: Review proposed changes carefully
|
||||
✗ DON'T: Sync to all repos without testing
|
||||
```
|
||||
|
||||
### 2. Use Override Files for Custom Repos
|
||||
|
||||
For repositories with special requirements:
|
||||
|
||||
```
|
||||
✓ DO: Create override.config.tf with exclusions
|
||||
✓ DO: Protect custom files in protected_files list
|
||||
✓ DO: Document reasons for exclusions
|
||||
✗ DON'T: Rely on manual PR rejection
|
||||
```
|
||||
|
||||
### 3. Monitor Monthly Syncs
|
||||
|
||||
After scheduled syncs:
|
||||
|
||||
```
|
||||
✓ DO: Review workflow run summary
|
||||
✓ DO: Check for failed syncs
|
||||
✓ DO: Review and merge PRs promptly
|
||||
✗ DON'T: Ignore sync failures
|
||||
```
|
||||
|
||||
### 4. Keep Override Files Updated
|
||||
|
||||
When changing repository structure:
|
||||
|
||||
```
|
||||
✓ DO: Update repository_type if platform changes
|
||||
✓ DO: Update exclude_files as needed
|
||||
✓ DO: Keep documentation current in reasons
|
||||
✗ DON'T: Leave stale override configuration
|
||||
```
|
||||
|
||||
### 5. Document Custom Workflows
|
||||
|
||||
For excluded workflows:
|
||||
|
||||
```
|
||||
✓ DO: Add clear comments explaining customization
|
||||
✓ DO: Keep custom workflows maintained
|
||||
✓ DO: Consider contributing improvements back to MokoStandards
|
||||
✗ DON'T: Duplicate standard functionality
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Token Security
|
||||
|
||||
**GH_TOKEN Management**:
|
||||
|
||||
✅ **DO**:
|
||||
- Use fine-grained PAT with minimal required permissions
|
||||
- Rotate token regularly (every 90 days)
|
||||
- Audit token usage periodically
|
||||
- Restrict token to MokoStandards repository only
|
||||
|
||||
❌ **DON'T**:
|
||||
- Share token with other workflows
|
||||
- Use token with broader permissions than needed
|
||||
- Store token in code or documentation
|
||||
- Use personal token (use organization token)
|
||||
|
||||
### Sync Security
|
||||
|
||||
**PR Review Process**:
|
||||
|
||||
✅ **DO**:
|
||||
- Always review PRs before merging
|
||||
- Check for unexpected file changes
|
||||
- Verify workflow modifications are intentional
|
||||
- Test workflows in PR branches before merging
|
||||
|
||||
❌ **DON'T**:
|
||||
- Auto-merge sync PRs without review
|
||||
- Skip CI checks on sync PRs
|
||||
- Merge without understanding changes
|
||||
|
||||
### Repository Protection
|
||||
|
||||
**Branch Protection Rules**:
|
||||
|
||||
Sync PRs respect branch protection:
|
||||
- Cannot override required reviewers
|
||||
- Cannot bypass required status checks
|
||||
- Cannot force-push to protected branches
|
||||
- Creates PRs even on protected branches
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
### Essential Reading
|
||||
|
||||
- **[Terraform Override Files Guide](../guide/terraform-override-files.md)** - Complete guide for configuring sync behavior
|
||||
- **[Workflow Architecture](./workflow-architecture.md)** - Understanding workflow hierarchy
|
||||
- **[Platform Detection](../guide/platform-detection.md)** - How auto-detection works
|
||||
|
||||
### Related Workflows
|
||||
|
||||
- **[Standards Compliance](./standards-compliance.md)** - Validation workflow
|
||||
- **[Auto-Update SHA](./auto-update-sha.md)** - SHA hash management
|
||||
- **[Terraform Drift Check](./terraform-drift-check.md)** - Infrastructure drift detection
|
||||
|
||||
### Sync-Related Documentation
|
||||
|
||||
- **[Branch Synchronization](../guide/branch-synchronization.md)** - Branch sync strategies
|
||||
- **[Changelog Synchronization](../guide/changelog-synchronization.md)** - Changelog management
|
||||
- **[Copilot Sync Standards](../guide/copilot-sync-standards.md)** - Copilot configuration sync
|
||||
|
||||
### Script Documentation
|
||||
|
||||
- **Script Source**: `api/automation/bulk_update_repos.php`
|
||||
- **Platform Detection**: `api/validate/auto_detect_platform.php`
|
||||
- **Run Help**: `php api/automation/bulk_update_repos.php --help`
|
||||
|
||||
---
|
||||
|
||||
## Maintenance and Updates
|
||||
|
||||
### Workflow Maintenance
|
||||
|
||||
**Updating the Workflow**:
|
||||
|
||||
1. Modify `.github/workflows/bulk-repo-sync.yml`
|
||||
2. Test changes with manual trigger on test repository
|
||||
3. Commit and push to MokoStandards
|
||||
4. Next scheduled run uses updated workflow
|
||||
|
||||
**Updating the Script**:
|
||||
|
||||
1. Modify `api/automation/bulk_update_repos.php`
|
||||
2. Test locally: `php api/automation/bulk_update_repos.php --dry-run --repos test-repo`
|
||||
3. Verify changes work as expected
|
||||
4. Commit and push to MokoStandards
|
||||
5. Next sync uses updated script
|
||||
|
||||
### Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 2.0.0 | 2026-01 | Terraform-based override system, platform detection priority |
|
||||
| 1.0.0 | 2025-12 | Initial schema-driven architecture |
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
### Getting Support
|
||||
|
||||
For questions or issues:
|
||||
|
||||
1. **Documentation**: Review this guide and related documentation
|
||||
2. **Dry Run**: Test with dry-run mode to diagnose issues
|
||||
3. **Logs**: Check workflow logs for detailed error messages
|
||||
4. **Issues**: Open issue in [MokoStandards](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/issues)
|
||||
|
||||
### Contributing
|
||||
|
||||
To improve the bulk sync workflow:
|
||||
|
||||
1. Test changes thoroughly in fork
|
||||
2. Document new features
|
||||
3. Submit PR with clear description
|
||||
4. Include examples and use cases
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-09
|
||||
**Maintained By**: MokoStandards Team
|
||||
**License**: GPL-3.0-or-later
|
||||
@@ -0,0 +1,338 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API/
|
||||
VERSION: 04.06.00
|
||||
PATH: /docs/workflows/changelog-management.md
|
||||
BRIEF: Documentation for changelog management workflows and scripts
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Changelog Management System
|
||||
|
||||
This document describes the changelog management system for MokoStandards, including scripts and workflows for maintaining CHANGELOG.md according to [Keep a Changelog](https://keepachangelog.com/) format.
|
||||
|
||||
## Overview
|
||||
|
||||
The changelog management system consists of:
|
||||
|
||||
1. **Scripts**: Python scripts for updating and releasing versions
|
||||
2. **Workflows**: GitHub Actions for automated changelog management
|
||||
3. **Format**: Follows Keep a Changelog with Semantic Versioning
|
||||
|
||||
## Scripts
|
||||
|
||||
### update_changelog.py
|
||||
|
||||
Updates CHANGELOG.md by adding entries to the UNRELEASED section.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Add a simple entry
|
||||
python3 api/maintenance/update_changelog.py --category Added --entry "New feature X"
|
||||
|
||||
# Add an entry with subcategory
|
||||
python3 api/maintenance/update_changelog.py --category Changed --entry "Updated API" --subcategory "API"
|
||||
|
||||
# Display current UNRELEASED section
|
||||
python3 api/maintenance/update_changelog.py --show
|
||||
```
|
||||
|
||||
**Categories**: Added, Changed, Deprecated, Removed, Fixed, Security
|
||||
|
||||
**Features**:
|
||||
- Automatically creates category sections if they don't exist
|
||||
- Maintains proper formatting and indentation
|
||||
- Supports subcategories for better organization
|
||||
- Validates category names
|
||||
|
||||
### release_version.py
|
||||
|
||||
Releases a version by moving UNRELEASED items to a versioned section, updating VERSION headers in files, and optionally creating a GitHub release.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Release version (updates CHANGELOG only)
|
||||
python3 api/maintenance/release_version.py --version 05.01.00
|
||||
|
||||
# Release with custom date
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --date 2026-01-15
|
||||
|
||||
# Release and update VERSION in all files
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --update-files
|
||||
|
||||
# Release, update files, and create GitHub release
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --update-files --create-release
|
||||
|
||||
# Dry run to preview changes
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --update-files --create-release --dry-run
|
||||
```
|
||||
|
||||
**Features**:
|
||||
- Validates version format (XX.YY.ZZ)
|
||||
- Moves UNRELEASED content to new version section
|
||||
- Updates VERSION header in all repository files
|
||||
- Creates GitHub releases with extracted notes
|
||||
- Supports dry-run mode for testing
|
||||
|
||||
## Workflows
|
||||
|
||||
### Update Changelog Workflow
|
||||
|
||||
**File**: `.github/workflows/changelog_update.yml`
|
||||
|
||||
**Trigger**: Manual workflow dispatch
|
||||
|
||||
**Purpose**: Add entries to CHANGELOG.md UNRELEASED section via GitHub Actions UI
|
||||
|
||||
**Inputs**:
|
||||
- `category`: Changelog category (Added/Changed/Deprecated/Removed/Fixed/Security)
|
||||
- `entry`: Entry text
|
||||
- `subcategory`: Optional subcategory/subheading
|
||||
|
||||
**Process**:
|
||||
1. Runs update_changelog.py script
|
||||
2. Creates a Pull Request with changes
|
||||
3. Labels PR with `documentation` and `automated`
|
||||
|
||||
**Usage**:
|
||||
1. Go to Actions → Update Changelog
|
||||
2. Click "Run workflow"
|
||||
3. Fill in the form
|
||||
4. Review and merge the created PR
|
||||
|
||||
### Version Release Workflow
|
||||
|
||||
**File**: `.github/workflows/version_release.yml`
|
||||
|
||||
**Trigger**: Manual workflow dispatch
|
||||
|
||||
**Purpose**: Release a new version by moving UNRELEASED items, updating files, and creating GitHub release
|
||||
|
||||
**Inputs**:
|
||||
- `version`: Version number in XX.YY.ZZ format
|
||||
- `date`: Optional release date (defaults to today)
|
||||
- `update_files`: Whether to update VERSION in all files
|
||||
- `create_release`: Whether to create GitHub release
|
||||
|
||||
**Process**:
|
||||
1. Validates version format
|
||||
2. Releases version in CHANGELOG.md
|
||||
3. Updates VERSION headers in all files (if enabled)
|
||||
4. Commits changes
|
||||
5. Creates Pull Request for review
|
||||
6. Creates GitHub release after PR merge (if enabled)
|
||||
|
||||
**Usage**:
|
||||
1. Go to Actions → Release Version
|
||||
2. Click "Run workflow"
|
||||
3. Enter version number (e.g., 05.01.00)
|
||||
4. Select options (update files, create release)
|
||||
5. Review and merge the created PR
|
||||
6. GitHub release is created automatically
|
||||
|
||||
## Changelog Format
|
||||
|
||||
### Structure
|
||||
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
## [05.01.00] - 2026-01-15
|
||||
### Added
|
||||
- New feature description
|
||||
|
||||
### Changed
|
||||
- Change description
|
||||
|
||||
### Security
|
||||
- Security improvement
|
||||
|
||||
## [05.00.00] - 2026-01-04
|
||||
...
|
||||
```
|
||||
|
||||
### Categories
|
||||
|
||||
- **Added**: New features
|
||||
- **Changed**: Changes in existing functionality
|
||||
- **Deprecated**: Soon-to-be removed features
|
||||
- **Removed**: Removed features
|
||||
- **Fixed**: Bug fixes
|
||||
- **Security**: Security improvements
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Be Specific**: Describe what changed and why
|
||||
2. **User-Focused**: Write from user's perspective
|
||||
3. **Group Related**: Use subcategories for related changes
|
||||
4. **Link Issues**: Reference issue/PR numbers when relevant
|
||||
5. **Keep Updated**: Add entries as changes are made
|
||||
|
||||
## Version Format
|
||||
|
||||
Versions follow the format: **XX.YY.ZZ**
|
||||
|
||||
- **XX**: Major version (breaking changes)
|
||||
- **YY**: Minor version (new features, backward compatible)
|
||||
- **ZZ**: Patch version (bug fixes)
|
||||
|
||||
Examples: `05.00.00`, `05.01.00`, `05.01.01`
|
||||
|
||||
## Integration with Development Workflow
|
||||
|
||||
### During Development
|
||||
|
||||
1. Make code changes
|
||||
2. Add changelog entry using script or workflow:
|
||||
```bash
|
||||
python3 api/maintenance/update_changelog.py --category Added --entry "Feature description"
|
||||
```
|
||||
3. Commit both code and changelog changes
|
||||
|
||||
### For Releases
|
||||
|
||||
1. Ensure all changes are in UNRELEASED section
|
||||
2. Run version release workflow:
|
||||
- Actions → Release Version
|
||||
- Enter version number
|
||||
- Enable "Update files" and "Create release"
|
||||
3. Review the created PR
|
||||
4. Merge PR to complete release
|
||||
5. GitHub release is created automatically
|
||||
|
||||
### Manual Release (Alternative)
|
||||
|
||||
```bash
|
||||
# 1. Release version
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --update-files
|
||||
|
||||
# 2. Commit changes
|
||||
git add .
|
||||
git commit -m "release: version 05.01.00"
|
||||
|
||||
# 3. Create GitHub release
|
||||
python3 api/maintenance/release_version.py --version 05.01.00 --create-release
|
||||
|
||||
# 4. Push changes
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## File VERSION Headers
|
||||
|
||||
All files with version headers are automatically updated during release:
|
||||
|
||||
```markdown
|
||||
VERSION: 04.06.00
|
||||
```
|
||||
|
||||
Supported file types:
|
||||
- Markdown (`.md`)
|
||||
- Python (`.py`)
|
||||
- YAML (`.yml`, `.yaml`)
|
||||
- Text (`.txt`)
|
||||
|
||||
## GitHub Release Creation
|
||||
|
||||
When `--create-release` is used, the script:
|
||||
|
||||
1. Extracts release notes from CHANGELOG.md for the version
|
||||
2. Creates a Git tag (e.g., `v05.01.00`)
|
||||
3. Creates GitHub release with:
|
||||
- Tag name: `v{version}`
|
||||
- Title: `Release {version}`
|
||||
- Notes: Extracted from CHANGELOG.md
|
||||
|
||||
Requires `gh` CLI to be installed and authenticated.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### UNRELEASED Section Not Found
|
||||
|
||||
Ensure CHANGELOG.md has an `## [UNRELEASED]` heading.
|
||||
|
||||
### Version Format Error
|
||||
|
||||
Use XX.YY.ZZ format (e.g., `05.01.00`, not `5.1.0`).
|
||||
|
||||
### GitHub Release Failed
|
||||
|
||||
- Ensure `gh` CLI is installed: `gh --version`
|
||||
- Authenticate: `gh auth login`
|
||||
- Check repository permissions
|
||||
|
||||
### File Update Issues
|
||||
|
||||
- Ensure files have VERSION headers in correct format
|
||||
- Check file permissions
|
||||
- Review dry-run output first
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Add New Feature
|
||||
|
||||
```bash
|
||||
# Add to UNRELEASED
|
||||
python3 api/maintenance/update_changelog.py \
|
||||
--category Added \
|
||||
--entry "Support for custom themes" \
|
||||
--subcategory "UI"
|
||||
|
||||
# View changes
|
||||
python3 api/maintenance/update_changelog.py --show
|
||||
```
|
||||
|
||||
### Example 2: Release Minor Version
|
||||
|
||||
```bash
|
||||
# Release 05.01.00
|
||||
python3 api/maintenance/release_version.py \
|
||||
--version 05.01.00 \
|
||||
--update-files \
|
||||
--create-release
|
||||
```
|
||||
|
||||
### Example 3: Security Update
|
||||
|
||||
```bash
|
||||
# Add security entry
|
||||
python3 api/maintenance/update_changelog.py \
|
||||
--category Security \
|
||||
--entry "Fix XSS vulnerability in user input"
|
||||
|
||||
# Release patch version
|
||||
python3 api/maintenance/release_version.py \
|
||||
--version 05.00.01 \
|
||||
--update-files \
|
||||
--create-release
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Keep a Changelog](https://keepachangelog.com/)
|
||||
- [Semantic Versioning](https://semver.org/)
|
||||
- [GitHub CLI Documentation](https://cli.github.com/manual/)
|
||||
|
||||
---
|
||||
|
||||
## Metadata
|
||||
|
||||
**Document Version**: 05.00.00
|
||||
**Last Updated**: 2026-01-04
|
||||
**Status**: Active
|
||||
|
||||
## Revision History
|
||||
|
||||
| Version | Date | Description |
|
||||
|---------|------|-------------|
|
||||
| 05.00.00 | 2026-01-04 | Initial changelog management system documentation |
|
||||
@@ -0,0 +1,75 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/demo-deployment.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for the SFTP demo server deployment workflow
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Demo Server Deployment
|
||||
|
||||
Automated SFTP deployment of the `src/` directory to the demo server on merge to main.
|
||||
|
||||
## Overview
|
||||
|
||||
The `deploy-demo.yml` workflow pushes the contents of `src/` to a demo server over **SFTP** when:
|
||||
|
||||
- A commit is pushed to `main` or `master`
|
||||
- A pull request targeting `main`/`master` is **merged**
|
||||
- Triggered manually via workflow dispatch
|
||||
|
||||
Unlike `deploy-dev.yml`, the demo workflow deploys the **real version** (no "development" override).
|
||||
|
||||
## Required Variables
|
||||
|
||||
| Variable | Scope | Description |
|
||||
|----------|-------|-------------|
|
||||
| `DEMO_FTP_HOST` | org | Demo server hostname (may include `:port` suffix) |
|
||||
| `DEMO_FTP_PATH` | org | Base remote path (e.g., `/var/www/demo`) |
|
||||
| `DEMO_FTP_USERNAME` | org | SFTP username |
|
||||
| `DEMO_FTP_SUFFIX` | repo | Repo-specific subdirectory appended to `DEMO_FTP_PATH` |
|
||||
| `DEMO_FTP_PORT` | org (optional) | Explicit port override (auto-detected from host or defaults to 22) |
|
||||
|
||||
## Required Secrets
|
||||
|
||||
| Secret | Scope | Description |
|
||||
|--------|-------|-------------|
|
||||
| `DEMO_FTP_KEY` | org | SSH private key (preferred) |
|
||||
| `DEMO_FTP_PASSWORD` | org | SFTP password or key passphrase |
|
||||
|
||||
At least one of `DEMO_FTP_KEY` or `DEMO_FTP_PASSWORD` must be set.
|
||||
|
||||
## Behaviour
|
||||
|
||||
1. **Permission check** — `jmiller-moko` and `github-actions[bot]` are always authorized; other actors need `admin` or `maintain` role
|
||||
2. **Skip on chore/ branches** — PRs from `chore/` branches do not trigger deployment
|
||||
3. **Skip if DEMO_FTP_SUFFIX not set** — repos without the variable are silently skipped
|
||||
4. **Clear remote folder** — always clears the remote destination before uploading
|
||||
5. **Upload** — deploys via `deploy-sftp.php` using phpseclib3
|
||||
6. **Failure issue** — creates/updates a `deploy-failure` issue on error
|
||||
|
||||
## Differences from Dev Deployment
|
||||
|
||||
| Feature | Dev | Demo |
|
||||
|---------|-----|------|
|
||||
| Triggers | `dev/**`, `develop`, `development` | `main`, `master` |
|
||||
| Version | Set to `"development"` | Real version from README.md |
|
||||
| Variables | `DEV_FTP_*` | `DEMO_FTP_*` |
|
||||
|
||||
## See Also
|
||||
|
||||
- [Dev Deployment](dev-deployment.md)
|
||||
- [SFTP Guide](../deployment/sftp.md)
|
||||
- [.ftpignore Reference](../deployment/ftpignore.md)
|
||||
|
||||
> **Note:** `deploy-rs.yml` has been retired. RS deployment is handled via the release pipeline only.
|
||||
@@ -0,0 +1,390 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/dev-branch-tracking.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Dev branch tracking and issue coordination system documentation
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Dev Branch Tracking and Issue Coordination
|
||||
|
||||
**Status**: Active | **Version**: 02.00.00 | **Effective**: 2026-04-07
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the dev/rc branch tracking and issue coordination system. Dev branches use **manual workflow_dispatch** to create tracking issues, while RC branches **auto-create** tracking issues and a draft GitHub Release on branch creation.
|
||||
|
||||
## Branch Issue Summary
|
||||
|
||||
| Branch Type | Issue Creation | Sub-Issues | Draft Release? |
|
||||
|-------------|---------------|------------|----------------|
|
||||
| `dev/**` | Manual (workflow_dispatch) | 7 sub-issues | No |
|
||||
| `alpha/**` | Manual (workflow_dispatch) | 7 sub-issues | No |
|
||||
| `beta/**` | Manual (workflow_dispatch) | 7 sub-issues | No |
|
||||
| `rc/**` | Automatic (on branch creation) | 5 sub-issues | Yes |
|
||||
|
||||
**Note**: Alpha and beta branches are optional stages. Dev can go directly to rc when internal/external testing stages are not needed.
|
||||
|
||||
## System Components
|
||||
|
||||
The tracking system consists of three main components:
|
||||
|
||||
### 1. Dev Branch Issue Creation (Manual)
|
||||
|
||||
**Trigger**: Manual `workflow_dispatch` only
|
||||
|
||||
**Purpose**: Creates a tracking issue + 7 sub-issues for a dev branch when manually triggered.
|
||||
|
||||
**Why manual?** Dev branches are exploratory and may be short-lived. Not every dev branch needs full tracking overhead.
|
||||
|
||||
**Actions**:
|
||||
1. Creates tracking issue with branch details and version info
|
||||
2. Creates 7 sub-issues:
|
||||
- Feature development
|
||||
- Unit testing
|
||||
- Integration testing
|
||||
- Code review
|
||||
- Documentation updates
|
||||
- Changelog updates
|
||||
- Version management
|
||||
3. Assigns issues to `copilot` and `jmiller-moko`
|
||||
4. Adds labels: `automation`, `version-management`, `dev-branch`
|
||||
|
||||
### 2. RC Branch Issue Creation (Automatic)
|
||||
|
||||
**Trigger**: Automatic on `rc/**` branch creation
|
||||
|
||||
**Purpose**: Auto-creates a tracking issue + 5 sub-issues + draft GitHub Release when an RC branch is pushed.
|
||||
|
||||
**Actions**:
|
||||
1. Creates tracking issue with RC branch details and version
|
||||
2. Creates 5 sub-issues:
|
||||
- Comprehensive testing (functional, integration, performance)
|
||||
- Bug fixes and regression testing
|
||||
- Documentation and changelog finalization
|
||||
- Release notes preparation
|
||||
- Final verification and sign-off
|
||||
3. Creates a **draft GitHub Release** for the major version (`vXX`)
|
||||
4. Assigns issues to `copilot` and `jmiller-moko`
|
||||
5. Adds labels: `automation`, `version-management`, `rc-branch`
|
||||
|
||||
The draft release is later published by `auto-release.yml` when the RC merges to main.
|
||||
|
||||
### 2. Enterprise Issue Manager Workflow
|
||||
|
||||
**File**: `.github/workflows/enterprise-issue-manager.yml`
|
||||
|
||||
**Purpose**: Coordinates pull requests with dev branch tracking issues throughout the PR lifecycle.
|
||||
|
||||
**Triggers**:
|
||||
- Pull request events: `opened`, `closed`, `reopened`, `ready_for_review`
|
||||
- Branch deletion events
|
||||
- Manual workflow dispatch
|
||||
|
||||
**Actions for PRs**:
|
||||
|
||||
**When PR Opens** (targeting dev/rc branch):
|
||||
1. Finds the tracking issue for the base branch
|
||||
2. Adds PR as checklist item in the "📝 Pull Requests" section
|
||||
3. Comments on the tracking issue with PR details
|
||||
|
||||
**When PR Merges** (to dev/rc branch):
|
||||
1. Updates checklist item from `[ ]` to `[x]` in tracking issue
|
||||
2. Comments on tracking issue confirming merge
|
||||
|
||||
**When PR Merges to Main**:
|
||||
1. Closes the tracking issue for the merged branch
|
||||
2. Adds comprehensive closing comment with merge details
|
||||
|
||||
**When Branch Deleted**:
|
||||
1. Finds and closes the tracking issue
|
||||
2. Adds comment explaining branch deletion
|
||||
|
||||
### 3. Dev Branch Tracking Issue Template
|
||||
|
||||
**File**: `.github/ISSUE_TEMPLATE/dev-branch-tracking.md`
|
||||
|
||||
**Purpose**: Manual creation of tracking issues for dev branches not created by the workflow.
|
||||
|
||||
**Use Cases**:
|
||||
- Manually created dev branches
|
||||
- Retroactively adding tracking for existing branches
|
||||
- Custom branch naming outside standard pattern
|
||||
|
||||
**Contents**:
|
||||
- Placeholder fields for branch name and version
|
||||
- Complete 10-section launch checklist
|
||||
- PR tracking section
|
||||
- Labels and assignees pre-configured
|
||||
|
||||
## Sub-Issue Checklists
|
||||
|
||||
### Dev Branch Sub-Issues (7)
|
||||
|
||||
When manually triggered via workflow_dispatch, the following sub-issues are created:
|
||||
|
||||
1. **Feature Development** — implement planned features for this version
|
||||
2. **Unit Testing** — write and pass unit tests for new code
|
||||
3. **Integration Testing** — verify integration with other components
|
||||
4. **Code Review** — address all review comments, re-review significant changes
|
||||
5. **Documentation Updates** — update README, user guides, examples
|
||||
6. **Changelog Updates** — document all changes grouped by type (Added, Changed, Fixed, etc.)
|
||||
7. **Version Management** — ensure version consistency across all files, update headers
|
||||
|
||||
### RC Branch Sub-Issues (5)
|
||||
|
||||
Automatically created when an `rc/**` branch is pushed:
|
||||
|
||||
1. **Comprehensive Testing** — functional, integration, and performance testing
|
||||
2. **Bug Fixes and Regression** — fix issues found in testing, verify no regressions
|
||||
3. **Documentation and Changelog** — finalize docs and CHANGELOG.md
|
||||
4. **Release Notes Preparation** — draft release notes, document breaking changes, migration guide
|
||||
5. **Final Verification and Sign-off** — all PRs merged, no blocking issues, ready for main
|
||||
|
||||
## Workflow Sequence
|
||||
|
||||
### Dev Branch Lifecycle (Manual Trigger)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as Developer
|
||||
participant GH as GitHub Actions
|
||||
participant Issue as Tracking Issue
|
||||
participant EIM as Enterprise Issue Manager
|
||||
participant DevBranch as dev/XX.YY
|
||||
|
||||
Dev->>DevBranch: Create dev branch manually
|
||||
Dev->>GH: Run workflow_dispatch
|
||||
GH->>Issue: Create tracking issue + 7 sub-issues
|
||||
|
||||
Dev->>DevBranch: Open PR #123
|
||||
DevBranch->>EIM: Trigger on PR opened
|
||||
EIM->>Issue: Add PR #123 to checklist
|
||||
|
||||
Dev->>DevBranch: Merge PR #123
|
||||
DevBranch->>EIM: Trigger on PR closed
|
||||
EIM->>Issue: Mark PR #123 as [x]
|
||||
```
|
||||
|
||||
### RC Branch Lifecycle (Automatic)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as Developer
|
||||
participant RCBranch as rc/XX.YY.ZZ
|
||||
participant GH as GitHub Actions
|
||||
participant Issue as Tracking Issue
|
||||
participant Release as Draft Release
|
||||
participant Main as main
|
||||
|
||||
Dev->>RCBranch: Push rc/XX.YY.ZZ branch
|
||||
RCBranch->>GH: Auto-trigger on branch creation
|
||||
GH->>Issue: Create tracking issue + 5 sub-issues
|
||||
GH->>Release: Create draft GitHub Release (vXX)
|
||||
|
||||
Dev->>RCBranch: Test and fix bugs
|
||||
Dev->>Main: Merge RC to main via PR
|
||||
Main->>GH: auto-release.yml publishes draft release
|
||||
GH->>Issue: Close tracking issue
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Automatic Workflow
|
||||
|
||||
No action required. When a PR is merged to main:
|
||||
|
||||
```bash
|
||||
# Developer merges PR to main via GitHub UI
|
||||
# Workflow automatically:
|
||||
# 1. Creates dev/04.01 branch
|
||||
# 2. Creates tracking issue #456
|
||||
# 3. Assigns to copilot and jmiller-moko
|
||||
```
|
||||
|
||||
### Manual Issue Creation
|
||||
|
||||
For manually created dev branches:
|
||||
|
||||
1. Navigate to repository Issues
|
||||
2. Click "New Issue"
|
||||
3. Select "Dev Branch Tracking" template
|
||||
4. Fill in the placeholders:
|
||||
- Replace `XX.YY.ZZ` with actual version
|
||||
- Update branch name in details
|
||||
- Add creation date
|
||||
5. Submit issue
|
||||
|
||||
### Working with Tracking Issues
|
||||
|
||||
**As a Developer:**
|
||||
|
||||
```bash
|
||||
# 1. Check out the dev branch
|
||||
git fetch origin
|
||||
git checkout dev/04.01
|
||||
|
||||
# 2. Find the tracking issue (labeled 'dev-branch')
|
||||
# 3. Create PR targeting the dev branch
|
||||
gh pr create --base dev/04.01 --title "Add feature X"
|
||||
|
||||
# 4. PR automatically added to tracking issue
|
||||
# 5. When ready to merge to main, complete checklist in tracking issue
|
||||
# 6. Create final PR to main
|
||||
gh pr create --base main --head dev/04.01 --title "Release 04.00.04"
|
||||
```
|
||||
|
||||
**As a Reviewer:**
|
||||
|
||||
1. Review PR targeting dev branch
|
||||
2. Check tracking issue for context
|
||||
3. Verify checklist items as they're completed
|
||||
4. Before approving final PR to main, verify all checklist items are complete
|
||||
|
||||
## Integration with Other Workflows
|
||||
|
||||
### Pre-Merge Checklist Policy
|
||||
|
||||
The launch checklist aligns with the [Copilot Pre-Merge Checklist Policy](../policy/copilot-pre-merge-checklist.md):
|
||||
|
||||
- Same 8 core sections
|
||||
- Additional 2 sections specific to branch merges
|
||||
- Reference link included in every tracking issue
|
||||
|
||||
### Standards Compliance Workflow
|
||||
|
||||
The "Standards Compliance" checklist section integrates with:
|
||||
- `.github/workflows/standards-compliance.yml`
|
||||
- File header validation
|
||||
- Formatting standards checks
|
||||
|
||||
### Security Workflows
|
||||
|
||||
The "Security Scanning" checklist section integrates with:
|
||||
- CodeQL security analysis
|
||||
- Dependency review workflow
|
||||
- Secret scanning
|
||||
|
||||
## Configuration
|
||||
|
||||
### Assignees
|
||||
|
||||
Default assignees for tracking issues:
|
||||
- `copilot` (GitHub Copilot agent)
|
||||
- `jmiller-moko` (organization owner — GitHub assignees must be a user account, not an org)
|
||||
|
||||
To change assignees:
|
||||
- **Auto-created issues**: Edit `.github/workflows/auto-create-dev-branch.yml` line 289
|
||||
- **Manual template**: Edit `.github/ISSUE_TEMPLATE/dev-branch-tracking.md` line 6
|
||||
|
||||
### Labels
|
||||
|
||||
Default labels for tracking issues:
|
||||
- `automation` - Automated process
|
||||
- `version-management` - Version tracking
|
||||
- `dev-branch` - Development branch marker
|
||||
|
||||
To change labels:
|
||||
- **Auto-created issues**: Edit `.github/workflows/auto-create-dev-branch.yml` line 288
|
||||
- **Manual template**: Edit `.github/ISSUE_TEMPLATE/dev-branch-tracking.md` line 5
|
||||
|
||||
### Branch Patterns
|
||||
|
||||
The system tracks branches matching:
|
||||
- `dev/*` - Development branches
|
||||
- `alpha/*` - Alpha testing branches (optional stage)
|
||||
- `beta/*` - Beta testing branches (optional stage)
|
||||
- `rc/*` - Release candidate branches
|
||||
|
||||
To modify patterns, edit `.github/workflows/enterprise-issue-manager.yml` line 143.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Tracking Issue Not Found
|
||||
|
||||
**Symptom**: PR opened but not linked to tracking issue
|
||||
|
||||
**Causes**:
|
||||
1. Branch name doesn't match pattern (`dev/*`, `alpha/*`, `beta/*`, or `rc/*`)
|
||||
2. Tracking issue doesn't exist
|
||||
3. Tracking issue missing `dev-branch` label
|
||||
|
||||
**Solution**:
|
||||
1. Verify branch name starts with `dev/`, `alpha/`, `beta/`, or `rc/`
|
||||
2. Check if tracking issue exists with label `dev-branch`
|
||||
3. Manually create issue using template if needed
|
||||
|
||||
### PR Not Added to Tracking Issue
|
||||
|
||||
**Symptom**: PR opened but not appearing in tracking issue
|
||||
|
||||
**Causes**:
|
||||
1. Tracking issue has non-standard format
|
||||
2. Missing "📝 Pull Requests" section
|
||||
3. Workflow error (check Actions tab)
|
||||
|
||||
**Solution**:
|
||||
1. Check workflow run in Actions tab for errors
|
||||
2. Manually add PR to tracking issue: `- [ ] #123 - PR Title (@author)`
|
||||
3. Ensure tracking issue has "📝 Pull Requests" section
|
||||
|
||||
### Tracking Issue Not Closing
|
||||
|
||||
**Symptom**: Dev branch merged to main but issue still open
|
||||
|
||||
**Causes**:
|
||||
1. Branch name mismatch in issue body
|
||||
2. Workflow not triggered on merge
|
||||
3. Issue manually closed earlier
|
||||
|
||||
**Solution**:
|
||||
1. Verify issue body contains correct branch name in backticks
|
||||
2. Check Actions tab for workflow run on merge
|
||||
3. Manually close issue if workflow didn't run
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Maintainers
|
||||
|
||||
1. **Monitor tracking issues** - Review open dev-branch issues regularly
|
||||
2. **Complete checklists** - Don't skip checklist items before merging to main
|
||||
3. **Update assignees** - Add relevant team members to tracking issues
|
||||
4. **Link related issues** - Reference related issues in tracking issue comments
|
||||
|
||||
### For Contributors
|
||||
|
||||
1. **Check tracking issue** - Review before creating PR to dev branch
|
||||
2. **Follow checklist** - Use checklist as guide for PR requirements
|
||||
3. **Update status** - Comment on tracking issue with progress updates
|
||||
4. **Test thoroughly** - Verify all checklist items apply to your changes
|
||||
|
||||
### For CI/CD
|
||||
|
||||
1. **Status checks** - Reference tracking issue in PR descriptions
|
||||
2. **Automated tests** - Run tests mentioned in checklist automatically
|
||||
3. **Quality gates** - Block merge if checklist items incomplete
|
||||
4. **Documentation** - Auto-generate release notes from tracking issues
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Copilot Pre-Merge Checklist Policy](../policy/copilot-pre-merge-checklist.md)
|
||||
- [Auto-Create Dev Branch Workflow](../../.github/workflows/auto-create-dev-branch.yml)
|
||||
- [Enterprise Issue Manager Workflow](../../.github/workflows/enterprise-issue-manager.yml)
|
||||
- [Dev Branch Tracking Template](../../.github/ISSUE_TEMPLATE/dev-branch-tracking.md)
|
||||
- [Workflow Architecture](./workflow-architecture.md)
|
||||
- [Contributing Guide](../../CONTRIBUTING.md)
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 02.00.00 | 2026-04-07 | Rewrite: dev branches use manual workflow_dispatch, RC branches auto-create issues + draft release. Updated sub-issue counts (7 for dev, 5 for RC) |
|
||||
| 01.00.00 | 2026-02-06 | Initial documentation of dev branch tracking system |
|
||||
@@ -0,0 +1,280 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/dev-deployment.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for the SFTP development server deployment workflow
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Development Server Deployment
|
||||
|
||||
Automated SFTP deployment of the `src/` directory to the development server.
|
||||
|
||||
## Overview
|
||||
|
||||
The `deploy-dev.yml` workflow pushes the contents of `src/` to a development server over **SFTP only** when:
|
||||
|
||||
- A commit is pushed to `dev/**`, `alpha/**`, `beta/**`, `rc/**`, `develop`, or `development` branches (and `src/**` changed)
|
||||
- A pull request targeting those branches is **merged** (skips `chore/` branches)
|
||||
- Triggered manually via workflow dispatch
|
||||
|
||||
**Access control:** `jmiller-moko` and `github-actions[bot]` are always authorized. Other actors need **admin** or **maintain** role.
|
||||
|
||||
**Skips when:** `DEV_FTP_SUFFIX` variable is not set, or the branch starts with `chore/`.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Organization Variables (required)
|
||||
|
||||
Configure at the **organization** level in **Settings → Secrets and variables → Actions → Variables**:
|
||||
|
||||
| Variable | Example | Description |
|
||||
|----------|---------|-------------|
|
||||
| `DEV_FTP_HOST` | `dev.example.com` | Dev server hostname. May include an explicit port suffix — `dev.example.com:2222`. |
|
||||
| `DEV_FTP_PATH` | `/var/www/html` | Base remote path where files are deployed. |
|
||||
| `DEV_FTP_USERNAME` | `deployuser` | SFTP username for authentication. |
|
||||
|
||||
### Organization Variable (optional)
|
||||
|
||||
| Variable | Example | Description |
|
||||
|----------|---------|-------------|
|
||||
| `DEV_FTP_PORT` | `2222` | Explicit port override. See **Port resolution** below. |
|
||||
|
||||
### Repository Variable (optional)
|
||||
|
||||
| Variable | Example | Description |
|
||||
|----------|---------|-------------|
|
||||
| `DEV_FTP_SUFFIX` | `my-module` | Appended to `DEV_FTP_PATH` to form the final deploy path: `DEV_FTP_PATH/DEV_FTP_SUFFIX`. Useful for deploying multiple repos to the same server. |
|
||||
|
||||
### Organization Secrets (credentials)
|
||||
|
||||
At least one of the following must be set:
|
||||
|
||||
| Secret | Description |
|
||||
|--------|-------------|
|
||||
| `DEV_FTP_KEY` | **Preferred.** SSH private key (any format supported by OpenSSH). |
|
||||
| `DEV_FTP_PASSWORD` | SFTP password. Also used as the key passphrase when set alongside `DEV_FTP_KEY`. |
|
||||
|
||||
---
|
||||
|
||||
## Authentication logic
|
||||
|
||||
The workflow determines the connection method at runtime:
|
||||
|
||||
| Secrets present | Behaviour |
|
||||
|-----------------|-----------|
|
||||
| `DEV_FTP_KEY` + `DEV_FTP_PASSWORD` | Key auth with `DEV_FTP_PASSWORD` as the key passphrase. If key auth fails, retries with `DEV_FTP_PASSWORD` alone as an SFTP password. |
|
||||
| `DEV_FTP_KEY` only | Key auth (no passphrase). Fails hard on auth error — no password fallback. |
|
||||
| `DEV_FTP_PASSWORD` only | Password auth directly. |
|
||||
| Neither | Workflow fails with an error message. |
|
||||
|
||||
---
|
||||
|
||||
## Port resolution
|
||||
|
||||
The SFTP port is determined in the following order — the first match wins:
|
||||
|
||||
1. **`DEV_FTP_PORT` variable** — explicit override, highest priority.
|
||||
2. **Port suffix in `DEV_FTP_HOST`** — if the host value contains `:`, the suffix is extracted and the bare hostname is used (e.g. `dev.example.com:2222` → host `dev.example.com`, port `2222`).
|
||||
3. **Default** — port **22** is assumed when neither of the above is present.
|
||||
|
||||
---
|
||||
|
||||
## Remote path
|
||||
|
||||
The final remote path is constructed as:
|
||||
|
||||
```
|
||||
DEV_FTP_PATH/DEV_FTP_SUFFIX
|
||||
```
|
||||
|
||||
`DEV_FTP_SUFFIX` is optional. When set, exactly one `/` is inserted between the base path and the value regardless of trailing/leading slashes in the values.
|
||||
|
||||
---
|
||||
|
||||
## Manual dispatch
|
||||
|
||||
1. Go to **Actions → Deploy to Dev Server (SFTP)**.
|
||||
2. Click **Run workflow**.
|
||||
3. Optionally override the source directory (default: `src`) or enable **Dry run** to list files without uploading.
|
||||
|
||||
---
|
||||
|
||||
## Repository health checks
|
||||
|
||||
The `check_repo_health.php` script scores deployment readiness as part of the overall health report. When `--repo owner/repo` is supplied, it also calls the GitHub API to verify secrets and variables are configured.
|
||||
|
||||
### Deployment category checks
|
||||
|
||||
| Check | Points | Requires `--repo` |
|
||||
|-------|--------|------------------|
|
||||
| `deploy-dev.yml` workflow exists | 5 | No |
|
||||
| `DEV_FTP_HOST` variable configured | 3 | Yes |
|
||||
| `DEV_FTP_PATH` variable configured | 3 | Yes |
|
||||
| `DEV_FTP_USERNAME` variable configured | 2 | Yes |
|
||||
| SFTP credentials configured (`DEV_FTP_KEY` or `DEV_FTP_PASSWORD`) | 2 | Yes |
|
||||
|
||||
Variables and secrets are checked at both the **org level** and **repo level** — a check passes if the item exists at either scope.
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1 — SSH key with passphrase, custom port
|
||||
|
||||
**Org variables:**
|
||||
```
|
||||
DEV_FTP_HOST = dev.example.com
|
||||
DEV_FTP_PORT = 2222
|
||||
DEV_FTP_PATH = /var/www/html
|
||||
DEV_FTP_USERNAME = deployuser
|
||||
```
|
||||
|
||||
**Org secrets:**
|
||||
```
|
||||
DEV_FTP_KEY = <passphrase-protected SSH private key>
|
||||
DEV_FTP_PASSWORD = mysecretphrase
|
||||
```
|
||||
|
||||
**Behaviour:** Key loaded with `mysecretphrase` as passphrase. If key auth fails, retries with `mysecretphrase` as the SFTP password.
|
||||
|
||||
---
|
||||
|
||||
### Example 2 — SSH key, port embedded in host
|
||||
|
||||
**Org variables:**
|
||||
```
|
||||
DEV_FTP_HOST = dev.example.com:2222
|
||||
DEV_FTP_PATH = /var/www/html
|
||||
DEV_FTP_USERNAME = deployuser
|
||||
```
|
||||
|
||||
**Org secret:**
|
||||
```
|
||||
DEV_FTP_KEY = <unprotected SSH private key>
|
||||
```
|
||||
|
||||
**Behaviour:** Port `2222` extracted from host. Key used without passphrase; no password fallback.
|
||||
|
||||
---
|
||||
|
||||
### Example 3 — Password only, default port
|
||||
|
||||
**Org variables:**
|
||||
```
|
||||
DEV_FTP_HOST = dev.example.com
|
||||
DEV_FTP_PATH = /var/www/html
|
||||
DEV_FTP_USERNAME = deployuser
|
||||
```
|
||||
|
||||
**Org secret:**
|
||||
```
|
||||
DEV_FTP_PASSWORD = secretpass
|
||||
```
|
||||
|
||||
**Behaviour:** Port defaults to 22. Connects with password directly.
|
||||
|
||||
---
|
||||
|
||||
### Example 4 — Multiple repos, same server
|
||||
|
||||
Each repo sets its own `DEV_FTP_SUFFIX`:
|
||||
|
||||
| Repo | Suffix | Deploys to |
|
||||
|------|--------|------------|
|
||||
| `project-a` | `/project-a` | `/var/www/html/project-a` |
|
||||
| `project-b` | `/project-b` | `/var/www/html/project-b` |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Permission denied
|
||||
|
||||
```
|
||||
❌ Deployment requires admin or maintain role.
|
||||
```
|
||||
|
||||
Only org/repo administrators and maintainers may deploy. Contact your org administrator.
|
||||
|
||||
### No credentials configured
|
||||
|
||||
```
|
||||
❌ No SFTP credentials configured.
|
||||
Set DEV_FTP_KEY (preferred) or DEV_FTP_PASSWORD as an org-level secret.
|
||||
```
|
||||
|
||||
Set at least one of `DEV_FTP_KEY` or `DEV_FTP_PASSWORD` in **Org Settings → Secrets**.
|
||||
|
||||
### Key authentication failed, no fallback
|
||||
|
||||
```
|
||||
RuntimeError: Key authentication failed and no password fallback is available: ...
|
||||
```
|
||||
|
||||
The SSH private key was rejected and `DEV_FTP_PASSWORD` is not set. Check the key is correct and authorized on the server, or add `DEV_FTP_PASSWORD` as a fallback.
|
||||
|
||||
### Missing source directory
|
||||
|
||||
```
|
||||
⚠️ Source directory 'src' not found — skipping deployment
|
||||
```
|
||||
|
||||
Expected behaviour for repos without a `src/` directory. No files are uploaded; the workflow exits successfully.
|
||||
|
||||
### Connection refused
|
||||
|
||||
```
|
||||
[Errno 111] Connection refused
|
||||
```
|
||||
|
||||
- Verify `DEV_FTP_HOST` is correct.
|
||||
- Check the resolved port (shown in the **Resolve SFTP host and port** step log).
|
||||
- Confirm the server firewall allows inbound SFTP on that port.
|
||||
|
||||
---
|
||||
|
||||
## Related documentation
|
||||
|
||||
- [Workflow inventory](./workflow-inventory.md)
|
||||
- [Bulk repository sync](./bulk-repo-sync.md)
|
||||
- [MokoStandards repo-sync guide](../guide/repo-sync.md)
|
||||
- [Workflow template source](../../templates/workflows/shared/deploy-dev.yml.template)
|
||||
|
||||
---
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|---------------|-------------------------------------------------------------|
|
||||
| Document Type | Guide |
|
||||
| Domain | Operations |
|
||||
| Applies To | All Repositories |
|
||||
| Jurisdiction | Tennessee, USA |
|
||||
| Owner | Moko Consulting |
|
||||
| Repo | https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards |
|
||||
| Path | /docs/workflows/dev-deployment.md |
|
||||
| Version | 04.06.00 |
|
||||
| Status | Active |
|
||||
| Last Reviewed | 2026-04-07 |
|
||||
| Reviewed By | Documentation Team |
|
||||
|
||||
## Revision History
|
||||
|
||||
| Date | Author | Change |
|
||||
|------------|-----------------|----------------------------------------------------------------------|
|
||||
| 2026-03-12 | Moko Consulting | Rewrote for SFTP-only workflow; added auth fallback, port resolution, health check docs |
|
||||
| 2026-01-28 | Moko Consulting | Standardized metadata and revision history |
|
||||
| 2026-01-17 | Moko Consulting | Initial dev deployment workflow documentation |
|
||||
@@ -0,0 +1,71 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Docs Index: /docs/workflows
|
||||
|
||||
## Purpose
|
||||
|
||||
Documentation for all GitHub Actions workflows used across governed repositories.
|
||||
|
||||
## Deployment Workflows
|
||||
|
||||
### Dolibarr + Generic (automatic FTP deploy)
|
||||
|
||||
- [Dev Deployment](./dev-deployment.md) — deploy to dev FTP on push to `dev/**`, `alpha/**`, `beta/**`, or `rc/**`
|
||||
- [Demo Deployment](./demo-deployment.md) — deploy to demo FTP on push to `main`
|
||||
|
||||
> **Note:** `deploy-rs.yml` is **retired**. RS deployment is handled via the release pipeline only. See [RS Deployment (deprecated)](./rs-deployment.md).
|
||||
|
||||
### Joomla (no automatic FTP deploy)
|
||||
|
||||
Joomla repos use GitHub Release ZIPs via `auto-release.yml` + `updates.xml`. No automatic FTP deploy.
|
||||
|
||||
- [Deploy Manual](./deploy-manual.md) — manual workflow_dispatch FTP deploy for Joomla dev testing
|
||||
|
||||
## Release & Version Workflows
|
||||
|
||||
- [Auto Release](./auto-release.md) — platform-specific GitHub Release on push to main (generic, Joomla, Dolibarr)
|
||||
- [Build Release](./build-release.md) — build release artifacts
|
||||
- [Release System](./release-system.md) — end-to-end release lifecycle (dev → rc → main)
|
||||
- [Changelog Management](./changelog-management.md) — automated changelog generation
|
||||
- [Changelog Validation](./changelog-validation.md) — validates CHANGELOG.md format on PR
|
||||
|
||||
## CI & Compliance Workflows
|
||||
|
||||
- [CI Joomla](./ci-joomla.md) — Joomla-specific CI checks (manifest validation, language files, XML lint)
|
||||
- [CI Dolibarr](./ci-dolibarr.md) — Dolibarr-specific CI checks (module descriptor, PHP lint)
|
||||
- [Standards Compliance](./standards-compliance.md) — enterprise standards validation
|
||||
- [Repo Health](./repo-health.md) — platform-aware repository health checks
|
||||
- [Shared Workflows](./shared-workflows.md) — reusable workflow templates
|
||||
- [Reusable Workflows](./reusable-workflows.md) — reusable workflow reference
|
||||
- [Workflow Architecture](./workflow-architecture.md) — design and architecture
|
||||
- [Workflow Inventory](./workflow-inventory.md) — complete inventory of all workflows
|
||||
|
||||
## Branch & Issue Management
|
||||
|
||||
- [Dev Branch Tracking](./dev-branch-tracking.md) — manual issue creation for dev branches, auto-creation for rc branches
|
||||
- [Sub-Issue Management](./sub-issue-management.md) — hierarchical issue tracking
|
||||
|
||||
## Update Server
|
||||
|
||||
- [Update Server](./update-server.md) — multi-entry Joomla updates.xml with stability filtering
|
||||
- [Reserve Dolibarr Module ID](./reserve-dolibarr-module-id.md) — module ID reservation
|
||||
|
||||
## Platform Workflow Matrix
|
||||
|
||||
| Workflow | Joomla | Dolibarr | Generic |
|
||||
|----------|--------|----------|---------|
|
||||
| `auto-release.yml` | Yes (ZIP + SHA-256 + updates.xml) | Yes (update.txt) | Yes |
|
||||
| `deploy-dev.yml` | No | Yes | Yes |
|
||||
| `deploy-demo.yml` | No | Yes | Yes |
|
||||
| `deploy-manual.yml` | Yes | No | No |
|
||||
| `update-server.yml` | Yes | No | No |
|
||||
| `ci-joomla.yml` | Yes | No | No |
|
||||
| `ci-dolibarr.yml` | No | Yes | No |
|
||||
| `repo_health.yml` | Yes | Yes | Yes |
|
||||
| `changelog-validation.yml` | Yes | Yes | Yes |
|
||||
|
||||
## Metadata
|
||||
|
||||
- **Document Type:** index
|
||||
- **Last Updated:** 2026-04-07
|
||||
- **Version:** 04.06.00
|
||||
@@ -0,0 +1,211 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/release-system.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Documentation for the unified release system
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Release System
|
||||
|
||||
## Overview
|
||||
|
||||
The MokoStandards release system uses a branch-based pipeline with platform-specific packaging. Releases flow through development, optional alpha/beta testing, release candidate, and production stages with automated GitHub Release creation, version archiving, and platform-aware asset publishing.
|
||||
|
||||
## Release Lifecycle
|
||||
|
||||
### Version Numbering
|
||||
|
||||
All version files use three-part format: `XX.YY.ZZ`
|
||||
|
||||
- **Patch 00** (`XX.YY.00`) = development only, no release created
|
||||
- **Patch 01** (`XX.YY.01`) = first release for a minor version
|
||||
- **Patch 02+** = subsequent releases (bug fixes, improvements)
|
||||
|
||||
### Branch Flow
|
||||
|
||||
```
|
||||
dev → [alpha] → [beta] → rc → version/XX → main → dev
|
||||
optional (integration) (production) (feedback)
|
||||
```
|
||||
|
||||
1. **`dev/XX.YY`** or **`dev/feature-name`** — Active development. Patch is 00. No release.
|
||||
2. **`alpha/XX.YY.ZZ`** — *(Optional)* Early internal testing. Can be skipped — dev can go straight to rc.
|
||||
3. **`beta/XX.YY.ZZ`** — *(Optional)* Broader external testing. Can be skipped — dev can go straight to rc.
|
||||
4. **`rc/XX.YY.ZZ`** — Release candidate. Three-part version required (patch >= 01). Auto-creates tracking issue + draft GitHub Release.
|
||||
5. **`version/XX`** — Major version integration branch (major number only, e.g., `version/04`). All minors and patches flow into the same major branch.
|
||||
6. **`main`** — Production. Push triggers `auto-release.yml` which publishes the GitHub Release, creates/updates the major tag, and auto-bumps patch.
|
||||
7. **`main` merges back to `dev`** — Completes the cycle. Ensures dev has the latest production state.
|
||||
|
||||
### Release Tags
|
||||
|
||||
Each stability level has its own GitHub Release tag:
|
||||
|
||||
| Tag | Stability | Contents |
|
||||
|-----|-----------|----------|
|
||||
| `development` | Development | Dev ZIPs |
|
||||
| `alpha` | Alpha | Alpha ZIPs |
|
||||
| `beta` | Beta | Beta ZIPs |
|
||||
| `release-candidate` | RC | RC ZIPs |
|
||||
| `vXX` | Stable production | Stable ZIPs (major only, e.g., `v04`) |
|
||||
|
||||
- The `vXX` production tag is **major only** — one release per major version
|
||||
- All minor+patch versions **append** release notes and ZIP assets to the same `vXX` release
|
||||
- No minor or patch production tags are created
|
||||
- Example: versions `04.01.01`, `04.02.00`, `04.03.05` all update the same `v04` release
|
||||
- Pre-release tags (`development`, `alpha`, `beta`, `release-candidate`) are updated in-place
|
||||
|
||||
### Standard Release Process
|
||||
|
||||
1. **Start development**: Create `dev/XX.YY` branch from main
|
||||
2. **Develop**: Work on the dev branch with version set to `XX.YY.00`
|
||||
3. **Alpha testing** *(optional)*: Create `alpha/XX.YY.ZZ` branch from dev for early internal testing. Can be skipped.
|
||||
4. **Beta testing** *(optional)*: Create `beta/XX.YY.ZZ` branch from alpha (or dev) for broader external testing. Can be skipped.
|
||||
5. **Create RC**: Create `rc/XX.YY.01` branch from beta, alpha, or dev. This auto-creates a tracking issue with 5 sub-issues and a draft GitHub Release
|
||||
6. **Test RC**: Fix bugs on the RC branch. Deploy to dev server for final testing
|
||||
7. **Merge to version/XX**: Merge RC to the `version/XX` major integration branch
|
||||
8. **Merge to main**: Merge `version/XX` to main via PR. `auto-release.yml` fires:
|
||||
- Publishes the draft release (or creates new one)
|
||||
- Uploads platform-specific assets (ZIP for Joomla, etc.)
|
||||
- Creates/updates the `vXX` tag
|
||||
- Auto-bumps patch version with `[skip ci]` commit
|
||||
9. **Feedback loop**: Main merges back to dev to start the next cycle
|
||||
|
||||
## Platform-Specific Pipelines
|
||||
|
||||
### Generic Repos
|
||||
|
||||
- `auto-release.yml`: Creates GitHub Release with changelog notes, `vXX` tag
|
||||
- `deploy-dev.yml`: FTP deploy on push to `dev/**`, `alpha/**`, `beta/**`, or `rc/**`
|
||||
- `deploy-demo.yml`: FTP deploy on push to `main`
|
||||
- `changelog-validation.yml`: Validates CHANGELOG.md format on PRs
|
||||
|
||||
### Joomla Repos (waas-component)
|
||||
|
||||
Joomla repos do **not** use automatic FTP deploy workflows. Distribution is via `updates.xml` + GitHub Release ZIPs + manual dev deploy.
|
||||
|
||||
- `auto-release.yml`: Builds ZIP from `src/`, uploads to major release, writes SHA-256 in `updates.xml`
|
||||
- `update-server.yml`: Writes dev/alpha/beta/rc entries to `updates.xml` on branch push
|
||||
- `deploy-manual.yml`: Manual workflow_dispatch FTP deploy for dev testing (no automatic deploy)
|
||||
- `ci-joomla.yml`: Manifest validation, language file checks, XML lint
|
||||
- `repo_health.yml`: Platform-aware health checks
|
||||
- `changelog-validation.yml`: Validates CHANGELOG.md format on PRs
|
||||
|
||||
### Dolibarr Repos (crm-module, crm-platform)
|
||||
|
||||
- `auto-release.yml`: Creates GitHub Release, updates `update.txt` and module descriptor version
|
||||
- `deploy-dev.yml` / `deploy-demo.yml`: FTP deploy
|
||||
- `publish-to-mokodolimods.yml`: Publishes to MokoDolimods marketplace (crm-module only)
|
||||
- `ci-dolibarr.yml`: Module descriptor validation, PHP lint
|
||||
- `repo_health.yml`: Platform-aware health checks
|
||||
- `changelog-validation.yml`: Validates CHANGELOG.md format on PRs
|
||||
|
||||
## Version Format Summary
|
||||
|
||||
| Context | Format | Example |
|
||||
|---------|--------|---------|
|
||||
| Version files | `XX.YY.ZZ` (three-part always) | `04.06.00` |
|
||||
| Dev branches | `XX.YY` or `XX.YY.ZZ` or `feature-name` | `dev/04.06`, `dev/sidebar-fix` |
|
||||
| Alpha branches | `XX.YY.ZZ` (three-part, optional stage) | `alpha/04.06.01` |
|
||||
| Beta branches | `XX.YY.ZZ` (three-part, optional stage) | `beta/04.06.01` |
|
||||
| RC branches | `XX.YY.ZZ` (three-part required) | `rc/04.06.01` |
|
||||
| Version branches | `XX` (major only) | `version/04` |
|
||||
| Release tags (stable) | `vXX` (major only) | `v04` |
|
||||
| Release tags (pre) | Named per stability level | `development`, `alpha`, `beta`, `release-candidate` |
|
||||
|
||||
## Version Detection
|
||||
|
||||
The `auto-release.yml` workflow reads the version from the `VERSION:` field in the README.md FILE INFORMATION block. This is the single source of truth for the release version.
|
||||
|
||||
## Skipping Releases
|
||||
|
||||
To prevent automatic release creation, include `[skip ci]` in your commit message:
|
||||
|
||||
```bash
|
||||
git commit -m "docs: update README [skip ci]"
|
||||
```
|
||||
|
||||
Commits by `github-actions[bot]` are also skipped automatically (e.g., auto-bump commits).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Full Release Cycle
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ dev → [alpha] → [beta] → rc → version/XX → main │
|
||||
│ optional optional │ │
|
||||
│ └──→ dev│
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Auto-Release Pipeline (on push to main)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Push to main branch │
|
||||
│ (version in README.md FILE INFORMATION) │
|
||||
└────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ auto-release.yml (Detect + Route) │
|
||||
│ • Read VERSION from README.md │
|
||||
│ • Check if vXX tag exists (major-only) │
|
||||
│ • Detect platform (.mokostandards → platform field) │
|
||||
└────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
┌──────────┼──────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────────┐
|
||||
│ Generic │ │ Joomla │ │ Dolibarr │
|
||||
│ │ │ │ │ │
|
||||
│ Tag vXX │ │ Build ZIP│ │ Update │
|
||||
│ Release │ │ SHA-256 │ │ update.txt │
|
||||
│ notes │ │ update │ │ mod*.class │
|
||||
│ │ │ .xml │ │ Tag + release│
|
||||
└──────────┘ └──────────┘ └──────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ GitHub Release (one per major) │
|
||||
│ • Create or update vXX release │
|
||||
│ • Append release notes for this minor.patch │
|
||||
│ • Upload ZIP assets (Joomla) │
|
||||
│ • Auto-bump patch version ([skip ci]) │
|
||||
│ • Main merges back to dev (feedback loop) │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
- `.github/workflows/auto-release.yml` - Main release workflow (platform-aware)
|
||||
- `.github/workflows/update-server.yml` - Joomla updates.xml generation for dev/alpha/beta/rc
|
||||
- `.github/workflows/changelog-validation.yml` - CHANGELOG.md format validation
|
||||
- `.mokostandards` - Platform configuration (`platform: joomla|dolibarr|generic`)
|
||||
- `README.md` - VERSION field (single source of truth)
|
||||
- `CHANGELOG.md` - Release notes source
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Patch 00 is always dev** — never release from patch 00
|
||||
2. **RC before release** — always go through `rc/` before merging to main (alpha/beta are optional)
|
||||
3. **Alpha and beta are optional** — dev can go straight to rc when internal/external testing stages are not needed
|
||||
4. **One major release object** — all minor+patch append to the same `vXX` GitHub Release
|
||||
5. **Let auto-bump handle patch** — don't manually bump patch on main
|
||||
6. **Write clear changelog entries** before creating RC
|
||||
7. **Test RC on dev server** — RC branches deploy to dev FTP (Dolibarr/Generic) or generate dev updates.xml entries (Joomla)
|
||||
8. **Main feeds back to dev** — always merge main back to dev after a release to start the next cycle
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-04-07
|
||||
**Maintained by**: Moko Consulting Infrastructure Team
|
||||
@@ -0,0 +1,693 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Reserve Dolibarr Module ID Workflow
|
||||
|
||||
**Status**: Active | **Version**: 04.00.04 | **Effective**: 2026-02-21
|
||||
|
||||
## Overview
|
||||
|
||||
The `reserve-dolibarr-module-id.yml` workflow automates the reservation of Dolibarr module IDs from the Moko Consulting reserved range. Check the **[Module Registry](../development/crm/module-registry.md)** for the current next available ID. It simplifies the module ID reservation process by automatically updating the module registry table and creating a pull request for approval.
|
||||
|
||||
## Quick Links
|
||||
|
||||
- **[Module Registry](../development/crm/module-registry.md)** - Official Dolibarr module number registry
|
||||
- **[Run Workflow](../../.github/workflows/reserve-dolibarr-module-id.yml)** - Reserve a module ID now
|
||||
- **[Development Guide](../guide/crm/dolibarr-development-guide.md)** - CRM development guide
|
||||
- **[Development Standards](../policy/crm/development-standards.md)** - Coding standards
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Automatic URL Construction**: Repository URL automatically constructed from repo name with `mokoconsulting-tech` organization
|
||||
- **Simple Input**: Only requires repository name - all other details are automatically handled
|
||||
- **Auto-Assignment or Manual ID Selection**: Automatically assigns next available ID or accepts manual specification
|
||||
- **Conflict Detection**: Validates that the requested ID is not already in use
|
||||
- **Registry Update**: Updates the [module registry](../development/crm/module-registry.md) in MokoStandards
|
||||
- **Pull Request Creation**: Automatically creates PR with all changes
|
||||
- **Optional Remote Push**: Optionally scans the target repository for module ID references (`$this->numero`, `DOLIBARR_MODULE_ID=`), updates them, and opens a PR in that repository
|
||||
|
||||
### Workflow Location
|
||||
|
||||
**File**: `.github/workflows/reserve-dolibarr-module-id.yml`
|
||||
**Trigger**: Manual (workflow_dispatch)
|
||||
**Permissions**: `contents: write`, `pull-requests: write`
|
||||
**Repository**: [https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
## Architecture
|
||||
|
||||
### Workflow Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ WORKFLOW FLOW DIAGRAM │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
TRIGGER: Manual Workflow Dispatch
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Extract Module │
|
||||
│ Name from Repo │───┐ github.repository → ModuleName
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────┐ │
|
||||
│ Determine ID │◀──┘ Manual or Auto-assign
|
||||
│ (see registry) │
|
||||
└──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Check for │
|
||||
│ Conflicts │───┐ Scan registry table
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────┐ │
|
||||
│ Update Module │◀──┘
|
||||
│ Registry Table │
|
||||
└──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Update Override │───┐ Protect workflow file
|
||||
│ Configuration │ │
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────┐ │
|
||||
│ Create Branch │◀──┘ reserve-module-id/<id>
|
||||
│ and Commit │
|
||||
└──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Create Pull │───┐ Automated PR
|
||||
│ Request │ │
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
├─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Push to Remote │ (Optional)
|
||||
│ Repository │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
### Module ID Range
|
||||
|
||||
**Reserved Range**: 185051-185099 (Moko Consulting)
|
||||
**Assignment**: Sequential; the workflow scans the [module registry](../development/crm/module-registry.md) for all used IDs and auto-assigns the first free one.
|
||||
|
||||
Always check the **[Module Registry](../development/crm/module-registry.md#dolibarr-extensions-registry)** to see which IDs are currently available before making a reservation.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage (Auto-Assign, No Remote Push)
|
||||
|
||||
When you want to reserve the next available module ID without pushing to remote:
|
||||
|
||||
```yaml
|
||||
# Trigger: Actions → Reserve Dolibarr Module ID → Run workflow
|
||||
|
||||
Inputs:
|
||||
repo_name: "MokoDoliExample"
|
||||
module_id: (leave empty for auto-assignment)
|
||||
push_to_remote: false
|
||||
```
|
||||
|
||||
**Result**:
|
||||
- Workflow will auto-assign the next available ID (check the [registry](../development/crm/module-registry.md#dolibarr-extensions-registry) to see which ID that will be) and create PR
|
||||
- Repository URL automatically constructed as `https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliExample`
|
||||
- Module ID file NOT pushed to remote (you can create it manually later)
|
||||
|
||||
### With Remote Push
|
||||
|
||||
When you want the workflow to scan the remote repository for existing module ID references, update them, and open a PR:
|
||||
|
||||
```yaml
|
||||
Inputs:
|
||||
repo_name: "MokoDoliSign"
|
||||
module_id: 185070
|
||||
push_to_remote: true
|
||||
```
|
||||
|
||||
**Result**:
|
||||
- Workflow will validate and reserve ID 185070 (if available)
|
||||
- Repository URL automatically constructed as `https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliSign`
|
||||
- Scans PHP files for `$this->numero = <number>` and updates them to `$this->numero = 185070`
|
||||
- Scans other files for `DOLIBARR_MODULE_ID=<number>` and updates them
|
||||
- Creates `src/DOLIBARR_MODULE_ID.txt` with the reserved ID
|
||||
- Opens a PR in the remote repository with all changes
|
||||
|
||||
## Workflow Inputs
|
||||
|
||||
### Required Inputs
|
||||
|
||||
| Input | Type | Description | Example |
|
||||
|-------|------|-------------|---------|
|
||||
| `repo_name` | string | Repository name (org automatically set to mokoconsulting-tech) | "MokoDoliExample" |
|
||||
|
||||
**Note**: The repository URL is automatically constructed as `https://git.mokoconsulting.tech/mokoconsulting-tech/{repo_name}`.
|
||||
|
||||
### Optional Inputs
|
||||
|
||||
| Input | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `module_id` | number | (auto-assign) | Specific module ID to assign (185064-185099) |
|
||||
| `push_to_remote` | boolean | false | Scan remote repository for module ID references, update them, and open a PR with the new ID |
|
||||
|
||||
## What the Workflow Does
|
||||
|
||||
### 1. Module Name and URL Construction
|
||||
|
||||
The workflow uses the provided `repo_name` input and automatically constructs the full repository URL:
|
||||
|
||||
```bash
|
||||
# Example transformations:
|
||||
repo_name: "MokoDoliExample" → https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliExample
|
||||
repo_name: "MokoDoliSign" → https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliSign
|
||||
repo_name: "MyModule" → https://git.mokoconsulting.tech/mokoconsulting-tech/MyModule
|
||||
```
|
||||
|
||||
**Note**: The organization is always `mokoconsulting-tech` and cannot be changed.
|
||||
|
||||
### 2. Module ID Determination
|
||||
|
||||
**Auto-Assignment Mode** (default):
|
||||
- Scans [module registry](../development/crm/module-registry.md) for used IDs in range 185064-185099
|
||||
- Assigns first available ID sequentially
|
||||
- Fails if all IDs are reserved
|
||||
|
||||
**Manual Assignment Mode**:
|
||||
- Validates ID is in range 185064-185099
|
||||
- Checks for conflicts
|
||||
- Fails if ID is already in use
|
||||
|
||||
### 3. Registry Table Update
|
||||
|
||||
Updates [`docs/development/crm/module-registry.md`](../development/crm/module-registry.md):
|
||||
|
||||
```markdown
|
||||
| Module Name | Module Number | Status | Description | Repository |
|
||||
|-------------|---------------|--------|-------------|------------|
|
||||
| MokoDoliExample | 185064 | Reserved | Example module | https://git.mokoconsulting.tech/mokoconsulting-tech/repo |
|
||||
```
|
||||
|
||||
**Insertion Point**: Before the "Available for Assignment" line.
|
||||
|
||||
### 4. Override Configuration Update
|
||||
|
||||
Updates `override.config.tf` to protect the workflow file:
|
||||
|
||||
```hcl
|
||||
{
|
||||
path = ".github/workflows/reserve-dolibarr-module-id.yml"
|
||||
reason = "Dolibarr module ID reservation workflow"
|
||||
},
|
||||
```
|
||||
|
||||
**Purpose**: Prevents the workflow file from being overwritten during bulk sync operations.
|
||||
|
||||
### 5. Pull Request Creation
|
||||
|
||||
Creates a PR with:
|
||||
- **Branch**: `reserve-module-id/<module_id>`
|
||||
- **Title**: "Reserve Dolibarr Module ID {id} for {module_name}"
|
||||
- **Labels**: `dolibarr`, `module-id-reservation`, `automated`
|
||||
- **Description**: Comprehensive details about the reservation
|
||||
|
||||
### 6. Optional Remote Push
|
||||
|
||||
If `push_to_remote` is enabled, the workflow:
|
||||
|
||||
1. Clones the remote repository using `GH_TOKEN` for authentication
|
||||
2. Creates a new branch `reserve-module-id/<ID>` in the remote repo
|
||||
3. Creates `src/DOLIBARR_MODULE_ID.txt` with the reserved ID
|
||||
4. Scans all PHP files for the `$this->numero = <number>` pattern and updates every match to the new ID
|
||||
5. Scans all other files for `DOLIBARR_MODULE_ID=<number>` and updates every match
|
||||
6. Commits all changes to the new branch
|
||||
7. Opens a PR in the remote repository via the GitHub CLI
|
||||
|
||||
The generated `src/DOLIBARR_MODULE_ID.txt` contains:
|
||||
|
||||
```
|
||||
DOLIBARR_MODULE_ID=185064
|
||||
|
||||
This module ID has been officially reserved in MokoStandards.
|
||||
|
||||
Module Name: MokoDoliExample
|
||||
Module ID: 185064
|
||||
Reserved Range: 185051-185099 (Moko Consulting)
|
||||
Description: Dolibarr module MokoDoliExample
|
||||
|
||||
Reserved: 2026-02-19 16:30:00 UTC
|
||||
|
||||
DO NOT CHANGE THIS ID!
|
||||
|
||||
This ID is registered in the MokoStandards module registry:
|
||||
https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/blob/main/docs/development/crm/module-registry.md
|
||||
```
|
||||
|
||||
If `push_to_remote` is disabled (default), you can manually create this file and update the module descriptor later.
|
||||
|
||||
## Workflow Steps
|
||||
|
||||
### Detailed Step Breakdown
|
||||
|
||||
1. **Checkout repository** - Fetches MokoStandards repository
|
||||
2. **Configure Git** - Sets up git credentials for commits
|
||||
3. **Extract module name** - Uses provided repo_name and constructs full URL
|
||||
4. **Determine module ID** - Auto-assigns or validates manual ID
|
||||
5. **Check for conflicts** - Ensures ID is available
|
||||
6. **Update registry table** - Adds new entry to registry with auto-generated description
|
||||
7. **Update override config** - Protects workflow file
|
||||
8. **Create branch and commit** - Commits changes to new branch
|
||||
9. **Create pull request** - Automated PR creation
|
||||
10. **Add labels** - Tags PR with relevant labels
|
||||
11. **Push to remote** - (Optional) Scans remote repo for module ID patterns, updates them, and opens a PR if enabled
|
||||
12. **Output summary** - Displays reservation summary
|
||||
|
||||
## Output
|
||||
|
||||
### GitHub Actions Summary
|
||||
|
||||
The workflow generates a summary with:
|
||||
|
||||
```markdown
|
||||
## 🎉 Module ID Reservation Summary
|
||||
|
||||
**Module Name:** MokoDoliExample
|
||||
**Reserved ID:** 185064
|
||||
**Repository:** https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliExample
|
||||
**Pull Request:** https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/pull/123
|
||||
|
||||
### Next Steps
|
||||
1. The GitHub Actions workflow has created the pull request above automatically
|
||||
2. Review the pull request
|
||||
3. Get approval from CRM Development Lead
|
||||
4. Merge the PR to officially reserve the module ID
|
||||
5. Verify DOLIBARR_MODULE_ID.txt was created in https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliExample
|
||||
```
|
||||
|
||||
### Files Modified
|
||||
|
||||
**In MokoStandards Repository**:
|
||||
- `docs/development/crm/module-registry.md` - Registry table updated
|
||||
- `override.config.tf` - Workflow protection added
|
||||
|
||||
**In Remote Repository** (when `push_to_remote` is enabled):
|
||||
- `src/DOLIBARR_MODULE_ID.txt` — module ID file created
|
||||
- PHP module descriptor(s) — `$this->numero` updated to the reserved ID
|
||||
- Any other files containing `DOLIBARR_MODULE_ID=` — updated to the reserved ID
|
||||
- A PR is opened in the remote repository on branch `reserve-module-id/<ID>`
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors and Solutions
|
||||
|
||||
#### Error: "Module ID already in use"
|
||||
|
||||
**Cause**: The requested module ID is already reserved in the registry.
|
||||
|
||||
**Solution**:
|
||||
- If auto-assigning: Workflow will try next available ID
|
||||
- If manual: Choose a different ID or use auto-assignment
|
||||
|
||||
```bash
|
||||
# Check available IDs
|
||||
grep -E "185064|185065|185066" docs/policy/crm/development-standards.md
|
||||
```
|
||||
|
||||
#### Error: "Module ID must be in range 185064-185099"
|
||||
|
||||
**Cause**: Manual module_id is outside the allowed range.
|
||||
|
||||
**Solution**: Use an ID between 185064 and 185099 (inclusive).
|
||||
|
||||
#### Error: "No available module IDs in range 185064-185099"
|
||||
|
||||
**Cause**: All 36 IDs in the range are already reserved.
|
||||
|
||||
**Solution**: Contact repository maintainers to discuss expanding the range or removing obsolete reservations.
|
||||
|
||||
#### Error: "push_to_remote is enabled but remote_repository is not provided"
|
||||
|
||||
**This error no longer applies** - The workflow now always pushes to the remote repository automatically constructed from the repo name.
|
||||
|
||||
#### Error: "Could not find 'Available for Assignment' line in registry"
|
||||
|
||||
**Cause**: Registry table structure has changed.
|
||||
|
||||
**Solution**: Verify `docs/policy/crm/development-standards.md` contains the "Available for Assignment" marker line.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Reservation Guidelines
|
||||
|
||||
1. **Use Descriptive Names**: Module name should clearly indicate purpose
|
||||
2. **Provide Accurate Descriptions**: Help others understand the module
|
||||
3. **Reserve Before Development**: Reserve ID before starting module development
|
||||
4. **One ID Per Module**: Each module should have exactly one ID
|
||||
5. **Update Status**: Change from "Reserved" to "Active" once deployed
|
||||
|
||||
### Module Naming Conventions
|
||||
|
||||
- **Prefix with "MokoDoli"**: Indicates Moko Consulting Dolibarr module
|
||||
- **CamelCase**: Use PascalCase for module names
|
||||
- **Descriptive**: Name should indicate functionality
|
||||
|
||||
**Examples**:
|
||||
- ✅ `MokoDoliSign` - Clear, follows conventions
|
||||
- ✅ `MokoDoliForm` - Concise, descriptive
|
||||
- ❌ `my-module` - Not CamelCase, not descriptive
|
||||
- ❌ `Test123` - Not descriptive
|
||||
|
||||
### Repository Structure
|
||||
|
||||
After reservation, structure your Dolibarr module repository:
|
||||
|
||||
```
|
||||
MokoDoliExample/
|
||||
├── src/
|
||||
│ ├── DOLIBARR_MODULE_ID.txt # Created by workflow
|
||||
│ └── modMokoDoliExample.class.php # Module descriptor
|
||||
├── class/ # Business logic
|
||||
├── langs/ # Translations
|
||||
│ ├── en_US/
|
||||
│ └── fr_FR/
|
||||
├── sql/ # Database scripts
|
||||
├── admin/ # Admin pages
|
||||
├── README.md
|
||||
└── CHANGELOG.md
|
||||
```
|
||||
|
||||
## Integration with MokoStandards
|
||||
|
||||
### Module Registry
|
||||
|
||||
The workflow updates the official module registry at:
|
||||
`docs/policy/crm/development-standards.md`
|
||||
|
||||
This registry is the single source of truth for all Moko Consulting Dolibarr module IDs.
|
||||
|
||||
### Override Protection
|
||||
|
||||
The workflow protects itself from being overwritten during bulk repository sync operations by adding an entry to `override.config.tf`.
|
||||
|
||||
### Policy Compliance
|
||||
|
||||
This workflow follows the module ID reservation process defined in:
|
||||
[CRM Development Standards](../policy/crm/development-standards.md#module-id-reservation-process)
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Batch Reservations
|
||||
|
||||
For reserving multiple module IDs, run the workflow multiple times. Each run will auto-assign the next available ID.
|
||||
|
||||
```bash
|
||||
# First run: Reserves 185064
|
||||
# Second run: Reserves 185065
|
||||
# Third run: Reserves 185066
|
||||
```
|
||||
|
||||
### Checking Available IDs
|
||||
|
||||
To see which IDs are still available:
|
||||
|
||||
```bash
|
||||
cd /home/runner/work/MokoStandards/MokoStandards
|
||||
grep -oP '(?<=\| )1850(6[4-9]|[7-8][0-9]|9[0-9])(?= \|)' \
|
||||
docs/policy/crm/development-standards.md | sort -n
|
||||
```
|
||||
|
||||
### Updating Reserved Status
|
||||
|
||||
Once a module is deployed, update its status from "Reserved" to "Active":
|
||||
|
||||
1. Edit `docs/policy/crm/development-standards.md`
|
||||
2. Change status column from "Reserved" to "Active"
|
||||
3. Update repository URL if needed
|
||||
4. Create PR with changes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Workflow Run Failed
|
||||
|
||||
**Check the Actions tab**: Review the failed step for error messages.
|
||||
|
||||
**Common issues**:
|
||||
- YAML syntax errors (validate with yamllint)
|
||||
- Git configuration issues
|
||||
- Permission errors
|
||||
- Network connectivity to remote repository
|
||||
|
||||
### PR Creation Failed
|
||||
|
||||
**Possible causes**:
|
||||
- Insufficient permissions
|
||||
- Base branch doesn't exist
|
||||
- Branch already exists
|
||||
|
||||
**Solution**: Check workflow permissions in repository settings.
|
||||
|
||||
### Remote Push Failed
|
||||
|
||||
**Causes**:
|
||||
- `GH_TOKEN` secret not set or lacks write access to the remote repository
|
||||
- Invalid repository name (remote repo does not exist)
|
||||
- Branch `reserve-module-id/<ID>` already exists in the remote repo
|
||||
|
||||
**Solution**:
|
||||
- Verify repository URL is correct
|
||||
- Ensure GitHub token has push permissions
|
||||
- Check default branch name (main vs master)
|
||||
|
||||
### ID Conflict After Merge
|
||||
|
||||
If two PRs reserve the same ID simultaneously:
|
||||
|
||||
1. The first merged PR wins
|
||||
2. The second PR will show conflicts
|
||||
3. Close the second PR and re-run the workflow
|
||||
4. The workflow will auto-assign the next available ID
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating the Workflow
|
||||
|
||||
When updating the workflow:
|
||||
|
||||
1. Update the VERSION field in the file header
|
||||
2. Update this documentation
|
||||
3. Test with dry-run if possible
|
||||
4. Update the workflow inventory
|
||||
|
||||
### Monitoring
|
||||
|
||||
Monitor the module registry regularly:
|
||||
|
||||
```bash
|
||||
# Count reserved IDs
|
||||
grep -c "| Reserved |" docs/policy/crm/development-standards.md
|
||||
|
||||
# Count active IDs
|
||||
grep -c "| Active |" docs/policy/crm/development-standards.md
|
||||
|
||||
# Show available slots
|
||||
echo $((36 - $(grep -cE "185064|185065|..." docs/policy/crm/development-standards.md)))
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Simple Reservation (No Remote Push)
|
||||
|
||||
```yaml
|
||||
# Input
|
||||
repo_name: "MokoDoliPasskey"
|
||||
push_to_remote: false
|
||||
|
||||
# Result
|
||||
Module ID: 185064 (auto-assigned)
|
||||
Module Name: MokoDoliPasskey
|
||||
Repository URL: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliPasskey
|
||||
PR Created: #123
|
||||
Remote File: NOT created (manual creation required)
|
||||
```
|
||||
|
||||
### Example 2: Specific ID with Remote Push
|
||||
|
||||
```yaml
|
||||
# Input
|
||||
repo_name: "MokoDoliMulti"
|
||||
module_id: 185070
|
||||
push_to_remote: true
|
||||
|
||||
# Result
|
||||
Module ID: 185070 (manual)
|
||||
Module Name: MokoDoliMulti
|
||||
Repository URL: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoDoliMulti
|
||||
PR Created: #124
|
||||
Remote PR: opened in MokoDoliMulti with $this->numero and DOLIBARR_MODULE_ID.txt updated to 185070
|
||||
```
|
||||
|
||||
### Example 3: Conflict Handling
|
||||
|
||||
```yaml
|
||||
# First run - Success
|
||||
module_id: 185065
|
||||
Result: Reserved successfully
|
||||
|
||||
# Second run - Conflict
|
||||
module_id: 185065
|
||||
Error: "Module ID 185065 is already in use!"
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Token Permissions
|
||||
|
||||
The workflow requires:
|
||||
- `contents: write` - To create branches and commits
|
||||
- `pull-requests: write` - To create PRs
|
||||
|
||||
### Remote Repository Access
|
||||
|
||||
The workflow interacts with remote repositories using `GH_TOKEN`, which is an **organization-level Actions secret** (set under GitHub organization Settings → Secrets and variables → Actions):
|
||||
|
||||
- Repository URL is constructed as `https://git.mokoconsulting.tech/mokoconsulting-tech/{repo_name}`
|
||||
- `GH_TOKEN` must have `repo` (contents write) and `pull-requests: write` on the target repository
|
||||
- The workflow creates a branch `reserve-module-id/<ID>` and opens a PR — it never pushes directly to the default branch
|
||||
- Because `GH_TOKEN` is an organization secret it is automatically available to all repositories in the `mokoconsulting-tech` organization without any per-repo configuration
|
||||
|
||||
### Protected Files
|
||||
|
||||
The workflow file itself is protected via `override.config.tf` to prevent accidental deletion or modification during bulk sync operations.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [CRM Development Standards](../policy/crm/development-standards.md) - Module ID reservation policy
|
||||
- [Dolibarr Module Development Guide](../guide/crm/dolibarr-development-guide.md) - Complete development guide
|
||||
- [Dolibarr Workflow Templates](../templates/workflows/dolibarr.md) - CI/CD templates for modules
|
||||
- [Bulk Repository Sync](./bulk-repo-sync.md) - Understanding override protection
|
||||
- [Workflow Architecture](./workflow-architecture.md) - Overall workflow design patterns
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 04.00.04 (2026-03-04)
|
||||
|
||||
**Changed**:
|
||||
- `push_to_remote` now scans remote repository PHP files for `$this->numero = <number>` and updates them to the reserved ID
|
||||
- `push_to_remote` now scans other files for `DOLIBARR_MODULE_ID=<number>` and updates them
|
||||
- `push_to_remote` now creates a branch `reserve-module-id/<ID>` and opens a PR in the remote repository instead of pushing directly to the default branch
|
||||
- Remote push uses `GH_TOKEN` for authenticated clone and PR creation
|
||||
- Output summary now shows the remote PR URL when `push_to_remote` is enabled
|
||||
|
||||
### Version 04.00.04 (2026-02-21)
|
||||
|
||||
**Changed**:
|
||||
- Remote push is now **optional** with `push_to_remote` input parameter (default: false)
|
||||
- PR description now shows whether remote push was enabled
|
||||
- Output summary shows remote push status (Enabled/Skipped)
|
||||
- Next steps conditional based on push status
|
||||
|
||||
**Added**:
|
||||
- `push_to_remote` boolean input parameter (optional, default: false)
|
||||
- Conditional execution of push step based on `push_to_remote` value
|
||||
- Status indicator in workflow outputs
|
||||
|
||||
**Fixed**:
|
||||
- Push step now skips if `push_to_remote` is false
|
||||
- Documentation updated to reflect optional push behavior
|
||||
- Workflow diagram correctly shows push as "(Optional)"
|
||||
|
||||
### Version 04.00.04 (2026-02-20)
|
||||
|
||||
**Changed**:
|
||||
- Simplified workflow inputs to only require `repo_name`
|
||||
- Repository URL now automatically constructed as `https://git.mokoconsulting.tech/mokoconsulting-tech/{repo_name}`
|
||||
- Organization is always assumed to be `mokoconsulting-tech`
|
||||
- Description is automatically generated from module name
|
||||
- Remote push is now always enabled (no longer optional)
|
||||
|
||||
**Fixed**:
|
||||
- Removed outdated "(Optional)" label from workflow diagram
|
||||
- Updated documentation to reflect that remote push is mandatory
|
||||
- Clarified that `DOLIBARR_MODULE_ID.txt` is always created in remote repository
|
||||
|
||||
**Removed**:
|
||||
- `description` input (auto-generated)
|
||||
- `repository` input (auto-constructed)
|
||||
- `push_to_remote` input (always true)
|
||||
- `remote_repository` input (auto-constructed)
|
||||
- `developer` input (removed in v04.00.04)
|
||||
|
||||
**Added**:
|
||||
- `repo_name` required input - single field for repository name
|
||||
|
||||
### Version 04.00.04 (2026-02-19)
|
||||
|
||||
**Changed**:
|
||||
- Simplified from 866 to 450 lines (48% reduction)
|
||||
- Removed module documentation generation
|
||||
- Module name now auto-detected from repository name
|
||||
- Added optional manual module ID assignment
|
||||
- Focused on core functionality: ID assignment and registry update only
|
||||
|
||||
**Added**:
|
||||
- `module_id` optional input for manual ID assignment
|
||||
- Automatic module name extraction from repository
|
||||
|
||||
**Removed**:
|
||||
- Module documentation creation (docs/modules/)
|
||||
- Module README creation
|
||||
- Module ID reference file creation
|
||||
- Override protection for module docs (now only protects workflow)
|
||||
- Module descriptor template creation in remote repos
|
||||
- README creation in remote repos
|
||||
|
||||
### Version 03.00.00 (2026-02-16)
|
||||
|
||||
**Initial release**:
|
||||
- Full documentation generation
|
||||
- Registry table updates
|
||||
- PR automation
|
||||
- Remote push support
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions about this workflow:
|
||||
|
||||
1. Check this documentation
|
||||
2. Review the [CRM Development Standards](../policy/crm/development-standards.md)
|
||||
3. Open an issue in the MokoStandards repository
|
||||
4. Contact the MokoStandards maintainers
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-19
|
||||
**Maintained By**: MokoStandards Team
|
||||
**Category**: Workflow Documentation
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Document Type | Workflow Documentation |
|
||||
| Domain | Documentation |
|
||||
| Applies To | MokoStandards Repository |
|
||||
| Jurisdiction | Tennessee, USA |
|
||||
| Owner | Moko Consulting |
|
||||
| Repo | https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards |
|
||||
| Path | /docs/workflows/reserve-dolibarr-module-id.md |
|
||||
| Version | 04.00.04 |
|
||||
| Status | Active |
|
||||
| Last Reviewed | 2026-02-19 |
|
||||
| Reviewed By | Documentation Team |
|
||||
|
||||
## Revision History
|
||||
|
||||
| Date | Author | Change | Notes |
|
||||
|------|--------|--------|-------|
|
||||
| 2026-02-19 | GitHub Copilot | Initial documentation creation | Comprehensive workflow documentation for v04.00.04 |
|
||||
@@ -0,0 +1,567 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API/
|
||||
VERSION: 04.06.00
|
||||
PATH: /docs/workflows/reusable-workflows.md
|
||||
BRIEF: Documentation for reusable GitHub Actions workflows
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Reusable Workflows
|
||||
|
||||
MokoStandards provides seven reusable GitHub Actions workflows that enable consistent CI/CD across all organization repositories, with automatic project type detection for Joomla extensions, Dolibarr modules, and generic applications.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```yaml
|
||||
# Basic quality check
|
||||
jobs:
|
||||
quality:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
|
||||
# Type-aware build and release
|
||||
build:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-build.yml@main
|
||||
|
||||
release:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-release.yml@main
|
||||
with:
|
||||
version: '1.0.0'
|
||||
```
|
||||
|
||||
## Workflow Categories
|
||||
|
||||
### Quality & Testing Workflows
|
||||
- **reusable-php-quality.yml** - PHP code quality analysis (PHPCS, PHPStan, Psalm)
|
||||
- **reusable-joomla-testing.yml** - Joomla extension testing with matrix PHP/Joomla versions
|
||||
- **reusable-ci-validation.yml** - Repository standards validation
|
||||
|
||||
### Repository Maintenance Workflows
|
||||
- **reusable-branch-cleanup.yml** - Automated cleanup of stale and merged branches
|
||||
|
||||
### Type-Aware Orchestration Workflows
|
||||
- **reusable-project-detector.yml** - Automatic project type detection
|
||||
- **reusable-build.yml** - Universal build for all project types
|
||||
- **reusable-release.yml** - Type-aware release creation and packaging
|
||||
- **reusable-deploy.yml** - Multi-environment deployment
|
||||
|
||||
> **Type-Aware Workflows** automatically detect whether your project is a Joomla extension, Dolibarr module, or generic application, and apply appropriate build/release/deploy steps. This enables a single workflow definition to work across all repositories.
|
||||
|
||||
---
|
||||
|
||||
## Quality & Testing Workflows
|
||||
|
||||
### PHP Quality Analysis
|
||||
|
||||
Runs comprehensive PHP code quality checks using PHPCS, PHPStan, and Psalm with configurable standards and analysis levels.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
quality:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
with:
|
||||
php-versions: '["8.1", "8.2"]'
|
||||
tools: '["phpcs", "phpstan", "psalm"]'
|
||||
phpcs-standard: 'PSR12'
|
||||
phpstan-level: '6'
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `php-versions` (string) - JSON array of PHP versions, default: `["7.4", "8.0", "8.1", "8.2"]`
|
||||
- `tools` (string) - JSON array of tools, default: `["phpcs", "phpstan", "psalm"]`
|
||||
- `phpcs-standard` (string) - Coding standard, default: `PSR12`
|
||||
- `phpstan-level` (string) - Analysis level 0-9, default: `5`
|
||||
- `fail-on-error` (boolean) - Fail on errors, default: `true`
|
||||
|
||||
**Outputs:** `quality-score` - Overall quality score percentage (0-100)
|
||||
|
||||
### Joomla Testing
|
||||
|
||||
Matrix testing for Joomla extensions across PHP and Joomla versions with PHPUnit, MySQL, and code coverage support.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-joomla-testing.yml@main
|
||||
with:
|
||||
php-versions: '["8.1", "8.2"]'
|
||||
joomla-versions: '["4.4", "5.0", "5.1"]'
|
||||
coverage: true
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `php-versions` (string) - JSON array, default: `["7.4", "8.0", "8.1", "8.2"]`
|
||||
- `joomla-versions` (string) - JSON array, default: `["4.4", "5.0", "5.1"]`
|
||||
- `coverage` (boolean) - Enable coverage, default: `false`
|
||||
- `run-integration-tests` (boolean) - Run integration tests, default: `true`
|
||||
|
||||
> Automatically excludes incompatible combinations (e.g., PHP 7.4 + Joomla 5.x)
|
||||
|
||||
### CI Validation
|
||||
|
||||
Repository standards validation with configurable profiles (basic, full, strict).
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
validate:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
with:
|
||||
profile: 'full'
|
||||
validate-security: true
|
||||
```
|
||||
|
||||
**Validation Profiles:**
|
||||
- **basic** - Manifest, XML, PHP syntax, security checks
|
||||
- **full** - Basic + changelog, license headers, language structure, paths, whitespace
|
||||
- **strict** - Full validation with fail-on-warnings enabled
|
||||
|
||||
**Key Inputs:**
|
||||
- `profile` (string) - Validation profile, default: `basic`
|
||||
- `validate-manifests` (boolean) - Validate XML manifests, default: `true`
|
||||
- `validate-changelogs` (boolean) - Validate CHANGELOG.md, default: `true`
|
||||
- `validate-licenses` (boolean) - Validate license headers, default: `true`
|
||||
- `validate-security` (boolean) - Security checks, default: `true`
|
||||
- `fail-on-warnings` (boolean) - Fail on warnings, default: `false`
|
||||
|
||||
---
|
||||
|
||||
## Repository Maintenance Workflows
|
||||
|
||||
### Branch Cleanup
|
||||
|
||||
Automatically cleans up stale and merged branches with configurable exclusion patterns and dry-run support.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
cleanup:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-branch-cleanup.yml@main
|
||||
with:
|
||||
stale-days: 90
|
||||
delete-merged: true
|
||||
delete-stale: true
|
||||
dry-run: false
|
||||
permissions:
|
||||
contents: write
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `stale-days` (number) - Days before branch is stale, default: `90`
|
||||
- `delete-merged` (boolean) - Delete merged branches, default: `true`
|
||||
- `delete-stale` (boolean) - Delete stale branches, default: `true`
|
||||
- `dry-run` (boolean) - Preview without deleting, default: `false`
|
||||
- `exclude-patterns` (string) - JSON array of regex patterns to exclude, default: `["main", "master", "develop", "dev", "dev/.*", "rc/.*", "release/.*", "staging", "production"]`
|
||||
- `exclude-prefix` (string) - Comma-separated prefixes to exclude, default: `"dependabot/,renovate/"`
|
||||
|
||||
**Features:**
|
||||
- Detects and deletes branches merged into default branch
|
||||
- Identifies stale branches based on last commit date
|
||||
- Configurable exclusion patterns (regex and prefix-based)
|
||||
- Dry-run mode for previewing changes
|
||||
- Detailed summary of deleted and failed branches
|
||||
|
||||
**Example with custom exclusions:**
|
||||
```yaml
|
||||
jobs:
|
||||
cleanup:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-branch-cleanup.yml@main
|
||||
with:
|
||||
stale-days: 60
|
||||
delete-merged: true
|
||||
delete-stale: true
|
||||
dry-run: false
|
||||
exclude-patterns: '["main", "master", "develop", "hotfix/.*"]'
|
||||
exclude-prefix: 'dependabot/,renovate/,feature/'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Type-Aware Orchestration Workflows
|
||||
|
||||
### Project Type Detection
|
||||
|
||||
Automatically detects project type and provides outputs for downstream workflows.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
detect:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-project-detector.yml@main
|
||||
```
|
||||
|
||||
**Outputs:**
|
||||
- `project-type` - Detected type: `joomla`, `dolibarr`, or `generic`
|
||||
- `extension-type` - Extension type: `component`, `module`, `plugin`, `template`, `package`, or `application`
|
||||
- `has-php` - Whether project contains PHP files (true/false)
|
||||
- `has-node` - Whether project contains package.json (true/false)
|
||||
|
||||
### Type-Aware Build
|
||||
|
||||
Universal build workflow that adapts to project type with automatic dependency management.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-build.yml@main
|
||||
with:
|
||||
php-version: '8.1'
|
||||
node-version: '20.x'
|
||||
upload-artifacts: true
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `php-version` (string) - PHP version, default: `8.1`
|
||||
- `node-version` (string) - Node.js version, default: `20.x`
|
||||
- `upload-artifacts` (boolean) - Upload build artifacts, default: `true`
|
||||
- `artifact-name` (string) - Artifact name, default: `build-artifacts`
|
||||
|
||||
**Build Logic:**
|
||||
- **Joomla:** Installs dependencies, runs npm build if available, prepares extension
|
||||
- **Dolibarr:** Installs production dependencies, runs build scripts
|
||||
- **Generic:** Runs npm build, checks for Makefile, executes build commands
|
||||
|
||||
### Type-Aware Release
|
||||
|
||||
Creates releases with type-specific packaging and marketplace support.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
release:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-release.yml@main
|
||||
with:
|
||||
version: '1.0.0'
|
||||
prerelease: false
|
||||
create-github-release: true
|
||||
permissions:
|
||||
contents: write
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `version` (string, **required**) - Release version in semver format
|
||||
- `prerelease` (boolean) - Mark as pre-release, default: `false`
|
||||
- `draft` (boolean) - Create as draft, default: `false`
|
||||
- `create-github-release` (boolean) - Create GitHub release, default: `true`
|
||||
- `publish-to-marketplace` (boolean) - Publish to marketplace, default: `false`
|
||||
|
||||
**Package Creation:**
|
||||
- **Joomla/Dolibarr:** ZIP package with manifest version updates
|
||||
- **Generic:** TAR.GZ package with build artifacts
|
||||
- All packages include SHA256 and MD5 checksums
|
||||
|
||||
### Type-Aware Deployment
|
||||
|
||||
Multi-environment deployment with type-specific logic and health checks.
|
||||
|
||||
**Usage:**
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: staging
|
||||
deployment-method: rsync
|
||||
health-check-url: https://staging.example.com/health
|
||||
secrets:
|
||||
DEPLOY_HOST: ${{ secrets.STAGING_HOST }}
|
||||
DEPLOY_USER: ${{ secrets.STAGING_USER }}
|
||||
DEPLOY_KEY: ${{ secrets.STAGING_SSH_KEY }}
|
||||
DEPLOY_PATH: ${{ secrets.STAGING_PATH }}
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
```
|
||||
|
||||
**Key Inputs:**
|
||||
- `environment` (string, **required**) - Target: `staging` or `production`
|
||||
- `deployment-method` (string) - Method: `rsync`, `ssh`, `ftp`, `kubernetes`, `custom`, default: `custom`
|
||||
- `health-check-url` (string) - URL for post-deployment health check
|
||||
- `health-check-timeout` (number) - Timeout in seconds, default: `300`
|
||||
|
||||
**Deployment Methods:**
|
||||
- **rsync:** Direct sync to remote server
|
||||
- **ssh:** Package transfer and extraction via SSH
|
||||
- **custom:** Type-specific deployment logic (Joomla extension, Dolibarr module, generic app)
|
||||
|
||||
---
|
||||
|
||||
## Complete Pipeline Examples
|
||||
|
||||
### Example 1: Type-Aware CI/CD Pipeline
|
||||
|
||||
Single pipeline that works for Joomla, Dolibarr, and generic projects:
|
||||
|
||||
```yaml
|
||||
name: CI/CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, staging, dev/**]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
deployments: write
|
||||
pull-requests: write
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
# Auto-detect project type
|
||||
detect:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-project-detector.yml@main
|
||||
|
||||
# Validate code
|
||||
validate:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
with:
|
||||
profile: 'full'
|
||||
|
||||
# Check quality (PHP projects only)
|
||||
quality:
|
||||
needs: detect
|
||||
if: needs.detect.outputs.has-php == 'true'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
with:
|
||||
php-versions: '["8.1", "8.2"]'
|
||||
|
||||
# Test Joomla extensions
|
||||
test:
|
||||
needs: [detect, quality]
|
||||
if: needs.detect.outputs.project-type == 'joomla'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-joomla-testing.yml@main
|
||||
with:
|
||||
php-versions: '["8.1", "8.2"]'
|
||||
coverage: true
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
# Build (works for all types)
|
||||
build:
|
||||
needs: [detect, validate]
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-build.yml@main
|
||||
|
||||
# Deploy to staging
|
||||
deploy-staging:
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/staging'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: staging
|
||||
deployment-method: rsync
|
||||
secrets: inherit
|
||||
|
||||
# Create release on tag
|
||||
release:
|
||||
needs: [detect, build]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-release.yml@main
|
||||
with:
|
||||
version: ${{ github.ref_name }}
|
||||
|
||||
# Deploy to production
|
||||
deploy-production:
|
||||
needs: release
|
||||
if: github.event_name == 'release'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: production
|
||||
version: ${{ github.event.release.tag_name }}
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
### Example 2: Basic Quality and Testing
|
||||
|
||||
Simple quality and testing pipeline:
|
||||
|
||||
```yaml
|
||||
name: Quality & Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
with:
|
||||
profile: 'full'
|
||||
|
||||
quality:
|
||||
needs: validate
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
with:
|
||||
php-versions: '["8.1", "8.2"]'
|
||||
|
||||
test:
|
||||
needs: quality
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-joomla-testing.yml@main
|
||||
with:
|
||||
coverage: true
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Version Pinning
|
||||
|
||||
**Recommended:** Pin to main branch for automatic updates
|
||||
```yaml
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
```
|
||||
|
||||
**Stable:** Pin to specific tag
|
||||
```yaml
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@v1.0.0
|
||||
```
|
||||
|
||||
**Maximum Stability:** Pin to commit SHA
|
||||
```yaml
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@abc1234
|
||||
```
|
||||
|
||||
### Secret Management
|
||||
|
||||
**Pass all secrets:**
|
||||
```yaml
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
**Pass specific secrets:**
|
||||
```yaml
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||||
```
|
||||
|
||||
### Progressive Adoption
|
||||
|
||||
Start with basic validation, gradually increase strictness:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
# Dev branches: basic validation
|
||||
validate-dev:
|
||||
if: startsWith(github.ref, 'refs/heads/dev/')
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
with:
|
||||
profile: 'basic'
|
||||
|
||||
# Main branch: strict validation
|
||||
validate-main:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
with:
|
||||
profile: 'strict'
|
||||
fail-on-warnings: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Workflow Not Found
|
||||
**Error:** `Unable to resolve action mokoconsulting-tech/MokoStandards/.github/workflows/...`
|
||||
|
||||
**Solution:** Ensure calling repository has access to MokoStandards. For private repositories, configure proper access permissions.
|
||||
|
||||
### Missing Secrets
|
||||
**Error:** `Secret CODECOV_TOKEN is not available`
|
||||
|
||||
**Solution:** Add secret at organization or repository level, or pass explicitly:
|
||||
```yaml
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
```
|
||||
|
||||
### Matrix Job Failures
|
||||
Random matrix job failures may indicate rate limiting or resource contention.
|
||||
|
||||
**Solution:** Reduce concurrency
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
php: ['8.1', '8.2']
|
||||
max-parallel: 2 # Limit concurrent jobs
|
||||
```
|
||||
|
||||
### Health Check Timeout
|
||||
**Solution:** Increase timeout or verify URL accessibility
|
||||
```yaml
|
||||
with:
|
||||
health-check-timeout: 600 # 10 minutes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration from Local Workflows
|
||||
|
||||
**Steps:**
|
||||
1. Identify workflow type (quality, testing, validation, build, release, deploy)
|
||||
2. Map your inputs to reusable workflow parameters
|
||||
3. Update workflow file to call reusable workflow
|
||||
4. Test on development branch
|
||||
5. Archive old workflow once validated
|
||||
|
||||
**Example Migration:**
|
||||
|
||||
```yaml
|
||||
# Before: Local workflow
|
||||
jobs:
|
||||
phpcs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: shivammathur/setup-php@v2
|
||||
- run: phpcs --standard=PSR12 src/
|
||||
|
||||
# After: Reusable workflow
|
||||
jobs:
|
||||
quality:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
with:
|
||||
phpcs-standard: 'PSR12'
|
||||
tools: '["phpcs"]'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Support & Resources
|
||||
|
||||
**Support:**
|
||||
- Documentation: [CI Migration Guide](../CI_MIGRATION_GUIDE.md)
|
||||
- Issues: Open issue in MokoStandards repository
|
||||
- Slack: #devops-support channel
|
||||
|
||||
**Related Documentation:**
|
||||
- [CI Migration Guide](../CI_MIGRATION_GUIDE.md) - Detailed migration strategy
|
||||
- [GitHub Reusing Workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows)
|
||||
- [Workflow Templates](../../templates/workflows/) - Additional templates
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 02.01.00 | 2026-01-11 | Added reusable-branch-cleanup workflow, standards-compliance workflow |
|
||||
| 02.00.00 | 2026-01-09 | Consolidated documentation, added type-aware workflows |
|
||||
| 01.00.00 | 2026-01-09 | Initial release (php-quality, joomla-testing, ci-validation) |
|
||||
@@ -0,0 +1,43 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/rs-deployment.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Guide for the SFTP release staging server deployment workflow
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Release Staging (RS) Server Deployment
|
||||
|
||||
> **DEPRECATED (v04.06.00):** The `deploy-rs.yml` workflow has been **retired**. RS deployment is now handled exclusively through the release pipeline. Release artifacts are published via GitHub Releases (`auto-release.yml`) and distributed through platform-specific channels (Joomla `updates.xml`, Dolibarr `update.txt`). The `RS_FTP_*` variables and secrets are no longer used.
|
||||
|
||||
## Current Release Pipeline
|
||||
|
||||
```
|
||||
dev → [alpha] → [beta] → rc → version/XX → main → dev
|
||||
optional optional
|
||||
```
|
||||
|
||||
Production/RS deployment is achieved by:
|
||||
|
||||
1. **Joomla** — GitHub Release ZIP + SHA-256 + `updates.xml` with 5 stability entries (`development`, `alpha`, `beta`, `release-candidate`, `vXX`)
|
||||
2. **Dolibarr** — GitHub Release + `update.txt`
|
||||
3. **Generic** — GitHub Release
|
||||
|
||||
There is no longer a separate SFTP deployment step to a release staging server.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Dev Deployment](dev-deployment.md) — development server (still active)
|
||||
- [Demo Deployment](demo-deployment.md) — demo server (still active)
|
||||
- [Auto Release](auto-release.md) — release pipeline that replaced RS deployment
|
||||
- [Release System](release-system.md) — end-to-end release lifecycle
|
||||
@@ -0,0 +1,239 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/shared-workflows.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Reference for shared workflow templates synced to all governed repos
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Shared Workflow Templates
|
||||
|
||||
These workflows are synced to every governed repository via `bulk_sync.php`. They live in `templates/workflows/shared/` and are registered in all platform definitions.
|
||||
|
||||
## Workflow Summary
|
||||
|
||||
| Workflow | Triggers | Purpose |
|
||||
|----------|----------|---------|
|
||||
| `deploy-dev.yml` | `dev/**`, `alpha/**`, `beta/**`, `rc/**`, `develop` (src/** only) | SFTP deploy to dev server (dev=development, alpha/beta auto-bump patch, rc=rc tag) |
|
||||
| `deploy-demo.yml` | `main`, `master` (src/** only) | SFTP deploy to demo server (stable tag) + update files |
|
||||
| `sync-version-on-merge.yml` | push to `main` | Auto-bump patch version, propagate to all headers |
|
||||
| `auto-release.yml` | push to `main` | Build & Release: every push tags + updates platform version/badges; minor (XX.YY.00) creates version branch + new Release; patch updates existing Release |
|
||||
| `auto-dev-issue.yml` | branch creation (`dev/**`, `rc/**`) | Auto-create tracking issue (dev=feature, rc=release) |
|
||||
| `repository-cleanup.yml` | schedule (1st + 15th) + dispatch | Recurring maintenance: labels, branches, logs, workflows, doc indexes |
|
||||
| `enterprise-firewall-setup.yml` | push to `main` | Configure trusted domain access for enterprise environments |
|
||||
| `repo_health.yml` | every push + PR | Platform-specific health checks (Dolibarr: module descriptor; Joomla: XML manifest) |
|
||||
|
||||
### MokoStandards-only workflows (not synced)
|
||||
|
||||
| Workflow | Triggers | Purpose |
|
||||
|----------|----------|---------|
|
||||
| `composer-validate.yml` | every push + PR | Validate composer.json schema, version consistency, autoload paths, bin scripts, enterprise dep pattern |
|
||||
| `standards-compliance.yml` | push + PR | 28-job, 4-tier compliance check |
|
||||
| `bulk-repo-sync.yml` | dispatch | Sync standards to all governed repos |
|
||||
|
||||
---
|
||||
|
||||
## sync-version-on-merge.yml
|
||||
|
||||
**Trigger:** Every push to `main`/`master`
|
||||
|
||||
**What it does:**
|
||||
1. If README.md was NOT part of the push, auto-increments the patch version (e.g., `04.00.72` → `04.00.73`)
|
||||
2. Reads the VERSION from README.md FILE INFORMATION block
|
||||
3. Runs `update_version_from_readme.php` to propagate to all file headers and badges
|
||||
4. Commits updated files with `[skip ci]`
|
||||
|
||||
**Requirements:** `secrets.GH_TOKEN` with write access
|
||||
|
||||
**Skips:** Commits by `github-actions[bot]`, commits with `[skip ci]`
|
||||
|
||||
---
|
||||
|
||||
## auto-release.yml
|
||||
|
||||
**Trigger:** Every push to `main`/`master` (skips bot commits and `[skip ci]`)
|
||||
|
||||
**What it does on every push:**
|
||||
1. Reads version from README.md
|
||||
2. Creates or updates `version/XX` branch (patches force-update existing branch)
|
||||
3. Sets platform version (Dolibarr `$this->version`, Joomla `<version>`)
|
||||
4. Updates `[VERSION: XX.YY.ZZ]` badges in markdown files
|
||||
5. Writes update files (Dolibarr `update.txt`, Joomla `updates.xml` with `<tag>stable</tag>`)
|
||||
6. Creates git tag `vXX.YY.ZZ`
|
||||
|
||||
**Additional steps on minor releases (patch == 00):**
|
||||
7. Creates new GitHub Release with changelog notes
|
||||
|
||||
**On patch releases (patch != 00):**
|
||||
7. Updates the existing minor release (appends patch notes, updates title)
|
||||
|
||||
**Protection:** Workflow files are protected by CODEOWNERS (requires @jmiller-moko review) and a file path restriction ruleset. Only bypass actors can modify `.github/workflows/`.
|
||||
|
||||
| Version | What happens |
|
||||
|---------|-------------|
|
||||
| `01.02.00` | Full release: version branch + tag + new GitHub Release |
|
||||
| `01.02.01` | Patch: tag + update existing `v01.02.00` Release with patch notes |
|
||||
| `01.02.02` | Patch: tag + update existing Release again |
|
||||
| `01.03.00` | Full release: new version branch + tag + new GitHub Release |
|
||||
|
||||
**Requirements:** `secrets.GH_TOKEN` with write access
|
||||
|
||||
---
|
||||
|
||||
## enterprise-firewall-setup.yml
|
||||
|
||||
**Trigger:** Push to `main`
|
||||
|
||||
**What it does:** Configures trusted domain access rules for enterprise network environments. Ensures governed repositories can access required external services through corporate firewalls.
|
||||
|
||||
---
|
||||
|
||||
## Deploy Workflows
|
||||
|
||||
See dedicated docs:
|
||||
- [Dev Deployment](dev-deployment.md) — development server
|
||||
- [Demo Deployment](demo-deployment.md) — demo server
|
||||
|
||||
> **Note:** `deploy-rs.yml` has been **retired** (v04.06.00). RS deployment is now via the release pipeline only. See [RS Deployment (deprecated)](rs-deployment.md).
|
||||
|
||||
### Common Features (both deploy workflows)
|
||||
|
||||
- **Permission check:** `jmiller-moko` and `github-actions[bot]` hardcoded as authorized; others need `admin`/`maintain` role
|
||||
- **Chore skip:** PRs from `chore/` branches do not deploy
|
||||
- **Suffix required:** `{ENV}_FTP_SUFFIX` must be set or deployment is skipped
|
||||
- **Clear before upload:** Remote folder is always cleared before uploading
|
||||
- **`.ftpignore` support:** Gitignore-style file exclusion
|
||||
- **Failure tracking:** Creates/updates a `deploy-failure` issue on error
|
||||
|
||||
### Version Handling by Environment
|
||||
|
||||
| Environment | Module Version |
|
||||
|-------------|----------------|
|
||||
| Dev (`dev/**`) | `"development"` — Dolibarr `$this->version` and Joomla `<version>` set to literal "development" |
|
||||
| Alpha (`alpha/**`) | `XX.YY.ZZ-alpha` — version with `-alpha` suffix (auto-bumps patch) |
|
||||
| Beta (`beta/**`) | `XX.YY.ZZ-beta` — version with `-beta` suffix (auto-bumps patch) |
|
||||
| RC (`rc/**`) | `XX.YY.ZZ-rc` — version with `-rc` suffix |
|
||||
| Demo (`main`) | Real version from README.md |
|
||||
|
||||
### Update Server Files by Environment
|
||||
|
||||
| Environment | Dolibarr `update.txt` | Joomla `updates.xml <tag>` |
|
||||
|-------------|----------------------|--------------------------|
|
||||
| Dev (`dev/**`) | `development` | `development` |
|
||||
| Alpha (`alpha/**`) | `XX.YY.ZZ-alpha` | `alpha` |
|
||||
| Beta (`beta/**`) | `XX.YY.ZZ-beta` | `beta` |
|
||||
| RC (`rc/**`) | `XX.YY.ZZ-rc` | `release-candidate` |
|
||||
| Release (`main` via auto-release) | `XX.YY.ZZ` | `vXX` |
|
||||
|
||||
See [update-server.md](update-server.md) for the full update server specification.
|
||||
|
||||
---
|
||||
|
||||
## auto-dev-issue.yml
|
||||
|
||||
**Trigger:** Branch creation matching `dev/**` or `rc/**`
|
||||
|
||||
**What it does:** Auto-creates a tracking issue when a new `dev/**` or `rc/**` branch is pushed. Assigns `jmiller-moko`.
|
||||
|
||||
| Branch type | Title prefix | Label |
|
||||
|-------------|-------------|-------|
|
||||
| `dev/**` | `feat(XX.YY.ZZ)` | `type: feature` |
|
||||
| `rc/**` | `rc(XX.YY.ZZ)` | `type: release` |
|
||||
|
||||
Skips if an issue for that version already exists.
|
||||
|
||||
---
|
||||
|
||||
## repository-cleanup.yml
|
||||
|
||||
**Trigger:** Schedule (1st + 15th of each month at 6:00 AM UTC) + manual dispatch
|
||||
|
||||
**What it does (always):**
|
||||
- Deletes 25 retired workflow files
|
||||
- Checks for version drift across all files
|
||||
- Creates `.github/workflows/custom/` directory if missing
|
||||
|
||||
**What it does (toggleable):**
|
||||
- Reset labels to 58-label standard set (manual only, off by default)
|
||||
- Delete old sync branches
|
||||
- Clean cancelled/stale workflow runs
|
||||
- Delete workflow logs older than 30 days
|
||||
- Strip copyright blocks from issue templates
|
||||
- Rebuild `docs/` index files
|
||||
|
||||
---
|
||||
|
||||
## Custom Workflows
|
||||
|
||||
Every governed repo has a `.github/workflows/custom/` directory that is **never touched by sync or cleanup**. Place repo-specific workflows here:
|
||||
|
||||
```
|
||||
.github/workflows/
|
||||
├── deploy-dev.yml ← Synced (overwritten on sync)
|
||||
├── auto-release.yml ← Synced (overwritten on sync)
|
||||
├── repository-cleanup.yml ← Synced (overwritten on sync)
|
||||
└── custom/ ← SAFE — never touched
|
||||
├── README.md
|
||||
└── my-custom-workflow.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## repo_health.yml (platform-specific)
|
||||
|
||||
**Trigger:** Every push and PR (no path filter)
|
||||
|
||||
**What it does:** Platform-specific health checks in addition to shared guardrails (release vars, scripts governance, repo artifacts, extended checks).
|
||||
|
||||
### Dolibarr (`crm-module`) checks
|
||||
- Module descriptor (`src/core/modules/mod*.class.php`) exists
|
||||
- `$this->numero` is set and non-zero
|
||||
- `$this->version` is not hardcoded
|
||||
- `url_last_version` points to `update.txt` (not `update.json`)
|
||||
- `url_last_version` references `/main/` on main branch
|
||||
- `src/README.md` exists (module store requirement)
|
||||
- `update.txt` exists in root
|
||||
|
||||
### Joomla (`waas-component`) checks
|
||||
- XML manifest with `<extension>` tag exists
|
||||
- `<version>`, `<name>`, `<author>`, `<namespace>` tags present
|
||||
- Extension `type` attribute is valid
|
||||
- Language `.ini` files exist
|
||||
- `updates.xml` exists in root
|
||||
- `index.html` directory listing protection in `src/`, `src/admin/`, `src/site/`
|
||||
|
||||
---
|
||||
|
||||
## composer-validate.yml (MokoStandards only)
|
||||
|
||||
**Trigger:** Every push and PR
|
||||
|
||||
**What it does:** Validates the `composer.json` integrity for the MokoStandards enterprise library:
|
||||
- Schema validation (`composer validate --strict`)
|
||||
- Lock file freshness
|
||||
- Dependency resolution (dry run)
|
||||
- Security advisories (`composer audit`)
|
||||
- Version consistency: `composer.json` version = `README.md` VERSION = `STANDARDS_VERSION` in `RepositorySynchronizer.php`
|
||||
- All autoload paths (PSR-4, classmap, files) exist on disk
|
||||
- All bin scripts exist
|
||||
- Enterprise dep constraint uses `dev-version/XX` pattern (not `dev-main`)
|
||||
|
||||
> **Note:** Governed repos can manually set `dev-main` for bleeding-edge installs, but the sync system always corrects this to `dev-version/XX` on the next sync run.
|
||||
|
||||
---
|
||||
|
||||
## Composer Enterprise Dependency
|
||||
|
||||
On every sync, the `RepositorySynchronizer` checks if the remote `composer.json` requires `mokoconsulting-tech/enterprise`. If missing or stale (`dev-main`), it adds/updates it to `"dev-version/XX"` — always pinned to the current version branch, never bleeding-edge main.
|
||||
|
||||
Governed repos can manually override to `dev-main` for bleeding-edge testing, but this will be corrected on the next sync.
|
||||
@@ -0,0 +1,588 @@
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Standards Compliance Workflow
|
||||
|
||||
**Workflow**: `standards-compliance.yml`
|
||||
**Status**: Active | **Version**: 04.00.04 | **Last Updated**: 2026-02-21
|
||||
|
||||
## Overview
|
||||
|
||||
The Standards Compliance workflow is a comprehensive validation system that ensures repositories meet MokoStandards requirements across multiple dimensions including structure, documentation quality, coding standards, security, and maintainability.
|
||||
|
||||
## Purpose
|
||||
|
||||
- **Enforce Standards**: Automatically validate compliance with MokoStandards policies
|
||||
- **Quality Assurance**: Ensure consistent quality across all organization repositories
|
||||
- **Early Detection**: Catch compliance issues before merge
|
||||
- **Actionable Feedback**: Provide clear remediation steps for any violations
|
||||
- **Comprehensive Reporting**: Generate detailed compliance reports with scores
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev/**
|
||||
- rc/**
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev/**
|
||||
- rc/**
|
||||
workflow_dispatch:
|
||||
```
|
||||
|
||||
**Runs on**:
|
||||
- Every push to main, dev/*, or rc/* branches
|
||||
- Every pull request targeting main, dev/*, or rc/*
|
||||
- Manual trigger via GitHub Actions UI
|
||||
|
||||
## Validation Areas
|
||||
|
||||
The workflow performs 10 comprehensive validation checks organized into two categories:
|
||||
|
||||
### Critical Checks (Must Pass)
|
||||
|
||||
These checks are **blocking** - the workflow will fail if any critical check fails:
|
||||
|
||||
| Check | Description | Validator | Priority |
|
||||
|-------|-------------|-----------|----------|
|
||||
| 📁 **Repository Structure** | Validates required directories and files exist | Built-in shell | 🔴 Critical |
|
||||
| 📚 **Documentation Quality** | Analyzes README, checks documentation completeness | Built-in shell | 🔴 Critical |
|
||||
| 💻 **Coding Standards** | Runs language-specific linters (Python, PHP, YAML) | yamllint, black, pylint, phpcs | 🔴 Critical |
|
||||
| ⚖️ **License Compliance** | Validates license file and SPDX identifiers | Built-in shell | 🔴 Critical |
|
||||
| 🧹 **Git Repository Hygiene** | Checks commit messages, branch naming, .gitignore | Built-in shell | 🔴 Critical |
|
||||
| ⚙️ **Workflow Configuration** | Validates GitHub Actions workflow files | actionlint, custom checks | 🔴 Critical |
|
||||
| 🔢 **Version Consistency** | Ensures all version numbers match across repository | check_version_consistency.php | 🔴 Critical |
|
||||
| 🔐 **Script Integrity** | Validates SHA-256 hashes of critical scripts | validate_script_registry.py | 🔴 Critical |
|
||||
|
||||
### Informational Checks (Non-Blocking)
|
||||
|
||||
These checks provide **recommendations** but don't fail the workflow:
|
||||
|
||||
| Check | Description | Validator | Priority |
|
||||
|-------|-------------|-----------|----------|
|
||||
| 🏢 **Enterprise Readiness** | Assesses enterprise-grade features and patterns | check_enterprise_readiness.php | ℹ️ Info |
|
||||
| 🏥 **Repository Health** | Evaluates overall repository quality metrics | check_repo_health.php | ℹ️ Info |
|
||||
|
||||
## Detailed Check Descriptions
|
||||
|
||||
### 1. Repository Structure Validation
|
||||
|
||||
**What it checks**:
|
||||
- Required directories: `docs/`, `scripts/`, `.github/`
|
||||
- Required files: `README.md`, `LICENSE`, `CONTRIBUTING.md`, `SECURITY.md`, `CHANGELOG.md`, `.editorconfig`
|
||||
- File size and completeness validation
|
||||
|
||||
**Compliance Requirements**:
|
||||
- All required directories must exist
|
||||
- All required files must be present
|
||||
- README must be at least 500 bytes
|
||||
- LICENSE must be at least 100 bytes
|
||||
|
||||
**Remediation**:
|
||||
```bash
|
||||
# Create missing directories
|
||||
mkdir -p docs scripts .github/workflows
|
||||
|
||||
# Create required files from templates
|
||||
cp templates/docs/required/README.md ./
|
||||
cp templates/docs/required/CONTRIBUTING.md ./
|
||||
cp templates/docs/required/SECURITY.md ./
|
||||
```
|
||||
|
||||
### 2. Documentation Quality Check
|
||||
|
||||
**What it checks**:
|
||||
- README.md metrics (size, lines, words, headings, links, code blocks)
|
||||
- Documentation completeness
|
||||
- Content quality indicators
|
||||
|
||||
**Compliance Requirements**:
|
||||
- README minimum 500 bytes, 20 lines, 100 words
|
||||
- At least 3 headings for structure
|
||||
- Include links and code examples
|
||||
|
||||
**Scoring**:
|
||||
- Size: 500+ bytes (good), <500 (warning), >50KB (warning - too long)
|
||||
- Headings: 3+ (good), <3 (warning)
|
||||
- Links: 1+ (good), 0 (info - consider adding)
|
||||
- Code blocks: 1+ (good), 0 (info - consider adding)
|
||||
|
||||
### 3. Coding Standards Validation
|
||||
|
||||
**What it checks**:
|
||||
- YAML files: Validates syntax and formatting with `yamllint`
|
||||
- Python files: Code formatting with `black`, linting with `pylint`
|
||||
- PHP files: Coding standards with `phpcs` (PSR-12)
|
||||
|
||||
**Compliance Requirements**:
|
||||
- All YAML files must be valid and properly formatted
|
||||
- Python code must follow Black formatting
|
||||
- PHP code must follow PSR-12 standards
|
||||
|
||||
**Remediation**:
|
||||
```bash
|
||||
# Fix YAML formatting
|
||||
yamllint --format auto .github/workflows/*.yml
|
||||
|
||||
# Fix Python formatting
|
||||
black scripts/**/*.py
|
||||
|
||||
# Fix PHP code style
|
||||
phpcs --standard=PSR12 src/
|
||||
```
|
||||
|
||||
### 4. License Compliance
|
||||
|
||||
**What it checks**:
|
||||
- LICENSE file exists
|
||||
- File headers contain copyright and SPDX identifiers
|
||||
- Consistent licensing across repository
|
||||
|
||||
**Compliance Requirements**:
|
||||
- LICENSE file present at repository root
|
||||
- All source files include copyright header
|
||||
- SPDX-License-Identifier present in headers
|
||||
|
||||
**Example Header**:
|
||||
```php
|
||||
<?php
|
||||
// Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
```
|
||||
|
||||
### 5. Git Repository Hygiene
|
||||
|
||||
**What it checks**:
|
||||
- Commit message format
|
||||
- Branch naming conventions
|
||||
- .gitignore completeness
|
||||
- No sensitive files in repository
|
||||
|
||||
**Compliance Requirements**:
|
||||
- Conventional commit messages
|
||||
- Branch names follow pattern: `feature/*`, `bugfix/*`, `hotfix/*`, `release/*`
|
||||
- Comprehensive .gitignore file
|
||||
|
||||
### 6. Workflow Configuration Validation
|
||||
|
||||
**What it checks**:
|
||||
- Valid YAML syntax in workflow files
|
||||
- Required workflows present
|
||||
- CodeQL configuration if applicable
|
||||
- Action version pinning for security
|
||||
|
||||
**Compliance Requirements**:
|
||||
- All workflows have valid YAML syntax
|
||||
- Actions pinned to commit hashes for security
|
||||
- Proper permissions configured
|
||||
|
||||
### 7. Version Consistency Check ⭐ NEW
|
||||
|
||||
**What it checks**:
|
||||
- All version references match the canonical version in `composer.json`
|
||||
- Checks 39+ files including:
|
||||
- Documentation (README.md, CHANGELOG.md, CONTRIBUTING.md)
|
||||
- Workflows (.github/workflows/*.yml)
|
||||
- PHP source files (src/**/*.php)
|
||||
- Configuration files
|
||||
|
||||
**Compliance Requirements**:
|
||||
- Single source of truth: version in `composer.json`
|
||||
- All references must match exactly
|
||||
- No version drift across repository
|
||||
|
||||
**Validator**: `api/validate/check_version_consistency.php`
|
||||
|
||||
**Remediation**:
|
||||
```bash
|
||||
# Check current status
|
||||
php api/validate/check_version_consistency.php --verbose
|
||||
|
||||
# Update all version references (if mismatches found)
|
||||
# Manually update files or use bulk search/replace
|
||||
```
|
||||
|
||||
### 8. Script Integrity Validation ⭐ NEW
|
||||
|
||||
**What it checks**:
|
||||
- SHA-256 hashes of critical scripts match registry
|
||||
- No unauthorized modifications to security-critical scripts
|
||||
- Registry file (scripts/.script-registry.json) is up-to-date
|
||||
|
||||
**Compliance Requirements**:
|
||||
- All scripts in registry must have valid SHA-256 hashes
|
||||
- Critical priority scripts cannot have mismatches
|
||||
- Changes to scripts must update registry
|
||||
|
||||
**Validator**: `api/maintenance/validate_script_registry.py`
|
||||
|
||||
**Remediation**:
|
||||
```bash
|
||||
# Validate current hashes
|
||||
python3 api/maintenance/validate_script_registry.py --priority critical
|
||||
|
||||
# Update registry after legitimate changes
|
||||
python3 api/maintenance/generate_script_registry.py --update
|
||||
|
||||
# Or use auto-update workflow
|
||||
# .github/workflows/auto-update-sha.yml
|
||||
```
|
||||
|
||||
### 9. Enterprise Readiness Check ⭐ NEW (Informational)
|
||||
|
||||
**What it checks**:
|
||||
- Enterprise-grade features implementation
|
||||
- Security best practices
|
||||
- Scalability patterns
|
||||
- Error handling and logging
|
||||
- Transaction management
|
||||
- API design patterns
|
||||
|
||||
**Assessment Areas**:
|
||||
- Architecture patterns
|
||||
- Error recovery mechanisms
|
||||
- Monitoring and observability
|
||||
- Documentation completeness
|
||||
- Test coverage
|
||||
- Security controls
|
||||
|
||||
**Validator**: `api/validate/check_enterprise_readiness.php`
|
||||
|
||||
**Note**: This check is **informational only** and does not block merges. It provides recommendations for improving enterprise readiness.
|
||||
|
||||
### 10. Repository Health Check ⭐ NEW (Informational)
|
||||
|
||||
**What it checks**:
|
||||
- Code quality metrics
|
||||
- Technical debt indicators
|
||||
- Dependency health
|
||||
- Documentation coverage
|
||||
- Test coverage
|
||||
- Issue/PR activity
|
||||
|
||||
**Health Metrics**:
|
||||
- File structure organization
|
||||
- Code duplication
|
||||
- Dependency freshness
|
||||
- Security vulnerabilities
|
||||
- Community engagement
|
||||
|
||||
**Validator**: `api/validate/check_repo_health.php`
|
||||
|
||||
**Note**: This check is **informational only** and does not block merges. It provides insights for continuous improvement.
|
||||
|
||||
## Compliance Scoring
|
||||
|
||||
The workflow calculates a compliance percentage based on critical checks:
|
||||
|
||||
```
|
||||
Compliance % = (Critical Checks Passed / Total Critical Checks) × 100
|
||||
```
|
||||
|
||||
### Score Interpretation
|
||||
|
||||
| Score | Status | Description |
|
||||
|-------|--------|-------------|
|
||||
| 100% | ✅ **COMPLIANT** | All critical checks passed - repository fully compliant |
|
||||
| 80-99% | ⚠️ **MOSTLY COMPLIANT** | Most checks passed - minor issues to address |
|
||||
| 50-79% | ⚠️ **PARTIALLY COMPLIANT** | Significant issues - requires attention |
|
||||
| 0-49% | ❌ **NON-COMPLIANT** | Major compliance violations - immediate action required |
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
## ✅ Overall Status: COMPLIANT (100%)
|
||||
|
||||
**Critical Checks:** 8/8 passed
|
||||
**Total Checks:** 10/10 passed
|
||||
**Informational:** 0 warning(s)
|
||||
|
||||
████████████████████ 100%
|
||||
|
||||
## Validation Results
|
||||
|
||||
| Area | Status | Result | Priority |
|
||||
|-----------------------------|---------|------------|-------------|
|
||||
| 📁 Repository Structure | ✅ Pass | Compliant | - |
|
||||
| 📚 Documentation Quality | ✅ Pass | Compliant | - |
|
||||
| 💻 Coding Standards | ✅ Pass | Compliant | - |
|
||||
| ⚖️ License Compliance | ✅ Pass | Compliant | - |
|
||||
| 🧹 Git Repository Hygiene | ✅ Pass | Compliant | - |
|
||||
| ⚙️ Workflow Configuration | ✅ Pass | Compliant | - |
|
||||
| 🔢 Version Consistency | ✅ Pass | All versions match | - |
|
||||
| 🔐 Script Integrity | ✅ Pass | SHA hashes validated | - |
|
||||
| 🏢 Enterprise Readiness | ✅ Pass | Ready for enterprise | ℹ️ Info |
|
||||
| 🏥 Repository Health | ✅ Pass | Health check passed | ℹ️ Info |
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Running Manually
|
||||
|
||||
```bash
|
||||
# Trigger workflow manually via GitHub Actions UI
|
||||
# Go to: Actions → Standards Compliance → Run workflow
|
||||
|
||||
# Or use GitHub CLI
|
||||
gh workflow run standards-compliance.yml
|
||||
```
|
||||
|
||||
### Local Validation
|
||||
|
||||
Run individual validators locally before pushing:
|
||||
|
||||
```bash
|
||||
# Check version consistency
|
||||
php api/validate/check_version_consistency.php --verbose
|
||||
|
||||
# Validate script integrity
|
||||
python3 api/maintenance/validate_script_registry.py --priority critical --verbose
|
||||
|
||||
# Check enterprise readiness
|
||||
php api/validate/check_enterprise_readiness.php --verbose
|
||||
|
||||
# Check repository health
|
||||
php api/validate/check_repo_health.php --verbose
|
||||
|
||||
# Lint YAML files
|
||||
yamllint .github/workflows/*.yml
|
||||
|
||||
# Format Python code
|
||||
black --check scripts/**/*.py
|
||||
|
||||
# Check PHP code style
|
||||
phpcs --standard=PSR12 src/
|
||||
```
|
||||
|
||||
### Fixing Common Issues
|
||||
|
||||
#### Version Mismatches
|
||||
|
||||
```bash
|
||||
# 1. Identify current version
|
||||
grep '"version"' composer.json
|
||||
|
||||
# 2. Find mismatches
|
||||
php api/validate/check_version_consistency.php
|
||||
|
||||
# 3. Update all references to match
|
||||
# Use sed or manually update files listed in output
|
||||
```
|
||||
|
||||
#### Script Integrity Violations
|
||||
|
||||
```bash
|
||||
# If changes are legitimate:
|
||||
python3 api/maintenance/generate_script_registry.py --update
|
||||
|
||||
# If changes are NOT authorized:
|
||||
git checkout HEAD -- scripts/
|
||||
```
|
||||
|
||||
#### Coding Standard Violations
|
||||
|
||||
```bash
|
||||
# Auto-fix Python formatting
|
||||
black scripts/**/*.py
|
||||
|
||||
# Auto-fix PHP code style
|
||||
phpcbf --standard=PSR12 src/
|
||||
|
||||
# Fix YAML issues
|
||||
# Manual fixes required based on yamllint output
|
||||
```
|
||||
|
||||
## Integration with Pull Requests
|
||||
|
||||
The workflow automatically:
|
||||
|
||||
1. **Runs on every PR** to main, dev/*, or rc/* branches
|
||||
2. **Posts results** in the PR checks section
|
||||
3. **Provides detailed summary** in the workflow run
|
||||
4. **Blocks merge** if critical checks fail
|
||||
5. **Offers remediation steps** for any violations
|
||||
|
||||
### PR Status Checks
|
||||
|
||||
| Check Result | PR Status | Merge Allowed |
|
||||
|--------------|-----------|---------------|
|
||||
| All critical checks pass | ✅ Success | Yes |
|
||||
| Any critical check fails | ❌ Failure | No (blocked) |
|
||||
| Only informational warnings | ✅ Success | Yes |
|
||||
|
||||
## Workflow Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ PARALLEL VALIDATION CHECKS │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├─────────────┬──────────────┬──────────────┬────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐
|
||||
│Repository │File Header │Code Style│ │ Docs │ │ License │
|
||||
│Structure│ │ Validation│ │ Check │ │ Check │ │ Check │
|
||||
└─────────┘ └──────────┘ └──────────┘ └─────────┘ └──────────┘
|
||||
│ │ │ │ │
|
||||
├─────────────┼──────────────┼──────────────┼────────────┤
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐
|
||||
│ Git │ │ Workflow │ │ Version │ │ Script │ │Enterprise│
|
||||
│ Hygiene │ │ Config │ │Consistency│ │Integrity│ │Readiness │
|
||||
└─────────┘ └──────────┘ └──────────┘ └─────────┘ └──────────┘
|
||||
│ │ │ │ │
|
||||
└─────────────┴──────────────┴──────────────┴────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ All Checks Pass?│
|
||||
└──────────────────┘
|
||||
│ │
|
||||
YES │ │ NO
|
||||
▼ ▼
|
||||
┌──────────┐ ┌──────────────┐
|
||||
│ SUCCESS │ │ CREATE ISSUE │
|
||||
│ Summary │ │ with Failure │
|
||||
└──────────┘ │ Details │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Adjusting Severity
|
||||
|
||||
To change a critical check to informational (non-blocking):
|
||||
|
||||
```yaml
|
||||
# In the summary job, change from:
|
||||
[ "$CHECK_STATUS" = "success" ] && PASSED=$((PASSED + 1)) || FAILED=$((FAILED + 1))
|
||||
|
||||
# To:
|
||||
if [ "$CHECK_STATUS" = "success" ]; then
|
||||
PASSED=$((PASSED + 1))
|
||||
else
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
fi
|
||||
```
|
||||
|
||||
### Adding Custom Checks
|
||||
|
||||
Add a new validation job:
|
||||
|
||||
```yaml
|
||||
custom-check:
|
||||
name: Custom Validation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run Custom Validator
|
||||
run: |
|
||||
./scripts/custom-validator.sh
|
||||
```
|
||||
|
||||
Then add it to the summary `needs` array.
|
||||
|
||||
### Skipping Checks
|
||||
|
||||
To skip a check temporarily, add to job:
|
||||
|
||||
```yaml
|
||||
if: false # Skip this check
|
||||
```
|
||||
|
||||
Or make conditional:
|
||||
|
||||
```yaml
|
||||
if: ${{ github.event_name != 'pull_request' }} # Skip on PRs
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Workflow Fails Unexpectedly
|
||||
|
||||
**Check**:
|
||||
1. Review workflow run logs in GitHub Actions
|
||||
2. Look for specific error messages in failed jobs
|
||||
3. Check if required scripts exist (new checks depend on PHP/Python scripts)
|
||||
|
||||
**Common Issues**:
|
||||
- Missing validator scripts (version/enterprise/health checks)
|
||||
- PHP/Python not available in runner
|
||||
- Permissions issues with files
|
||||
|
||||
### Version Consistency Always Fails
|
||||
|
||||
**Cause**: Multiple version references across repository don't match
|
||||
|
||||
**Fix**:
|
||||
1. Identify canonical version: `grep '"version"' composer.json`
|
||||
2. Find mismatches: `php api/validate/check_version_consistency.php`
|
||||
3. Update all references to match canonical version
|
||||
|
||||
### Script Integrity Violations
|
||||
|
||||
**Legitimate Changes**:
|
||||
```bash
|
||||
# Update registry after modifying scripts
|
||||
python3 api/maintenance/generate_script_registry.py --update
|
||||
git add scripts/.script-registry.json
|
||||
git commit -m "chore: update script registry"
|
||||
```
|
||||
|
||||
**Unauthorized Changes**:
|
||||
```bash
|
||||
# Restore original scripts
|
||||
git checkout HEAD -- scripts/
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Workflow Architecture](./workflow-architecture.md)
|
||||
- [Workflow Inventory](./workflow-inventory.md)
|
||||
- [Repository Structure Standards](../policy/core-structure.md)
|
||||
- [Coding Style Guide](../policy/coding-style-guide.md)
|
||||
- [File Header Standards](../policy/file-header-standards.md)
|
||||
- [License Compliance Policy](../policy/license-compliance.md)
|
||||
- [Version Management](../guide/version-badge-guide.md)
|
||||
- [Script Integrity Guide](../guide/script-integrity-validation.md)
|
||||
|
||||
## Changelog
|
||||
|
||||
### v04.00.04 (2026-02-21)
|
||||
|
||||
**Added**:
|
||||
- ✨ Version Consistency Check - Validates all version numbers match
|
||||
- ✨ Script Integrity Validation - Verifies SHA-256 hashes
|
||||
- ✨ Enterprise Readiness Check - Assesses enterprise patterns (informational)
|
||||
- ✨ Repository Health Check - Evaluates overall quality (informational)
|
||||
|
||||
**Changed**:
|
||||
- 📊 Enhanced compliance scoring with critical vs informational distinction
|
||||
- 📊 Improved summary reporting with detailed breakdowns
|
||||
- 📊 Total validation checks increased from 6 to 10
|
||||
|
||||
**Fixed**:
|
||||
- 🐛 Compliance percentage now correctly calculates based on critical checks only
|
||||
|
||||
### v04.00.04 (2026-01-07)
|
||||
|
||||
**Added**:
|
||||
- Initial comprehensive standards compliance workflow
|
||||
- Repository structure validation
|
||||
- Documentation quality checks
|
||||
- Coding standards enforcement
|
||||
- License compliance validation
|
||||
- Git hygiene checks
|
||||
- Workflow configuration validation
|
||||
|
||||
---
|
||||
|
||||
**Maintained by**: MokoStandards Team
|
||||
**Last Review**: 2026-02-21
|
||||
**Next Review**: 2026-03-21
|
||||
@@ -0,0 +1,219 @@
|
||||
# Sub-Issue Management Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Sub-issues (also called sub-tasks) are a way to break down complex parent issues into smaller, manageable pieces of work. This guide explains how to create and manage sub-issues in the MokoStandards repository.
|
||||
|
||||
## When to Use Sub-Issues
|
||||
|
||||
Use sub-issues when:
|
||||
|
||||
- A parent issue is too large to tackle in one PR
|
||||
- Multiple people need to work on different aspects of an issue
|
||||
- You want to track progress on specific components of a larger task
|
||||
- An issue requires multiple sequential steps that should be tracked separately
|
||||
|
||||
## Creating Sub-Issues
|
||||
|
||||
### Method 1: Using the Issue Template (Manual)
|
||||
|
||||
1. Go to the [New Issue page](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/issues/new/choose)
|
||||
2. Select the "Sub-Task" template
|
||||
3. Fill in the required fields:
|
||||
- **Parent Issue**: The issue number this sub-task belongs to (e.g., #193)
|
||||
- **Task Title**: A brief, descriptive title
|
||||
- **Task Description**: Detailed description of the work
|
||||
- **Task Type**: Investigation, Bug Fix, Feature Implementation, etc.
|
||||
- **Priority**: Low, Medium, High, or Critical
|
||||
4. Optionally add:
|
||||
- Acceptance criteria (checklist format)
|
||||
- Dependencies on other issues
|
||||
- Additional notes or context
|
||||
5. Submit the issue
|
||||
|
||||
### Method 2: Using the Automated Workflow
|
||||
|
||||
For programmatic sub-issue creation:
|
||||
|
||||
1. Go to **Actions** → **Create Sub-Issue**
|
||||
2. Click "Run workflow"
|
||||
3. Fill in the workflow inputs:
|
||||
- **Parent issue**: The parent issue number (e.g., 193)
|
||||
- **Title**: Sub-issue title
|
||||
- **Description**: Detailed description
|
||||
- **Task type**: Choose from dropdown
|
||||
- **Priority**: Choose from dropdown
|
||||
- **Assignees**: Comma-separated GitHub usernames (optional)
|
||||
- **Labels**: Additional labels, comma-separated (optional)
|
||||
4. Click "Run workflow"
|
||||
|
||||
The workflow will:
|
||||
- Validate the parent issue exists
|
||||
- Create the sub-issue with appropriate labels
|
||||
- Link it to the parent issue
|
||||
- Add a comment to the parent issue
|
||||
- Validate all assignees before assignment
|
||||
|
||||
## Sub-Issue Best Practices
|
||||
|
||||
### Naming Convention
|
||||
|
||||
Use clear, action-oriented titles:
|
||||
|
||||
- ✅ Good: `[Task] Investigate GH_TOKEN permissions`
|
||||
- ✅ Good: `[Task] Update documentation for bulk sync process`
|
||||
- ❌ Bad: `Token stuff`
|
||||
- ❌ Bad: `Fix #193`
|
||||
|
||||
### Description Guidelines
|
||||
|
||||
Include:
|
||||
- Clear description of what needs to be done
|
||||
- Why this work is necessary
|
||||
- Any relevant context or background
|
||||
- Links to related issues, PRs, or documentation
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
Use checkboxes to define when the sub-task is complete:
|
||||
|
||||
```markdown
|
||||
- [ ] All token permissions verified
|
||||
- [ ] Documentation updated with findings
|
||||
- [ ] Changes tested in staging environment
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Sub-issues automatically receive the `sub-task` label. Add additional labels as appropriate:
|
||||
|
||||
- Priority labels: `priority/low`, `priority/medium`, `priority/high`, `priority/critical`
|
||||
- Type labels: `bug`, `enhancement`, `documentation`
|
||||
- Component labels: `automation`, `infrastructure`, `security`
|
||||
|
||||
### Linking to Parent Issues
|
||||
|
||||
Always reference the parent issue in the sub-issue description:
|
||||
|
||||
```markdown
|
||||
**Parent Issue**: #193 - Bulk Repository Sync Failed
|
||||
```
|
||||
|
||||
The automated workflow does this automatically.
|
||||
|
||||
## Tracking Progress
|
||||
|
||||
### In the Sub-Issue
|
||||
|
||||
Use the progress checklist in the sub-issue body to track completion:
|
||||
|
||||
```markdown
|
||||
### Progress Tracking
|
||||
- [x] Task started
|
||||
- [x] Implementation complete
|
||||
- [x] Tests passing
|
||||
- [ ] Documentation updated
|
||||
- [ ] Code review complete
|
||||
- [ ] Ready to close
|
||||
```
|
||||
|
||||
### In the Parent Issue
|
||||
|
||||
Add a section to the parent issue to track all sub-issues:
|
||||
|
||||
```markdown
|
||||
## Sub-Issues
|
||||
|
||||
- [ ] #194 - Investigate GH_TOKEN permissions
|
||||
- [x] #195 - Update bulk sync documentation
|
||||
- [ ] #196 - Add retry logic to sync script
|
||||
```
|
||||
|
||||
Update this as sub-issues are completed.
|
||||
|
||||
## Example: Creating Sub-Issues for Issue #193
|
||||
|
||||
For issue #193 (Bulk Repository Sync Failed), you might create these sub-issues:
|
||||
|
||||
1. **Investigation**: `[Task] Investigate GH_TOKEN permissions and scopes`
|
||||
2. **Bug Fix**: `[Task] Add retry logic for transient network failures`
|
||||
3. **Documentation**: `[Task] Document troubleshooting steps for sync failures`
|
||||
4. **Testing**: `[Task] Test bulk sync with different repository configurations`
|
||||
|
||||
Each sub-issue would:
|
||||
- Reference #193 as the parent
|
||||
- Have a clear, specific scope
|
||||
- Include acceptance criteria
|
||||
- Be assigned to the appropriate team member
|
||||
|
||||
## Configuration
|
||||
|
||||
Sub-issue behavior is controlled by `.github/issue-management-config.yml`:
|
||||
|
||||
```yaml
|
||||
# Sub-Issue Management
|
||||
sub_issues:
|
||||
enabled: true
|
||||
|
||||
# Automatically create sub-issues for
|
||||
auto_create_for:
|
||||
- prs: true
|
||||
- tasks: false
|
||||
|
||||
# Sub-issue naming
|
||||
naming:
|
||||
pr_prefix: "[PR]"
|
||||
task_prefix: "[Task]"
|
||||
|
||||
# Progress tracking
|
||||
progress:
|
||||
update_parent: true
|
||||
show_percentage: true
|
||||
show_checklist: true
|
||||
```
|
||||
|
||||
## Closing Sub-Issues
|
||||
|
||||
Close a sub-issue when:
|
||||
- All acceptance criteria are met
|
||||
- The work has been reviewed and approved
|
||||
- Any related PRs have been merged
|
||||
- The parent issue acknowledges completion
|
||||
|
||||
Add a closing comment explaining what was accomplished:
|
||||
|
||||
```markdown
|
||||
Closing this sub-issue. All acceptance criteria met:
|
||||
- Token permissions verified and documented
|
||||
- Updated documentation with findings
|
||||
- Changes tested and working
|
||||
|
||||
See PR #XXX for implementation details.
|
||||
```
|
||||
|
||||
## Automation
|
||||
|
||||
The Create Sub-Issue workflow provides automation for:
|
||||
|
||||
- **Validation**: Ensures parent issue exists before creating sub-issue
|
||||
- **Linking**: Automatically links sub-issue to parent with comments
|
||||
- **Assignee validation**: Verifies assignees are valid GitHub users
|
||||
- **Label management**: Applies appropriate labels based on inputs
|
||||
- **Summary generation**: Provides clear summary of created sub-issue
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Issue Management Configuration](.github/issue-management-config.yml)
|
||||
- [Sub-Task Template](.github/ISSUE_TEMPLATE/sub-task.yml)
|
||||
- [Create Sub-Issue Workflow](.github/workflows/create-sub-issue.yml)
|
||||
- [GitHub Issues Documentation](https://docs.github.com/en/issues)
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues with sub-issue creation:
|
||||
|
||||
1. Check that the parent issue number is correct
|
||||
2. Verify you have permission to create issues
|
||||
3. Ensure assignees are valid GitHub usernames
|
||||
4. Review the workflow run logs for error details
|
||||
5. Open a bug report if the issue persists
|
||||
@@ -0,0 +1,333 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/update-server.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: How update files (update.txt and updates.xml) are generated per platform
|
||||
-->
|
||||
|
||||
# Update Server Files
|
||||
|
||||
MokoStandards automatically generates platform-specific update server files on every release and dev/alpha/beta/rc deployment.
|
||||
|
||||
## Overview
|
||||
|
||||
| Platform | File | Format | Reference |
|
||||
|----------|------|--------|-----------|
|
||||
| Dolibarr (`crm-module`) | `update.txt` | Plain text version string (< 30 chars) | Dolibarr `url_last_version` check |
|
||||
| Joomla (`waas-component`) | `updates.xml` | Multi-entry XML following Joomla update server spec | [Joomla Update Server Docs](https://docs.joomla.org/Deploying_an_Update_Server) |
|
||||
|
||||
## Stability Tags
|
||||
|
||||
Joomla's `updates.xml` contains **multiple `<update>` entries simultaneously** — one per stability level. Joomla filters which entries the admin sees based on the site's **Minimum Stability** setting (Extensions > Update > Options).
|
||||
|
||||
| Stability | Joomla `<tag>` | Who sees it | Source workflow |
|
||||
|-----------|---------------|-------------|----------------|
|
||||
| Stable | `<tag>stable</tag>` | All sites (default) | `auto-release.yml` on `main` |
|
||||
| Release Candidate | `<tag>rc</tag>` | Sites set to RC or lower | `update-server.yml` on `rc/**` push |
|
||||
| Beta | `<tag>beta</tag>` | Sites set to Beta or lower | `update-server.yml` on `beta/**` push |
|
||||
| Alpha | `<tag>alpha</tag>` | Sites set to Alpha or lower | `update-server.yml` on `alpha/**` push |
|
||||
| Development | `<tag>development</tag>` | Sites set to Development | `update-server.yml` on `dev/**` push |
|
||||
|
||||
**Note**: Alpha and beta are optional stages. Not every release cycle will have alpha/beta entries.
|
||||
|
||||
### How Joomla Filters Updates
|
||||
|
||||
Joomla's update system reads all `<update>` entries from the XML file but only presents entries whose `<tag>` matches the site's minimum stability threshold:
|
||||
|
||||
- **Minimum Stability = Stable** (default): Only sees `<tag>stable</tag>` entries
|
||||
- **Minimum Stability = RC**: Sees `stable` + `rc` entries
|
||||
- **Minimum Stability = Beta**: Sees `stable` + `rc` + `beta` entries
|
||||
- **Minimum Stability = Alpha**: Sees `stable` + `rc` + `beta` + `alpha` entries
|
||||
- **Minimum Stability = Development**: Sees all entries (`stable` + `rc` + `beta` + `alpha` + `development`)
|
||||
|
||||
The admin always gets the **highest version** among visible entries.
|
||||
|
||||
### Dolibarr Stability
|
||||
|
||||
| Workflow | Branch | `update.txt` content |
|
||||
|----------|--------|---------------------|
|
||||
| `auto-release.yml` | `main` | `XX.YY.ZZ` (real version) |
|
||||
| `deploy-dev.yml` | `rc/**` | `XX.YY.ZZ-rc` |
|
||||
| `deploy-dev.yml` | `beta/**` | `XX.YY.ZZ-beta` |
|
||||
| `deploy-dev.yml` | `alpha/**` | `XX.YY.ZZ-alpha` |
|
||||
| `deploy-dev.yml` | `dev/**` | `development` |
|
||||
|
||||
### Branch Lifecycle
|
||||
|
||||
```
|
||||
dev → [alpha] → [beta] → rc → version/XX → main → dev
|
||||
optional optional (integration) (production) (feedback)
|
||||
```
|
||||
|
||||
- **`dev/**`**: Active development. Update files tagged as `development`.
|
||||
- **`alpha/**`**: *(Optional)* Early internal testing. Update files tagged as `alpha`. Can be skipped.
|
||||
- **`beta/**`**: *(Optional)* Broader external testing. Update files tagged as `beta`. Can be skipped.
|
||||
- **`rc/**`**: Release candidate. Update files tagged as `rc`. RC branches deploy to dev server for final testing.
|
||||
- **`version/XX`**: Major version integration branch (major only). All minors and patches flow into the same major branch.
|
||||
- **`main`**: Stable release. `auto-release.yml` creates GitHub Release and `vXX` tag. Update files tagged as `stable`.
|
||||
- **Main merges back to `dev`** to start the next cycle.
|
||||
|
||||
## Dolibarr: `update.txt`
|
||||
|
||||
Dolibarr modules check for updates by fetching a plain-text file from the URL in `$this->url_last_version`. The file must contain only the version string (e.g., `01.02.03`) — no JSON, no XML, no newlines.
|
||||
|
||||
**On release (main):**
|
||||
```
|
||||
01.02.03
|
||||
```
|
||||
|
||||
**On RC deploy (rc/**):**
|
||||
```
|
||||
01.02.03-rc
|
||||
```
|
||||
|
||||
**On dev deploy (dev/**):**
|
||||
```
|
||||
development
|
||||
```
|
||||
|
||||
The module descriptor's `url_last_version` should point to:
|
||||
```
|
||||
https://raw.githubusercontent.com/{org}/{repo}/main/update.txt
|
||||
```
|
||||
|
||||
## Joomla: `updates.xml` (Multi-Entry)
|
||||
|
||||
The `updates.xml` file contains **up to five stability entries at once** (one per stability level). Joomla reads the entire file and filters by the site's minimum stability setting.
|
||||
|
||||
### Complete Multi-Entry Example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<updates>
|
||||
<!-- Stable entry: visible to all sites (default minimum stability) -->
|
||||
<update>
|
||||
<name>My Extension</name>
|
||||
<description>My Extension stable release</description>
|
||||
<element>com_myextension</element>
|
||||
<type>component</type>
|
||||
<version>01.02.03</version>
|
||||
<client>site</client>
|
||||
<tags>
|
||||
<tag>stable</tag>
|
||||
</tags>
|
||||
<infourl title="My Extension">https://github.com/org/repo/releases/tag/v01</infourl>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">https://github.com/org/repo/releases/download/v01/com_myextension-01.02.03.zip</downloadurl>
|
||||
</downloads>
|
||||
<sha256>abc123...full-hash-here</sha256>
|
||||
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||
</update>
|
||||
|
||||
<!-- RC entry: visible to sites with minimum stability = RC or lower -->
|
||||
<update>
|
||||
<name>My Extension</name>
|
||||
<description>My Extension release candidate</description>
|
||||
<element>com_myextension</element>
|
||||
<type>component</type>
|
||||
<version>01.03.01-rc</version>
|
||||
<client>site</client>
|
||||
<tags>
|
||||
<tag>rc</tag>
|
||||
</tags>
|
||||
<infourl title="My Extension">https://github.com/org/repo/tree/rc/01.03.01</infourl>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/rc/01.03.01.zip</downloadurl>
|
||||
</downloads>
|
||||
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||
</update>
|
||||
|
||||
<!-- Beta entry: visible to sites with minimum stability = Beta or lower -->
|
||||
<update>
|
||||
<name>My Extension</name>
|
||||
<description>My Extension beta build</description>
|
||||
<element>com_myextension</element>
|
||||
<type>component</type>
|
||||
<version>01.03.01-beta</version>
|
||||
<client>site</client>
|
||||
<tags>
|
||||
<tag>beta</tag>
|
||||
</tags>
|
||||
<infourl title="My Extension">https://github.com/org/repo/tree/beta/01.03.01</infourl>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/beta/01.03.01.zip</downloadurl>
|
||||
</downloads>
|
||||
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||
</update>
|
||||
|
||||
<!-- Alpha entry: visible to sites with minimum stability = Alpha or lower -->
|
||||
<update>
|
||||
<name>My Extension</name>
|
||||
<description>My Extension alpha build</description>
|
||||
<element>com_myextension</element>
|
||||
<type>component</type>
|
||||
<version>01.03.01-alpha</version>
|
||||
<client>site</client>
|
||||
<tags>
|
||||
<tag>alpha</tag>
|
||||
</tags>
|
||||
<infourl title="My Extension">https://github.com/org/repo/tree/alpha/01.03.01</infourl>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/alpha/01.03.01.zip</downloadurl>
|
||||
</downloads>
|
||||
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||
</update>
|
||||
|
||||
<!-- Development entry: visible to sites with minimum stability = Development -->
|
||||
<update>
|
||||
<name>My Extension</name>
|
||||
<description>My Extension development build</description>
|
||||
<element>com_myextension</element>
|
||||
<type>component</type>
|
||||
<version>01.04.00-dev</version>
|
||||
<client>site</client>
|
||||
<tags>
|
||||
<tag>development</tag>
|
||||
</tags>
|
||||
<infourl title="My Extension">https://github.com/org/repo/tree/dev/01.04</infourl>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">https://github.com/org/repo/archive/refs/heads/dev/01.04.zip</downloadurl>
|
||||
</downloads>
|
||||
<targetplatform name="joomla" version="((4\.[3-9])|(5\.[0-9]))" />
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
||||
</update>
|
||||
</updates>
|
||||
```
|
||||
|
||||
### Which Workflow Writes Which Entry
|
||||
|
||||
| Workflow | Trigger | Entry written |
|
||||
|----------|---------|---------------|
|
||||
| `auto-release.yml` | Push to `main` | `<tag>stable</tag>` — writes the stable entry with SHA-256 hash of the ZIP |
|
||||
| `update-server.yml` | Push to `rc/**` | `<tag>rc</tag>` — adds/updates the RC entry |
|
||||
| `update-server.yml` | Push to `beta/**` | `<tag>beta</tag>` — adds/updates the beta entry |
|
||||
| `update-server.yml` | Push to `alpha/**` | `<tag>alpha</tag>` — adds/updates the alpha entry |
|
||||
| `update-server.yml` | Push to `dev/**` | `<tag>development</tag>` — adds/updates the development entry |
|
||||
|
||||
The `auto-release.yml` workflow writes the stable entry and preserves any existing pre-release entries. The `update-server.yml` workflow writes only its specific entry (rc, beta, alpha, or dev) and preserves the others.
|
||||
|
||||
### XML Elements
|
||||
|
||||
All metadata is auto-extracted from the extension's XML manifest at build time:
|
||||
|
||||
| Element | Source | Notes |
|
||||
|---------|--------|-------|
|
||||
| `<name>` | `<name>` in manifest | Extension display name |
|
||||
| `<element>` | `<element>` in manifest, or manifest filename | Must match installed extension |
|
||||
| `<type>` | `type` attribute on `<extension>` | `component`, `module`, `plugin`, `library`, `package`, `template` |
|
||||
| `<client>` | `client` attribute on `<extension>` | `site` or `administrator` — **required for plugins and modules** |
|
||||
| `<folder>` | `group` attribute on `<extension>` | Plugin group (e.g., `system`, `content`) — **required for plugins** |
|
||||
| `<version>` | README.md VERSION field | Real version on release, `development` on dev |
|
||||
| `<tags><tag>` | Workflow determines | `stable` on release, `development` on dev |
|
||||
| `<targetplatform>` | `<targetplatform>` in manifest | Falls back to Joomla 5.x / 6.x |
|
||||
| `<php_minimum>` | `<php_minimum>` in manifest | Optional, included if present |
|
||||
| `<infourl>` | GitHub release/branch URL | Links to release page or branch |
|
||||
| `<downloads><downloadurl>` | GitHub release asset or branch archive | `type="full" format="zip"` |
|
||||
|
||||
### Extension Manifest Setup
|
||||
|
||||
For the updates.xml generation to work correctly, your Joomla extension manifest must include:
|
||||
|
||||
```xml
|
||||
<extension type="component" client="site" method="upgrade">
|
||||
<name>My Extension</name>
|
||||
<element>com_myextension</element>
|
||||
<!-- ... -->
|
||||
<updateservers>
|
||||
<server type="extension" priority="1" name="My Extension Update Server (Gitea)">
|
||||
https://git.mokoconsulting.tech/mokoconsulting-tech/{repo}/raw/branch/main/updates.xml
|
||||
</server>
|
||||
<server type="extension" priority="2" name="My Extension Update Server (GitHub)">
|
||||
https://raw.githubusercontent.com/mokoconsulting-tech/{repo}/main/updates.xml
|
||||
</server>
|
||||
</updateservers>
|
||||
</extension>
|
||||
```
|
||||
|
||||
The `<updateservers>` tag tells Joomla where to check for updates. Both servers are declared for redundancy — Gitea (primary, priority 1) and GitHub mirror (fallback, priority 2).
|
||||
|
||||
## How It Works
|
||||
|
||||
### Joomla (updates.xml)
|
||||
|
||||
1. **On release** (`auto-release.yml` → main branch):
|
||||
- Builds ZIP from `src/` directory
|
||||
- Uploads ZIP to the `vXX` major release on GitHub
|
||||
- Computes SHA-256 hash of the ZIP
|
||||
- Writes/updates the `<tag>stable</tag>` entry in `updates.xml` with version, download URL, and SHA-256
|
||||
- Preserves any existing rc/dev entries in the file
|
||||
- Commits updated `updates.xml` to main
|
||||
|
||||
2. **On RC push** (`update-server.yml` → rc/** branches):
|
||||
- Writes/updates the `<tag>rc</tag>` entry in `updates.xml`
|
||||
- Download URL points to the branch archive ZIP
|
||||
- Preserves all other stability entries
|
||||
- Commits updated `updates.xml` to the rc branch
|
||||
|
||||
3. **On beta push** (`update-server.yml` → beta/** branches):
|
||||
- Writes/updates the `<tag>beta</tag>` entry in `updates.xml`
|
||||
- Download URL points to the branch archive ZIP
|
||||
- Preserves all other stability entries
|
||||
- Commits updated `updates.xml` to the beta branch
|
||||
|
||||
4. **On alpha push** (`update-server.yml` → alpha/** branches):
|
||||
- Writes/updates the `<tag>alpha</tag>` entry in `updates.xml`
|
||||
- Download URL points to the branch archive ZIP
|
||||
- Preserves all other stability entries
|
||||
- Commits updated `updates.xml` to the alpha branch
|
||||
|
||||
5. **On dev push** (`update-server.yml` → dev/** branches):
|
||||
- Writes/updates the `<tag>development</tag>` entry in `updates.xml`
|
||||
- Download URL points to the branch archive ZIP
|
||||
- Preserves all other stability entries
|
||||
- Commits updated `updates.xml` to the dev branch
|
||||
|
||||
### Dolibarr (update.txt)
|
||||
|
||||
1. **On release** (`auto-release.yml` → main): writes real version to `update.txt`
|
||||
2. **On RC deploy** (`deploy-dev.yml` → rc/**): writes `XX.YY.ZZ-rc` to `update.txt`
|
||||
3. **On beta deploy** (`deploy-dev.yml` → beta/**): writes `XX.YY.ZZ-beta` to `update.txt`
|
||||
4. **On alpha deploy** (`deploy-dev.yml` → alpha/**): writes `XX.YY.ZZ-alpha` to `update.txt`
|
||||
5. **On dev deploy** (`deploy-dev.yml` → dev/**): writes `development` to `update.txt`
|
||||
|
||||
### RC --> Main Flow
|
||||
|
||||
When a release candidate is ready:
|
||||
|
||||
1. `rc/XX.YY.ZZ` branch is tested with `<tag>rc</tag>` update entries
|
||||
2. RC branch is merged to `main` via PR
|
||||
3. Push to main triggers `auto-release.yml` → GitHub Release + `vXX` tag
|
||||
4. `updates.xml` on main gets a new/updated `<tag>stable</tag>` entry
|
||||
5. `version/XX` archive branch is auto-created
|
||||
|
||||
## Health Checks
|
||||
|
||||
The platform-specific `repo_health.yml` workflows verify:
|
||||
- **Dolibarr**: `update.txt` exists in root, module descriptor valid, url_last_version correct
|
||||
- **Joomla**: `updates.xml` exists in root, XML manifest valid, language files present
|
||||
|
||||
## Rulesets
|
||||
|
||||
Branch protection rulesets (applied via `sync_rulesets.php`):
|
||||
- **MAIN**: prevents deletion, non-fast-forward, requires PRs
|
||||
- **VERSION**: immutable — prevents updates, deletion, force-push
|
||||
- **DEV**: prevents deletion, non-fast-forward
|
||||
- **ALPHA**: prevents deletion, non-fast-forward
|
||||
- **BETA**: prevents deletion, non-fast-forward
|
||||
- **RC**: prevents deletion, non-fast-forward
|
||||
@@ -0,0 +1,559 @@
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: MokoStandards.Documentation
|
||||
INGROUP: MokoStandards.Workflows
|
||||
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
PATH: /docs/workflows/workflow-architecture.md
|
||||
VERSION: 04.06.00
|
||||
BRIEF: Workflow architecture, hierarchy, and design patterns
|
||||
-->
|
||||
|
||||
[](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
|
||||
# Workflow Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
This document explains the workflow architecture used across Moko Consulting repositories, including the hierarchy, design patterns, reusable workflow patterns, and decision-making processes for workflow selection.
|
||||
|
||||
## Purpose
|
||||
|
||||
This architecture guide provides:
|
||||
|
||||
- **Understanding**: Clear mental model of workflow organization
|
||||
- **Guidance**: Decision trees for workflow selection
|
||||
- **Patterns**: Reusable patterns and best practices
|
||||
- **Relationships**: How workflows interact and depend on each other
|
||||
- **Evolution**: How to extend and improve the workflow architecture
|
||||
|
||||
## Three-Tier Workflow Architecture
|
||||
|
||||
Moko Consulting uses a three-tier architecture for GitHub Actions workflows:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tier 1: Organization-Wide Reusable Workflows │
|
||||
│ Location: .github-private repository │
|
||||
│ Visibility: Private │
|
||||
│ Purpose: Shared across all organization repositories │
|
||||
│ Examples: Deployment, compliance audits, security scanning │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓ (called by)
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tier 2: Public Reusable Workflows │
|
||||
│ Location: MokoStandards repository │
|
||||
│ Visibility: Public │
|
||||
│ Purpose: Templates and patterns for community use │
|
||||
│ Examples: CI validation, build automation, health checks │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓ (called by)
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tier 3: Local Workflows │
|
||||
│ Location: Individual repository .github/workflows/ │
|
||||
│ Visibility: Matches repository visibility │
|
||||
│ Purpose: Repository-specific automation │
|
||||
│ Examples: Project builds, tests, custom deployments │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Tier 1: Organization-Wide Reusable Workflows
|
||||
|
||||
**Location**: `mokoconsulting-tech/.github-private/.github/workflows/`
|
||||
|
||||
**Characteristics**:
|
||||
- Private and secure
|
||||
- Contains sensitive organizational logic
|
||||
- Requires organization secrets
|
||||
- Enforces organization-wide compliance
|
||||
- Centrally maintained with high governance
|
||||
- Performs cross-repository operations
|
||||
|
||||
**Examples**:
|
||||
- `reusable-compliance-audit.yml` - Monthly compliance audits
|
||||
- `reusable-standards-scan.yml` - Organization-wide standards scanning
|
||||
- `reusable-branch-cleanup.yml` - Automated branch cleanup
|
||||
- `reusable-auto-label.yml` - Automated issue/PR labeling
|
||||
- `reusable-stale-management.yml` - Stale issue/PR management
|
||||
|
||||
**When to Use**:
|
||||
- Workflow contains proprietary logic
|
||||
- Workflow requires organization-level secrets
|
||||
- Workflow performs cross-repository operations
|
||||
- Workflow enforces organization-wide policies
|
||||
- Workflow handles sensitive data or operations
|
||||
|
||||
### Tier 2: Public Reusable Workflows
|
||||
|
||||
**Location**: `mokoconsulting-tech/MokoStandards/.github/workflows/`
|
||||
|
||||
**Characteristics**:
|
||||
- Public and community-accessible
|
||||
- Demonstrates best practices
|
||||
- Platform-agnostic where possible
|
||||
- Well-documented with examples
|
||||
- Follows standards defined in `/docs/policy/`
|
||||
- Suitable for open-source sharing
|
||||
|
||||
**Examples**:
|
||||
- `reusable-ci-validation.yml` - CI validation with project detection
|
||||
- `reusable-build.yml` - Universal build workflow
|
||||
- `reusable-deploy.yml` - Deployment workflow template
|
||||
- `reusable-joomla-testing.yml` - Joomla-specific testing
|
||||
- `reusable-php-quality.yml` - PHP code quality checks
|
||||
- `reusable-project-detector.yml` - Automatic project type detection
|
||||
|
||||
**When to Use**:
|
||||
- Workflow is a common pattern across repositories
|
||||
- Workflow can be public and shared
|
||||
- Workflow demonstrates best practices
|
||||
- Workflow is platform-agnostic or extensible
|
||||
- Workflow serves as template for community
|
||||
|
||||
### Tier 3: Local Workflows
|
||||
|
||||
**Location**: Individual repository `.github/workflows/`
|
||||
|
||||
**Characteristics**:
|
||||
- Repository-specific
|
||||
- Calls reusable workflows from Tier 1 or Tier 2
|
||||
- Contains minimal logic (orchestration only)
|
||||
- Easy to understand and maintain
|
||||
- Project-specific configuration
|
||||
|
||||
**Examples**:
|
||||
- `ci.yml` - Calls reusable CI validation workflow
|
||||
- `release-pipeline.yml` - Orchestrates release process
|
||||
- `repo-health.yml` - Repository health monitoring
|
||||
- `standards-compliance.yml` - Standards validation
|
||||
|
||||
**When to Use**:
|
||||
- Workflow is specific to one repository
|
||||
- Workflow doesn't fit reusable pattern
|
||||
- Workflow is experimental or temporary
|
||||
- Workflow orchestrates multiple reusable workflows
|
||||
|
||||
## Workflow Design Patterns
|
||||
|
||||
### Pattern 1: Project Detection and Conditional Execution
|
||||
|
||||
Automatically detect project type and execute appropriate build/test strategy.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
detect:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-project-detector.yml@main
|
||||
|
||||
build-joomla:
|
||||
needs: detect
|
||||
if: needs.detect.outputs.project-type == 'joomla'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-joomla-testing.yml@main
|
||||
|
||||
build-generic:
|
||||
needs: detect
|
||||
if: needs.detect.outputs.project-type == 'generic'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-build.yml@main
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Single workflow supports multiple project types
|
||||
- No manual configuration needed
|
||||
- Easy to maintain and extend
|
||||
|
||||
### Pattern 2: Composition through Reusable Workflows
|
||||
|
||||
Build complex workflows by composing simple reusable workflows.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
# Step 1: Validate code
|
||||
validate:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-ci-validation.yml@main
|
||||
|
||||
# Step 2: Build if validation passes
|
||||
build:
|
||||
needs: validate
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-build.yml@main
|
||||
|
||||
# Step 3: Deploy if build passes
|
||||
deploy:
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Clear separation of concerns
|
||||
- Reusable components
|
||||
- Easy to test and debug
|
||||
- Flexible composition
|
||||
|
||||
### Pattern 3: Matrix Strategy for Multi-Platform Testing
|
||||
|
||||
Test across multiple versions or platforms using matrix strategy.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: ['7.4', '8.0', '8.1', '8.2']
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-php-quality.yml@main
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Comprehensive testing coverage
|
||||
- Parallel execution
|
||||
- Configurable test matrix
|
||||
|
||||
### Pattern 4: Conditional Deployment Based on Environment
|
||||
|
||||
Deploy to different environments based on branch or tag.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
deploy-staging:
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: staging
|
||||
|
||||
deploy-production:
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: production
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Safe deployment practices
|
||||
- Environment-specific configuration
|
||||
- Clear deployment triggers
|
||||
|
||||
### Pattern 5: Workflow Dispatch with Manual Controls
|
||||
|
||||
Allow manual triggering with customizable inputs.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: 'Deployment environment'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- production
|
||||
dry-run:
|
||||
description: 'Perform dry run'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
uses: mokoconsulting-tech/MokoStandards/.github/workflows/reusable-deploy.yml@main
|
||||
with:
|
||||
environment: ${{ inputs.environment }}
|
||||
dry-run: ${{ inputs.dry-run }}
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Manual control when needed
|
||||
- Safe defaults (dry-run)
|
||||
- Clear input options
|
||||
|
||||
## Workflow Relationships
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
```
|
||||
repo-health.yml
|
||||
│
|
||||
└──> Uses: reusable-project-detector.yml
|
||||
│
|
||||
└──> Provides: project-type output
|
||||
|
||||
ci.yml
|
||||
│
|
||||
├──> Uses: reusable-ci-validation.yml
|
||||
│ │
|
||||
│ ├──> Uses: reusable-project-detector.yml
|
||||
│ └──> Uses: reusable-php-quality.yml (if PHP)
|
||||
│
|
||||
└──> Uses: reusable-build.yml
|
||||
│
|
||||
└──> Uses: reusable-project-detector.yml
|
||||
|
||||
release-pipeline.yml
|
||||
│
|
||||
├──> Uses: reusable-build.yml
|
||||
├──> Uses: reusable-release.yml
|
||||
└──> Uses: reusable-deploy.yml
|
||||
```
|
||||
|
||||
### Workflow Inheritance
|
||||
|
||||
Workflows inherit behavior through composition:
|
||||
|
||||
1. **Base Workflows**: Provide core functionality
|
||||
- `reusable-project-detector.yml`
|
||||
- `reusable-build.yml`
|
||||
|
||||
2. **Specialized Workflows**: Add domain-specific logic
|
||||
- `reusable-joomla-testing.yml` (extends base build)
|
||||
- `reusable-php-quality.yml` (extends base validation)
|
||||
|
||||
3. **Orchestration Workflows**: Combine multiple workflows
|
||||
- `ci.yml` (combines validation + build)
|
||||
- `release-pipeline.yml` (combines build + release + deploy)
|
||||
|
||||
## Decision Trees
|
||||
|
||||
### Choosing the Right Tier
|
||||
|
||||
```
|
||||
Start: Need to create/modify workflow
|
||||
│
|
||||
├──> Contains sensitive/proprietary logic?
|
||||
│ └──> YES: Use Tier 1 (.github-private)
|
||||
│
|
||||
├──> Common pattern across repositories?
|
||||
│ └──> YES: Use Tier 2 (MokoStandards)
|
||||
│
|
||||
└──> Repository-specific?
|
||||
└──> YES: Use Tier 3 (local workflow)
|
||||
```
|
||||
|
||||
### Choosing Between Reusable vs Local
|
||||
|
||||
```
|
||||
Start: Creating new workflow
|
||||
│
|
||||
├──> Used by multiple repositories?
|
||||
│ └──> YES: Create reusable workflow
|
||||
│
|
||||
├──> Complex multi-step process?
|
||||
│ └──> YES: Break into reusable components
|
||||
│
|
||||
└──> Simple repository-specific task?
|
||||
└──> YES: Create local workflow
|
||||
```
|
||||
|
||||
### Choosing Workflow Trigger
|
||||
|
||||
```
|
||||
Start: When should workflow run?
|
||||
│
|
||||
├──> On code changes?
|
||||
│ └──> Use: on.push, on.pull_request
|
||||
│
|
||||
├──> On schedule?
|
||||
│ └──> Use: on.schedule (cron)
|
||||
│
|
||||
├──> Manual trigger needed?
|
||||
│ └──> Use: on.workflow_dispatch
|
||||
│
|
||||
└──> Called by other workflows?
|
||||
└──> Use: on.workflow_call
|
||||
```
|
||||
|
||||
## Workflow Evolution
|
||||
|
||||
### Adding New Workflows
|
||||
|
||||
1. **Identify Need**: What problem does this workflow solve?
|
||||
2. **Check Existing**: Can existing workflow be extended?
|
||||
3. **Design Interface**: Define inputs, outputs, secrets
|
||||
4. **Choose Tier**: Public (Tier 2) or Private (Tier 1)?
|
||||
5. **Implement**: Follow [Workflow Standards](../docs/policy/workflow-standards.md)
|
||||
6. **Document**: Add to [REUSABLE_WORKFLOWS.md](./workflows/REUSABLE_WORKFLOWS.md)
|
||||
7. **Test**: Validate in test repository
|
||||
8. **Deploy**: Merge and communicate
|
||||
|
||||
### Refactoring Workflows
|
||||
|
||||
Signs a workflow needs refactoring:
|
||||
- Duplicated logic across repositories
|
||||
- Complex, hard-to-maintain workflow
|
||||
- Frequent changes to same workflow across repos
|
||||
- Lack of clear purpose or focus
|
||||
|
||||
Refactoring process:
|
||||
1. Identify common patterns
|
||||
2. Extract to reusable workflow
|
||||
3. Define clear interface
|
||||
4. Update calling workflows
|
||||
5. Test thoroughly
|
||||
6. Document changes
|
||||
7. Deprecate old approach
|
||||
|
||||
### Deprecating Workflows
|
||||
|
||||
Process for deprecating workflows:
|
||||
1. Add deprecation notice to workflow
|
||||
2. Provide migration path
|
||||
3. Update documentation
|
||||
4. Communicate to users
|
||||
5. Wait minimum 90 days
|
||||
6. Move to `archived/` directory
|
||||
7. Update inventories
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Keep Workflows Focused
|
||||
|
||||
✅ **Good**: Single-purpose workflow
|
||||
```yaml
|
||||
# reusable-php-quality.yml - PHP quality checks only
|
||||
jobs:
|
||||
quality:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run PHP CodeSniffer
|
||||
- name: Run PHPStan
|
||||
- name: Run PHP Mess Detector
|
||||
```
|
||||
|
||||
❌ **Bad**: Kitchen-sink workflow
|
||||
```yaml
|
||||
# mega-workflow.yml - Too many responsibilities
|
||||
jobs:
|
||||
everything:
|
||||
steps:
|
||||
- name: Lint
|
||||
- name: Test
|
||||
- name: Build
|
||||
- name: Deploy
|
||||
- name: Notify
|
||||
- name: Update docs
|
||||
```
|
||||
|
||||
### Use Composition Over Duplication
|
||||
|
||||
✅ **Good**: Compose from reusable workflows
|
||||
```yaml
|
||||
jobs:
|
||||
validate:
|
||||
uses: org/repo/.github/workflows/reusable-validate.yml@main
|
||||
build:
|
||||
uses: org/repo/.github/workflows/reusable-build.yml@main
|
||||
```
|
||||
|
||||
❌ **Bad**: Duplicate logic
|
||||
```yaml
|
||||
jobs:
|
||||
validate-and-build:
|
||||
steps:
|
||||
- name: Checkout
|
||||
- name: Setup
|
||||
- name: Lint (duplicated across repos)
|
||||
- name: Test (duplicated across repos)
|
||||
- name: Build (duplicated across repos)
|
||||
```
|
||||
|
||||
### Fail Fast
|
||||
|
||||
✅ **Good**: Quick feedback on failures
|
||||
```yaml
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Quick syntax check
|
||||
run: |
|
||||
if ! php -l src/*.php; then
|
||||
echo "::error::PHP syntax errors found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test:
|
||||
needs: validate # Only run if validation passes
|
||||
```
|
||||
|
||||
❌ **Bad**: Slow feedback
|
||||
```yaml
|
||||
jobs:
|
||||
everything:
|
||||
steps:
|
||||
- name: Run all tests (30 minutes)
|
||||
- name: Then check syntax # Should be first!
|
||||
```
|
||||
|
||||
## Common Anti-Patterns
|
||||
|
||||
### Anti-Pattern 1: Monolithic Workflows
|
||||
|
||||
**Problem**: One huge workflow that does everything
|
||||
|
||||
**Solution**: Break into focused, composable workflows
|
||||
|
||||
### Anti-Pattern 2: Hardcoded Values
|
||||
|
||||
**Problem**: Hardcoded configuration in workflow files
|
||||
|
||||
**Solution**: Use inputs and variables
|
||||
|
||||
### Anti-Pattern 3: Insufficient Error Handling
|
||||
|
||||
**Problem**: Workflows fail silently or with unclear errors
|
||||
|
||||
**Solution**: Add error handling and clear error messages
|
||||
|
||||
### Anti-Pattern 4: Overly Broad Permissions
|
||||
|
||||
**Problem**: Workflows request more permissions than needed
|
||||
|
||||
**Solution**: Follow principle of least privilege
|
||||
|
||||
### Anti-Pattern 5: No Testing
|
||||
|
||||
**Problem**: Workflows deployed without testing
|
||||
|
||||
**Solution**: Test in feature branches first
|
||||
|
||||
## References
|
||||
|
||||
- [Workflow Standards Policy](../docs/policy/workflow-standards.md)
|
||||
- [Reusable Workflows Documentation](./workflows/REUSABLE_WORKFLOWS.md)
|
||||
- [Workflow Inventory](./WORKFLOW_INVENTORY.md)
|
||||
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
||||
- [Repository Organization Guide](../docs/guide/repository-organization.md)
|
||||
|
||||
## Metadata
|
||||
|
||||
* **Document**: .github/WORKFLOW_ARCHITECTURE.md
|
||||
* **Repository**: [MokoStandards](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
|
||||
* **Owner**: Moko Consulting Engineering Team
|
||||
* **Scope**: Workflow architecture and design patterns
|
||||
* **Lifecycle**: Active
|
||||
* **Audience**: All engineers and workflow authors
|
||||
|
||||
## Revision History
|
||||
|
||||
| Version | Date | Author | Notes |
|
||||
| -------- | ---------- | ------------------------------- | ----------------------------------------------- |
|
||||
| 01.00.00 | 2026-01-13 | GitHub Copilot | Initial workflow architecture documentation |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Fix
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/fix/fix_line_endings.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /fix/fix_line_endings.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: CLI script to fix line endings (CRLF → LF) in tracked files
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Fix
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/fix/fix_permissions.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /fix/fix_permissions.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: CLI script to fix file permissions (dirs 755, files 644, scripts 755)
|
||||
*/
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Fix
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/fix/fix_tabs.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /fix/fix_tabs.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: CLI script to convert tabs to spaces in tracked source files
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Fix
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/fix/fix_trailing_spaces.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /fix/fix_trailing_spaces.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: CLI script to remove trailing whitespace from tracked source files
|
||||
*/
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Lib
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/CliBase.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/CliBase.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Standalone base CLI class for api/ scripts that do not use CliFramework
|
||||
*/
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Lib
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Common.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Common.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Common utility functions for api/ scripts
|
||||
* NOTE: Version format used throughout is zero-padded semver: XX.YY.ZZ (e.g. 04.00.04).
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.CLI
|
||||
* INGROUP: MokoStandards.Enterprise
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/CliFramework.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/CliFramework.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: CLI base classes — CliFramework (current) and CLIApp (legacy)
|
||||
* NOTE: All new scripts must extend CliFramework, not CLIApp.
|
||||
|
||||
@@ -60,7 +60,7 @@ class Config
|
||||
private const DEFAULT_CONFIG = [
|
||||
'version' => '04.00.04',
|
||||
'environment' => 'development',
|
||||
'platform' => 'github',
|
||||
'platform' => 'gitea',
|
||||
'github' => [
|
||||
'organization' => 'mokoconsulting-tech',
|
||||
'rate_limit' => 5000,
|
||||
@@ -213,8 +213,8 @@ class Config
|
||||
$configData['github']['organization'] = $org;
|
||||
}
|
||||
|
||||
// Gitea token resolution: GITEA_TOKEN env var
|
||||
$giteaToken = getenv('GITEA_TOKEN') ?: '';
|
||||
// Gitea token resolution: GA_TOKEN env var (Gitea Actions)
|
||||
$giteaToken = getenv('GA_TOKEN') ?: '';
|
||||
if (!empty($giteaToken)) {
|
||||
$configData['gitea']['token'] = $giteaToken;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/DefinitionParser.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/DefinitionParser.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Parses Terraform HCL repository definition files into a flat sync-file list
|
||||
*/
|
||||
@@ -23,7 +23,7 @@ namespace MokoEnterprise;
|
||||
* Definition Parser
|
||||
*
|
||||
* Parses the Terraform HCL repository definition files stored in
|
||||
* api/definitions/default/ and returns a flat list of file sync entries.
|
||||
* definitions/default/ and returns a flat list of file sync entries.
|
||||
*
|
||||
* File blocks that carry either a `template` field (external file path) or a
|
||||
* `stub_content` heredoc (inline content) are returned — these are the files
|
||||
@@ -59,7 +59,7 @@ class DefinitionParser
|
||||
private const FALLBACK_DEFINITION = 'default-repository.tf';
|
||||
|
||||
/** Directory containing the base definition files */
|
||||
private const DEFINITIONS_DIR = 'api/definitions/default';
|
||||
private const DEFINITIONS_DIR = 'definitions/default';
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Public API
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/EnterpriseReadinessValidator.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/EnterpriseReadinessValidator.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise readiness validation library
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards.Lib
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/FileFixUtility.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/FileFixUtility.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Utility class for fixing file formatting issues (line endings, permissions, tabs, trailing spaces)
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Platform
|
||||
* INGROUP: MokoStandards.Enterprise
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/GitHubAdapter.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/GitHubAdapter.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: GitHub implementation of GitPlatformAdapter
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Platform
|
||||
* INGROUP: MokoStandards.Enterprise
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/GitPlatformAdapter.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/GitPlatformAdapter.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Interface defining all git platform operations for GitHub/Gitea abstraction
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Platform
|
||||
* INGROUP: MokoStandards.Enterprise
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/GiteaAdapter.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/GiteaAdapter.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Gitea implementation of GitPlatformAdapter
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards.Lib
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/PackageBuilder.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/PackageBuilder.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Builds release packages for generic, Dolibarr module, and Joomla component projects
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Platform
|
||||
* INGROUP: MokoStandards.Enterprise
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/PlatformAdapterFactory.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/PlatformAdapterFactory.php
|
||||
* VERSION: 04.06.10
|
||||
* BRIEF: Factory for creating platform-specific GitPlatformAdapter instances
|
||||
*/
|
||||
@@ -48,7 +48,7 @@ class PlatformAdapterFactory
|
||||
*/
|
||||
public static function create(Config $config, ?string $platformOverride = null): GitPlatformAdapter
|
||||
{
|
||||
$platform = $platformOverride ?? $config->getString('platform', 'github');
|
||||
$platform = $platformOverride ?? $config->getString('platform', 'gitea');
|
||||
|
||||
return match ($platform) {
|
||||
'github' => self::createGitHubAdapter($config),
|
||||
@@ -96,7 +96,7 @@ class PlatformAdapterFactory
|
||||
$token = $config->getString('gitea.token', '');
|
||||
if (empty($token)) {
|
||||
throw new RuntimeException(
|
||||
'Gitea token not found. Set GITEA_TOKEN environment variable.'
|
||||
'Gitea token not found. Set GA_TOKEN environment variable.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -128,4 +128,66 @@ class PlatformAdapterFactory
|
||||
'gitea' => self::createGiteaAdapter($config),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync a file between Gitea (primary) and GitHub (mirror) for a given repo.
|
||||
*
|
||||
* Reads the file from Gitea and pushes it to GitHub, ensuring both platforms
|
||||
* serve identical content. Commonly used for updates.xml sync after releases.
|
||||
*
|
||||
* @param Config $config Configuration instance
|
||||
* @param string $repo Repository name
|
||||
* @param string $branch Branch to sync (default: 'main')
|
||||
* @param string $filePath Path to the file (default: 'updates.xml')
|
||||
* @return bool True if sync succeeded or file was already identical
|
||||
* @throws RuntimeException If either platform is unreachable
|
||||
*/
|
||||
public static function syncUpdatesBetweenPlatforms(
|
||||
Config $config,
|
||||
string $repo,
|
||||
string $branch = 'main',
|
||||
string $filePath = 'updates.xml'
|
||||
): bool {
|
||||
$adapters = self::createBoth($config);
|
||||
$giteaOrg = $config->getString('gitea.organization', 'mokoconsulting-tech');
|
||||
$githubOrg = $config->getString('github.organization', 'mokoconsulting-tech');
|
||||
|
||||
// Read from Gitea (primary)
|
||||
try {
|
||||
$giteaFile = $adapters['gitea']->getFileContents($giteaOrg, $repo, $filePath, $branch);
|
||||
} catch (\Exception $e) {
|
||||
throw new RuntimeException("Failed to read {$filePath} from Gitea ({$giteaOrg}/{$repo}): " . $e->getMessage());
|
||||
}
|
||||
|
||||
$giteaContent = base64_decode($giteaFile['content'] ?? '');
|
||||
if (empty($giteaContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read from GitHub (mirror) to check if update is needed
|
||||
$githubSha = null;
|
||||
try {
|
||||
$githubFile = $adapters['github']->getFileContents($githubOrg, $repo, $filePath, $branch);
|
||||
$githubContent = base64_decode($githubFile['content'] ?? '');
|
||||
$githubSha = $githubFile['sha'] ?? null;
|
||||
|
||||
if ($githubContent === $giteaContent) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$adapters['github']->getApiClient()->resetCircuitBreaker();
|
||||
}
|
||||
|
||||
$adapters['github']->createOrUpdateFile(
|
||||
$githubOrg,
|
||||
$repo,
|
||||
$filePath,
|
||||
$giteaContent,
|
||||
"chore(sync): sync {$filePath} from Gitea primary",
|
||||
$githubSha,
|
||||
$branch
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/ApiPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/ApiPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for API/Microservices projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/DocumentationPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/DocumentationPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for documentation projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/DolibarrPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/DolibarrPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for Dolibarr modules
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/GenericPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/GenericPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for generic projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/JoomlaPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/JoomlaPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for Joomla projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/MobilePlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/MobilePlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for mobile app projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/NodeJsPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/NodeJsPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for Node.js/TypeScript projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/PythonPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/PythonPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for Python projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/TerraformPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/TerraformPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for Terraform projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.Plugins
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/Plugins/WordPressPlugin.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/Plugins/WordPressPlugin.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise plugin for WordPress projects
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.ProjectTypes
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/ProjectConfigValidator.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/ProjectConfigValidator.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise library for validating project configurations
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.ProjectTypes
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/ProjectMetricsCollector.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/ProjectMetricsCollector.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise library for collecting project-specific metrics
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise.ProjectTypes
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/ProjectTypeDetector.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/ProjectTypeDetector.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Enterprise library for detecting project types
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/RepositoryHealthChecker.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/RepositoryHealthChecker.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Repository health checking enterprise library
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/RepositorySynchronizer.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/RepositorySynchronizer.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Repository synchronization enterprise library
|
||||
*/
|
||||
@@ -30,7 +30,7 @@ use RuntimeException;
|
||||
*/
|
||||
class RepositorySynchronizer
|
||||
{
|
||||
private const SYNC_DEFINITION_DIR = 'api/definitions/sync';
|
||||
private const SYNC_DEFINITION_DIR = 'definitions/sync';
|
||||
/** Override file path — resolved at runtime via adapter's getMetadataDir(). */
|
||||
private const SYNC_OVERRIDE_FILE_SUFFIX = 'override.tf';
|
||||
private const STANDARDS_VERSION = '04.06.00';
|
||||
@@ -219,7 +219,7 @@ class RepositorySynchronizer
|
||||
if ($prNumber) {
|
||||
$this->logger->logInfo("Successfully created PR #{$prNumber} for {$repo}");
|
||||
|
||||
// Generate / update api/definitions/sync/{repo}.def.tf AFTER the sync so it
|
||||
// Generate / update definitions/sync/{repo}.def.tf AFTER the sync so it
|
||||
// reflects exactly what was pushed in this run.
|
||||
$this->generateRepositoryDefinition($org, $repo, $platform, $repoInfo, $summary);
|
||||
|
||||
@@ -253,7 +253,7 @@ class RepositorySynchronizer
|
||||
/**
|
||||
* Generate / update the repository tracking definition after a successful sync.
|
||||
*
|
||||
* Writes api/definitions/sync/{repo}.def.tf with:
|
||||
* Writes definitions/sync/{repo}.def.tf with:
|
||||
* - the base platform definition as a foundation
|
||||
* - a sync_record block recording what was actually pushed (files created/updated/skipped)
|
||||
* - full timestamps and platform metadata
|
||||
@@ -281,9 +281,9 @@ class RepositorySynchronizer
|
||||
|
||||
// Resolve repo root relative to this file's location
|
||||
$repoRoot = dirname(dirname(dirname(__DIR__)));
|
||||
$baseDefPath = "{$repoRoot}/api/definitions/default/{$platform}.tf";
|
||||
$baseDefPath = "{$repoRoot}/definitions/default/{$platform}.tf";
|
||||
if (!file_exists($baseDefPath)) {
|
||||
$baseDefPath = "{$repoRoot}/api/definitions/default/default-repository.tf";
|
||||
$baseDefPath = "{$repoRoot}/definitions/default/default-repository.tf";
|
||||
}
|
||||
$baseDefinition = file_get_contents($baseDefPath) ?: '';
|
||||
|
||||
@@ -328,7 +328,7 @@ class RepositorySynchronizer
|
||||
* Description: {$description}
|
||||
*
|
||||
* DO NOT EDIT MANUALLY — this file is regenerated on every successful sync.
|
||||
* To change what gets synced, edit api/definitions/default/{$platform}.tf
|
||||
* To change what gets synced, edit definitions/default/{$platform}.tf
|
||||
* and re-run the bulk-repo-sync workflow.
|
||||
*/
|
||||
|
||||
@@ -341,7 +341,7 @@ locals {
|
||||
description = "{$description}"
|
||||
sync_timestamp = "{$timestamp}"
|
||||
source_repo = "mokoconsulting-tech/MokoStandards"
|
||||
base_definition = "api/definitions/default/{$platform}.tf"
|
||||
base_definition = "definitions/default/{$platform}.tf"
|
||||
}
|
||||
|
||||
sync_stats = {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Enterprise
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/Enterprise/SynchronizationException.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/Enterprise/SynchronizationException.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Custom exception for repository synchronization errors
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Joomla
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/lib/plugins/Joomla/UpdateXmlGenerator.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /lib/plugins/Joomla/UpdateXmlGenerator.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Generates and updates Joomla extension updates.xml files
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/pin_action_shas.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/pin_action_shas.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Pin GitHub Actions to immutable commit SHAs in workflow files
|
||||
* NOTE: Resolves tag/branch refs to commit SHAs via the GitHub API to satisfy
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/repo_inventory.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/repo_inventory.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Generate a live inventory dashboard of all governed repos as a GitHub issue
|
||||
*
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/rotate_secrets.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/rotate_secrets.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Audit FTP secrets and variables across all governed repos — report missing or stale
|
||||
*
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/setup_labels.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/setup_labels.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: REQUIRED label deployment script for all MokoStandards-governed repositories
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/sync_dolibarr_readmes.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/sync_dolibarr_readmes.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Keeps root README.md and src/README.md in sync for Dolibarr module repositories
|
||||
* NOTE: Version format is zero-padded semver: XX.YY.ZZ (e.g. 04.00.04). All version regex
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/update_repo_inventory.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/update_repo_inventory.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Queries GitHub org repos and rewrites the auto-generated section of REPOSITORY_INVENTORY.md
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/update_sha_hashes.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/update_sha_hashes.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Update SHA-256 hashes in script registry
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoStandards.Scripts.Maintenance
|
||||
* INGROUP: MokoStandards
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||
* PATH: /api/maintenance/update_version_from_readme.php
|
||||
* REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
||||
* PATH: /maintenance/update_version_from_readme.php
|
||||
* VERSION: 04.06.00
|
||||
* BRIEF: Reads VERSION from README.md FILE INFORMATION block and propagates it to all badges and FILE INFORMATION headers
|
||||
* NOTE: README.md is the single source of truth for the repository version.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user