Skip to content

Raise runner version to ubuntu-22.04#6744

Merged
paulbalandan merged 2 commits intocodeigniter4:developfrom
paulbalandan:ubuntu-runner
Oct 24, 2022
Merged

Raise runner version to ubuntu-22.04#6744
paulbalandan merged 2 commits intocodeigniter4:developfrom
paulbalandan:ubuntu-runner

Conversation

@paulbalandan
Copy link
Copy Markdown
Member

Description
The runner image for Ubuntu 22.04 LTS has been out for a while now.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@paulbalandan paulbalandan added the github_actions Pull requests that update Github_actions code label Oct 23, 2022
Copy link
Copy Markdown
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

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

🙏

@MGatner
Copy link
Copy Markdown
Member

MGatner commented Oct 24, 2022

"Child process timed out after 120 seconds". On line: 103

Some kind of parallel processing error? Strange if this is related to the runner version 🤔

@paulbalandan
Copy link
Copy Markdown
Member Author

I always get that error when running rector on Windows.

@samsonasik
Copy link
Copy Markdown
Member

set timeout, max number of process may be needed:

$rectorConfig->parallel(240, 3);

@samsonasik
Copy link
Copy Markdown
Member

@paulbalandan child error on windows seems resolved in rector 0.14.5 already https://github.com/rectorphp/rector/releases/tag/0.14.5

@paulbalandan
Copy link
Copy Markdown
Member Author

I'm using 0.14.6:

vendor/bin/rector process --dry-run system
  20/419 [=>--------------------------]   4%
                                                               
                                                               
 [ERROR] Could not process "C:\Users\P\Desktop\Web             
                                                               
         Dev\CodeIgniter4\vendor\rector\rector\vendor\symplify\easy-parallel\src\ValueObject\ParallelProcess.php" file,       
         due to:                                               
                                                               
         "Child process timed out after 120 seconds". On line: 103                                                            
                                                               
                                                               


 [ERROR] Could not process some files, due to:
         "Reached system errors count limit of 50, exiting...".

@samsonasik
Copy link
Copy Markdown
Member

@paulbalandan increase timeout and change max number process doesn't solve it?

$rectorConfig->parallel(240, 3);

If the issue persist, disable parallel can be used for last resort:

$rectorConfig->disableParallel();

@samsonasik
Copy link
Copy Markdown
Member

For note, Rector is using ReactPHP https://github.com/reactphp so it probably need wait to be there support Ubuntu 22.04 LTS to make parallel enabled.

@paulbalandan
Copy link
Copy Markdown
Member Author

paulbalandan commented Oct 24, 2022

Disabling parallel process fixes the issue on Windows.

I'm curious, though, why rector doesn't report these refactors in Github Actions.

Details
PS C:\Users\P\Desktop\Web Dev\CodeIgniter4> vendor/bin/rector process --dry-run system
 409/409 [============================] 100%
4 files with changes
====================

1) system/bootstrap.php:102

    ---------- begin diff ----------
@@ @@

 // Initialize and register the loader with the SPL autoloader stack.
 Services::autoloader()->initialize(new Autoload(), new Modules())->register();
+Services::autoloader()->loadHelpers();

 // Now load Composer's if it's available
 if (is_file(COMPOSER_PATH)) {
@@ @@

     require_once COMPOSER_PATH;
 }
-
-// Always load the URL helper, it should be used in most of apps.
-helper('url');
    ----------- end diff -----------

2) system/View/Cell.php:11

    ---------- begin diff ----------
@@ @@
 namespace CodeIgniter\View;

 use CodeIgniter\Cache\CacheInterface;
+use CodeIgniter\Config\Factories;
+use CodeIgniter\View\Cells\Cell as BaseCell;
 use CodeIgniter\View\Exceptions\ViewException;
 use Config\Services;
 use ReflectionException;
@@ @@
      */
     public function render(string $library, $params = null, int $ttl = 0, ?string $cacheName = null): string
     {
-        [$class, $method] = $this->determineClass($library);  
+        [$instance, $method] = $this->determineClass($library);

-        // Is it cached?
+        $class = is_object($instance)
+            ? get_class($instance)
+            : null;
+
+        // Is the output cached?
         $cacheName = ! empty($cacheName)
             ? $cacheName
             : str_replace(['\\', '/'], '', $class) . $method . md5(serialize($params));
@@ @@
             return $output;
         }

