Skip to content

Improve GH Actions in CLI #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 71 additions & 7 deletions console/create.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;

Expand Down Expand Up @@ -158,16 +159,31 @@ protected function get_component_data()
$components = $this->packager->get_component_dialog_values();
foreach ($components as $component => $details)
{
foreach ($details['dependencies'] as $depends)
// Skip early as it's handled elsewhere
if ($component === 'githubactions_custom')
{
if (empty($this->data['components'][$depends]))
{
$this->data['components'][$component] = false;
continue 2;
}
continue;
}
Comment on lines 159 to 166
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the get_component_data() method, you're now skipping the 'githubactions_custom' component early in the loop. This creates a special case that might be confusing for future developers. Consider restructuring this to handle special components in a more systematic way, perhaps through a component registry or handler pattern.

Suggested change
$components = $this->packager->get_component_dialog_values();
foreach ($components as $component => $details)
{
foreach ($details['dependencies'] as $depends)
// Skip early as it's handled elsewhere
if ($component === 'githubactions_custom')
{
if (empty($this->data['components'][$depends]))
{
$this->data['components'][$component] = false;
continue 2;
}
continue;
}
protected function get_component_data()
{
$components = $this->packager->get_component_dialog_values();
$special_components = ['githubactions', 'githubactions_custom'];
foreach ($components as $component => $details)
{
// Handle special components with custom logic
if (in_array($component, $special_components, true))
{
if ($component === 'githubactions')
{
$this->handle_github_actions();
}
continue;
}
// Check dependencies
if (!$this->check_dependencies($details['dependencies']))
{
$this->data['components'][$component] = false;
continue;
}
// Default logic for all other components
$this->data['components'][$component] = $this->get_user_input(
'component_' . $component,
$details['default']
);
}
}


$this->data['components'][$component] = $this->get_user_input('component_' . $component, $details['default']);
// Check dependencies
if (!$this->check_dependencies($details['dependencies']))
{
$this->data['components'][$component] = false;
continue;
}

// Handle GitHub Actions
if ($component === 'githubactions')
{
$this->handle_github_actions();
continue;
}

// Default logic for all other components
$this->data['components'][$component] = $this->get_user_input(
'component_' . $component,
$details['default']
);
}
}

Expand Down Expand Up @@ -201,4 +217,52 @@ protected function get_user_input($value, $default)

return $return_value;
}

/**
* Check if all dependencies are satisfied
*
* @param array $dependencies List of dependencies to check
* @return bool
*/
private function check_dependencies(array $dependencies): bool
{
foreach ($dependencies as $depends)
Comment on lines 217 to +229
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've extracted the dependency checking logic to a separate method check_dependencies() which is a good practice for code reusability and maintainability. However, this method returns a boolean but doesn't provide any information about which dependency failed. Consider enhancing it to return more descriptive information for better error handling or logging.

Suggested change
return $return_value;
}
/**
* Check if all dependencies are satisfied
*
* @param array $dependencies List of dependencies to check
* @return bool
*/
private function check_dependencies(array $dependencies): bool
{
foreach ($dependencies as $depends)
/**
* Check if all dependencies are satisfied
*
* @param array $dependencies List of dependencies to check
* @return array|bool Returns true if all dependencies are met, or array with failed dependency info
*/
private function check_dependencies(array $dependencies): bool|array
{
$failed_dependencies = [];
foreach ($dependencies as $depends)
{
if (empty($this->data['components'][$depends]))
{
$failed_dependencies[] = $depends;
}
}
return empty($failed_dependencies) ? true : $failed_dependencies;
}

{
if (empty($this->data['components'][$depends]))
{
return false;
}
}
return true;
}

