61a232dfc6
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 56s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
New: lib/Enterprise/ManifestReader.php — shared manifest.xml parser with typed accessors for platform, package-type, entry-point, source-dir. Updated CLI tools to read manifest.xml: - updates_xml_build.php: supports non-Joomla platforms (dolibarr, generic, mcp) — builds generic updates.xml when no Joomla manifest found - release_package.php: reads entry-point from manifest.xml for source dir resolution instead of hard-coded src/htdocs fallback - pre-release.yml: replaced 75 lines of inline logic with CLI tool calls (manifest_read.php, manifest_element.php, updates_xml_build.php) Closes #163 Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
197 lines
5.8 KiB
PHP
197 lines
5.8 KiB
PHP
#!/usr/bin/env php
|
|
<?php
|
|
|
|
/**
|
|
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* FILE INFORMATION
|
|
* DEFGROUP: moko-platform.Enterprise
|
|
* INGROUP: moko-platform
|
|
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
|
* PATH: /lib/Enterprise/ManifestReader.php
|
|
* BRIEF: Read and parse .mokogitea/manifest.xml — shared across all CLI tools
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace MokoEnterprise;
|
|
|
|
/**
|
|
* Manifest Reader
|
|
*
|
|
* Parses .mokogitea/manifest.xml and provides typed access to all fields.
|
|
* Used by CLI tools and the Enterprise library to determine platform,
|
|
* build configuration, and deployment settings from the repository manifest.
|
|
*
|
|
* @since 09.01.00
|
|
*/
|
|
class ManifestReader
|
|
{
|
|
/** @var array<string, string> Parsed manifest fields */
|
|
private array $fields = [];
|
|
|
|
/** @var bool Whether a manifest was found and parsed */
|
|
private bool $loaded = false;
|
|
|
|
/**
|
|
* Load manifest from a repository root directory.
|
|
*
|
|
* @param string $root Repository root path
|
|
* @return self
|
|
*/
|
|
public static function fromPath(string $root): self
|
|
{
|
|
$reader = new self();
|
|
$reader->load($root);
|
|
return $reader;
|
|
}
|
|
|
|
/**
|
|
* Load and parse the manifest file.
|
|
*
|
|
* @param string $root Repository root path
|
|
*/
|
|
public function load(string $root): void
|
|
{
|
|
$candidates = [
|
|
"{$root}/.mokogitea/manifest.xml",
|
|
"{$root}/.mokogitea/.manifest.xml",
|
|
"{$root}/.mokogitea/.moko-platform",
|
|
];
|
|
|
|
$manifestFile = null;
|
|
foreach ($candidates as $candidate) {
|
|
if (file_exists($candidate)) {
|
|
$manifestFile = $candidate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($manifestFile === null) {
|
|
return;
|
|
}
|
|
|
|
$xml = @simplexml_load_file($manifestFile);
|
|
if ($xml === false) {
|
|
// Fallback: YAML legacy format
|
|
$content = file_get_contents($manifestFile);
|
|
if (preg_match('/^platform:\s*(.+)/m', $content, $m)) {
|
|
$this->fields['platform'] = trim($m[1], " \t\n\r\"'");
|
|
}
|
|
$this->loaded = true;
|
|
return;
|
|
}
|
|
|
|
$this->fields = [
|
|
'name' => (string)($xml->identity->name ?? ''),
|
|
'org' => (string)($xml->identity->org ?? ''),
|
|
'description' => (string)($xml->identity->description ?? ''),
|
|
'license' => (string)($xml->identity->license ?? ''),
|
|
'license-spdx' => (string)($xml->identity->license['spdx'] ?? ''),
|
|
'version' => (string)($xml->identity->version ?? ''),
|
|
'platform' => (string)($xml->governance->platform ?? ''),
|
|
'standards-version' => (string)($xml->governance->{"standards-version"} ?? ''),
|
|
'language' => (string)($xml->build->language ?? ''),
|
|
'package-type' => (string)($xml->build->{"package-type"} ?? ''),
|
|
'entry-point' => (string)($xml->build->{"entry-point"} ?? ''),
|
|
'source-dir' => (string)($xml->deploy->{"source-dir"} ?? ''),
|
|
'remote-subdir' => (string)($xml->deploy->{"remote-subdir"} ?? ''),
|
|
'dev-host' => (string)($xml->deploy->{"dev-host"} ?? ''),
|
|
'demo-host' => (string)($xml->deploy->{"demo-host"} ?? ''),
|
|
];
|
|
|
|
// Strip empty values
|
|
$this->fields = array_filter($this->fields, fn($v) => $v !== '');
|
|
$this->loaded = true;
|
|
}
|
|
|
|
/**
|
|
* Whether a manifest was found and loaded.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isLoaded(): bool
|
|
{
|
|
return $this->loaded;
|
|
}
|
|
|
|
/**
|
|
* Get a single field value.
|
|
*
|
|
* @param string $key Field name (e.g. 'platform', 'package-type')
|
|
* @param string $default Default value if field is missing
|
|
* @return string
|
|
*/
|
|
public function get(string $key, string $default = ''): string
|
|
{
|
|
return $this->fields[$key] ?? $default;
|
|
}
|
|
|
|
/**
|
|
* Get the platform slug, normalized to canonical values.
|
|
*
|
|
* @return string One of: joomla, dolibarr, generic, mcp, nodejs
|
|
*/
|
|
public function getPlatform(): string
|
|
{
|
|
$raw = $this->get('platform', 'generic');
|
|
return match ($raw) {
|
|
'waas-component' => 'joomla',
|
|
'crm-module' => 'dolibarr',
|
|
default => $raw,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the source/entry-point directory.
|
|
*
|
|
* @param string $root Repository root for existence checking
|
|
* @return string Resolved source directory path (e.g. 'src', 'htdocs')
|
|
*/
|
|
public function getSourceDir(string $root = ''): string
|
|
{
|
|
$entryPoint = $this->get('entry-point', '');
|
|
if ($entryPoint !== '') {
|
|
// Strip trailing filename (e.g. src/index.ts → src)
|
|
$dir = rtrim(dirname($entryPoint) === '.' ? $entryPoint : dirname($entryPoint), '/');
|
|
if ($root === '' || is_dir("{$root}/{$dir}")) {
|
|
return $dir;
|
|
}
|
|
}
|
|
|
|
// Fallback: check common directories
|
|
if ($root !== '') {
|
|
if (is_dir("{$root}/src")) {
|
|
return 'src';
|
|
}
|
|
if (is_dir("{$root}/htdocs")) {
|
|
return 'htdocs';
|
|
}
|
|
}
|
|
|
|
return 'src';
|
|
}
|
|
|
|
/**
|
|
* Get the package type for build decisions.
|
|
*
|
|
* @return string e.g. 'package', 'dolibarr', 'generic', 'mcp-server'
|
|
*/
|
|
public function getPackageType(): string
|
|
{
|
|
return $this->get('package-type', 'generic');
|
|
}
|
|
|
|
/**
|
|
* Get all parsed fields.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
public function getAll(): array
|
|
{
|
|
return $this->fields;
|
|
}
|
|
}
|