Skip to content

Commit bec8be9

Browse files
authored
Merge pull request #64 from hydephp/add-internal-hydefront-post-build-script
Merge changes from hydephp/develop#1360
2 parents 8f73001 + 8c58b9d commit bec8be9

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed

.github/scripts/minima.php

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
// This file is part of Minima.
4+
interface Minima{const VERSION='v0.1.0-dev';}interface Console{const INPUT=STDIN;const OUTPUT=STDOUT;}interface ANSI extends ANSI_EXT,XML_ANSI{const BLACK="\033[30m";const RED="\033[31m";const GREEN="\033[32m";const YELLOW="\033[33m";const BLUE="\033[34m";const MAGENTA="\033[35m";const CYAN="\033[36m";const WHITE="\033[37m";const GRAY="\033[90m";const RESET="\033[0m";}interface ANSI_EXT{const BRIGHT_RED="\033[91m";const BRIGHT_GREEN="\033[92m";const BRIGHT_YELLOW="\033[93m";const BRIGHT_BLUE="\033[94m";const BRIGHT_MAGENTA="\033[95m";const BRIGHT_CYAN="\033[96m";const BRIGHT_WHITE="\033[97m";}interface XML_ANSI{const INFO=ANSI::GREEN;const WARNING=ANSI::YELLOW;const ERROR=ANSI::RED;const COMMENT=ANSI::GRAY;const RESET=ANSI::RESET;}trait InteractsWithIO{public function write(string $string):void{Output::write($string);}public function line(string $message=''):void{Output::write($message."\n");}public function info(string $message):void{$this->line(XML_ANSI::INFO.$message.ANSI::RESET);}public function warning(string $message):void{$this->line(XML_ANSI::WARNING.$message.ANSI::RESET);}public function error(string $message):void{$this->line(XML_ANSI::ERROR.$message.ANSI::RESET);}public function formatted(string $message,bool $newLine=true):void{$startTags=['<info>'=>XML_ANSI::INFO,'<warning>'=>XML_ANSI::WARNING,'<error>'=>XML_ANSI::ERROR,'<comment>'=>XML_ANSI::COMMENT,'<reset>'=>XML_ANSI::RESET,'<red>'=>ANSI::RED,'<green>'=>ANSI::GREEN,'<blue>'=>ANSI::BLUE,'<yellow>'=>ANSI::YELLOW,'<magenta>'=>ANSI::MAGENTA,'<cyan>'=>ANSI::CYAN,];$endTags=['</info>'=>XML_ANSI::RESET,'</warning>'=>XML_ANSI::RESET,'</error>'=>XML_ANSI::RESET,'</comment>'=>XML_ANSI::RESET,'</reset>'=>XML_ANSI::RESET,'</>'=>XML_ANSI::RESET,'</red>'=>ANSI::RESET,'</green>'=>ANSI::RESET,'</blue>'=>ANSI::RESET,'</yellow>'=>ANSI::RESET,'</magenta>'=>ANSI::RESET,'</cyan>'=>ANSI::RESET,];$formatted=str_replace(array_keys($startTags),array_values($startTags),$message);$formatted=str_replace(array_keys($endTags),array_values($endTags),$formatted);if($newLine){$this->line($formatted);}else{$this->write($formatted);}}public function ask(string $question,string $default=''):string{return Input::readline(ANSI::YELLOW."$question: ".ANSI::RESET)?:$default;}}trait AccessesArguments{protected function options():array{return $this->options;}protected function arguments():array{return $this->arguments;}protected function hasOption(string $name):bool{return isset($this->options[$name]);}protected function hasArgument(string $name):bool{return isset($this->arguments[$name])||isset(array_flip(array_values($this->arguments))[$name]);}protected function getOption(string $name,mixed $default=null):mixed{return $this->options[$name]?? $default;}protected function getArgument(string $name,mixed $default=null):mixed{return $this->arguments[$name]?? $this->getArgumentByValue($name)?? $default;}private function getArgumentByValue(string $value):?string{$index=array_flip(array_values($this->arguments))[$value]?? null;return $this->arguments[$index]?? null;}private static function parseOptions(array $options):array{$formatted=[];foreach($options as $index=>$option){$option=ltrim($option,'-');if(str_contains($option,'=')){$parts=explode('=',$option);$formatted[$parts[0]]=$parts[1];}else{$formatted[$option]=true;}}return $formatted;}private static function parseArguments(array $arguments):array{$formatted=[];foreach($arguments as $index=>$argument){if(str_contains($argument,'=')){$parts=explode('=',$argument);$formatted[$parts[0]]=$parts[1];}else{$formatted[$index]=$argument;}}return $formatted;}private static function parseCommandArguments():array{global $argc;global $argv;$options=[];$arguments=[];for($i=1;$i<$argc;$i++){if(str_starts_with($argv[$i],'-')){$options[]=$argv[$i];}else{$arguments[]=$argv[$i];}}return[self::parseOptions($options),self::parseArguments($arguments)];}}class Output{public static function write(string $string):void{file_put_contents('php://output',$string);}}class Input{public static function readline(?string $prompt=null):string{return readline($prompt);}public static function getline():string{return trim(fgets(Console::INPUT));}}class Command{use InteractsWithIO;use AccessesArguments;protected Output $output;protected array $options;protected array $arguments;protected function __construct(){$this->output=new Output();[$this->options,$this->arguments]=$this->parseCommandArguments();}public static function main(Closure $logic):int{$command=new static();$logic=$logic->bindTo($command,static::class);return $logic()?? 0;}}class Dumper{public static int $arrayBreakLevel=2;const INDENT=' ';const ARRAY_OPEN=ANSI::WHITE.'['.ANSI::RESET;const ARRAY_CLOSE=ANSI::WHITE.']'.ANSI::RESET;const STRING_OPEN=ANSI::BLUE."'".ANSI::GREEN;const STRING_CLOSE=ANSI::BLUE."'".ANSI::RESET;const INTEGER_OPEN=ANSI::YELLOW;const INTEGER_CLOSE=ANSI::RESET;const BOOLEAN_OPEN=ANSI::RED;const BOOLEAN_CLOSE=ANSI::RESET;const OBJECT_OPEN=ANSI::YELLOW;const OBJECT_CLOSE=ANSI::RESET;const NULL=ANSI::RED.'null'.ANSI::RESET;protected int $indentationLevel=0;protected bool $inOpenArray=false;public static function highlight(mixed $data):string{return(new static())->runHighlighter($data);}protected function runHighlighter(mixed $data):string{if(is_null($data)){return $this->null($data);}if(is_string($data)){return $this->string($data);}if(is_int($data)){return $this->int($data);}if(is_bool($data)){return $this->bool($data);}if(is_array($data)){return $this->array($data);}if(is_object($data)){return static::OBJECT_OPEN.$data::class.static::OBJECT_CLOSE;}return (string) $data;}protected function null(null|string $value):string{return static::NULL;}protected function string(string $value):string{return static::STRING_OPEN.$value.static::STRING_CLOSE;}protected function int(int $value):string{return static::INTEGER_OPEN.$value.static::INTEGER_CLOSE;}protected function bool(bool $value):string{return static::BOOLEAN_OPEN.($value?'true':'false').static::BOOLEAN_CLOSE;}protected function array(array $array):string{$this->indentationLevel++;if($this->indentationLevel>=static::$arrayBreakLevel-1){$this->inOpenArray=true;}$parts=[];foreach($array as $key=>$value){if($this->inOpenArray){$indent=str_repeat(self::INDENT,$this->indentationLevel);}else{$indent='';}if(is_int($key)){$parts[]=$indent.$this->runHighlighter($value);}else{$parts[]=$indent.$this->string($key).' => '.$this->runHighlighter($value);}}if($this->inOpenArray){$this->indentationLevel--;$indent=str_repeat(self::INDENT,$this->indentationLevel);return static::ARRAY_OPEN."\n".implode(",\n",$parts)."\n$indent".static::ARRAY_CLOSE;}else{return static::ARRAY_OPEN.''.implode(', ',$parts).''.static::ARRAY_CLOSE;}}}if(!function_exists('main')){function main(Closure $logic):int{return Command::main($logic);}}if(!function_exists('dump')){function dump(mixed $value,bool $highlight=false):void{if($highlight){echo Dumper::highlight($value)."\n";}else{var_dump($value);}}}if(!function_exists('dd')){function dd(mixed $value,bool $highlight=false):never{dump($value,$highlight);exit(1);}}if(!function_exists('task')){function task(string $name,callable $task):void{$timeStart=microtime(true);global $argv;if(in_array('--skip-tasks',$argv)){putenv('SKIP_TASKS=true');$setLocation='option';}Output::write(ANSI::GREEN.'Running task '.ANSI::YELLOW."$name".ANSI::GREEN.'...'.ANSI::RESET.' ');if(!getenv('SKIP_TASKS')){ob_start();$task();$buffer=ob_get_clean();$time=round((microtime(true)-$timeStart)*1000,2);Output::write(ANSI::GREEN.'Done! '.ANSI::GRAY."(took {$time}ms)"." \n".ANSI::RESET);}else{$setLocation=$setLocation ?? 'environment variable';Output::write(ANSI::YELLOW.'Skipped '.ANSI::GRAY."(as set in $setLocation)\n".ANSI::RESET);}if(!empty($buffer)){foreach(explode("\n",trim($buffer))as $line){Output::write(" $line\n");}}}}