/**
* Handle GitHub Actions specific logic
*/
private function handle_github_actions(): void
{
// Lookup table of GitHub Action component settings
$github_actions_types = [
Comment on lines +230 to +245
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handle_github_actions() method is a good separation of concerns for handling GitHub Actions specific logic. However, the hardcoded array indices (0, 1, 2) in the lookup table might make the code less maintainable if you add more options in the future. Consider using named constants or an enum-like approach for better readability and maintainability.

Suggested change
{
if (empty($this->data['components'][$depends]))
{
return false;
}
}
return true;
}
/**
* Handle GitHub Actions specific logic
*/
private function handle_github_actions(): void
{
// Lookup table of GitHub Action component settings
$github_actions_types = [
/**
* Handle GitHub Actions specific logic
*/
private function handle_github_actions(): void
{
// Define option constants for better readability
const OPTION_NONE = 0;
const OPTION_REUSABLE = 1;
const OPTION_STANDALONE = 2;
// Lookup table of GitHub Action component settings
$github_actions_types = [
self::OPTION_NONE => ['githubactions' => false, 'githubactions_custom' => false], // No (default)
self::OPTION_REUSABLE => ['githubactions' => true, 'githubactions_custom' => false], // Reusable
self::OPTION_STANDALONE => ['githubactions' => false, 'githubactions_custom' => true], // Standalone
];
// Rest of the method remains the same
$question_text = $this->language->lang('SKELETON_QUESTION_COMPONENT_GITHUBACTIONS') . $this->language->lang('COLON');
$choices = [];
foreach (array_keys($github_actions_types) as $i)
{
$choices[] = $this->language->lang('SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CLI', $i);
}

0 => ['githubactions' => false, 'githubactions_custom' => false], // No (default)
1 => ['githubactions' => true, 'githubactions_custom' => false], // Reusable
2 => ['githubactions' => false, 'githubactions_custom' => true], // Standalone
];

$question_text = $this->language->lang('SKELETON_QUESTION_COMPONENT_GITHUBACTIONS') . $this->language->lang('COLON');
$choices = [];
foreach (array_keys($github_actions_types) as $i)
{
$choices[] = $this->language->lang('SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CLI', $i);
}

$question = new ChoiceQuestion($question_text, $choices, 0);
$choice = $this->helper->ask($this->input, $this->output, $question);
$index = array_search($choice, $choices, true);

$component_settings = $github_actions_types[$index] ?? $github_actions_types[0];
$this->data['components'] = array_merge(
$this->data['components'] ?? [],
$component_settings
);
}
Comment on lines +260 to +267
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of component dependencies and GitHub Actions has been improved, but I noticed that you're manually merging arrays with array_merge(). Consider using PHP 7.4+ array spread operator ([...$array1, ...$array2]) for a more modern and readable approach if your minimum PHP version supports it.

Suggested change
$index = array_search($choice, $choices, true);
$component_settings = $github_actions_types[$index] ?? $github_actions_types[0];
$this->data['components'] = array_merge(
$this->data['components'] ?? [],
$component_settings
);
}
$this->data['components'] = [
...$this->data['components'] ?? [],
...$component_settings
];

}
39 changes: 22 additions & 17 deletions language/en/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,55 +78,60 @@
'SKELETON_QUESTION_PHPBB_VERSION_MAX_UI' => 'Maximum phpBB requirement of the extension',
'SKELETON_QUESTION_PHPBB_VERSION_MAX_EXPLAIN' => 'default: <' . \phpbb\skeleton\ext::DEFAULT_PHPBB_MAX,

