Skip to content

Commit

Permalink
Merge pull request #45 from statamic/misc-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseleite authored Mar 3, 2022
2 parents 72cf37e + 14a991a commit 37319d2
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Once installed, you should be able to run `statamic {command name}` from within
When you install starter kits, the CLI might present you with a warning that the GitHub API limit is reached. [Generate a Personal acces token](https://github.com/settings/tokens/new) and paste it in your terminal with this command so Composer will save it for future use:

```bash
composer config --global github-oauth.github.com [your_token_here]
composer config --global --auth github-oauth.github.com [your_token_here]
```

Read more on this in the [Composer Docs](https://getcomposer.org/doc/articles/authentication-for-private-packages.md).
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"require": {
"php": ">=7.2.5",
"guzzlehttp/guzzle": "^6.5.5|^7.0.1",
"symfony/console": "^4.0|^5.0",
"symfony/process": "^4.2|^5.0"
"symfony/console": "^4.0|^5.0|^6.0",
"symfony/process": "^4.2|^5.0|^6.0"
},
"require-dev": {
"phpunit/phpunit": "^8.0"
Expand Down
18 changes: 12 additions & 6 deletions src/Concerns/RunsCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ trait RunsCommands
* Run the given command.
*
* @param string $command
* @param bool $disableOutput
* @return Process
*/
protected function runCommand($command)
protected function runCommand($command, $disableOutput = false)
{
return $this->runCommands([$command]);
return $this->runCommands([$command], $disableOutput);
}

/**
* Run the given commands.
*
* @param array $commands
* @param bool $disableOutput
* @return Process
*/
protected function runCommands($commands)
protected function runCommands($commands, $disableOutput = false)
{
if (! $this->output->isDecorated()) {
$commands = array_map(function ($value) {
Expand Down Expand Up @@ -55,9 +57,13 @@ protected function runCommands($commands)
}
}

$process->run(function ($type, $line) {
$this->output->write(' '.$line);
});
if ($disableOutput) {
$process->disableOutput()->run();
} else {
$process->run(function ($type, $line) {
$this->output->write($line);
});
}

return $process;
}
Expand Down
179 changes: 171 additions & 8 deletions src/NewCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ class NewCommand extends Command

const BASE_REPO = 'statamic/statamic';
const OUTPOST_ENDPOINT = 'https://outpost.statamic.com/v3/starter-kits/';
const GITHUB_LATEST_RELEASE_ENDPOINT = 'https://api.github.com/repos/statamic/cli/releases/latest';

public $input;
public $output;
public $relativePath;
public $absolutePath;
public $name;
public $starterKit;
public $starterKitVcs;
public $starterKitLicense;
public $local;
public $withConfig;
public $force;
public $v2;
public $baseInstallSuccessful;
public $shouldUpdateCliToVersion = false;

/**
* Configure the command options.
Expand Down Expand Up @@ -69,6 +72,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->output = $output;

$this
->checkCliVersion()
->notifyIfOldCliVersion()
->processArguments()
->validateArguments()
->showStatamicTitleArt();
Expand All @@ -79,15 +84,64 @@ protected function execute(InputInterface $input, OutputInterface $output)

$this
->askForRepo()
->detectRepoVcs()
->detectMissingVcsAuth()
->validateStarterKitLicense()
->installBaseProject()
->installStarterKit()
->makeSuperUser()
->notifyIfOldCliVersion()
->showSuccessMessage();

return 0;
}

/**
* Check cli version.
*
* @return $this
*/
protected function checkCliVersion()
{
$request = new Client;

if (! $currentVersion = Version::get()) {
return $this;
}

try {
$response = $request->get(self::GITHUB_LATEST_RELEASE_ENDPOINT);
$latestVersion = json_decode($response->getBody(), true)['tag_name'];
} catch (\Throwable $exception) {
return $this;
}

if (version_compare($currentVersion, $latestVersion, '<')) {
$this->shouldUpdateCliToVersion = $latestVersion;
}

return $this;
}

/**
* Notify user if a statamic/cli upgrade exists.
*
* @return $this
*/
protected function notifyIfOldCliVersion()
{
if (! $this->shouldUpdateCliToVersion) {
return $this;
}

$this->output->write(PHP_EOL);
$this->output->write("<comment>This is an old version of the Statamic CLI Tool, please upgrade to {$this->shouldUpdateCliToVersion}!</comment>".PHP_EOL);
$this->output->write("<comment>If you have a global composer installation, you may upgrade by running the following command:</comment>".PHP_EOL);
$this->output->write("<comment>composer global update statamic/cli</comment>".PHP_EOL);

return $this;
}

/**
* Process arguments and options.
*
Expand Down Expand Up @@ -171,7 +225,7 @@ protected function showStatamicTitleArt()
}

/**
* Ask which starter repo to install.
* Ask which starter kit repo to install.
*
* @return $this
*/
Expand Down Expand Up @@ -211,6 +265,54 @@ protected function askForRepo()
return $this;
}

/**
* Detect starter kit repo vcs, using same precedence logic used in statamic/cms.
*
* @return $this
*/
protected function detectRepoVcs()
{
if ($this->local) {
return $this;
}

$request = new Client(['http_errors' => false]);

if ($request->get("https://repo.packagist.org/p2/{$this->starterKit}.json")->getStatusCode() === 200) {
return $this;
}

if ($request->get("https://github.com/{$this->starterKit}")->getStatusCode() === 200) {
$this->starterKitVcs = 'github';
} elseif ($request->get($bitbucketUrl = "https://bitbucket.org/{$this->starterKit}.git")->getStatusCode() === 200) {
$this->starterKitVcs = 'bitbucket';
} elseif ($request->get($gitlabUrl = "https://gitlab.com/{$this->starterKit}")->getStatusCode() === 200) {
$this->starterKitVcs = 'gitlab';
}

return $this;
}

/**
* Detect missing starter kit repo vcs auth, and prompt user to properly authenticate.
*
* @return $this
*/
protected function detectMissingVcsAuth()
{
if ($this->starterKitVcs === 'github' && $this->hasMissingComposerToken('github-oauth.github.com')) {
$this->output->write(PHP_EOL);
$this->output->write('<error>Composer could not authenticate with GitHub!</error>'.PHP_EOL);
$this->output->write('<comment>Please generate a personal access token at: https://github.com/settings/tokens/new</comment>'.PHP_EOL);
$this->output->write('<comment>Then save your token for future use by running the following command:</comment>'.PHP_EOL);
$this->output->write('<comment>composer config --global --auth github-oauth.github.com [your-token-here]</comment>'.PHP_EOL);

return $this->exitInstallation();
}

return $this;
}

/**
* Validate starter kit license.
*
Expand Down Expand Up @@ -246,11 +348,13 @@ protected function validateStarterKitLicense()
$kitSlug = $details['data']['slug'];
$marketplaceUrl = "https://statamic.com/starter-kits/{$sellerSlug}/{$kitSlug}";

$this->output->write(PHP_EOL);
$this->output->write('<comment>This is a paid starter kit. If you haven\'t already, you may purchase a license at:</comment>'.PHP_EOL);
$this->output->write("<comment>{$marketplaceUrl}</comment>".PHP_EOL);
if ($this->input->isInteractive()) {
$this->output->write(PHP_EOL);
$this->output->write('<comment>This is a paid starter kit. If you haven\'t already, you may purchase a license at:</comment>'.PHP_EOL);
$this->output->write("<comment>{$marketplaceUrl}</comment>".PHP_EOL);
}

$license = $this->getStarterkitLicense();
$license = $this->getStarterKitLicense();

try {
$response = $request->post(self::OUTPOST_ENDPOINT.'validate', ['json' => [
Expand All @@ -271,7 +375,7 @@ protected function validateStarterKitLicense()

$this->starterKitLicense = $license;

return $this;
return $this->confirmSingleSiteLicense();
}

/**
Expand All @@ -294,6 +398,38 @@ protected function confirmUnlistedKit()
return $this;
}

/**
* Confirm single-site license.
*
* @return $this
*/
protected function confirmSingleSiteLicense()
{
$appendedContinueText = $this->input->isInteractive() ? ' Would you like to continue installation?' : PHP_EOL;

$this->output->write(PHP_EOL);
$this->output->write('<comment>Once successfully installed, this single-site license will be marked as used</comment>'.PHP_EOL);
$this->output->write("<comment>and cannot be installed on future Statamic sites!{$appendedContinueText}</comment>");

if (! $this->input->isInteractive()) {
return $this;
}

$helper = $this->getHelper('question');

$questionText = 'I am aware this is a single-site license (yes/no) [<comment>no</comment>]: ';

$question = new ConfirmationQuestion($questionText, false);

$this->output->write(PHP_EOL);

if (! $helper->ask($this->input, $this->output, $question)) {
return $this->exitInstallation();
}

return $this;
}

/**
* Install base project.
*
Expand Down Expand Up @@ -348,6 +484,11 @@ protected function installStarterKit()

$options = ['--no-interaction', '--clear-site'];

// Temporary option to inform statamic/cms that user is using new CLI Tool installer.
// Since this newer version of the CLI tool will also notify the user of older
// CLI tool versions going forward, so we can rip this option out later.
$options[] = '--cli-install';

if ($this->local) {
$options[] = '--local';
}
Expand Down Expand Up @@ -637,12 +778,16 @@ protected function throwConnectionException()
*
* @return string
*/
protected function getStarterkitLicense()
protected function getStarterKitLicense()
{
if ($this->starterKitLicense) {
return $this->starterKitLicense;
}

if (! $this->input->isInteractive()) {
throw new RuntimeException('A starter kit license is required, please pass using the `--license` option!');
}

$helper = $this->getHelper('question');

$question = new Question('Please enter your license key: ');
Expand All @@ -654,13 +799,31 @@ protected function getStarterkitLicense()
return $license;
}

/**
* Check if user has missing composer token.
*
* @param string $tokenKey
* @return bool
*/
protected function hasMissingComposerToken($tokenKey)
{
$composer = $this->findComposer();

return ! $this
->runCommand("{$composer} config --global --auth {$tokenKey}", true)
->isSuccessful();
}

/**
* Exit installation.
*
* @return \stdClass
*/
protected function exitInstallation()
{
return new class {
function __call($method, $args) {
public function __call($method, $args)
{
return $this;
}
};
Expand Down

0 comments on commit 37319d2

Please sign in to comment.