.github/scripts/post-build.php

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require_once __DIR__ . '/minima.php';
6+
7+
exit(main(function (): int {
8+
$this->info('Verifying build files...');
9+
10+
$exitCode = 0;
11+
$baseDir = __DIR__.'/../../';
12+
13+
$package = json_decode(file_get_contents($baseDir.'package.json'), true);
14+
$version = $package['version'];
15+
$this->line("Found version '$version' in package.json");
16+
17+
$hydeCssVersion = getCssVersion($baseDir.'dist/hyde.css');
18+
$this->line("Found version '$hydeCssVersion' in dist/hyde.css");
19+
20+
$appCssVersion = getCssVersion($baseDir.'dist/app.css');
21+
$this->line("Found version '$appCssVersion' in dist/app.css");
22+
23+
if ($version !== $hydeCssVersion) {
24+
$this->error('Version mismatch in package.json and dist/hyde.css:');
25+
$this->warning("Expected hyde.css to have version '$version', but found '$hydeCssVersion'");
26+
$exitCode = 1;
27+
}
28+
29+
if ($version !== $appCssVersion) {
30+
$this->error('Version mismatch in package.json and dist/app.css:');
31+
$this->warning("Expected app.css to have version '$version', but found '$appCssVersion'");
32+
$exitCode = 1;
33+
}
34+
35+
if ($this->hasOption('fix')) {
36+
$this->info('Fixing build files...');
37+
38+
if ($version !== $hydeCssVersion) {
39+
$this->line(' > Updating dist/hyde.css...');
40+
$contents = file_get_contents($baseDir.'dist/hyde.css');
41+
$contents = str_replace($hydeCssVersion, $version, $contents);
42+
file_put_contents($baseDir.'dist/hyde.css', $contents);
43+
$filesChanged = true;
44+
}
45+
46+
if ($version !== $appCssVersion) {
47+
$this->line(' > Updating dist/app.css...');
48+
$contents = file_get_contents($baseDir.'dist/app.css');
49+
$contents = str_replace($appCssVersion, $version, $contents);
50+
file_put_contents($baseDir.'dist/app.css', $contents);
51+
$filesChanged = true;
52+
}
53+
54+
if (isset($filesChanged)) {
55+
$this->info('Build files fixed');
56+
} else {
57+
$this->warning('Nothing to fix!');
58+
}
59+
}
60+
61+
if ($exitCode > 0) {
62+
$this->error('Exiting with errors.');
63+
} else {
64+
$this->info('Build files verified. All looks good!');
65+
}
66+
67+
return $exitCode;
68+
}));
69+
70+
function getCssVersion(string $path): string
71+
{
72+
$contents = file_get_contents($path);
73+
$prefix = '/*! HydeFront v';
74+
if (! str_starts_with($contents, $prefix)) {
75+
throw new Exception('Invalid CSS file');
76+
}
77+
$contents = substr($contents, strlen($prefix));
78+
// Get everything before |
79+
$pipePos = strpos($contents, '|');
80+
if ($pipePos === false) {
81+
throw new Exception('Invalid CSS file');
82+
}
83+
$contents = substr($contents, 0, $pipePos);
84+
return trim($contents);
85+
}

