Files
mokoplatform/lib/Enterprise/AbstractProjectPlugin.php
Jonathan Miller b73c1eba25
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Failing after 2s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Security Audit / Dependency Audit (pull_request) Successful in 8s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Failing after 11s
Universal: PR Check / Validate PR (pull_request) Successful in 11s
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 21s
Generic: Project CI / Lint & Validate (pull_request) Failing after 32s
Platform: mokoplatform CI / Gate 1: Code Quality (pull_request) Failing after 1m31s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: mokoplatform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: mokoplatform CI / CI Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
feat: add manifest_detect.php CLI tool for auto-detecting manifest fields
Scans source files to detect platform, name, version, element_name,
package_type, language, entry_point, description, and license_spdx.
Supports Joomla, Dolibarr, Go, MCP/Node, and generic platforms.

Includes --diff and --update modes for comparing against and pushing
to the Gitea manifest API. Warns on missing core fields.

Also removes deprecated mcp/servers/mokowaas_api (consolidated to
separate repo) and syncs dev branch changes.
2026-06-07 15:37:24 -05:00

274 lines
7.4 KiB
PHP

<?php
declare(strict_types=1);
/* 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: MokoPlatform.Enterprise.Plugins
* INGROUP: MokoPlatform.Enterprise
* REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
* PATH: /lib/Enterprise/AbstractProjectPlugin.php
* BRIEF: Abstract base class for project plugins
*/
namespace MokoEnterprise;
/**
* Abstract base class for project type plugins
*
* Provides common functionality for all project type plugins
*
* @package MokoPlatform\Enterprise
* @version 1.0.0
*/
abstract class AbstractProjectPlugin implements ProjectPluginInterface
{
/** @var AuditLogger */
protected $logger;
/** @var MetricsCollector */
protected $metricsCollector;
/** @var array Plugin configuration */
protected $config;
/**
* Constructor
*
* @param AuditLogger|null $logger Optional audit logger
* @param MetricsCollector|null $metricsCollector Optional metrics collector
* @param array $config Plugin configuration
*/
public function __construct(
?AuditLogger $logger = null,
?MetricsCollector $metricsCollector = null,
array $config = []
) {
$this->logger = $logger ?? new AuditLogger('project_plugin');
$this->metricsCollector = $metricsCollector ?? new MetricsCollector();
$this->config = $config;
}
/**
* {@inheritdoc}
*/
abstract public function getProjectType(): string;
/**
* {@inheritdoc}
*/
abstract public function getPluginName(): string;
/**
* {@inheritdoc}
*/
public function getPluginVersion(): string
{
return '1.0.0';
}
/**
* {@inheritdoc}
*/
abstract public function validateProject(array $config, string $projectPath): array;
/**
* {@inheritdoc}
*/
abstract public function collectMetrics(string $projectPath, array $config): array;
/**
* {@inheritdoc}
*/
abstract public function healthCheck(string $projectPath, array $config): array;
/**
* {@inheritdoc}
*/
abstract public function getRequiredFiles(): array;
/**
* {@inheritdoc}
*/
abstract public function getRecommendedFiles(): array;
/**
* {@inheritdoc}
*/
abstract public function getConfigSchema(): array;
/**
* {@inheritdoc}
*/
abstract public function getBestPractices(): array;
/**
* {@inheritdoc}
*/
public function checkReadiness(string $projectPath, array $config): array
{
$validation = $this->validateProject($config, $projectPath);
$health = $this->healthCheck($projectPath, $config);
$blockers = array_merge(
$validation['errors'] ?? [],
array_filter($health['issues'] ?? [], function ($issue) {
return ($issue['severity'] ?? '') === 'critical';
})
);
$warnings = array_merge(
$validation['warnings'] ?? [],
array_filter($health['issues'] ?? [], function ($issue) {
return ($issue['severity'] ?? '') === 'warning';
})
);
return [
'ready' => empty($blockers),
'blockers' => $blockers,
'warnings' => $warnings,
'score' => $health['score'] ?? 0,
];
}
/**
* {@inheritdoc}
*/
public function getCommands(): array
{
// Default: no custom commands
return [];
}
/**
* {@inheritdoc}
*/
public function initializeProject(string $projectPath, array $options = []): array
{
// Default: no initialization
return [
'success' => true,
'message' => 'No initialization required for ' . $this->getProjectType(),
'files_created' => [],
];
}
/**
* Check if a file exists in the project
*
* @param string $projectPath Project directory path
* @param string $filePath Relative file path
* @return bool True if file exists
*/
protected function fileExists(string $projectPath, string $filePath): bool
{
return file_exists(rtrim($projectPath, '/') . '/' . ltrim($filePath, '/'));
}
/**
* Read a file from the project
*
* @param string $projectPath Project directory path
* @param string $filePath Relative file path
* @return string|null File contents or null if not found
*/
protected function readFile(string $projectPath, string $filePath): ?string
{
$fullPath = rtrim($projectPath, '/') . '/' . ltrim($filePath, '/');
return file_exists($fullPath) ? file_get_contents($fullPath) : null;
}
/**
* Check if files match a pattern in the project
*
* @param string $projectPath Project directory path
* @param string $pattern Glob pattern
* @return array Matching file paths
*/
protected function findFiles(string $projectPath, string $pattern): array
{
$fullPattern = rtrim($projectPath, '/') . '/' . ltrim($pattern, '/');
$matches = glob($fullPattern);
return is_array($matches) ? $matches : [];
}
/**
* Count files matching a pattern
*
* @param string $projectPath Project directory path
* @param string $pattern Glob pattern
* @return int Number of matching files
*/
protected function countFiles(string $projectPath, string $pattern): int
{
return count($this->findFiles($projectPath, $pattern));
}
/**
* Parse JSON file
*
* @param string $projectPath Project directory path
* @param string $filePath Relative file path
* @return array|null Parsed JSON data or null on error
*/
protected function parseJsonFile(string $projectPath, string $filePath): ?array
{
$content = $this->readFile($projectPath, $filePath);
if ($content === null) {
return null;
}
$data = json_decode($content, true);
return json_last_error() === JSON_ERROR_NONE ? $data : null;
}
/**
* Log plugin activity
*
* @param string $message Log message
* @param string $level Log level (info, warning, error)
* @param array $context Additional context
* @return void
*/
protected function log(string $message, string $level = 'info', array $context = []): void
{
$context['plugin'] = $this->getPluginName();
$context['project_type'] = $this->getProjectType();
switch ($level) {
case 'error':
$this->logger->logError($message, $context);
break;
case 'warning':
$this->logger->logWarning($message, $context);
break;
default:
$this->logger->logInfo($message, $context);
break;
}
}
/**
* Record metrics
*
* @param string $category Metric category
* @param string $name Metric name
* @param mixed $value Metric value
* @param array $tags Optional tags
* @return void
*/
protected function recordMetric(string $category, string $name, $value, array $tags = []): void
{
$tags['plugin'] = $this->getPluginName();
$tags['project_type'] = $this->getProjectType();
$this->metricsCollector->observe("{$category}.{$name}", (float) $value, $tags);
}
}