diff --git a/src/Api/GitlabClient.php b/src/Api/GitlabClient.php new file mode 100644 index 0000000..4f29da9 --- /dev/null +++ b/src/Api/GitlabClient.php @@ -0,0 +1,92 @@ +push( + new CacheMiddleware( + new PublicCacheStrategy( + new Psr6CacheStorage(Cache::getCache()) + ) + ), + 'cache' + ); + + $this->client = new \GuzzleHttp\Client( + [ + 'base_uri' => self::API_URL, + 'cookies' => true, + 'handler' => $stack, + 'headers' => [ + 'User-Agent' => 'DrupalOrgCli/0.0.1', + 'Accept' => 'application/json', + 'Accept-Encoding' => '*', + ], + ] + ); + } + + /** + * @param Request $request + * + * @return \mglaman\DrupalOrg\Response + * @throws \Exception + */ + public function request(Request $request): Response + { + $res = $this->client->request('GET', $request->getUrl()); + if ($res->getStatusCode() === 200) { + return new Response($res->getBody()->getContents()); + } + + throw new \Exception('Error code', $res->getStatusCode()); + } + + public function getProject(string $machineName): ?\stdClass + { + $request = new Request( + 'projects', + [ + 'search' => $machineName, + ] + ); + $res = $this->request($request); + foreach ($res->getAll() as $project) { + if ($project->name === $machineName) { + return $project; + } + } + return null; + } + + public function getProjectBranches(int $projectId): array + { + $request = new Request( + 'projects/' . $projectId . '/repository/branches' + ); + $res = $this->request($request); + return array_column($res->getAll()->getArrayCopy(), 'name'); + } +} diff --git a/src/Api/GitlabRequest.php b/src/Api/GitlabRequest.php new file mode 100644 index 0000000..3254c19 --- /dev/null +++ b/src/Api/GitlabRequest.php @@ -0,0 +1,9 @@ +get('list')); } + + /** + * @return \ArrayObject + */ + public function getAll(): \ArrayObject + { + return new \ArrayObject($this->response); + } } diff --git a/src/Cli/Application.php b/src/Cli/Application.php index f89f4db..731ba62 100644 --- a/src/Cli/Application.php +++ b/src/Cli/Application.php @@ -50,6 +50,7 @@ public function getCommands(): array $commands[] = new Command\Project\Link(); $commands[] = new Command\Project\Kanban(); $commands[] = new Command\Project\ProjectIssues(); + $commands[] = new Command\Project\ProjectClone(); $commands[] = new Command\Project\Releases(); $commands[] = new Command\Project\ReleaseNotes(); $commands[] = new Command\TravisCi\ListBuilds(); diff --git a/src/Cli/Command/Project/ProjectClone.php b/src/Cli/Command/Project/ProjectClone.php new file mode 100644 index 0000000..4cf4d25 --- /dev/null +++ b/src/Cli/Command/Project/ProjectClone.php @@ -0,0 +1,88 @@ +setName('project:clone') + ->setAliases(['pc']) + ->addArgument('project', InputArgument::REQUIRED, 'project ID') + ->addOption( + 'branch', + 'b', + InputOption::VALUE_OPTIONAL, + 'Branch to clone' + ) + ->addOption( + 'method', + 'm', + InputOption::VALUE_OPTIONAL, + 'Method for cloning (ssh or https)', + 'ssh' + ) + ->setDescription('Clone a project\'s repository.'); + } + + /** + * {@inheritdoc} + */ + protected function execute( + InputInterface $input, + OutputInterface $output + ): int { + $method = mb_strtolower($this->stdIn->getOption('method')); + if (!in_array($method, ['ssh', 'https'], true)) { + $this->stdErr->writeln('Unexpected method ' . $method . '.'); + $this->stdErr->writeln('Allowed values are: ssh, https'); + return 1; + } + + $gitlabClient = new GitlabClient(); + $project = $gitlabClient->getProject($this->projectName); + $branches = $gitlabClient->getProjectBranches($project->id); + $defaultBranch = reset($branches); + + $branch = $this->stdIn->getOption('branch'); + if (null === $branch) { + $helper = $this->getHelper('question'); + $question = new ChoiceQuestion( + "Which branch do you want to clone? [$defaultBranch]", + $branches, + $defaultBranch + ); + $branch = $helper->ask($input, $output, $question); + } + if (!in_array($branch, $branches, true)) { + $this->stdErr->writeln('Unexpected branch ' . $branch . '.'); + $this->stdErr->writeln('Existing branches are: ' . implode(', ', $branches)); + return 2; + } + + $cloneUrl = $method === 'ssh' ? $project->ssh_url_to_repo : $project->http_url_to_repo; + + // Clone the repository. + $process = new Process(['git', 'clone', '--branch', $branch, $cloneUrl]); + $process->run(); + if (!$process->isSuccessful()) { + $this->stdErr->writeln('The clone process failed.'); + $this->stdErr->writeln($process->getErrorOutput()); + return 3; + } + + $this->stdOut->writeln('Clone successful!'); + $this->stdOut->writeln("$ cd $this->projectName"); + return 0; + } +}