.github/scripts/version.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require_once __DIR__ . '/minima.php';
6+
7+
exit(main(function (): int {
8+
if (! is_dir(getcwd() . '/packages')) {
9+
$this->error('This script must be run from the root of the monorepo');
10+
$this->warning('Current working directory: ' . getcwd());
11+
return 1;
12+
}
13+
14+
global $argv;
15+
$versionType = $argv[1] ?? null;
16+
if ($versionType === null) {
17+
$this->error('Missing version type (supply as first argument)');
18+
return 1;
19+
}
20+
/** @noinspection SpellCheckingInspection */
21+
$nodeJsVersions = ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease'];
22+
if (! in_array($versionType, $nodeJsVersions)) {
23+
$this->error('Invalid version type: ' . $versionType);
24+
$this->warning('Must be one of: '.implode(', ', $nodeJsVersions));
25+
return 1;
26+
}
27+
28+
$this->info("Creating a new HydeFront $versionType version...");
29+
$version = trim(shell_exec('npm version ' . $versionType . ' --no-git-tag-version'));
30+
$this->line("Updated package.json version to $version");
31+
32+
$this->info('Updating version in dist files...');
33+
$this->line('---');
34+
passthru('php packages/hydefront/.github/scripts/post-build.php --fix', $fixExitCode);
35+
if ($fixExitCode !== 0) {
36+
$this->error('Failed to update version in dist files');
37+
return $fixExitCode;
38+
}
39+
$this->line('---');
40+
41+
$this->info('Committing changes in HydeFront...');
42+
passthru('cd packages/hydefront && git add . && git commit -m "HydeFront ' . $version . '"');
43+
44+
$this->info('Committing changes in monorepo...');
45+
passthru('git add packages/hydefront && git commit -m "HydeFront ' . $version . '"');
46+
47+
$this->info('All done!');
48+
$this->warning("Don't forget to verify the changes, tag them, push them, then publish the NPM package and create the release on GitHub!");
49+
50+
return 0;
51+
}));

.github/workflows/lint.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
lint:
11+
name: Lint
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v3
18+
19+
- name: Run linter
20+
run: php .github/scripts/post-build.php

0 commit comments

Comments
 (0)