2026-04-15 02:35:30 +00:00
#!/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
2026-05-21 21:33:52 -05:00
* DEFGROUP: moko-platform.CLI
* INGROUP: moko-platform
2026-05-11 17:01:17 -05:00
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
2026-04-15 02:35:30 +00:00
* PATH: /cli/create_repo.php
* BRIEF: Scaffold a new governed repository with full MokoStandards baseline
*
* USAGE
2026-04-18 19:18:22 -05:00
* php cli/create_repo.php --name MokoNewModule --type dolibarr --description "My new module"
* php cli/create_repo.php --name MokoNewModule --type joomla --private
* php cli/create_repo.php --name MokoNewModule --type generic --dry-run
2026-04-15 02:35:30 +00:00
*/
declare ( strict_types = 1 );
2026-04-16 19:18:01 -05:00
require_once __DIR__ . '/../vendor/autoload.php' ;
2026-04-15 02:35:30 +00:00
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 , " \n Types: 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 } \n version: 04.02.30 \n managed: 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}
2026-05-21 21:33:52 -05:00
INGROUP: moko-platform
2026-04-15 02:35:30 +00:00
REPO: {$repoUrl}
PATH: /README.md
BRIEF: {$description}
-->
# {$name}
[]({$standardsUrl})
[]({$repoUrl})
{$description}
## Getting Started
This repository is governed by [MokoStandards]({$standardsUrl}).
## License
This project is licensed under the GPL-3.0-or-later license. See [LICENSE](LICENSE) for details.
---
*This file is part of the Moko Consulting ecosystem. All rights reserved.*
*This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.*
MD ;
if ( ! $dryRun ) {
// Get existing README sha (auto_init creates one)
$sha = null ;
try {
$existing = $adapter -> getFileContents ( $org , $name , 'README.md' );
$sha = $existing [ 'sha' ] ?? null ;
} catch ( \Exception $e ) {
$adapter -> getApiClient () -> resetCircuitBreaker ();
}
$adapter -> createOrUpdateFile (
$org , $name , 'README.md' , $readmeContent ,
'docs: initialize README with MokoStandards header [skip ci]' ,
$sha
);
echo " README.md created \n " ;
} else {
echo " (dry-run) would create README.md \n " ;
}
// ── Step 5: Provision labels ────────────────────────────────────────────
echo "Step 5: Provisioning labels... \n " ;
if ( ! $dryRun ) {
$labelScript = " { $repoRoot } /api/maintenance/setup_labels.php" ;
if ( file_exists ( $labelScript )) {
$exitCode = 0 ;
passthru ( "php " . escapeshellarg ( $labelScript ) . " --org " . escapeshellarg ( $org ) . " --repo " . escapeshellarg ( $name ), $exitCode );
echo $exitCode === 0 ? " Labels provisioned \n " : " Label provisioning had issues \n " ;
} else {
echo " Labels will be provisioned on next sync \n " ;
}
} else {
echo " (dry-run) would provision standard labels \n " ;
}
// ── Step 6: Run first sync ──────────────────────────────────────────────
echo "Step 6: Running initial sync... \n " ;
if ( ! $dryRun ) {
$syncScript = " { $repoRoot } /api/automation/bulk_sync.php" ;
if ( file_exists ( $syncScript )) {
passthru ( "php " . escapeshellarg ( $syncScript ) . " --repos " . escapeshellarg ( $name ) . " --force --yes" );
} else {
2026-04-18 19:18:22 -05:00
echo " Run manually: php automation/bulk_sync.php --repos { $name } --force --yes \n " ;
2026-04-15 02:35:30 +00:00
}
} 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 {
2026-04-18 19:18:22 -05:00
echo " Run manually: php cli/create_project.php --repo { $name } --type { $type } \n " ;
2026-04-15 02:35:30 +00:00
}
} 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 " ;