-        // Not cached - so grab it...
-        $instance = new $class();
-
         if (method_exists($instance, 'initController')) {     
             $instance->initController(Services::request(), Services::response(), Services::logger());
         }
@@ @@
             throw ViewException::forInvalidCellMethod($class, $method);
         }

-        // Try to match up the parameter list we were provided
-        // with the parameter name in the callback method.    
-        $paramArray = $this->prepareParams($params);
-        $refMethod  = new ReflectionMethod($instance, $method);
-        $paramCount = $refMethod->getNumberOfParameters();    
-        $refParams  = $refMethod->getParameters();
+        $params = $this->prepareParams($params);

-        if ($paramCount === 0) {
-            if (! empty($paramArray)) {
-                throw ViewException::forMissingCellParameters($class, $method);
-            }
+        $output = $instance instanceof BaseCell
+            ? $this->renderCell($instance, $method, $params)  
+            : $this->renderSimpleClass($instance, $method, $params, $class);

-            $output = $instance->{$method}();
-        } elseif (($paramCount === 1)
-            && ((! array_key_exists($refParams[0]->name, $paramArray))
-            || (array_key_exists($refParams[0]->name, $paramArray)
-            && count($paramArray) !== 1))
-        ) {
-            $output = $instance->{$method}($paramArray);      
-        } else {
-            $fireArgs     = [];
-            $methodParams = [];
-
-            foreach ($refParams as $arg) {
-                $methodParams[$arg->name] = true;
-                if (array_key_exists($arg->name, $paramArray)) {
-                    $fireArgs[$arg->name] = $paramArray[$arg->name];
-                }
-            }
-
-            foreach (array_keys($paramArray) as $key) {       
-                if (! isset($methodParams[$key])) {
-                    throw ViewException::forInvalidCellParameter($key);
-                }
-            }
-
-            $output = $instance->{$method}(...array_values($fireArgs));
-        }
         // Can we cache it?
         if (! empty($this->cache) && $ttl !== 0) {
             $this->cache->save($cacheName, $output, $ttl);    
@@ @@
         // by default, so convert any double colons.
         $library = str_replace('::', ':', $library);

+        // controlled cells might be called with just
+        // the class name, so add a default method
+        if (strpos($library, ':') === false) {
+            $library .= ':render';
+        }
+
         [$class, $method] = explode(':', $library);

         if (empty($class)) {
@@ @@
             throw ViewException::forNoCellClass();
         }

-        if (! class_exists($class, true)) {
+        // locate and return an instance of the cell
+        $class = Factories::cells($class);
+
+        if (! is_object($class)) {
             throw ViewException::forInvalidCellClass($class); 
         }

@@ @@
             $class,
             $method,
         ];
+    }
+
+    /**
+     * Renders a cell that extends the BaseCell class.        
+     */
+    final protected function renderCell(BaseCell $instance, string $method, array $params): string
+    {
+        // Only allow public properties to be set, or protected/private
+        // properties that have a method to get them (get<Foo>Property())
+        $publicProperties  = $instance->getPublicProperties();
+        $privateProperties = array_column($instance->getNonPublicProperties(), 'name');
+        $publicParams      = array_intersect_key($params, $publicProperties);
+
+        foreach ($params as $key => $value) {
+            $getter = 'get' . ucfirst($key) . 'Property';     
+            if (in_array($key, $privateProperties, true) && method_exists($instance, $getter)) {
+                $publicParams[$key] = $value;
+            }
+        }
+
+        // Fill in any public properties that were passed in  
+        // but only ones that are in the $pulibcProperties array.
+        $instance = $instance->fill($publicParams);
+
+        // If there are any protected/private properties, we need to
+        // send them to the mount() method.
+        if (method_exists($instance, 'mount')) {
+            // if any $params have keys that match the name of an argument in the
+            // mount method, pass those variables to the method.
+            $mountParams = $this->getMethodParams($instance, 'mount', $params);
+            $instance->mount(...$mountParams);
+        }
+
+        return $instance->{$method}();
+    }
+
+    /**
+     * Returns the values from $params that match the parameters
+     * for a method, in the order they are defined. This allows
+     * them to be passed directly into the method.
+     */
+    private function getMethodParams(BaseCell $instance, string $method, array $params)
+    {
+        $mountParams = [];
+
+        try {
+            $reflectionMethod = new ReflectionMethod($instance, $method);
+            $reflectionParams = $reflectionMethod->getParameters();
+
+            foreach ($reflectionParams as $reflectionParam) { 
+                $paramName = $reflectionParam->getName();     
+
+                if (array_key_exists($paramName, $params)) {  
+                    $mountParams[] = $params[$paramName];     
+                }
+            }
+        } catch (ReflectionException $e) {
+            // do nothing
+        }
+
+        return $mountParams;
+    }
+
+    /**
+     * Renders the non-Cell class, passing in the string/array params.
+     *
+     * @todo Determine if this can be refactored to use $this-getMethodParams().
+     *
+     * @param object $instance
+     */
+    final protected function renderSimpleClass($instance, string $method, array $params, string $class): string
+    {
+        // Try to match up the parameter list we were provided
+        // with the parameter name in the callback method.    
+        $refMethod  = new ReflectionMethod($instance, $method);
+        $paramCount = $refMethod->getNumberOfParameters();    
+        $refParams  = $refMethod->getParameters();
+
+        if ($paramCount === 0) {
+            if (! empty($params)) {
+                throw ViewException::forMissingCellParameters($class, $method);
+            }
+
+            $output = $instance->{$method}();
+        } elseif (($paramCount === 1)
+            && ((! array_key_exists($refParams[0]->name, $params))
+            || (array_key_exists($refParams[0]->name, $params)
+            && count($params) !== 1))
+        ) {
+            $output = $instance->{$method}($params);
+        } else {
+            $fireArgs     = [];
+            $methodParams = [];
+
+            foreach ($refParams as $arg) {
+                $methodParams[$arg->name] = true;
+                if (array_key_exists($arg->name, $params)) {  
+                    $fireArgs[$arg->name] = $params[$arg->name];
+                }
+            }
+
+            foreach (array_keys($params) as $key) {
+                if (! isset($methodParams[$key])) {
+                    throw ViewException::forInvalidCellParameter($key);
+                }
+            }
+
+            $output = $instance->{$method}(...array_values($fireArgs));
+        }
+
+        return $output;
     }
 }
    ----------- end diff -----------

