Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Drupal 8 || 9 - Getting info about projects and files using the Gitlab API v4 from PHP code

Well, maybe you need track some kind of information and data from Gitlab repositories and the Gitlab API (v4) seems to be very extensive and complex...ok, I understand you, really.

I had to connect a custom Drupal module to the Gitlab API in order to get some info, so I wrote down some notes with examples talkin' to the Gitlab API.

For the next examples, you only need to know your user id (no the @user, this is a keycode) and get an access token from your Gitlab profile settings. They are the basic resources requested by the Gitlab API for connections.

For more information, see the Gitlab API Resources documentation: https://docs.gitlab.com/ee/api/api_resources.html.

Author

Intro

Well, you're in a Drupal installation and you need get info from an external Gitlab installation in order to reach data and then processing them and finally showing them in a page node. That is the workflow but first, you need manage the connection to Gitlab. This doesn't allows using simple URLs directions, you'll need do some authentication and then the own Gitlab API for queries (nowadays in version V4).

Also in the next steps you'll see the use of a variable $http_client, that is, your selected client for connections. Here you can use your favorite option: maybe a injected service based provided by Drupal -Drupal::httpClient- a wrapper to using Guzzle under the hood. This will be something like:

// First: Creates a http client based in Guzzle.
// See: https://api.drupal.org/api/drupal/core!lib!Drupal.php/function/Drupal%3A%3AhttpClient/9.2
$http_client = \Drupal::httpClient();

Or you can use Guzzle (present as dependency available in your Drupal installation), will be like doing:

[...]

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

[...]
public function performRequest($siteUrl) {
    $http_client = new \GuzzleHttp\Client();
    try {
      // Launch the Request and return results.
      $results = $http_client->get($siteUrl, ['http_errors' => false]);
      return($results->getStatusCode());
    } catch (RequestException $e) {
      return($this->t('Error'));
    }

  }

[...]

As a third choice, you can select the using of the Http Client Manager, a contrib module based in Guzzle that allows you defining calls to external APIs by defining them in YAML files and then using like a injected service in your classes. Using the module

"you will no longer need to write down Http services calls each times specifying endpoints and parameters in a totally decentralized way".

Here its documentation: drupal.org/contributed-modules/http-client-manager.

In any case, you will need your HTTP Client ready to go, that will be the variable $http_client in the next steps.

Gets all groups the user belongs to

$groups = json_decode($http_client->get('https://gitlab.com/api/v4/groups', [
                              'query' => [
                                'private_token' => "[YOUR_ACCESS_TOKEN]",
                               ],
                              ])->getBody()->getContents());

And now get all IDs from all the related groups

$groups_ids = [];
foreach ($groups as $index => $group) {
  $groups_id[] = $group->id;
}

Then gets all the projects related to each group

$projects_per_group = [];
foreach ($groups_id as $key => $id_group) {
  $projects_per_group[] = json_decode($http_client->get('https://gitlab.com/api/v4/groups/' . $id_group . '/projects', [
                        'query' => [
                          'private_token' => "[YOUR_ACCESS_TOKEN]",
                        ],
                      ])->getBody()->getContents());
      }

Get all the public projects of a user by using the user ID (code number, not @user)

(Only returns the first 20 public projects with visibility = public)

$public_projects = json_decode($http_client->get('https://gitlab.com/api/v4/users/[YOUR_ID_CODE_USER]/projects')->getBody()->getContents());

Reference in Gitlab API DOC.

Get the first 100 projects from an user with private visibility

(Here, visibility = private)

$private_projects = json_decode($http_client->get('https://gitlab.com/api/v4/users/[YOUR_ID_CODE_USER]/projects', [
    'query' => [
    'private_token' => "[YOUR_ACCESS_TOKEN]",
    'visibility' => "private",
    'per_page' => 100,
    ],
])->getBody()->getContents());

Now get some values from the returned projects

// Will return an array of Objects.
$projects[0]->id;
23310646

$projects[0]->name_with_namespace
"David Rodríguez  / Custom Drupal Modules"

Case: Getting content from a Markdown README file in a Gitlab private repo and render in a Drupal page

First we need to take the README file URL in Gitlab in order to get the project ID.

// Initial URL of the README file.
$url_md = "https://gitlab.com/davidjguru/custom-drupal-modules/-/blob/master/README.md";

// Gets the project naming from slugs in URL.
$project_name = explode("/", $url_md)[4];

// Now search for the requested project.
$searching_project = json_decode($http_client->get('https://gitlab.com/api/v4/users/[YOUR_ID_CODE_USER]/projects', [
            'query' => [
            'private_token' => "[YOUR_ACCESS_TOKEN]",
            'per_page' => 100,
            'search' => $project_name,
            ],
          ])->getBody()->getContents());
// This will return an array with related results but by name, will be unique result.
// Search in public and private projects. 

Now gets some interesting values from the result.

// Get the ID from the located project.
$project_id = $searching_project[0]->id;
$project_name = $searching_project[0]->name;

Do you wanna execute the most exhaustive search?

Ok, just merge all the located projects (by groups, by search, privates and public) in a unique array of projects:

// Looping over the private, public projects, searched and by group.
$all_projects = array_merge($private_projects, $public_projects, $projects_per_group, $searching_project);
foreach ($all_projects as $index => $project_segment) {
  foreach($project_segment as $key => $project) {
    if($project->name == $project_name) {
      $located_project = $project;
    }
  }
}

// And so,
$project_id = $located_project->id;

We're getting a README markdown file from previous project

// Now get the README file from project.
$requested_file_contents = $http_client->get('https://gitlab.com/api/v4/projects/' . $project_id . '/repository/files/README.md/raw, [
                    'query' => [
                      'private_token' => "[YOUR_ACCESS_TOKEN]",
                      'ref' => 'master',
                      ],
])->getBody()->getContents();

Now I'm gonna change the received content by HTML formatted content. For this I'll use the Parsedown PHP Library. I'm loading in Drupal using Composer, just doing by prompt: $ ddev composer require erusev/parsedown

See the Parsedown PHP Library.

use Parsedown;
$Parsedown = new Parsedown();

// Finally get the parsed content converted to HTML and send to render.
$parsed_content = $Parsedown->text($requested_file_contents);

return [
      '#theme' => 'md-import',
      '#file_response' => $parsed_content,
    ];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment