diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d2013fef6f391f4e93f0b571706e914ca3160ac6
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,23 @@
+include:
+  - project: $_GITLAB_TEMPLATES_REPO
+    ref: $_GITLAB_TEMPLATES_REF
+    file:
+      - '/includes/include.drupalci.main.yml'
+      - '/includes/include.drupalci.variables.yml'
+      - '/includes/include.drupalci.workflows.yml'
+
+variables:
+  SKIP_ESLINT: '1'
+
+phpstan:
+  stage: validate
+  rules:
+    - if: '$SKIP_PHPSTAN == "1"'
+      when: never
+    - when: on_success
+  artifacts:
+    when: always
+    reports:
+      codequality: phpstan-report.json
+  script:
+    - vendor/bin/phpstan analyze --memory-limit=2G --no-interaction --no-progress --error-format=gitlab $_WEB_ROOT/modules/custom | tee phpstan-report.json
diff --git a/composer.json b/composer.json
index 351fc81b7e09587a5a64fc52309c1c98cc3be4ac..46288a323ad213e550007a862803910aec772b3f 100644
--- a/composer.json
+++ b/composer.json
@@ -21,9 +21,12 @@
     "source": "https://git.drupal.org/project/gitlab_api"
   },
   "require": {
-    "php": ">=7.4",
+    "php": ">=8.1",
     "zeichen32/gitlabapibundle": "^6.0",
     "symfony/http-client": "^5.4 | ^6.2",
     "nyholm/psr7": "^1.4"
+  },
+  "require-dev": {
+    "drupal/webform": "^6.2"
   }
 }
diff --git a/gitlab_api.info.yml b/gitlab_api.info.yml
index 36f25d5546e9bf4e836e9e512cc2c22968ab79c0..7bc0ce0a2221f5abbe83943a1ad3b3380621330f 100644
--- a/gitlab_api.info.yml
+++ b/gitlab_api.info.yml
@@ -2,5 +2,5 @@ name: GitLab API
 type: module
 description: Integrates your Drupal site into GitLab using the GitLab API.
 package: Web services
-core_version_requirement: ^9 || ^10
+core_version_requirement: ^10 || ^11
 configure: entity.gitlab_server.collection
diff --git a/gitlab_api.install b/gitlab_api.install
index 02b9640d0cd00433a8541d7071c6d18f78aa31cf..bf703487cddc9ad133374327b707f597c3aea031 100644
--- a/gitlab_api.install
+++ b/gitlab_api.install
@@ -11,7 +11,7 @@ use Drupal\gitlab_api\Entity\GitlabServer;
 /**
  * Migrate configuration to a config entity.
  */