'SKELETON_QUESTION_COMPONENT_PHPLISTENER' => 'Create sample PHP event listeners?',
'SKELETON_QUESTION_COMPONENT_PHPLISTENER' => 'Create sample PHP event listeners',
'SKELETON_QUESTION_COMPONENT_PHPLISTENER_UI' => 'PHP event listeners',
'SKELETON_QUESTION_COMPONENT_PHPLISTENER_EXPLAIN' => 'PHP event listeners work with core events to inject code into phpBB.',
'SKELETON_QUESTION_COMPONENT_HTMLLISTENER' => 'Create sample styles listeners?',
'SKELETON_QUESTION_COMPONENT_HTMLLISTENER' => 'Create sample styles listeners',
'SKELETON_QUESTION_COMPONENT_HTMLLISTENER_UI' => 'Style listeners',
'SKELETON_QUESTION_COMPONENT_HTMLLISTENER_EXPLAIN' => 'Style listeners use template events to inject HTML, JS and CSS into phpBB’s style files.',
'SKELETON_QUESTION_COMPONENT_ACP' => 'Create a sample ACP administration module?',
'SKELETON_QUESTION_COMPONENT_ACP' => 'Create a sample ACP administration module',
'SKELETON_QUESTION_COMPONENT_ACP_UI' => 'Administration control panel (ACP)',
'SKELETON_QUESTION_COMPONENT_ACP_EXPLAIN' => 'Add a functional ACP module for an extension to the ACP’s Extensions tab.',
'SKELETON_QUESTION_COMPONENT_MCP' => 'Create a sample MCP moderation module?',
'SKELETON_QUESTION_COMPONENT_MCP' => 'Create a sample MCP moderation module',
'SKELETON_QUESTION_COMPONENT_MCP_UI' => 'Moderator control panel (MCP)',
'SKELETON_QUESTION_COMPONENT_MCP_EXPLAIN' => 'Add a functional MCP module tab for an extension to the MCP.',
'SKELETON_QUESTION_COMPONENT_UCP' => 'Create a sample UCP user module?',
'SKELETON_QUESTION_COMPONENT_UCP' => 'Create a sample UCP user module',
'SKELETON_QUESTION_COMPONENT_UCP_UI' => 'User control panel (UCP)',
'SKELETON_QUESTION_COMPONENT_UCP_EXPLAIN' => 'Add a functional UCP module tab for an extension to the UCP.',
'SKELETON_QUESTION_COMPONENT_MIGRATION' => 'Create sample database migrations?',
'SKELETON_QUESTION_COMPONENT_MIGRATION' => 'Create sample database migrations',
'SKELETON_QUESTION_COMPONENT_MIGRATION_UI' => 'Database migration',
'SKELETON_QUESTION_COMPONENT_MIGRATION_EXPLAIN' => 'Migration files are used to make database changes.',
'SKELETON_QUESTION_COMPONENT_SERVICE' => 'Create a sample service?',
'SKELETON_QUESTION_COMPONENT_SERVICE' => 'Create a sample service',
'SKELETON_QUESTION_COMPONENT_SERVICE_UI' => 'Service',
'SKELETON_QUESTION_COMPONENT_SERVICE_EXPLAIN' => 'This is a PHP class that does something behind the scenes. It is a class that can be accessed by controllers, event listeners, or control panel modules.',
'SKELETON_QUESTION_COMPONENT_CONTROLLER' => 'Create a sample controller?',
'SKELETON_QUESTION_COMPONENT_CONTROLLER' => 'Create a sample controller',
'SKELETON_QUESTION_COMPONENT_CONTROLLER_UI' => 'Controller (front page)',
'SKELETON_QUESTION_COMPONENT_CONTROLLER_EXPLAIN'=> 'Controllers are typically used for the front-facing files/classes. They run the code that produces the page the user views.',
'SKELETON_QUESTION_COMPONENT_EXT' => 'Create a sample ext.php?',
'SKELETON_QUESTION_COMPONENT_EXT' => 'Create a sample ext.php',
'SKELETON_QUESTION_COMPONENT_EXT_UI' => 'Extension base (ext.php)',
'SKELETON_QUESTION_COMPONENT_EXT_EXPLAIN' => 'Create the optional ext.php file which can be used to run code before or during extension installation and removal.',
'SKELETON_QUESTION_COMPONENT_CONSOLE' => 'Create a sample console command?',
'SKELETON_QUESTION_COMPONENT_CONSOLE' => 'Create a sample console command',
'SKELETON_QUESTION_COMPONENT_CONSOLE_UI' => 'Console command',
'SKELETON_QUESTION_COMPONENT_CONSOLE_EXPLAIN' => 'A functional CLI interface to perform console/terminal commands.',
'SKELETON_QUESTION_COMPONENT_CRON' => 'Create a sample cron task?',
'SKELETON_QUESTION_COMPONENT_CRON' => 'Create a sample cron task',
'SKELETON_QUESTION_COMPONENT_CRON_UI' => 'Cron task',
'SKELETON_QUESTION_COMPONENT_CRON_EXPLAIN' => 'Add a cron task to be able to schedule and run cron-based actions from an extension.',
'SKELETON_QUESTION_COMPONENT_NOTIFICATION' => 'Create a sample notification?',
'SKELETON_QUESTION_COMPONENT_NOTIFICATION' => 'Create a sample notification',
'SKELETON_QUESTION_COMPONENT_NOTIFICATION_UI' => 'Notifications',
'SKELETON_QUESTION_COMPONENT_NOTIFICATION_EXPLAIN' => 'Notifications allow an extension to notify users of specific activities. When choosing notifications, do not use phpBB 3.1 as the minimum requirement. Notifications changed in phpBB 3.2.0 and are not backwards compatible with 3.1.x.',
'SKELETON_QUESTION_COMPONENT_PERMISSIONS' => 'Create sample permissions?',
'SKELETON_QUESTION_COMPONENT_PERMISSIONS' => 'Create sample permissions',
'SKELETON_QUESTION_COMPONENT_PERMISSIONS_UI' => 'Permissions',
'SKELETON_QUESTION_COMPONENT_PERMISSIONS_EXPLAIN' => 'Permissions can be used to grant users, groups and roles access to specific extension features.',
'SKELETON_QUESTION_COMPONENT_TESTS' => 'Create sample PHPUnit tests?',
'SKELETON_QUESTION_COMPONENT_TESTS' => 'Create sample PHPUnit tests',
'SKELETON_QUESTION_COMPONENT_TESTS_UI' => 'Tests (PHPUnit)',
'SKELETON_QUESTION_COMPONENT_TESTS_EXPLAIN' => 'Unit tests can test an extension to verify that specific portions of its source code work properly. This helps ensure basic code integrity and prevents regressions as an extension is being developed and debugged.',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS' => 'Create a GitHub Actions workflow to run tests in your repository?',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS' => 'Create a GitHub Actions workflow',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CLI' => [
0 => 'No (Default)',
1 => 'Reusable (Recommended - uses phpBB\'s maintained workflow)',
2 => 'Standalone (Deprecated - customise and maintain your own workflow)',
],
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_UI' => 'GitHub Actions Workflow (Reusable – Recommended)',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_EXPLAIN' => 'Creates a GitHub Actions workflow that uses a reusable, phpBB-maintained framework to run PHPUnit tests on your repository. The workflow file is saved in .github/workflows and runs automatically on each commit and pull request.',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CUSTOM' => 'Create a fully customisable GitHub Actions workflow? (Select this if you plan to modify jobs or steps.)',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CUSTOM' => 'Create a standalone GitHub Actions workflow [Deprecated: not recommended unless you plan to modify jobs or steps]',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CUSTOM_UI' => 'GitHub Actions Workflow (Standalone – Deprecated)',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CUSTOM_EXPLAIN' => 'Deprecated: Creates a fully standalone workflow to run PHPUnit tests without using the shared phpBB framework. This overrides the reusable workflow and is no longer recommended. The file is saved in .github/workflows and runs on each commit and pull request.',
'SKELETON_QUESTION_COMPONENT_BUILD' => 'Create a sample build script for phing?',
'SKELETON_QUESTION_COMPONENT_BUILD' => 'Create a sample build script for phing',
'SKELETON_QUESTION_COMPONENT_BUILD_UI' => 'Build script (phing)',
'SKELETON_QUESTION_COMPONENT_BUILD_EXPLAIN' => 'A phing build script is generated for your extension which can be used to generate build packages to help simplify the release or deployment processes.',

Expand Down
9 changes: 8 additions & 1 deletion tests/console/create_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public function setUp(): void
'files' => ['.github/workflows/tests.yml'],
'group' => 'TEST_DEPLOY',
],
'githubactions_custom' => [
'default' => false,
'dependencies' => [],
'files' => ['.github/workflows/tests.yml'],
'group' => 'TEST_DEPLOY',
],
]);
}

Expand Down Expand Up @@ -184,7 +190,8 @@ public function get_questions()
// 'SKELETON_QUESTION_COMPONENT_NOTIFICATION' => 'y',
// 'SKELETON_QUESTION_COMPONENT_PERMISSIONS' => 'y',
'SKELETON_QUESTION_COMPONENT_TESTS' => 'y',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS' => 'y',
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS' => 0,
'SKELETON_QUESTION_COMPONENT_GITHUBACTIONS_CUSTOM' => null,
// 'SKELETON_QUESTION_COMPONENT_BUILD' => 'y',
];
}
Expand Down