3) system/Validation/ValidationInterface.php:19

    ---------- begin diff ----------
@@ @@
 {
     /**
      * Runs the validation process, returning true/false determining whether
-     * or not validation was successful.
+     * validation was successful or not.
      *
-     * @param array  $data  The array of data to validate.    
-     * @param string $group The pre-defined group of rules to apply.
+     * @param array|null  $data    The array of data to validate.
+     * @param string|null $group   The predefined group of rules to apply.
+     * @param string|null $dbGroup The database group to use. 
      */
-    public function run(?array $data = null, ?string $group = null): bool;
+    public function run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool;

     /**
      * Check; runs the validation process, returning true or false
@@ @@
     public function withRequest(RequestInterface $request): ValidationInterface;

     /**
+     * Sets an individual rule and custom error messages for a single field.
+     *
+     * The custom error message should be just the messages that apply to
+     * this field, like so:
+     *
+     *    [
+     *        'rule' => 'message',
+     *        'rule' => 'message',
+     *    ]
+     *
+     * @param array|string $rules
+     *
+     * @return $this
+     */
+    public function setRule(string $field, ?string $label, $rules, array $errors = []);
+
+    /**
      * Stores the rules that should be used to validate the items.
      */
     public function setRules(array $rules, array $messages = []): ValidationInterface;

     /**
+     * Returns all of the rules currently defined.
+     */
+    public function getRules(): array;
+
+    /**
      * Checks to see if the rule for key $field has been set or not.
      */
     public function hasRule(string $field): bool;

     /**
+     * Get rule group.
+     *
+     * @param string $group Group.
+     *
+     * @return string[] Rule group.
+     */
+    public function getRuleGroup(string $group): array;       
+
+    /**
+     * Set rule group.
+     *
+     * @param string $group Group.
+     */
+    public function setRuleGroup(string $group);
+
+    /**
      * Returns the error for a specified $field (or empty string if not set).
      */
     public function getError(string $field): string;
@@ @@
      * you need to process more than one array.
      */
     public function reset(): ValidationInterface;
+
+    /**
+     * Loads custom rule groups (if set) into the current rules.
+     *
+     * Rules can be pre-defined in Config\Validation and can  
+     * be any name, but must all still be an array of the     
+     * same format used with setRules(). Additionally, check  
+     * for {group}_errors for an array of custom error messages.
+     *
+     * @return array
+     */
+    public function loadRuleGroup(?string $group = null);     
+
+    /**
+     * Checks to see if an error exists for the given field.  
+     */
+    public function hasError(string $field): bool;
+
+    /**
+     * Returns the rendered HTML of the errors as defined in $template.
+     */
+    public function listErrors(string $template = 'list'): string;
+
+    /**
+     * Displays a single error in formatted HTML as defined in the $template view.
+     */
+    public function showError(string $field, string $template = 'single'): string;
 }
    ----------- end diff -----------