-function gitlab_api_update_8001() {
+function gitlab_api_update_8001(): void {
   $config = \Drupal::config('gitlab_api.settings');
   $url = $config->get('url');
   $token = $config->get('token');
@@ -28,7 +28,6 @@ function gitlab_api_update_8001() {
     ]);
     if ($server->save()) {
       \Drupal::configFactory()->getEditable('gitlab_api.settings')->delete();
-      return t('The Gitlab Server configuration has been migrated to a config entity');
     }
   }
 }
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000000000000000000000000000000000000..f9b218b18e6f52009b9eec1352803f9b70c5d7dc
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,4 @@
+parameters:
+  level: 6
+  checkMissingIterableValueType: false
+  checkGenericClassInNonGenericObjectType: false
diff --git a/src/Api.php b/src/Api.php
index 0cd3052265de474fbaa16496eb8004782a3c5bdd..7615e1ef13665236983f9e965ed96b4ab2d2ac3b 100644
--- a/src/Api.php
+++ b/src/Api.php
@@ -159,10 +159,12 @@ class Api {
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
    *    Use ::getClient()->createPipeline() instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
    */
   public function createPipeline(int $project_id, string $commit_ref, array $variables = []): array {
     $this->init();
-    return $this->client->projects()->createPipeline($project_id, $commit_ref, $variables);
+    return $this->client->projects()
+      ->createPipeline($project_id, $commit_ref, $variables);
   }
 
   /**
@@ -194,7 +196,7 @@ class Api {
     if ($due_date) {
       $params['due_date'] = $due_date->format('Y-m-d');
     }
-    if ($labels && count($labels) > 0) {
+    if (count($labels) > 0) {
       $params['labels'] = implode(',', $labels);
     }
 
@@ -208,7 +210,9 @@ class Api {
    *   The list of namespaces.
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
-   *     Use ::getClient()->namespaces()->all() instead.   */
+   *     Use ::getClient()->namespaces()->all() instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
+   */
   public function namespaces(): array {
     $this->init();
     return $this->client->namespaces()->all();
@@ -246,7 +250,7 @@ class Api {
     }
   }
 
-    /**
+  /**
    * Gets a project.
    *
    * @param int $project_id
@@ -301,6 +305,7 @@ class Api {
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
    *     Use ::getClient()->projects()->pipeline() instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
    */
   public function pipeline(int $project_id, int $pipeline_id): array {
     $this->init();
@@ -320,6 +325,7 @@ class Api {
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
    *      Use ::getClient()->pipelineJobs() instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
    */
   public function jobs(int $project_id, int $pipeline_id): array {
     $this->init();
@@ -431,6 +437,7 @@ class Api {
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
    *      Use ::getClient()->repositories()->branches() instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
    */
   public function branches(int $project_id): array {
     $this->init();
@@ -450,6 +457,7 @@ class Api {
    *
    * @deprecated in gitlab_api:2.1.2 and is removed from gitlab_apit:2.2.0.
    *      Use ::getClient()->repositories()->branch instead.
+   * @see https://www.drupal.org/project/gitlab_api/issues/3384270
    */
   public function branch(int $project_id, string $branch): array {
     $this->init();
diff --git a/src/CommitAction.php b/src/CommitAction.php
index 3e7065a7803e6e168a22d3aaed49d2cbaafe5113..46e9de0405755b894f2c82a8905dc39ddc1d7c40 100644
--- a/src/CommitAction.php
+++ b/src/CommitAction.php
@@ -15,34 +15,75 @@ class CommitAction {
   public const ENCODING_TEXT = 'text';
   public const ENCODING_BASE64 = 'base64';
 
+  /**
+   * The type of commit, which can be one of the TYPE_* constants.
+   *
+   * @var string
+   */
   protected string $type;
 
+  /**
+   * The relative path to the file that should be committed.
+   *
+   * @var string
+   */
   protected string $path;
 
+  /**
+   * The content of that file to be committed.
+   *
+   * @var string
+   */
   protected string $content;
 
+  /**
+   * The encoding of content, which can be one of the ENCODING_* constants.
+   *
+   * @var string
+   */
   protected string $encoding;
 
+  /**
+   * The previous path, if the commit is about moving a file.
+   *
+   * @var string|null
+   */
   protected ?string $previousPath;
 
   /**
+   * Creates and return a new CommitAction object.
+   *
    * @param string $type
+   *   The type of commit, which can be one of the TYPE_* constants.
    * @param string $path
+   *   The relative path to the file that should be committed.
    * @param string $content
+   *   The content of that file to be committed.
    * @param string $encoding
+   *   The encoding of content, which can be one of the ENCODING_* constants.
    * @param string $previousPath
+   *   The previous path, if the commit is about moving a file.
    *
    * @return \Drupal\gitlab_api\CommitAction
+   *   The new CommitAction object.
    *
    * @see \Gitlab\Api\Repositories::createCommit
    */
   public static function create(string $type, string $path, string $content, string $encoding = self::ENCODING_TEXT, string $previousPath = ''): CommitAction {
-    assert(in_array($type, [self::TYPE_CREATE, self::TYPE_DELETE, self::TYPE_MOVE, self::TYPE_UPDATE]));
-    assert(in_array($encoding, [self::ENCODING_TEXT, self::ENCODING_BASE64]));
+    assert(in_array($type, [
+      self::TYPE_CREATE,
+      self::TYPE_DELETE,
+      self::TYPE_MOVE,
+      self::TYPE_UPDATE,
+    ]));
+    assert(in_array($encoding, [
+      self::ENCODING_TEXT,
+      self::ENCODING_BASE64,
+    ]));
     if ($type === self::TYPE_MOVE) {
       assert($previousPath !== '');
     }
-    $instance = new static();
+    $instance = new self();
     $instance->type = $type;
     $instance->path = $path;
     $instance->content = $content;
@@ -52,7 +93,10 @@ class CommitAction {
   }
 
   /**
+   * Get an array of all relevant properties.
+   *
    * @return array
+   *   The array of relevant properties.
    */
   public function toArray(): array {
     return [