php 删除Gitlab项目的所有合并分支。生的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php 删除Gitlab项目的所有合并分支。生的相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env php
<?php
/**
 * Gitlab offers the ability to remove all branches in a projects that have
 * already been merged to master. However, as project count grows, it can become
 * cumbersome to visit each project an press that "delete" button.
 *
 * This script automated that task.
 *
 * When given the URL for a Gitlab REST API and a api-token, this script will
 * fetch a list of all projects (that are not archived and do not belong to a user)
 * and remove all branches that have already been merged to master.
 *
 * Requires PHP 5.4 or higher to run
 */

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

/**
 * @param array $arguments
 *
 * @return int The exit code
 */
function run(array $arguments)
{
    $exitCode = 1;

    $logger = new Logger();

    if (count($arguments) !== 3) {
        $message = vsprintf('Usage: %s <gitlab-domain> <api-token>', [$arguments[0]]);
        $logger->error($message);
        $exitCode = 64;
    } else {
        array_shift($arguments);
        list($domain, $apiToken) = $arguments;

        $url = vsprintf('https://%s/api/%s/', [$domain, 'v4']);

        $message = vsprintf(' ====> Removing all merged branches for non-archived, non-user projects at "%s"', [$url]);
        $logger->info($message);

        try {
            $api = new GitlabApi($url, $apiToken, $logger);
            $api->removeAllMergedBranches();
            $exitCode = 0;
        } catch (\Exception $exception) {
            $message = vsprintf(' ! ERROR An %s occurred: %s (line %s)', [get_class($exception), $exception->getMessage(), $exception->getLine()]);
            if (strpos($exception->getMessage(), 'certificate verify failed') !== false) {
                $message .= "\n".'This issue might be solved by this solution: https://stackoverflow.com/a/29405127/153049';
            }
            $logger->error("\n".$message);
            $exitCode = 65;
        }
    }

    return $exitCode;
}

/**
 * Class to Log to the CLI
 */
class Logger
{
    final public function info($message)
    {
        $this->log(STDOUT, $message);
    }

    final public function error($message)
    {
        $this->log(STDERR, $message);
    }

    private function log($handle, $message)
    {
        fwrite($handle, $message.PHP_EOL);
    }
}

/**
 * Class to communicate with the Gitlab REST API
 */
class GitlabApi
{
    const HTTP_STATUS_PATTERN = '/^.* (?<CODE>[0-9]{3}) (?<STATUS>.*)$/';
    /** @var string */
    private $api;
    /** @var Logger */
    private $logger;
    /** @var string */
    private $token;
    /** @var bool */
    private $urlIsUsable;

    /**
     * @param string $api
     * @param string $token
     * @param Logger $logger
     */
    final public function __construct($api, $token, Logger $logger)
    {
        $this->api = $api;
        $this->logger = $logger;
        $this->token = $token;
    }

    /**
     * @throws \RuntimeException
     */
    final public function removeAllMergedBranches()
    {
        $projects = $this->fetchProjects();

        $this->removeMergedBranches($projects);
    }

    /**
     * @param $method
     * @param $path
     *
     * @return bool|string
     *
     * @throws \RuntimeException
     */
    private function call($method, $path) {
        $this->validateApiUrl();

        return file_get_contents($this->api.$path, false, $this->getStreamContext($method));
    }

    /**
     * @param string $method
     *
     * @return resource
     */
    private function getStreamContext($method)
    {
        $contextOptions = [
            'http' => [
                'method' => $method,
                'header' => 'PRIVATE-TOKEN: '.$this->token
            ]
        ];

        return stream_context_create($contextOptions);
    }

    /**
     * @return array
     *
     * @throws \RuntimeException
     */
    private function fetchProjects()
    {
        $this->logger->info(' ====> Fetching project list');

        $path = '/projects?archived=false&per_page=100';

        $response = $this->call('GET', $path);
        $projectLists = json_decode($response, true);

        $projects = [];

        array_walk($projectLists, function ($project) use (&$projects) {
            if ($project['archived'] === false && $project['namespace']['kind'] === 'group') {
                $name = $project['path_with_namespace'];
                $projects[$name] = $project['id'];
            }
        });

        ksort($projects);

        return $projects;
    }

    /**
     * @param array $projects
     *
     * @throws \RuntimeException
     */
    private function removeMergedBranches(array $projects)
    {
        array_walk($projects, function ($id, $name) {
            $message = vsprintf(' ----> Removing all merged branches for: "%s" (id:%d)', [$name, $id]);

            $this->logger->info($message);

            $url = vsprintf('/projects/%s/repository/merged_branches', [$id]);
            try {
                $this->call('DELETE', $url);
            } catch (\ErrorException $exception) {
                preg_match(self::HTTP_STATUS_PATTERN, $exception->getMessage(), $matches);
                $message = vsprintf('       Could not remove branches for "%s": %s (%d)', [
                    $name,
                    $matches['STATUS'],
                    $matches['CODE'],
                ]);
                $this->logger->error($message);
            }
        });
    }

    /**
     * @throws \RuntimeException
     */
    private function validateApiUrl()
    {
        if ($this->urlIsUsable === null) {

            $streamContext = $this->getStreamContext('GET');

            if (PHP_MAJOR_VERSION >= 7 && PHP_MINOR_VERSION >= 1) {
                $headers = get_headers($this->api . '/version', true, $streamContext);
            } else {
                $options = stream_context_get_options($streamContext);
                stream_context_set_default($options);
                $headers = get_headers($this->api . '/version', true);
            }

            if (PHP_MAJOR_VERSION >= 7 || (PHP_MAJOR_VERSION === 5 && PHP_MINOR_VERSION >= 6)) {
                $headers = array_filter($headers, 'is_int', ARRAY_FILTER_USE_KEY);
            } else {
                $keys = array_filter(array_keys($headers), 'is_string');
                $headers = array_diff_key($headers, array_flip($keys));
            }

            $statusHeader = array_pop($headers);
            preg_match(self::HTTP_STATUS_PATTERN, $statusHeader, $matches);

            $this->urlIsUsable = ($matches['CODE'] >= 200 && $matches['CODE'] <= 299);

            if ($this->urlIsUsable !== true) {
                $message = vsprintf('Could not connect to API at %s. Got non-OK response: %s (%d)', [
                    $this->api,
                    $matches['STATUS'],
                    $matches['CODE'],
                ]);
                throw new \RuntimeException($message);
            }
        }
    }
}

exit(run($argv));

/*EOF*/

以上是关于php 删除Gitlab项目的所有合并分支。生的的主要内容,如果未能解决你的问题,请参考以下文章

使用gitlab cicd自动合并分支

Gitlab应用——开发人员fetch分支,合并到master主分支申请

通过 Gitlab 找回远程本地都删除的Commit

gitlab开发权限可以删除分支吗

Git 分支的创建、切换、合并以及解决冲突、删除

禁用开发人员可以在Gitlab项目中合并