diff --git a/src/ncc/Classes/PhpExtension/Templates/GitHubWorkflowTemplate.php b/src/ncc/Classes/PhpExtension/Templates/GitHubWorkflowTemplate.php new file mode 100644 index 0000000..ea0d0fd --- /dev/null +++ b/src/ncc/Classes/PhpExtension/Templates/GitHubWorkflowTemplate.php @@ -0,0 +1,68 @@ +getProjectPath() . DIRECTORY_SEPARATOR . '.github' . DIRECTORY_SEPARATOR . 'workflows'; + + if(!file_exists($ci_dir)) + { + mkdir($ci_dir, 0777, true); + } + + IO::fwrite( + $ci_dir . DIRECTORY_SEPARATOR . 'ncc_workflow.yml', + ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), + IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'github_ci.yml.tpl') + ) + ); + } +} \ No newline at end of file diff --git a/src/ncc/Classes/PhpExtension/Templates/github_ci.yml.tpl b/src/ncc/Classes/PhpExtension/Templates/github_ci.yml.tpl new file mode 100644 index 0000000..39cb01e --- /dev/null +++ b/src/ncc/Classes/PhpExtension/Templates/github_ci.yml.tpl @@ -0,0 +1,158 @@ +name: CI + +on: + push: + branches: + - '**' + release: + types: [created] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + container: + image: php:8.3 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt update -yqq + apt install git libpq-dev libzip-dev zip make wget gnupg -yqq + + - name: Install phive + run: | + wget -O phive.phar https://phar.io/releases/phive.phar + wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc + gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79 + gpg --verify phive.phar.asc phive.phar + chmod +x phive.phar + mv phive.phar /usr/local/bin/phive + + - name: Install phab + run: | + phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C + + - name: Install latest version of NCC + run: | + git clone https://git.n64.cc/nosial/ncc.git + cd ncc + make redist + NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1) + if [ -z "$NCC_DIR" ]; then + echo "NCC build directory not found" + exit 1 + fi + php "$NCC_DIR/INSTALL" --auto + cd .. && rm -rf ncc + + - name: Build project + run: | + ncc build --config release --log-level debug + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: %ASSEMBLY.NAME%_build + path: build/release/%ASSEMBLY.PACKAGE%.ncc + + test: + needs: build + runs-on: ubuntu-latest + container: + image: php:8.3 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check for phpunit.xml + id: file_check + run: | + if [ -f phpunit.xml ]; then + echo "::set-output name=exists::true" + else + echo "::set-output name=exists::false" + fi + + - name: Skip if no phpunit.xml + if: steps.file_check.outputs.exists == 'false' + run: exit 78 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: %ASSEMBLY.NAME%_build + path: %ASSEMBLY.NAME%_build # Adjust this to download the artifact directly under '%ASSEMBLY.NAME%_build' + + - name: Install dependencies + run: | + apt update -yqq + apt install git libpq-dev libzip-dev zip make wget gnupg -yqq + curl -sSLf -o /usr/local/bin/install-php-extensions https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions + chmod +x /usr/local/bin/install-php-extensions + install-php-extensions zip + + - name: Install phive + run: | + wget -O phive.phar https://phar.io/releases/phive.phar + wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc + gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79 + gpg --verify phive.phar.asc phive.phar + chmod +x phive.phar + mv phive.phar /usr/local/bin/phive + + - name: Install phab + run: | + phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C + + - name: Install latest version of NCC + run: | + git clone https://git.n64.cc/nosial/ncc.git + cd ncc + make redist + NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1) + if [ -z "$NCC_DIR" ]; then + echo "NCC build directory not found" + exit 1 + fi + php "$NCC_DIR/INSTALL" --auto + cd .. && rm -rf ncc + + - name: Install NCC packages + run: | + ncc package install --package="%ASSEMBLY.NAME%_build/%ASSEMBLY.PACKAGE%.ncc" --build-source --reinstall -y --log-level debug + + - name: Run PHPUnit tests + run: | + wget https://phar.phpunit.de/phpunit-11.3.phar + php phpunit-11.3.phar --configuration phpunit.xml + + release: + needs: [build, test] + permissions: write-all + runs-on: ubuntu-latest + container: + image: php:8.3 + if: github.event_name == 'release' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: %ASSEMBLY.NAME%_build + path: %ASSEMBLY.NAME%_build + + - name: Upload to GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: | + %ASSEMBLY.NAME%_build/%ASSEMBLY.PACKAGE%.ncc + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/ncc/Enums/ProjectTemplates.php b/src/ncc/Enums/ProjectTemplates.php index b938004..a5f08fa 100644 --- a/src/ncc/Enums/ProjectTemplates.php +++ b/src/ncc/Enums/ProjectTemplates.php @@ -53,4 +53,40 @@ * Template that combines PHP_LIBRARY, PHP_MAKE, PHP_UNIT and PHP_CLI in one */ case PHP_CLI_FULL = 'phpcli_full'; + + /** + * Template that applies a GitHub workflow CI that builds the project, tests the project and creates + * automatic builds for releases + */ + case PHP_GITHUB_CI = 'phpci_github'; + + /** + * Suggests the closest matching `ProjectTemplates` instance based on the given input string. + * + * @param string $input The input string to compare against. + * @return ProjectTemplates|null The closest matching `ProjectTemplates` instance, or null if no close match is found. + */ + public static function suggest(string $input): ?ProjectTemplates + { + $closest = null; + $shortest_distance = -1; + + foreach (self::cases() as $case) + { + $distance = levenshtein($input, $case->value); + + if ($distance === 0) + { + return $case; + } + + if ($shortest_distance === -1 || $distance < $shortest_distance) + { + $closest = $case; + $shortest_distance = $distance; + } + } + + return $closest ?: null; + } } \ No newline at end of file diff --git a/src/ncc/Managers/ProjectManager.php b/src/ncc/Managers/ProjectManager.php index af6e3b8..ace3ed5 100644 --- a/src/ncc/Managers/ProjectManager.php +++ b/src/ncc/Managers/ProjectManager.php @@ -29,6 +29,7 @@ use ncc\Classes\PhpExtension\ExecutableCompiler; use ncc\Classes\PhpExtension\NccCompiler; use ncc\Classes\PhpExtension\Templates\CliTemplate; + use ncc\Classes\PhpExtension\Templates\GitHubWorkflowTemplate; use ncc\Classes\PhpExtension\Templates\LibraryTemplate; use ncc\Classes\PhpExtension\Templates\MakefileTemplate; use ncc\Classes\PhpExtension\Templates\PhpUnitTemplate; @@ -190,25 +191,25 @@ */ public function applyTemplate(string $template_name): void { - switch(strtolower($template_name)) + switch(ProjectTemplates::tryFrom(strtolower($template_name))) { - case ProjectTemplates::PHP_CLI->value: + case ProjectTemplates::PHP_CLI: CliTemplate::applyTemplate($this); break; - case ProjectTemplates::PHP_LIBRARY->value: + case ProjectTemplates::PHP_LIBRARY: LibraryTemplate::applyTemplate($this); break; - case ProjectTemplates::PHP_MAKE->value: + case ProjectTemplates::PHP_MAKE: MakefileTemplate::applyTemplate($this); break; - case ProjectTemplates::PHP_UNIT->value: + case ProjectTemplates::PHP_UNIT: PhpUnitTemplate::applyTemplate($this); break; - case ProjectTemplates::PHP_LIBRARY_FULL->value: + case ProjectTemplates::PHP_LIBRARY_FULL: LibraryTemplate::applyTemplate($this); MakefileTemplate::applyTemplate($this); PhpUnitTemplate::applyTemplate($this); @@ -221,7 +222,17 @@ PhpUnitTemplate::applyTemplate($this); break; + case ProjectTemplates::PHP_GITHUB_CI: + GitHubWorkflowTemplate::applyTemplate($this); + break; + default: + $suggestion = ProjectTemplates::suggest($template_name); + if($suggestion !== null) + { + throw new NotSupportedException('The given template \'' . $template_name . '\' is not supported, did you mean \'' . $suggestion->value . '\'?'); + } + throw new NotSupportedException('The given template \'' . $template_name . '\' is not supported'); } }