Skip to content

Commit 37319d2

Browse files
authored
Merge pull request #45 from statamic/misc-improvements
2 parents 72cf37e + 14a991a commit 37319d2

4 files changed

Lines changed: 186 additions & 17 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Once installed, you should be able to run `statamic {command name}` from within
2525
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:
2626

2727
```bash
28-
composer config --global github-oauth.github.com [your_token_here]
28+
composer config --global --auth github-oauth.github.com [your_token_here]
2929
```
3030

3131
Read more on this in the [Composer Docs](https://getcomposer.org/doc/articles/authentication-for-private-packages.md).

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"require": {
77
"php": ">=7.2.5",
88
"guzzlehttp/guzzle": "^6.5.5|^7.0.1",
9-
"symfony/console": "^4.0|^5.0",
10-
"symfony/process": "^4.2|^5.0"
9+
"symfony/console": "^4.0|^5.0|^6.0",
10+
"symfony/process": "^4.2|^5.0|^6.0"
1111
},
1212
"require-dev": {
1313
"phpunit/phpunit": "^8.0"

src/Concerns/RunsCommands.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@ trait RunsCommands
1010
* Run the given command.
1111
*
1212
* @param string $command
13+
* @param bool $disableOutput
1314
* @return Process
1415
*/
15-
protected function runCommand($command)
16+
protected function runCommand($command, $disableOutput = false)
1617
{
17-
return $this->runCommands([$command]);
18+
return $this->runCommands([$command], $disableOutput);
1819
}
1920

2021
/**
2122
* Run the given commands.
2223
*
2324
* @param array $commands
25+
* @param bool $disableOutput
2426
* @return Process
2527
*/
26-
protected function runCommands($commands)
28+
protected function runCommands($commands, $disableOutput = false)
2729
{
2830
if (! $this->output->isDecorated()) {
2931
$commands = array_map(function ($value) {
@@ -55,9 +57,13 @@ protected function runCommands($commands)
5557
}
5658
}
5759

58-
$process->run(function ($type, $line) {
59-
$this->output->write(' '.$line);
60-
});
60+
if ($disableOutput) {
61+
$process->disableOutput()->run();
62+
} else {
63+
$process->run(function ($type, $line) {
64+
$this->output->write($line);
65+
});
66+
}
6167

6268
return $process;
6369
}

src/NewCommand.php

Lines changed: 171 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,22 @@ class NewCommand extends Command
2323

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

2728
public $input;
2829
public $output;
2930
public $relativePath;
3031
public $absolutePath;
3132
public $name;
3233
public $starterKit;
34+
public $starterKitVcs;
3335
public $starterKitLicense;
3436
public $local;
3537
public $withConfig;
3638
public $force;
3739
public $v2;
3840
public $baseInstallSuccessful;
41+
public $shouldUpdateCliToVersion = false;
3942

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

7174
$this
75+
->checkCliVersion()
76+
->notifyIfOldCliVersion()
7277
->processArguments()
7378
->validateArguments()
7479
->showStatamicTitleArt();
@@ -79,15 +84,64 @@ protected function execute(InputInterface $input, OutputInterface $output)
7984

8085
$this
8186
->askForRepo()
87+
->detectRepoVcs()
88+
->detectMissingVcsAuth()
8289
->validateStarterKitLicense()
8390
->installBaseProject()
8491
->installStarterKit()
8592
->makeSuperUser()
93+
->notifyIfOldCliVersion()
8694
->showSuccessMessage();
8795

8896
return 0;
8997
}
9098

99+
/**
100+
* Check cli version.
101+
*
102+
* @return $this
103+
*/
104+
protected function checkCliVersion()
105+
{
106+
$request = new Client;
107+
108+
if (! $currentVersion = Version::get()) {
109+
return $this;
110+
}
111+
112+
try {
113+
$response = $request->get(self::GITHUB_LATEST_RELEASE_ENDPOINT);
114+
$latestVersion = json_decode($response->getBody(), true)['tag_name'];
115+
} catch (\Throwable $exception) {
116+
return $this;
117+
}
118+
119+
if (version_compare($currentVersion, $latestVersion, '<')) {
120+
$this->shouldUpdateCliToVersion = $latestVersion;
121+
}
122+
123+
return $this;
124+
}
125+
126+
/**
127+
* Notify user if a statamic/cli upgrade exists.
128+
*
129+
* @return $this
130+
*/
131+
protected function notifyIfOldCliVersion()
132+
{
133+
if (! $this->shouldUpdateCliToVersion) {
134+
return $this;
135+
}
136+
137+
$this->output->write(PHP_EOL);
138+
$this->output->write("<comment>This is an old version of the Statamic CLI Tool, please upgrade to {$this->shouldUpdateCliToVersion}!</comment>".PHP_EOL);
139+
$this->output->write("<comment>If you have a global composer installation, you may upgrade by running the following command:</comment>".PHP_EOL);
140+
$this->output->write("<comment>composer global update statamic/cli</comment>".PHP_EOL);
141+
142+
return $this;
143+
}
144+
91145
/**
92146
* Process arguments and options.
93147
*
@@ -171,7 +225,7 @@ protected function showStatamicTitleArt()
171225
}
172226

173227
/**
174-
* Ask which starter repo to install.
228+
* Ask which starter kit repo to install.
175229
*
176230
* @return $this
177231
*/
@@ -211,6 +265,54 @@ protected function askForRepo()
211265
return $this;
212266
}
213267

268+
/**
269+
* Detect starter kit repo vcs, using same precedence logic used in statamic/cms.
270+
*
271+
* @return $this
272+
*/
273+
protected function detectRepoVcs()
274+
{
275+
if ($this->local) {
276+
return $this;
277+
}
278+
279+
$request = new Client(['http_errors' => false]);
280+
281+
if ($request->get("https://repo.packagist.org/p2/{$this->starterKit}.json")->getStatusCode() === 200) {
282+
return $this;
283+
}
284+
285+
if ($request->get("https://github.com/{$this->starterKit}")->getStatusCode() === 200) {
286+
$this->starterKitVcs = 'github';
287+
} elseif ($request->get($bitbucketUrl = "https://bitbucket.org/{$this->starterKit}.git")->getStatusCode() === 200) {
288+
$this->starterKitVcs = 'bitbucket';
289+
} elseif ($request->get($gitlabUrl = "https://gitlab.com/{$this->starterKit}")->getStatusCode() === 200) {
290+
$this->starterKitVcs = 'gitlab';
291+
}
292+
293+
return $this;
294+
}
295+
296+
/**
297+
* Detect missing starter kit repo vcs auth, and prompt user to properly authenticate.
298+
*
299+
* @return $this
300+
*/
301+
protected function detectMissingVcsAuth()
302+
{
303+
if ($this->starterKitVcs === 'github' && $this->hasMissingComposerToken('github-oauth.github.com')) {
304+
$this->output->write(PHP_EOL);
305+
$this->output->write('<error>Composer could not authenticate with GitHub!</error>'.PHP_EOL);
306+
$this->output->write('<comment>Please generate a personal access token at: https://github.com/settings/tokens/new</comment>'.PHP_EOL);
307+
$this->output->write('<comment>Then save your token for future use by running the following command:</comment>'.PHP_EOL);
308+
$this->output->write('<comment>composer config --global --auth github-oauth.github.com [your-token-here]</comment>'.PHP_EOL);
309+
310+
return $this->exitInstallation();
311+
}
312+
313+
return $this;
314+
}
315+
214316
/**
215317
* Validate starter kit license.
216318
*
@@ -246,11 +348,13 @@ protected function validateStarterKitLicense()
246348
$kitSlug = $details['data']['slug'];
247349
$marketplaceUrl = "https://statamic.com/starter-kits/{$sellerSlug}/{$kitSlug}";
248350

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

253-
$license = $this->getStarterkitLicense();
357+
$license = $this->getStarterKitLicense();
254358

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

272376
$this->starterKitLicense = $license;
273377

274-
return $this;
378+
return $this->confirmSingleSiteLicense();
275379
}
276380

277381
/**
@@ -294,6 +398,38 @@ protected function confirmUnlistedKit()
294398
return $this;
295399
}
296400

401+
/**
402+
* Confirm single-site license.
403+
*
404+
* @return $this
405+
*/
406+
protected function confirmSingleSiteLicense()
407+
{
408+
$appendedContinueText = $this->input->isInteractive() ? ' Would you like to continue installation?' : PHP_EOL;
409+
410+
$this->output->write(PHP_EOL);
411+
$this->output->write('<comment>Once successfully installed, this single-site license will be marked as used</comment>'.PHP_EOL);
412+
$this->output->write("<comment>and cannot be installed on future Statamic sites!{$appendedContinueText}</comment>");
413+
414+
if (! $this->input->isInteractive()) {
415+
return $this;
416+
}
417+
418+
$helper = $this->getHelper('question');
419+
420+
$questionText = 'I am aware this is a single-site license (yes/no) [<comment>no</comment>]: ';
421+
422+
$question = new ConfirmationQuestion($questionText, false);
423+
424+
$this->output->write(PHP_EOL);
425+
426+
if (! $helper->ask($this->input, $this->output, $question)) {
427+
return $this->exitInstallation();
428+
}
429+
430+
return $this;
431+
}
432+
297433
/**
298434
* Install base project.
299435
*
@@ -348,6 +484,11 @@ protected function installStarterKit()
348484

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

487+
// Temporary option to inform statamic/cms that user is using new CLI Tool installer.
488+
// Since this newer version of the CLI tool will also notify the user of older
489+
// CLI tool versions going forward, so we can rip this option out later.
490+
$options[] = '--cli-install';
491+
351492
if ($this->local) {
352493
$options[] = '--local';
353494
}
@@ -637,12 +778,16 @@ protected function throwConnectionException()
637778
*
638779
* @return string
639780
*/
640-
protected function getStarterkitLicense()
781+
protected function getStarterKitLicense()
641782
{
642783
if ($this->starterKitLicense) {
643784
return $this->starterKitLicense;
644785
}
645786

787+
if (! $this->input->isInteractive()) {
788+
throw new RuntimeException('A starter kit license is required, please pass using the `--license` option!');
789+
}
790+
646791
$helper = $this->getHelper('question');
647792

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

802+
/**
803+
* Check if user has missing composer token.
804+
*
805+
* @param string $tokenKey
806+
* @return bool
807+
*/
808+
protected function hasMissingComposerToken($tokenKey)
809+
{
810+
$composer = $this->findComposer();
811+
812+
return ! $this
813+
->runCommand("{$composer} config --global --auth {$tokenKey}", true)
814+
->isSuccessful();
815+
}
816+
657817
/**
658818
* Exit installation.
819+
*
820+
* @return \stdClass
659821
*/
660822
protected function exitInstallation()
661823
{
662824
return new class {
663-
function __call($method, $args) {
825+
public function __call($method, $args)
826+
{
664827
return $this;
665828
}
666829
};

0 commit comments

Comments
 (0)