4) system/Validation/Validation.php:107

    ---------- begin diff ----------
@@ @@
      */
     public function run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool
     {
-        // If there are still validation errors for redirect_with_input request, remove them.
-        // See `getErrors()` method.
-        if (isset($_SESSION, $_SESSION['_ci_validation_errors'])) {
-            unset($_SESSION['_ci_validation_errors']);        
-        }
-
         $data ??= $this->data;

         // i.e. is_unique
@@ @@

                 $param = ($param === false) ? '' : $param;    

+                // @phpstan-ignore-next-line $error may be set by rule methods.
                 $this->errors[$field] = $error ?? $this->getErrorMessage(
                     $rule,
                     $field,
@@ @@
      *
      *    [
      *        'rule' => 'message',
-     *        'rule' => 'message'
+     *        'rule' => 'message',
      *    ]
      *
      * @param array|string $rules
@@ @@
      *
      * @return string[] Rule group.
      *
-     * @throws InvalidArgumentException If group not found.   
+     * @throws ValidationException If group not found.        
      */
     public function getRuleGroup(string $group): array        
     {
@@ @@
      *
      * @param string $group Group.
      *
-     * @throws InvalidArgumentException If group not found.   
+     * @throws ValidationException If group not found.        
      */
     public function setRuleGroup(string $group)
     {
@@ @@

     /**
      * Returns the rendered HTML of the errors as defined in $template.
+     *
+     * You can also use validation_list_errors() in Form helper.
      */
     public function listErrors(string $template = 'list'): string
     {
@@ @@

     /**
      * Displays a single error in formatted HTML as defined in the $template view.
+     *
+     * You can also use validation_show_error() in Form helper.
      */
     public function showError(string $field, string $template = 'single'): string
     {
@@ @@
      * same format used with setRules(). Additionally, check  
      * for {group}_errors for an array of custom error messages.
      *
-     * @return array|ValidationException|null
+     * @return array
+     *
+     * @throws ValidationException
      */
     public function loadRuleGroup(?string $group = null)      
     {
         if (empty($group)) {
-            return null;
+            return [];
         }

         if (! isset($this->config->{$group})) {
@@ @@
      */
     public function getErrors(): array
     {
-        // If we already have errors, we'll use those.        
-        // If we don't, check the session to see if any were  
-        // passed along from a redirect_with_input request.   
-        if (empty($this->errors) && ! is_cli() && isset($_SESSION, $_SESSION['_ci_validation_errors'])) {
-            $this->errors = unserialize($_SESSION['_ci_validation_errors']);
-        }
-
-        return $this->errors ?? [];
+        return $this->errors;
     }

     /**
    ----------- end diff -----------

                                                               

 [OK] 4 files would have changed (dry-run) by Rector           

                                                               

@samsonasik
Copy link
Copy Markdown
Member

@paulbalandan the change on windows seems invalid? I've no idea right now, it probably cache? Try running with --clear-cache probably help.

You possibly can also just run the whole project source as probably some symlink cause it:

vendor/bin/rector --dry-run --clear-cache

@samsonasik
Copy link
Copy Markdown
Member

@paulbalandan also, check on windows task manager if there is ongoing "php.exe" running

@paulbalandan
Copy link
Copy Markdown
Member Author

@samsonasik You're right, clearing the cache fixes the issue.

@paulbalandan paulbalandan merged commit 1fe58f0 into codeigniter4:develop Oct 24, 2022
@paulbalandan paulbalandan deleted the ubuntu-runner branch October 24, 2022 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github_actions Pull requests that update Github_actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants