feat: add templates, CLI dirs, docs, and Gitea-first platform config #1

Merged
jmiller merged 1 commits from dev into main 2026-04-15 02:35:30 +00:00
297 changed files with 37868 additions and 227 deletions
+29 -1
View File
@@ -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)
+1 -1
View File
@@ -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
*
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+19
View File
@@ -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
View File
@@ -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" "$@"
+158
View File
@@ -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";
+477
View File
@@ -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);
+255
View File
@@ -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}
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-blue)]({$standardsUrl})
[![Version](https://img.shields.io/badge/version-01.00.00-green)]({$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";
+394
View File
@@ -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());
+41
View File
@@ -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
View File
@@ -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";
+67
View File
@@ -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);
+178
View File
@@ -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);
+63
View File
@@ -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);
+38
View File
@@ -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);
+119
View File
@@ -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);
+2 -2
View File
@@ -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
*
+2 -2
View File
@@ -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
*/
+1 -1
View File
@@ -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]
+23
View File
@@ -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
+138
View File
@@ -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
+212
View File
@@ -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
+224
View File
@@ -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)
+162
View File
@@ -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
+114
View File
@@ -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
+322
View File
@@ -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
+20
View File
@@ -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
+180
View File
@@ -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
+176
View File
@@ -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 (0100).
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
+62
View File
@@ -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
+56
View File
@@ -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
+276
View File
@@ -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 (0100). 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 (0100) |
| `--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
+20
View File
@@ -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
+136
View File
@@ -0,0 +1,136 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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
+57
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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`
+114
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 |
+598
View File
@@ -0,0 +1,598 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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/)
+103
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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.
+87
View File
@@ -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 |
+775
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards)
![Enterprise Ready](https://img.shields.io/badge/enterprise-ready-green)
![Security Validated](https://img.shields.io/badge/security-validated-green)
# 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
+338
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 |
+75
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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.
+390
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 |
+280
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 |
+71
View File
@@ -0,0 +1,71 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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
+211
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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 |
+567
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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) |
+43
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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
+239
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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.
+588
View File
@@ -0,0 +1,588 @@
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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
+219
View File
@@ -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
+333
View File
@@ -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
+559
View File
@@ -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
-->
[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.06.00-orange)](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
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
View File
@@ -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
*/
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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).
+2 -2
View File
@@ -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.
+3 -3
View File
@@ -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;
}
+4 -4
View File
@@ -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
*/
+2 -2
View File
@@ -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)
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+66 -4
View File
@@ -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;
}
}
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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 -9
View File
@@ -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 = {
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
*
+2 -2
View File
@@ -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
*
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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
*/
+2 -2
View File
@@ -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