diff --git a/CLAUDE.md b/CLAUDE.md index c002df6..c91349f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -71,9 +71,9 @@ Flat structure. Each action self-contained with `action.yml`. -**26 Actions**: Setup (language-version-detect), Utilities (action-versioning, version-file-parser), +**24 Actions**: Setup (language-version-detect), Utilities (action-versioning, version-file-parser), Linting (ansible-lint-fix, biome-lint, csharp-lint-check, eslint-lint, go-lint, pr-lint, pre-commit, prettier-lint, python-lint-fix, terraform-lint-fix), -Testing (php-tests, php-laravel-phpunit, php-composer), Build (csharp-build, go-build, docker-build), +Testing (php-tests), Build (csharp-build, go-build, docker-build), Publishing (npm-publish, docker-publish, csharp-publish), Repository (release-monthly, sync-labels, stale, compress-images, codeql-analysis), Validation (validate-inputs) diff --git a/README.md b/README.md index fb62727..1172ab2 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,15 @@ Each action is fully self-contained and can be used independently in any GitHub ## ๐ Action Catalog -This repository contains **28 reusable GitHub Actions** for CI/CD automation. +This repository contains **25 reusable GitHub Actions** for CI/CD automation. -### Quick Reference (28 Actions) +### Quick Reference (25 Actions) | Icon | Action | Category | Description | Key Features | |:----:|:-----------------------------------------------------|:-----------|:----------------------------------------------------------------|:---------------------------------------------| | ๐ | [`action-versioning`][action-versioning] | Utilities | Automatically update SHA-pinned action references to match l... | Token auth, Outputs | | ๐ฆ | [`ansible-lint-fix`][ansible-lint-fix] | Linting | Lints and fixes Ansible playbooks, commits changes, and uplo... | Caching, Token auth, Outputs | -| โ | [`biome-lint`][biome-lint] | Linting | Run Biome linter in check or fix mode | Caching, Token auth, Outputs | +| โ | [`biome-lint`][biome-lint] | Linting | Run Biome linter in check or fix mode | Caching, Auto-detection, Token auth, Outputs | | ๐ก๏ธ | [`codeql-analysis`][codeql-analysis] | Repository | Run CodeQL security analysis for a single language with conf... | Auto-detection, Token auth, Outputs | | ๐ผ๏ธ | [`compress-images`][compress-images] | Repository | Compress images on demand (workflow_dispatch), and at 11pm e... | Token auth, Outputs | | ๐ | [`csharp-build`][csharp-build] | Build | Builds and tests C# projects. | Caching, Auto-detection, Token auth, Outputs | @@ -38,18 +38,15 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. | ๐ฆ | [`csharp-publish`][csharp-publish] | Publishing | Publishes a C# project to GitHub Packages. | Caching, Auto-detection, Token auth, Outputs | | ๐ฆ | [`docker-build`][docker-build] | Build | Builds a Docker image for multiple architectures with enhanc... | Caching, Auto-detection, Token auth, Outputs | | โ๏ธ | [`docker-publish`][docker-publish] | Publishing | Simple wrapper to publish Docker images to GitHub Packages a... | Token auth, Outputs | -| โ | [`eslint-lint`][eslint-lint] | Linting | Run ESLint in check or fix mode with advanced configuration ... | Caching, Token auth, Outputs | +| โ | [`eslint-lint`][eslint-lint] | Linting | Run ESLint in check or fix mode with advanced configuration ... | Caching, Auto-detection, Token auth, Outputs | | ๐ฆ | [`go-build`][go-build] | Build | Builds the Go project. | Caching, Auto-detection, Token auth, Outputs | | ๐ | [`go-lint`][go-lint] | Linting | Run golangci-lint with advanced configuration, caching, and ... | Caching, Token auth, Outputs | | ๐ | [`language-version-detect`][language-version-detect] | Setup | DEPRECATED: This action is deprecated. Inline version detect... | Auto-detection, Token auth, Outputs | -| ๐ฅ๏ธ | [`node-setup`][node-setup] | Setup | Sets up Node.js environment with version detection and packa... | Auto-detection, Token auth, Outputs | -| ๐ฆ | [`npm-publish`][npm-publish] | Publishing | Publishes the package to the NPM registry with configurable ... | Caching, Token auth, Outputs | -| ๐ฅ๏ธ | [`php-composer`][php-composer] | Testing | Runs Composer install on a repository with advanced caching ... | Caching, Auto-detection, Token auth, Outputs | -| ๐ป | [`php-laravel-phpunit`][php-laravel-phpunit] | Testing | Setup PHP, install dependencies, generate key, create databa... | Auto-detection, Token auth, Outputs | -| โ | [`php-tests`][php-tests] | Testing | Run PHPUnit tests on the repository | Token auth, Outputs | +| ๐ฆ | [`npm-publish`][npm-publish] | Publishing | Publishes the package to the NPM registry with configurable ... | Caching, Auto-detection, Token auth, Outputs | +| โ | [`php-tests`][php-tests] | Testing | Run PHPUnit tests with optional Laravel setup and Composer d... | Caching, Auto-detection, Token auth, Outputs | | โ | [`pr-lint`][pr-lint] | Linting | Runs MegaLinter against pull requests | Caching, Auto-detection, Token auth, Outputs | | ๐ฆ | [`pre-commit`][pre-commit] | Linting | Runs pre-commit on the repository and pushes the fixes back ... | Auto-detection, Token auth, Outputs | -| โ | [`prettier-lint`][prettier-lint] | Linting | Run Prettier in check or fix mode with advanced configuratio... | Caching, Token auth, Outputs | +| โ | [`prettier-lint`][prettier-lint] | Linting | Run Prettier in check or fix mode with advanced configuratio... | Caching, Auto-detection, Token auth, Outputs | | ๐ | [`python-lint-fix`][python-lint-fix] | Linting | Lints and fixes Python files, commits changes, and uploads S... | Caching, Auto-detection, Token auth, Outputs | | ๐ฆ | [`release-monthly`][release-monthly] | Repository | Creates a release for the current month, incrementing patch ... | Token auth, Outputs | | ๐ฆ | [`stale`][stale] | Repository | A GitHub Action to close stale issues and pull requests. | Token auth, Outputs | @@ -59,12 +56,11 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. ### Actions by Category -#### ๐ง Setup (2 actions) +#### ๐ง Setup (1 action) -| Action | Description | Languages | Features | -|:--------------------------------------------------------|:------------------------------------------------------|:--------------------------------|:------------------------------------| -| ๐ [`language-version-detect`][language-version-detect] | DEPRECATED: This action is deprecated. Inline vers... | PHP, Python, Go, .NET, Node.js | Auto-detection, Token auth, Outputs | -| ๐ฅ๏ธ [`node-setup`][node-setup] | Sets up Node.js environment with version detection... | Node.js, JavaScript, TypeScript | Auto-detection, Token auth, Outputs | +| Action | Description | Languages | Features | +|:--------------------------------------------------------|:------------------------------------------------------|:-------------------------------|:------------------------------------| +| ๐ [`language-version-detect`][language-version-detect] | DEPRECATED: This action is deprecated. Inline vers... | PHP, Python, Go, .NET, Node.js | Auto-detection, Token auth, Outputs | #### ๐ ๏ธ Utilities (1 action) @@ -77,23 +73,21 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. | Action | Description | Languages | Features | |:-----------------------------------------------|:------------------------------------------------------|:---------------------------------------------|:---------------------------------------------| | ๐ฆ [`ansible-lint-fix`][ansible-lint-fix] | Lints and fixes Ansible playbooks, commits changes... | Ansible, YAML | Caching, Token auth, Outputs | -| โ [`biome-lint`][biome-lint] | Run Biome linter in check or fix mode | JavaScript, TypeScript, JSON | Caching, Token auth, Outputs | +| โ [`biome-lint`][biome-lint] | Run Biome linter in check or fix mode | JavaScript, TypeScript, JSON | Caching, Auto-detection, Token auth, Outputs | | ๐ [`csharp-lint-check`][csharp-lint-check] | Runs linters like StyleCop or dotnet-format for C#... | C#, .NET | Auto-detection, Token auth, Outputs | -| โ [`eslint-lint`][eslint-lint] | Run ESLint in check or fix mode with advanced conf... | JavaScript, TypeScript | Caching, Token auth, Outputs | +| โ [`eslint-lint`][eslint-lint] | Run ESLint in check or fix mode with advanced conf... | JavaScript, TypeScript | Caching, Auto-detection, Token auth, Outputs | | ๐ [`go-lint`][go-lint] | Run golangci-lint with advanced configuration, cac... | Go | Caching, Token auth, Outputs | | โ [`pr-lint`][pr-lint] | Runs MegaLinter against pull requests | Conventional Commits | Caching, Auto-detection, Token auth, Outputs | | ๐ฆ [`pre-commit`][pre-commit] | Runs pre-commit on the repository and pushes the f... | Python, Multiple Languages | Auto-detection, Token auth, Outputs | -| โ [`prettier-lint`][prettier-lint] | Run Prettier in check or fix mode with advanced co... | JavaScript, TypeScript, Markdown, YAML, JSON | Caching, Token auth, Outputs | +| โ [`prettier-lint`][prettier-lint] | Run Prettier in check or fix mode with advanced co... | JavaScript, TypeScript, Markdown, YAML, JSON | Caching, Auto-detection, Token auth, Outputs | | ๐ [`python-lint-fix`][python-lint-fix] | Lints and fixes Python files, commits changes, and... | Python | Caching, Auto-detection, Token auth, Outputs | | ๐ฅ๏ธ [`terraform-lint-fix`][terraform-lint-fix] | Lints and fixes Terraform files with advanced vali... | Terraform, HCL | Token auth, Outputs | -#### ๐งช Testing (3 actions) +#### ๐งช Testing (1 action) -| Action | Description | Languages | Features | -|:------------------------------------------------|:------------------------------------------------------|:-------------|:---------------------------------------------| -| ๐ฅ๏ธ [`php-composer`][php-composer] | Runs Composer install on a repository with advance... | PHP | Caching, Auto-detection, Token auth, Outputs | -| ๐ป [`php-laravel-phpunit`][php-laravel-phpunit] | Setup PHP, install dependencies, generate key, cre... | PHP, Laravel | Auto-detection, Token auth, Outputs | -| โ [`php-tests`][php-tests] | Run PHPUnit tests on the repository | PHP | Token auth, Outputs | +| Action | Description | Languages | Features | +|:---------------------------|:------------------------------------------------------|:-------------|:---------------------------------------------| +| โ [`php-tests`][php-tests] | Run PHPUnit tests with optional Laravel setup and ... | PHP, Laravel | Caching, Auto-detection, Token auth, Outputs | #### ๐๏ธ Build (3 actions) @@ -109,7 +103,7 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. |:--------------------------------------|:------------------------------------------------------|:-------------|:---------------------------------------------| | ๐ฆ [`csharp-publish`][csharp-publish] | Publishes a C# project to GitHub Packages. | C#, .NET | Caching, Auto-detection, Token auth, Outputs | | โ๏ธ [`docker-publish`][docker-publish] | Simple wrapper to publish Docker images to GitHub ... | Docker | Token auth, Outputs | -| ๐ฆ [`npm-publish`][npm-publish] | Publishes the package to the NPM registry with con... | Node.js, npm | Caching, Token auth, Outputs | +| ๐ฆ [`npm-publish`][npm-publish] | Publishes the package to the NPM registry with con... | Node.js, npm | Caching, Auto-detection, Token auth, Outputs | #### ๐ฆ Repository (5 actions) @@ -133,7 +127,7 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. |:-----------------------------------------------------|:-------:|:--------------:|:----------:|:-------:| | [`action-versioning`][action-versioning] | - | - | โ | โ | | [`ansible-lint-fix`][ansible-lint-fix] | โ | - | โ | โ | -| [`biome-lint`][biome-lint] | โ | - | โ | โ | +| [`biome-lint`][biome-lint] | โ | โ | โ | โ | | [`codeql-analysis`][codeql-analysis] | - | โ | โ | โ | | [`compress-images`][compress-images] | - | - | โ | โ | | [`csharp-build`][csharp-build] | โ | โ | โ | โ | @@ -141,18 +135,15 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. | [`csharp-publish`][csharp-publish] | โ | โ | โ | โ | | [`docker-build`][docker-build] | โ | โ | โ | โ | | [`docker-publish`][docker-publish] | - | - | โ | โ | -| [`eslint-lint`][eslint-lint] | โ | - | โ | โ | +| [`eslint-lint`][eslint-lint] | โ | โ | โ | โ | | [`go-build`][go-build] | โ | โ | โ | โ | | [`go-lint`][go-lint] | โ | - | โ | โ | | [`language-version-detect`][language-version-detect] | - | โ | โ | โ | -| [`node-setup`][node-setup] | - | โ | โ | โ | -| [`npm-publish`][npm-publish] | โ | - | โ | โ | -| [`php-composer`][php-composer] | โ | โ | โ | โ | -| [`php-laravel-phpunit`][php-laravel-phpunit] | - | โ | โ | โ | -| [`php-tests`][php-tests] | - | - | โ | โ | +| [`npm-publish`][npm-publish] | โ | โ | โ | โ | +| [`php-tests`][php-tests] | โ | โ | โ | โ | | [`pr-lint`][pr-lint] | โ | โ | โ | โ | | [`pre-commit`][pre-commit] | - | โ | โ | โ | -| [`prettier-lint`][prettier-lint] | โ | - | โ | โ | +| [`prettier-lint`][prettier-lint] | โ | โ | โ | โ | | [`python-lint-fix`][python-lint-fix] | โ | โ | โ | โ | | [`release-monthly`][release-monthly] | - | - | โ | โ | | [`stale`][stale] | - | - | โ | โ | @@ -178,17 +169,17 @@ This repository contains **28 reusable GitHub Actions** for CI/CD automation. | JPEG | [`compress-images`][compress-images] | | JSON | [`biome-lint`][biome-lint], [`prettier-lint`][prettier-lint] | | Java | [`codeql-analysis`][codeql-analysis] | -| JavaScript | [`biome-lint`][biome-lint], [`codeql-analysis`][codeql-analysis], [`eslint-lint`][eslint-lint], [`node-setup`][node-setup], [`prettier-lint`][prettier-lint] | -| Laravel | [`php-laravel-phpunit`][php-laravel-phpunit] | +| JavaScript | [`biome-lint`][biome-lint], [`codeql-analysis`][codeql-analysis], [`eslint-lint`][eslint-lint], [`prettier-lint`][prettier-lint] | +| Laravel | [`php-tests`][php-tests] | | Markdown | [`prettier-lint`][prettier-lint] | | Multiple Languages | [`pre-commit`][pre-commit] | -| Node.js | [`language-version-detect`][language-version-detect], [`node-setup`][node-setup], [`npm-publish`][npm-publish] | -| PHP | [`language-version-detect`][language-version-detect], [`php-composer`][php-composer], [`php-laravel-phpunit`][php-laravel-phpunit], [`php-tests`][php-tests] | +| Node.js | [`language-version-detect`][language-version-detect], [`npm-publish`][npm-publish] | +| PHP | [`language-version-detect`][language-version-detect], [`php-tests`][php-tests] | | PNG | [`compress-images`][compress-images] | | Python | [`codeql-analysis`][codeql-analysis], [`language-version-detect`][language-version-detect], [`pre-commit`][pre-commit], [`python-lint-fix`][python-lint-fix] | | Ruby | [`codeql-analysis`][codeql-analysis] | | Terraform | [`terraform-lint-fix`][terraform-lint-fix] | -| TypeScript | [`biome-lint`][biome-lint], [`codeql-analysis`][codeql-analysis], [`eslint-lint`][eslint-lint], [`node-setup`][node-setup], [`prettier-lint`][prettier-lint] | +| TypeScript | [`biome-lint`][biome-lint], [`codeql-analysis`][codeql-analysis], [`eslint-lint`][eslint-lint], [`prettier-lint`][prettier-lint] | | YAML | [`ansible-lint-fix`][ansible-lint-fix], [`prettier-lint`][prettier-lint], [`sync-labels`][sync-labels], [`validate-inputs`][validate-inputs] | | npm | [`npm-publish`][npm-publish] | @@ -226,10 +217,7 @@ All actions can be used independently in your workflows: [go-build]: go-build/README.md [go-lint]: go-lint/README.md [language-version-detect]: language-version-detect/README.md -[node-setup]: node-setup/README.md [npm-publish]: npm-publish/README.md -[php-composer]: php-composer/README.md -[php-laravel-phpunit]: php-laravel-phpunit/README.md [php-tests]: php-tests/README.md [pr-lint]: pr-lint/README.md [pre-commit]: pre-commit/README.md diff --git a/_tests/unit/php-composer/validation.spec.sh b/_tests/unit/php-composer/validation.spec.sh deleted file mode 100755 index 4ba8ed0..0000000 --- a/_tests/unit/php-composer/validation.spec.sh +++ /dev/null @@ -1,407 +0,0 @@ -#!/usr/bin/env shellspec -# Unit tests for php-composer action validation and logic - -# Framework is automatically loaded via spec_helper.sh - -Describe "php-composer action" -ACTION_DIR="php-composer" -ACTION_FILE="$ACTION_DIR/action.yml" - -Context "when validating php input" -It "accepts valid PHP version" -When call validate_input_python "php-composer" "php" "8.4" -The status should be success -End - -It "accepts PHP version with patch" -When call validate_input_python "php-composer" "php" "8.4.1" -The status should be success -End - -It "accepts PHP 7.4" -When call validate_input_python "php-composer" "php" "7.4" -The status should be success -End - -It "accepts PHP 8.0" -When call validate_input_python "php-composer" "php" "8.0" -The status should be success -End - -It "accepts PHP 8.1" -When call validate_input_python "php-composer" "php" "8.1" -The status should be success -End - -It "rejects PHP version too old" -When call validate_input_python "php-composer" "php" "5.5" -The status should be failure -End - -It "rejects invalid version format" -When call validate_input_python "php-composer" "php" "php8.4" -The status should be failure -End - -It "rejects version with command injection" -When call validate_input_python "php-composer" "php" "8.4; rm -rf /" -The status should be failure -End - -It "rejects empty version" -When call validate_input_python "php-composer" "php" "" -The status should be failure -End -End - -Context "when validating extensions input" -It "accepts valid PHP extensions" -When call validate_input_python "php-composer" "extensions" "mbstring, xml, zip" -The status should be success -End - -It "accepts single extension" -When call validate_input_python "php-composer" "extensions" "mbstring" -The status should be success -End - -It "accepts extensions without spaces" -When call validate_input_python "php-composer" "extensions" "mbstring,xml,zip" -The status should be success -End - -It "accepts extensions with underscores" -When call validate_input_python "php-composer" "extensions" "pdo_mysql, gd_jpeg" -The status should be success -End - -It "rejects extensions with special characters" -When call validate_input_python "php-composer" "extensions" "mbstring@xml" -The status should be failure -End - -It "rejects extensions with command injection" -When call validate_input_python "php-composer" "extensions" "mbstring; rm -rf /" -The status should be failure -End - -It "rejects empty extensions" -When call validate_input_python "php-composer" "extensions" "" -The status should be failure -End -End - -Context "when validating tools input" -It "accepts valid Composer tools" -When call validate_input_python "php-composer" "tools" "composer:v2" -The status should be success -End - -It "accepts multiple tools" -When call validate_input_python "php-composer" "tools" "composer:v2, phpunit:^9.0" -The status should be success -End - -It "accepts tools with version constraints" -When call validate_input_python "php-composer" "tools" "phpcs, phpstan:1.10" -The status should be success -End - -It "accepts tools with stability flags (@ allowed)" -When call validate_input_python "php-composer" "tools" "dev-master@dev" -The status should be success -End - -It "accepts tools with version and stability flag" -When call validate_input_python "php-composer" "tools" "monolog/monolog@dev" -The status should be success -End - -It "rejects tools with backticks" -When call validate_input_python "php-composer" "tools" "composer\`whoami\`" -The status should be failure -End - -It "rejects tools with command injection" -When call validate_input_python "php-composer" "tools" "composer; rm -rf /" -The status should be failure -End - -It "rejects empty tools" -When call validate_input_python "php-composer" "tools" "" -The status should be failure -End -End - -Context "when validating composer-version input" -It "accepts composer version 1" -When call validate_input_python "php-composer" "composer-version" "1" -The status should be success -End - -It "accepts composer version 2" -When call validate_input_python "php-composer" "composer-version" "2" -The status should be success -End - -It "rejects invalid composer version" -When call validate_input_python "php-composer" "composer-version" "3" -The status should be failure -End - -It "rejects non-numeric composer version" -When call validate_input_python "php-composer" "composer-version" "latest" -The status should be failure -End - -It "rejects empty composer version" -When call validate_input_python "php-composer" "composer-version" "" -The status should be failure -End -End - -Context "when validating stability input" -It "accepts stable" -When call validate_input_python "php-composer" "stability" "stable" -The status should be success -End - -It "accepts RC" -When call validate_input_python "php-composer" "stability" "RC" -The status should be success -End - -It "accepts beta" -When call validate_input_python "php-composer" "stability" "beta" -The status should be success -End - -It "accepts alpha" -When call validate_input_python "php-composer" "stability" "alpha" -The status should be success -End - -It "accepts dev" -When call validate_input_python "php-composer" "stability" "dev" -The status should be success -End - -It "rejects invalid stability" -When call validate_input_python "php-composer" "stability" "unstable" -The status should be failure -End - -It "rejects stability with injection" -When call validate_input_python "php-composer" "stability" "stable; rm -rf /" -The status should be failure -End -End - -Context "when validating cache-directories input" -It "accepts valid cache directory" -When call validate_input_python "php-composer" "cache-directories" "vendor/cache" -The status should be success -End - -It "accepts multiple cache directories" -When call validate_input_python "php-composer" "cache-directories" "vendor/cache, .cache" -The status should be success -End - -It "accepts directories with underscores and hyphens" -When call validate_input_python "php-composer" "cache-directories" "cache_dir, cache-dir" -The status should be success -End - -It "rejects path traversal" -When call validate_input_python "php-composer" "cache-directories" "../malicious" -The status should be failure -End - -It "rejects absolute paths" -When call validate_input_python "php-composer" "cache-directories" "/etc/passwd" -The status should be failure -End - -It "rejects directories with command injection" -When call validate_input_python "php-composer" "cache-directories" "cache; rm -rf /" -The status should be failure -End - -It "rejects empty cache directories" -When call validate_input_python "php-composer" "cache-directories" "" -The status should be failure -End -End - -Context "when validating token input" -It "accepts GitHub token expression" -When call validate_input_python "php-composer" "token" "\${{ github.token }}" -The status should be success -End - -It "accepts GitHub fine-grained token" -When call validate_input_python "php-composer" "token" "ghp_abcdefghijklmnopqrstuvwxyz1234567890" -The status should be success -End - -It "accepts GitHub app token" -When call validate_input_python "php-composer" "token" "ghs_abcdefghijklmnopqrstuvwxyz1234567890" -The status should be success -End - -It "rejects invalid token format" -When call validate_input_python "php-composer" "token" "invalid-token" -The status should be failure -End - -It "rejects empty token" -When call validate_input_python "php-composer" "token" "" -The status should be failure -End -End - -Context "when validating max-retries input" -It "accepts valid retry count" -When call validate_input_python "php-composer" "max-retries" "3" -The status should be success -End - -It "accepts minimum retries" -When call validate_input_python "php-composer" "max-retries" "1" -The status should be success -End - -It "accepts maximum retries" -When call validate_input_python "php-composer" "max-retries" "10" -The status should be success -End - -It "rejects zero retries" -When call validate_input_python "php-composer" "max-retries" "0" -The status should be failure -End - -It "rejects too many retries" -When call validate_input_python "php-composer" "max-retries" "11" -The status should be failure -End - -It "rejects non-numeric retries" -When call validate_input_python "php-composer" "max-retries" "many" -The status should be failure -End - -It "rejects negative retries" -When call validate_input_python "php-composer" "max-retries" "-1" -The status should be failure -End -End - -Context "when validating args input" -It "accepts valid Composer arguments" -When call validate_input_python "php-composer" "args" "--no-progress --prefer-dist" -The status should be success -End - -It "rejects empty args" -When call validate_input_python "php-composer" "args" "" -The status should be failure -End - -It "rejects args with command injection" -When call validate_input_python "php-composer" "args" "--no-progress; rm -rf /" -The status should be failure -End - -It "rejects args with pipe" -When call validate_input_python "php-composer" "args" "--no-progress | cat /etc/passwd" -The status should be failure -End -End - -Context "when checking action.yml structure" -It "has valid YAML syntax" -When call validate_action_yml_quiet "$ACTION_FILE" -The status should be success -End - -It "has correct action name" -name=$(get_action_name "$ACTION_FILE") -When call echo "$name" -The output should equal "Run Composer Install" -End - -It "defines expected inputs" -When call get_action_inputs "$ACTION_FILE" -The output should include "php" -The output should include "extensions" -The output should include "tools" -The output should include "args" -The output should include "composer-version" -The output should include "stability" -The output should include "cache-directories" -The output should include "token" -The output should include "max-retries" -End - -It "defines expected outputs" -When call get_action_outputs "$ACTION_FILE" -The output should include "lock" -The output should include "php-version" -The output should include "composer-version" -The output should include "cache-hit" -End -End - -Context "when testing input requirements" -It "requires php input" -When call uv run "_tests/shared/validation_core.py" --property "$ACTION_FILE" "php" "required" -The output should equal "required" -End - -It "has extensions as optional input" -When call uv run "_tests/shared/validation_core.py" --property "$ACTION_FILE" "extensions" "optional" -The output should equal "optional" -End -End - -Context "when testing security validations" -It "validates against path traversal in cache directories" -When call validate_input_python "php-composer" "cache-directories" "../../etc/passwd" -The status should be failure -End - -It "validates against shell metacharacters in tools" -When call validate_input_python "php-composer" "tools" "composer && rm -rf /" -The status should be failure -End - -It "validates against backtick injection in args" -When call validate_input_python "php-composer" "args" "--no-progress \`whoami\`" -The status should be failure -End - -It "validates against variable expansion in extensions" -When call validate_input_python "php-composer" "extensions" "mbstring,\${HOME}" -The status should be failure -End -End - -Context "when testing PHP-specific validations" -It "validates PHP version boundaries" -When call validate_input_python "php-composer" "php" "10.0" -The status should be failure -End - -It "validates Composer version enum restriction" -When call validate_input_python "php-composer" "composer-version" "0" -The status should be failure -End - -It "validates stability enum values" -When call validate_input_python "php-composer" "stability" "experimental" -The status should be failure -End -End -End diff --git a/_tests/unit/php-laravel-phpunit/validation.spec.sh b/_tests/unit/php-laravel-phpunit/validation.spec.sh deleted file mode 100755 index cbc0c5b..0000000 --- a/_tests/unit/php-laravel-phpunit/validation.spec.sh +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env shellspec -# Unit tests for php-laravel-phpunit action validation and logic - -# Framework is automatically loaded via spec_helper.sh - -Describe "php-laravel-phpunit action" -ACTION_DIR="php-laravel-phpunit" -ACTION_FILE="$ACTION_DIR/action.yml" - -Context "when validating php-version input" -It "accepts latest" -When call validate_input_python "php-laravel-phpunit" "php-version" "latest" -The status should be success -End - -It "accepts valid PHP version" -When call validate_input_python "php-laravel-phpunit" "php-version" "8.4" -The status should be success -End - -It "accepts PHP version with patch" -When call validate_input_python "php-laravel-phpunit" "php-version" "8.4.1" -The status should be success -End - -It "accepts PHP 7.4" -When call validate_input_python "php-laravel-phpunit" "php-version" "7.4" -The status should be success -End - -It "accepts PHP 8.0" -When call validate_input_python "php-laravel-phpunit" "php-version" "8.0" -The status should be success -End - -It "rejects invalid version format" -When call validate_input_python "php-laravel-phpunit" "php-version" "php8.4" -The status should be failure -End - -It "rejects version with command injection" -When call validate_input_python "php-laravel-phpunit" "php-version" "8.4; rm -rf /" -The status should be failure -End - -It "accepts empty version (uses default)" -When call validate_input_python "php-laravel-phpunit" "php-version" "" -The status should be success -End -End - -Context "when validating php-version-file input" -It "accepts valid PHP version file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" ".php-version" -The status should be success -End - -It "accepts custom version file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "custom-php-version" -The status should be success -End - -It "accepts version file with path" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "config/.php-version" -The status should be success -End - -It "rejects path traversal in version file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "../../../etc/passwd" -The status should be failure -End - -It "rejects absolute path in version file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "/etc/passwd" -The status should be failure -End - -It "rejects version file with command injection" -When call validate_input_python "php-laravel-phpunit" "php-version-file" ".php-version; rm -rf /" -The status should be failure -End - -It "accepts empty version file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "" -The status should be success -End -End - -Context "when validating extensions input" -It "accepts valid PHP extensions" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring, intl, json" -The status should be success -End - -It "accepts single extension" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring" -The status should be success -End - -It "accepts extensions without spaces" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring,intl,json" -The status should be success -End - -It "accepts extensions with underscores" -When call validate_input_python "php-laravel-phpunit" "extensions" "pdo_sqlite, pdo_mysql" -The status should be success -End - -It "accepts extensions with numbers" -When call validate_input_python "php-laravel-phpunit" "extensions" "sqlite3, gd2" -The status should be success -End - -It "rejects extensions with special characters" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring@intl" -The status should be failure -End - -It "rejects extensions with command injection" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring; rm -rf /" -The status should be failure -End - -It "accepts empty extensions" -When call validate_input_python "php-laravel-phpunit" "extensions" "" -The status should be success -End -End - -Context "when validating coverage input" -It "accepts none coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "none" -The status should be success -End - -It "accepts xdebug coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "xdebug" -The status should be success -End - -It "accepts pcov coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "pcov" -The status should be success -End - -It "accepts xdebug3 coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "xdebug3" -The status should be success -End - -It "rejects invalid coverage driver" -When call validate_input_python "php-laravel-phpunit" "coverage" "invalid" -The status should be failure -End - -It "rejects coverage with command injection" -When call validate_input_python "php-laravel-phpunit" "coverage" "none; rm -rf /" -The status should be failure -End - -It "accepts empty coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "" -The status should be success -End -End - -Context "when validating token input" -It "accepts GitHub token expression" -When call validate_input_python "php-laravel-phpunit" "token" "\${{ github.token }}" -The status should be success -End - -It "accepts GitHub fine-grained token" -When call validate_input_python "php-laravel-phpunit" "token" "ghp_abcdefghijklmnopqrstuvwxyz1234567890" -The status should be success -End - -It "accepts GitHub app token" -When call validate_input_python "php-laravel-phpunit" "token" "ghs_abcdefghijklmnopqrstuvwxyz1234567890" -The status should be success -End - -It "rejects invalid token format" -When call validate_input_python "php-laravel-phpunit" "token" "invalid-token" -The status should be failure -End - -It "accepts empty token" -When call validate_input_python "php-laravel-phpunit" "token" "" -The status should be success -End -End - -Context "when checking action.yml structure" -It "has valid YAML syntax" -When call validate_action_yml_quiet "$ACTION_FILE" -The status should be success -End - -It "has correct action name" -name=$(get_action_name "$ACTION_FILE") -When call echo "$name" -The output should equal "Laravel Setup and Composer test" -End - -It "defines expected inputs" -When call get_action_inputs "$ACTION_FILE" -The output should include "php-version" -The output should include "php-version-file" -The output should include "extensions" -The output should include "coverage" -The output should include "token" -End - -It "defines expected outputs" -When call get_action_outputs "$ACTION_FILE" -The output should include "php-version" -The output should include "php-version-file" -The output should include "extensions" -The output should include "coverage" -End -End - -Context "when testing input requirements" -It "has all inputs as optional" -When call uv run "_tests/shared/validation_core.py" --property "$ACTION_FILE" "" "all_optional" -The output should equal "none" -End - -It "has correct default php-version" -When call uv run "_tests/shared/validation_core.py" --property "$ACTION_FILE" "php-version" "default" -The output should equal "latest" -End - -It "has correct default php-version-file" -When call uv run "_tests/shared/validation_core.py" --property "$ACTION_FILE" "php-version-file" "default" -The output should equal ".php-version" -End -End - -Context "when testing security validations" -It "validates against path traversal in php-version-file" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "../../etc/passwd" -The status should be failure -End - -It "validates against shell metacharacters in extensions" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring && rm -rf /" -The status should be failure -End - -It "validates against backtick injection in coverage" -When call validate_input_python "php-laravel-phpunit" "coverage" "none\`whoami\`" -The status should be failure -End - -It "validates against variable expansion in php-version" -When call validate_input_python "php-laravel-phpunit" "php-version" "8.4\${HOME}" -The status should be failure -End -End - -Context "when testing Laravel-specific validations" -It "validates coverage driver enum values" -When call validate_input_python "php-laravel-phpunit" "coverage" "invalid-driver" -The status should be failure -End - -It "validates php-version-file path safety" -When call validate_input_python "php-laravel-phpunit" "php-version-file" "/etc/shadow" -The status should be failure -End - -It "validates extensions format for Laravel requirements" -When call validate_input_python "php-laravel-phpunit" "extensions" "mbstring, intl, json, pdo_sqlite, sqlite3" -The status should be success -End -End -End diff --git a/action-versioning/rules.yml b/action-versioning/rules.yml index 4c72c5a..62aedb3 100644 --- a/action-versioning/rules.yml +++ b/action-versioning/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for action-versioning action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: action-versioning description: Automatically update SHA-pinned action references to match latest version tags diff --git a/ansible-lint-fix/rules.yml b/ansible-lint-fix/rules.yml index 108bc70..f37d3de 100644 --- a/ansible-lint-fix/rules.yml +++ b/ansible-lint-fix/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for ansible-lint-fix action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: ansible-lint-fix description: Lints and fixes Ansible playbooks, commits changes, and uploads SARIF report. diff --git a/biome-lint/rules.yml b/biome-lint/rules.yml index 6a455ac..c577002 100644 --- a/biome-lint/rules.yml +++ b/biome-lint/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for biome-lint action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: biome-lint description: Run Biome linter in check or fix mode diff --git a/codeql-analysis/rules.yml b/codeql-analysis/rules.yml index 3f819df..86c3490 100644 --- a/codeql-analysis/rules.yml +++ b/codeql-analysis/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for codeql-analysis action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: codeql-analysis description: Run CodeQL security analysis for a single language with configurable query suites diff --git a/compress-images/rules.yml b/compress-images/rules.yml index f87a225..2301f29 100644 --- a/compress-images/rules.yml +++ b/compress-images/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for compress-images action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: compress-images description: Compress images on demand (workflow_dispatch), and at 11pm every Sunday (schedule). diff --git a/csharp-build/rules.yml b/csharp-build/rules.yml index de339e6..105660b 100644 --- a/csharp-build/rules.yml +++ b/csharp-build/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for csharp-build action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: csharp-build description: Builds and tests C# projects. diff --git a/csharp-lint-check/README.md b/csharp-lint-check/README.md index c561e64..49fb1b0 100644 --- a/csharp-lint-check/README.md +++ b/csharp-lint-check/README.md @@ -8,18 +8,18 @@ Runs linters like StyleCop or dotnet-format for C# code style checks. ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `dotnet-version` |
Version of .NET SDK to use.
| `false` | `""` | -| `token` |GitHub token for authentication
| `false` | `""` | +| name | description | required | default | +|------------------|----------------------------------------|----------|---------| +| `dotnet-version` |Version of .NET SDK to use.
| `false` | `""` | +| `token` |GitHub token for authentication
| `false` | `""` | ### Outputs -| name | description | -| --- | --- | -| `lint_status` |Overall lint status (success/failure)
| -| `errors_count` |Number of formatting errors found
| -| `warnings_count` |Number of formatting warnings found
| +| name | description | +|------------------|----------------------------------------------| +| `lint_status` |Overall lint status (success/failure)
| +| `errors_count` |Number of formatting errors found
| +| `warnings_count` |Number of formatting warnings found
| ### Runs diff --git a/csharp-lint-check/rules.yml b/csharp-lint-check/rules.yml index d767d50..11966fe 100644 --- a/csharp-lint-check/rules.yml +++ b/csharp-lint-check/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for csharp-lint-check action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: csharp-lint-check description: Runs linters like StyleCop or dotnet-format for C# code style checks. diff --git a/csharp-publish/README.md b/csharp-publish/README.md index 2bfb2f0..b425e4f 100644 --- a/csharp-publish/README.md +++ b/csharp-publish/README.md @@ -8,19 +8,19 @@ Publishes a C# project to GitHub Packages. ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `dotnet-version` |Version of .NET SDK to use.
| `false` | `""` | -| `namespace` |GitHub namespace for the package.
| `true` | `ivuorinen` | -| `token` |GitHub token with package write permissions
| `false` | `""` | +| name | description | required | default | +|------------------|----------------------------------------------------|----------|-------------| +| `dotnet-version` |Version of .NET SDK to use.
| `false` | `""` | +| `namespace` |GitHub namespace for the package.
| `true` | `ivuorinen` | +| `token` |GitHub token with package write permissions
| `false` | `""` | ### Outputs -| name | description | -| --- | --- | -| `publish_status` |Overall publish status (success/failure)
| -| `package_version` |Version of the published package
| -| `package_url` |URL of the published package
| +| name | description | +|-------------------|-------------------------------------------------| +| `publish_status` |Overall publish status (success/failure)
| +| `package_version` |Version of the published package
| +| `package_url` |URL of the published package
| ### Runs diff --git a/csharp-publish/rules.yml b/csharp-publish/rules.yml index 6552bd7..342f4f9 100644 --- a/csharp-publish/rules.yml +++ b/csharp-publish/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for csharp-publish action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: csharp-publish description: Publishes a C# project to GitHub Packages. diff --git a/docker-build/rules.yml b/docker-build/rules.yml index d53970a..708e088 100644 --- a/docker-build/rules.yml +++ b/docker-build/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for docker-build action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: docker-build description: Builds a Docker image for multiple architectures with enhanced security and reliability. diff --git a/docker-publish/README.md b/docker-publish/README.md index 3171e4c..b3d6386 100644 --- a/docker-publish/README.md +++ b/docker-publish/README.md @@ -8,28 +8,28 @@ Simple wrapper to publish Docker images to GitHub Packages and/or Docker Hub ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `registry` |Registry to publish to (dockerhub, github, or both)
| `false` | `both` | -| `image-name` |Docker image name (defaults to repository name)
| `false` | `""` | -| `tags` |Comma-separated list of tags (e.g., latest,v1.0.0)
| `false` | `latest` | -| `platforms` |Platforms to build for (comma-separated)
| `false` | `linux/amd64,linux/arm64` | -| `context` |Build context path
| `false` | `.` | -| `dockerfile` |Path to Dockerfile
| `false` | `Dockerfile` | -| `build-args` |Build arguments (newline-separated KEY=VALUE pairs)
| `false` | `""` | -| `push` |Whether to push the image
| `false` | `true` | -| `token` |GitHub token for authentication (for GitHub registry)
| `false` | `""` | -| `dockerhub-username` |Docker Hub username (required if publishing to Docker Hub)
| `false` | `""` | -| `dockerhub-token` |Docker Hub token (required if publishing to Docker Hub)
| `false` | `""` | +| name | description | required | default | +|----------------------|-------------------------------------------------------------------|----------|---------------------------| +| `registry` |Registry to publish to (dockerhub, github, or both)
| `false` | `both` | +| `image-name` |Docker image name (defaults to repository name)
| `false` | `""` | +| `tags` |Comma-separated list of tags (e.g., latest,v1.0.0)
| `false` | `latest` | +| `platforms` |Platforms to build for (comma-separated)
| `false` | `linux/amd64,linux/arm64` | +| `context` |Build context path
| `false` | `.` | +| `dockerfile` |Path to Dockerfile
| `false` | `Dockerfile` | +| `build-args` |Build arguments (newline-separated KEY=VALUE pairs)
| `false` | `""` | +| `push` |Whether to push the image
| `false` | `true` | +| `token` |GitHub token for authentication (for GitHub registry)
| `false` | `""` | +| `dockerhub-username` |Docker Hub username (required if publishing to Docker Hub)
| `false` | `""` | +| `dockerhub-token` |Docker Hub token (required if publishing to Docker Hub)
| `false` | `""` | ### Outputs -| name | description | -| --- | --- | +| name | description | +|--------------|--------------------------------------| | `image-name` |Full image name with registry
| -| `tags` |Tags that were published
| -| `digest` |Image digest
| -| `metadata` |Build metadata
| +| `tags` |Tags that were published
| +| `digest` |Image digest
| +| `metadata` |Build metadata
| ### Runs diff --git a/docker-publish/rules.yml b/docker-publish/rules.yml index b328ec8..70aa1bc 100644 --- a/docker-publish/rules.yml +++ b/docker-publish/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for docker-publish action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: docker-publish description: Simple wrapper to publish Docker images to GitHub Packages and/or Docker Hub diff --git a/eslint-lint/rules.yml b/eslint-lint/rules.yml index 32d067a..ce75119 100644 --- a/eslint-lint/rules.yml +++ b/eslint-lint/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for eslint-lint action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: eslint-lint description: Run ESLint in check or fix mode with advanced configuration and reporting diff --git a/generate_listing.cjs b/generate_listing.cjs index 93b488c..e3f1157 100755 --- a/generate_listing.cjs +++ b/generate_listing.cjs @@ -28,8 +28,6 @@ const CATEGORIES = { // Testing & Quality 'php-tests': 'Testing', - 'php-laravel-phpunit': 'Testing', - 'php-composer': 'Testing', // Build & Package 'csharp-build': 'Build', @@ -55,9 +53,7 @@ const CATEGORIES = { // Language support mappings const LANGUAGE_SUPPORT = { 'language-version-detect': ['PHP', 'Python', 'Go', '.NET', 'Node.js'], - 'php-tests': ['PHP'], - 'php-laravel-phpunit': ['PHP', 'Laravel'], - 'php-composer': ['PHP'], + 'php-tests': ['PHP', 'Laravel'], 'python-lint-fix': ['Python'], 'go-lint': ['Go'], 'go-build': ['Go'], diff --git a/go-build/README.md b/go-build/README.md index fd21832..571cb45 100644 --- a/go-build/README.md +++ b/go-build/README.md @@ -8,22 +8,22 @@ Builds the Go project. ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `go-version` |Go version to use.
| `false` | `""` | -| `destination` |Build destination directory.
| `false` | `./bin` | -| `max-retries` |Maximum number of retry attempts for go mod download operations
| `false` | `3` | -| `token` |GitHub token for authentication
| `false` | `""` | +| name | description | required | default | +|---------------|------------------------------------------------------------------------|----------|---------| +| `go-version` |Go version to use.
| `false` | `""` | +| `destination` |Build destination directory.
| `false` | `./bin` | +| `max-retries` |Maximum number of retry attempts for go mod download operations
| `false` | `3` | +| `token` |GitHub token for authentication
| `false` | `""` | ### Outputs -| name | description | -| --- | --- | -| `build_status` |Build completion status (success/failure)
| -| `test_status` |Test execution status (success/failure/skipped)
| -| `go_version` |Version of Go used
| -| `binary_path` |Path to built binaries
| -| `coverage_path` |Path to coverage report
| +| name | description | +|-----------------|--------------------------------------------------------| +| `build_status` |Build completion status (success/failure)
| +| `test_status` |Test execution status (success/failure/skipped)
| +| `go_version` |Version of Go used
| +| `binary_path` |Path to built binaries
| +| `coverage_path` |Path to coverage report
| ### Runs diff --git a/go-build/rules.yml b/go-build/rules.yml index c5a9f50..1dd23b5 100644 --- a/go-build/rules.yml +++ b/go-build/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for go-build action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: go-build description: Builds the Go project. diff --git a/go-lint/rules.yml b/go-lint/rules.yml index 6cfbdf1..bfcd950 100644 --- a/go-lint/rules.yml +++ b/go-lint/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for go-lint action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: go-lint description: Run golangci-lint with advanced configuration, caching, and reporting diff --git a/language-version-detect/rules.yml b/language-version-detect/rules.yml index 1427f33..dc600aa 100644 --- a/language-version-detect/rules.yml +++ b/language-version-detect/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for language-version-detect action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,9 +8,11 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: language-version-detect -description: 'DEPRECATED: This action is deprecated. Inline version detection directly in your actions instead. Detects language version from project configuration files with support for PHP, Python, Go, and .NET.' +description: 'DEPRECATED: This action is deprecated. Inline version detection directly in your actions instead. Detects language + version from project configuration files with support for PHP, Python, Go, and .NET.' generator_version: 1.0.0 required_inputs: - language diff --git a/npm-publish/README.md b/npm-publish/README.md index c0ec44a..6c0f50f 100644 --- a/npm-publish/README.md +++ b/npm-publish/README.md @@ -8,21 +8,21 @@ Publishes the package to the NPM registry with configurable scope and registry U ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `npm_token` |NPM token.
| `true` | `""` | -| `registry-url` |Registry URL for publishing.
| `false` | `https://registry.npmjs.org/` | -| `scope` |Package scope to use.
| `false` | `@ivuorinen` | -| `package-version` |The version to publish.
| `false` | `${{ github.event.release.tag_name }}` | -| `token` |GitHub token for authentication
| `false` | `""` | +| name | description | required | default | +|-------------------|----------------------------------------|----------|----------------------------------------| +| `npm_token` |NPM token.
| `true` | `""` | +| `registry-url` |Registry URL for publishing.
| `false` | `https://registry.npmjs.org/` | +| `scope` |Package scope to use.
| `false` | `@ivuorinen` | +| `package-version` |The version to publish.
| `false` | `${{ github.event.release.tag_name }}` | +| `token` |GitHub token for authentication
| `false` | `""` | ### Outputs -| name | description | -| --- | --- | -| `registry-url` |Registry URL for publishing.
| -| `scope` |Package scope to use.
| -| `package-version` |The version to publish.
| +| name | description | +|-------------------|-------------------------------------| +| `registry-url` |Registry URL for publishing.
| +| `scope` |Package scope to use.
| +| `package-version` |The version to publish.
| ### Runs diff --git a/npm-publish/rules.yml b/npm-publish/rules.yml index 773dcde..678f1bf 100644 --- a/npm-publish/rules.yml +++ b/npm-publish/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for npm-publish action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: npm-publish description: Publishes the package to the NPM registry with configurable scope and registry URL. diff --git a/php-composer/CustomValidator.py b/php-composer/CustomValidator.py deleted file mode 100755 index c01fb14..0000000 --- a/php-composer/CustomValidator.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -"""Custom validator for php-composer action.""" - -from __future__ import annotations - -from pathlib import Path -import re -import sys - -# Add validate-inputs directory to path to import validators -validate_inputs_path = Path(__file__).parent.parent / "validate-inputs" -sys.path.insert(0, str(validate_inputs_path)) - -from validators.base import BaseValidator -from validators.boolean import BooleanValidator -from validators.file import FileValidator -from validators.numeric import NumericValidator -from validators.security import SecurityValidator -from validators.token import TokenValidator -from validators.version import VersionValidator - - -class CustomValidator(BaseValidator): - """Custom validator for php-composer action.""" - - def __init__(self, action_type: str = "php-composer") -> None: - """Initialize php-composer validator.""" - super().__init__(action_type) - self.boolean_validator = BooleanValidator() - self.file_validator = FileValidator() - self.numeric_validator = NumericValidator() - self.security_validator = SecurityValidator() - self.token_validator = TokenValidator() - self.version_validator = VersionValidator() - - def validate_inputs(self, inputs: dict[str, str]) -> bool: - """Validate php-composer action inputs.""" - valid = True - - # Validate required input: php - if "php" not in inputs or not inputs["php"]: - self.add_error("Input 'php' is required") - valid = False - elif inputs["php"]: - php_version = inputs["php"] - if not self.is_github_expression(php_version): - # PHP version validation with minimum version check - result = self.version_validator.validate_php_version(php_version, "php") - for error in self.version_validator.errors: - if error not in self.errors: - self.add_error(error) - self.version_validator.clear_errors() - if not result: - valid = False - elif php_version and not php_version.startswith("$"): - # Additional check for minimum PHP version (7.0) - try: - parts = php_version.split(".") - major = int(parts[0]) - minor = int(parts[1]) if len(parts) > 1 else 0 - if major < 7 or (major == 7 and minor < 0): - self.add_error("PHP version must be 7.0 or higher") - valid = False - except (ValueError, IndexError): - pass # Already handled by validate_php_version - - # Validate extensions (empty string is invalid) - if "extensions" in inputs: - extensions = inputs["extensions"] - if extensions == "": - self.add_error("Extensions cannot be empty string") - valid = False - elif extensions: - if not self.is_github_expression(extensions): - # Extensions should be comma-separated list (spaces allowed after commas) - if not re.match(r"^[a-zA-Z0-9_-]+(\s*,\s*[a-zA-Z0-9_-]+)*$", extensions): - self.add_error("Invalid extensions format: must be comma-separated list") - valid = False - - # Check for injection - result = self.security_validator.validate_no_injection(extensions, "extensions") - for error in self.security_validator.errors: - if error not in self.errors: - self.add_error(error) - self.security_validator.clear_errors() - if not result: - valid = False - - # Validate tools (empty string is invalid) - if "tools" in inputs: - tools = inputs["tools"] - if tools == "": - self.add_error("Tools cannot be empty string") - valid = False - elif tools: - if not self.is_github_expression(tools): - # Tools should be comma-separated list with optional version constraints - # Allow: letters, numbers, dash, underscore, colon, dot, caret, tilde, @, / - # @ symbol allows Composer stability flags like dev-master@dev - # / allows vendor/package format like monolog/monolog@dev - # spaces after commas - if not re.match( - r"^[a-zA-Z0-9_:.@/\-^~]+(\s*,\s*[a-zA-Z0-9_:.@/\-^~]+)*$", tools - ): - self.add_error("Invalid tools format: must be comma-separated list") - valid = False - - # Check for injection - result = self.security_validator.validate_no_injection(tools, "tools") - for error in self.security_validator.errors: - if error not in self.errors: - self.add_error(error) - self.security_validator.clear_errors() - if not result: - valid = False - - # Validate composer-version (empty string is invalid, only 1 or 2 accepted) - if "composer-version" in inputs: - composer_version = inputs["composer-version"] - if composer_version == "": - self.add_error("Composer version cannot be empty string") - valid = False - elif composer_version: - if not self.is_github_expression(composer_version) and composer_version not in [ - "1", - "2", - ]: - self.add_error("Composer version must be 1 or 2") - valid = False - - # Validate stability - if inputs.get("stability"): - stability = inputs["stability"] - if not self.is_github_expression(stability): - valid_stabilities = ["stable", "RC", "beta", "alpha", "dev", "snapshot"] - if stability not in valid_stabilities: - self.add_error( - f"Invalid stability: {stability}. " - f"Must be one of: {', '.join(valid_stabilities)}" - ) - valid = False - - # Check for injection - result = self.security_validator.validate_no_injection(stability, "stability") - for error in self.security_validator.errors: - if error not in self.errors: - self.add_error(error) - self.security_validator.clear_errors() - if not result: - valid = False - - # Validate cache-directories (empty string is invalid, accepts directory paths) - if "cache-directories" in inputs: - cache_dirs = inputs["cache-directories"] - if cache_dirs == "": - self.add_error("Cache directories cannot be empty string") - valid = False - elif cache_dirs: - if not self.is_github_expression(cache_dirs): - # Should be comma-separated list of directories - dirs = cache_dirs.split(",") - for dir_path in dirs: - dir_path = dir_path.strip() - if dir_path: - result = self.file_validator.validate_file_path( - dir_path, "cache-directories" - ) - for error in self.file_validator.errors: - if error not in self.errors: - self.add_error(error) - self.file_validator.clear_errors() - if not result: - valid = False - - # Validate token (empty string is invalid) - if "token" in inputs: - token = inputs["token"] - if token == "": - self.add_error("Token cannot be empty string") - valid = False - elif token: - result = self.token_validator.validate_github_token(token, required=False) - for error in self.token_validator.errors: - if error not in self.errors: - self.add_error(error) - self.token_validator.clear_errors() - if not result: - valid = False - - # Validate max-retries - if inputs.get("max-retries"): - result = self.numeric_validator.validate_numeric_range( - inputs["max-retries"], min_val=1, max_val=10, name="max-retries" - ) - for error in self.numeric_validator.errors: - if error not in self.errors: - self.add_error(error) - self.numeric_validator.clear_errors() - if not result: - valid = False - - # Validate args (empty string is invalid, checks for injection if provided) - if "args" in inputs: - args = inputs["args"] - if args == "": - self.add_error("Args cannot be empty string") - valid = False - elif args: - if not self.is_github_expression(args): - # Check for command injection patterns - result = self.security_validator.validate_no_injection(args, "args") - for error in self.security_validator.errors: - if error not in self.errors: - self.add_error(error) - self.security_validator.clear_errors() - if not result: - valid = False - - return valid - - def get_required_inputs(self) -> list[str]: - """Get list of required inputs.""" - return ["php"] - - def get_validation_rules(self) -> dict: - """Get validation rules.""" - rules_path = Path(__file__).parent / "rules.yml" - return self.load_rules(rules_path) diff --git a/php-composer/README.md b/php-composer/README.md deleted file mode 100644 index 6e84646..0000000 --- a/php-composer/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# ivuorinen/actions/php-composer - -## Run Composer Install - -### Description - -Runs Composer install on a repository with advanced caching and configuration. - -### Inputs - -| name | description | required | default | -|--------------------|---------------------------------------------------------------|----------|-----------------------------------------------------| -| `php` |PHP Version to use.
| `true` | `8.4` | -| `extensions` |Comma-separated list of PHP extensions to install
| `false` | `mbstring, xml, zip, curl, json` | -| `tools` |Comma-separated list of Composer tools to install
| `false` | `composer:v2` | -| `args` |Arguments to pass to Composer.
| `false` | `--no-progress --prefer-dist --optimize-autoloader` | -| `composer-version` |Composer version to use (1 or 2)
| `false` | `2` | -| `stability` |Minimum stability (stable, RC, beta, alpha, dev)
| `false` | `stable` | -| `token` |GitHub token for private repository access
| `false` | `""` | -| `max-retries` |Maximum number of retry attempts for Composer commands
| `false` | `3` | - -### Outputs - -| name | description | -|--------------------|-------------------------------------------------| -| `lock` |composer.lock or composer.json file hash
| -| `php-version` |Installed PHP version
| -| `composer-version` |Installed Composer version
| -| `cache-hit` |Indicates if there was a cache hit
| - -### Runs - -This action is a `composite` action. - -### Usage - -```yaml -- uses: ivuorinen/actions/php-composer@main - with: - php: - # PHP Version to use. - # - # Required: true - # Default: 8.4 - - extensions: - # Comma-separated list of PHP extensions to install - # - # Required: false - # Default: mbstring, xml, zip, curl, json - - tools: - # Comma-separated list of Composer tools to install - # - # Required: false - # Default: composer:v2 - - args: - # Arguments to pass to Composer. - # - # Required: false - # Default: --no-progress --prefer-dist --optimize-autoloader - - composer-version: - # Composer version to use (1 or 2) - # - # Required: false - # Default: 2 - - stability: - # Minimum stability (stable, RC, beta, alpha, dev) - # - # Required: false - # Default: stable - - token: - # GitHub token for private repository access - # - # Required: false - # Default: "" - - max-retries: - # Maximum number of retry attempts for Composer commands - # - # Required: false - # Default: 3 -``` diff --git a/php-composer/action.yml b/php-composer/action.yml deleted file mode 100644 index a28b445..0000000 --- a/php-composer/action.yml +++ /dev/null @@ -1,205 +0,0 @@ -# yaml-language-server: $schema=https://json.schemastore.org/github-action.json -# permissions: -# - contents: read # Required for checking out repository ---- -name: Run Composer Install -description: 'Runs Composer install on a repository with advanced caching and configuration.' -author: 'Ismo Vuorinen' - -branding: - icon: server - color: gray-dark - -inputs: - php: - description: 'PHP Version to use.' - required: true - default: '8.4' - extensions: - description: 'Comma-separated list of PHP extensions to install' - required: false - default: 'mbstring, xml, zip, curl, json' - tools: - description: 'Comma-separated list of Composer tools to install' - required: false - default: 'composer:v2' - args: - description: 'Arguments to pass to Composer.' - required: false - default: '--no-progress --prefer-dist --optimize-autoloader' - composer-version: - description: 'Composer version to use (1 or 2)' - required: false - default: '2' - stability: - description: 'Minimum stability (stable, RC, beta, alpha, dev)' - required: false - default: 'stable' - token: - description: 'GitHub token for private repository access' - required: false - default: '' - max-retries: - description: 'Maximum number of retry attempts for Composer commands' - required: false - default: '3' - -outputs: - lock: - description: 'composer.lock or composer.json file hash' - value: ${{ steps.hash.outputs.lock }} - php-version: - description: 'Installed PHP version' - value: ${{ steps.php.outputs.version }} - composer-version: - description: 'Installed Composer version' - value: ${{ steps.composer.outputs.version }} - cache-hit: - description: 'Indicates if there was a cache hit' - value: ${{ steps.composer-cache.outputs.cache-hit }} - -runs: - using: composite - steps: - - name: Mask Secrets - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.token || github.token }} - run: | - echo "::add-mask::$GITHUB_TOKEN" - - - name: Checkout Repository - uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta - with: - token: ${{ inputs.token || github.token }} - - - name: Validate Inputs - id: validate - uses: ivuorinen/actions/validate-inputs@0fa9a68f07a1260b321f814202658a6089a43d42 - with: - action-type: php-composer - - - name: Setup PHP - id: php - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 - with: - php-version: ${{ inputs.php }} - extensions: ${{ inputs.extensions }} - tools: ${{ inputs.tools }} - coverage: none - ini-values: memory_limit=1G, max_execution_time=600 - fail-fast: true - - - name: Get Dependency Hashes - id: hash - shell: bash - env: - COMPOSER_LOCK_HASH: ${{ hashFiles('**/composer.lock') }} - COMPOSER_JSON_HASH: ${{ hashFiles('**/composer.json') }} - run: | - set -euo pipefail - - # Get composer.lock hash or composer.json hash - if [ -f composer.lock ]; then - echo "lock=$COMPOSER_LOCK_HASH" >> $GITHUB_OUTPUT - else - echo "lock=$COMPOSER_JSON_HASH" >> $GITHUB_OUTPUT - fi - - - name: Configure Composer - id: composer - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.token || github.token }} - STABILITY: ${{ inputs.stability }} - COMPOSER_VERSION: ${{ inputs.composer-version }} - run: | - set -euo pipefail - - # Configure Composer environment - composer config --global process-timeout 600 - composer config --global allow-plugins true - composer config --global github-oauth.github.com "$GITHUB_TOKEN" - - if [ "$STABILITY" != "stable" ]; then - composer config minimum-stability "$STABILITY" - fi - - # Verify Composer installation - composer_full_version=$(composer --version | grep -oP 'Composer version \K[0-9]+\.[0-9]+\.[0-9]+') - if [ -z "$composer_full_version" ]; then - echo "::error::Failed to detect Composer version" - exit 1 - fi - - # Extract major version for comparison - composer_major_version=${composer_full_version%%.*} - expected_version="$COMPOSER_VERSION" - - echo "Detected Composer version: $composer_full_version (major: $composer_major_version)" - - if [ "$composer_major_version" != "$expected_version" ]; then - echo "::error::Composer major version mismatch. Expected $expected_version.x, got $composer_full_version" - exit 1 - fi - - # Store full version for output - echo "version=$composer_full_version" >> "$GITHUB_OUTPUT" - - # Log Composer configuration - echo "Composer Configuration:" - composer config --list - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: | - vendor - ~/.composer/cache - key: ${{ runner.os }}-php-${{ inputs.php }}-composer-${{ inputs.composer-version }}-composer-${{ hashFiles('composer.lock', 'composer.json') }} - restore-keys: | - ${{ runner.os }}-php-${{ inputs.php }}-composer-${{ inputs.composer-version }}-composer- - ${{ runner.os }}-php-${{ inputs.php }}-composer-${{ inputs.composer-version }}- - ${{ runner.os }}-php-${{ inputs.php }}-composer- - ${{ runner.os }}-php-${{ inputs.php }}- - - - name: Clear Composer Cache Before Final Attempt - if: steps.composer-cache.outputs.cache-hit != 'true' - shell: bash - run: | - set -euo pipefail - echo "Clearing Composer cache to ensure clean installation..." - composer clear-cache - - - name: Install Dependencies - uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3 - with: - timeout_minutes: 10 - max_attempts: ${{ inputs.max-retries }} - retry_wait_seconds: 30 - command: composer install ${{ inputs.args }} - - - name: Verify Installation - shell: bash - run: | - set -euo pipefail - - # Verify vendor directory - if [ ! -d "vendor" ]; then - echo "::error::vendor directory not found" - exit 1 - fi - - # Verify autoloader - if [ ! -f "vendor/autoload.php" ]; then - echo "::error::autoload.php not found" - exit 1 - fi - - - name: Generate Optimized Autoloader - if: success() - shell: bash - run: |- - set -euo pipefail - composer dump-autoload --optimize --classmap-authoritative diff --git a/php-composer/rules.yml b/php-composer/rules.yml deleted file mode 100644 index 3324d41..0000000 --- a/php-composer/rules.yml +++ /dev/null @@ -1,43 +0,0 @@ -# Validation rules for php-composer action -# Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY -# Schema version: 1.0 -# Coverage: 50% (4/8 inputs) -# -# This file defines validation rules for the php-composer GitHub Action. -# Rules are automatically applied by validate-inputs action when this -# action is used. -# -schema_version: '1.0' -action: php-composer -description: Runs Composer install on a repository with advanced caching and configuration. -generator_version: 1.0.0 -required_inputs: - - php -optional_inputs: - - args - - composer-version - - extensions - - max-retries - - stability - - token - - tools -conventions: - composer-version: semantic_version - max-retries: numeric_range_1_10 - php: semantic_version - token: github_token -overrides: {} -statistics: - total_inputs: 8 - validated_inputs: 4 - skipped_inputs: 0 - coverage_percentage: 50 -validation_coverage: 50 -auto_detected: true -manual_review_required: true -quality_indicators: - has_required_inputs: true - has_token_validation: true - has_version_validation: true - has_file_validation: false - has_security_validation: true diff --git a/php-laravel-phpunit/CustomValidator.py b/php-laravel-phpunit/CustomValidator.py deleted file mode 100755 index f198de5..0000000 --- a/php-laravel-phpunit/CustomValidator.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python3 -"""Custom validator for php-laravel-phpunit action.""" - -from __future__ import annotations - -from pathlib import Path -import sys - -# Add validate-inputs directory to path to import validators -validate_inputs_path = Path(__file__).parent.parent / "validate-inputs" -sys.path.insert(0, str(validate_inputs_path)) - -from validators.base import BaseValidator -from validators.file import FileValidator -from validators.token import TokenValidator -from validators.version import VersionValidator - - -class CustomValidator(BaseValidator): - """Custom validator for php-laravel-phpunit action.""" - - def __init__(self, action_type: str = "php-laravel-phpunit") -> None: - """Initialize php-laravel-phpunit validator.""" - super().__init__(action_type) - self.version_validator = VersionValidator() - self.file_validator = FileValidator() - self.token_validator = TokenValidator() - - def validate_inputs(self, inputs: dict[str, str]) -> bool: - """Validate php-laravel-phpunit action inputs.""" - valid = True - - # Validate php-version if provided and not empty - if inputs.get("php-version"): - value = inputs["php-version"] - # Special case: "latest" is allowed - if value != "latest": - result = self.version_validator.validate_php_version(value, "php-version") - - # Propagate errors from the version validator - for error in self.version_validator.errors: - if error not in self.errors: - self.add_error(error) - - self.version_validator.clear_errors() - - if not result: - valid = False - # Validate php-version-file if provided - if inputs.get("php-version-file"): - result = self.file_validator.validate_file_path( - inputs["php-version-file"], "php-version-file" - ) - for error in self.file_validator.errors: - if error not in self.errors: - self.add_error(error) - self.file_validator.clear_errors() - if not result: - valid = False - - # Validate extensions if provided - if inputs.get("extensions"): - value = inputs["extensions"] - # Basic validation for PHP extensions list - if ";" in value and not value.startswith("${{"): - self.add_error(f"Invalid extensions format in extensions: {value}") - valid = False - # Check for dangerous characters and invalid format (@ is not valid in PHP extensions) - if any(char in value for char in ["`", "$", "&", "|", ">", "<", "@", "\n", "\r"]): - self.add_error(f"Invalid characters in extensions: {value}") - valid = False - - # Validate coverage if provided - if inputs.get("coverage"): - value = inputs["coverage"] - # Valid coverage drivers for PHPUnit - valid_coverage = ["none", "xdebug", "xdebug3", "pcov"] - if value not in valid_coverage: - # Check for command injection attempts - if any(char in value for char in [";", "`", "$", "&", "|", ">", "<", "\n", "\r"]): - self.add_error(f"Command injection attempt in coverage: {value}") - valid = False - elif value and not value.startswith("${{"): - self.add_error( - f"Invalid coverage driver: {value}. " - f"Must be one of: {', '.join(valid_coverage)}" - ) - valid = False - - # Validate token if provided - if inputs.get("token"): - result = self.token_validator.validate_github_token(inputs["token"]) - for error in self.token_validator.errors: - if error not in self.errors: - self.add_error(error) - self.token_validator.clear_errors() - if not result: - valid = False - - return valid - - def get_required_inputs(self) -> list[str]: - """Get list of required inputs.""" - return [] - - def get_validation_rules(self) -> dict: - """Get validation rules.""" - return { - "php-version": { - "type": "php_version", - "required": False, - "description": "PHP version to use", - }, - "php-version-file": { - "type": "file", - "required": False, - "description": "PHP version file", - }, - "extensions": { - "type": "string", - "required": False, - "description": "PHP extensions to install", - }, - "coverage": { - "type": "string", - "required": False, - "description": "Coverage driver", - }, - "token": { - "type": "token", - "required": False, - "description": "GitHub token", - }, - } diff --git a/php-laravel-phpunit/README.md b/php-laravel-phpunit/README.md deleted file mode 100644 index 53f499d..0000000 --- a/php-laravel-phpunit/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# ivuorinen/actions/php-laravel-phpunit - -## Laravel Setup and Composer test - -### Description - -Setup PHP, install dependencies, generate key, create database and run composer test - -### Inputs - -| name | description | required | default | -| --- | --- | --- | --- | -| `php-version` |PHP Version to use, see https://github.com/marketplace/actions/setup-php-action#php-version-optional
| `false` | `latest` | -| `php-version-file` |PHP Version file to use, see https://github.com/marketplace/actions/setup-php-action#php-version-file-optional
| `false` | `.php-version` | -| `extensions` |PHP extensions to install, see https://github.com/marketplace/actions/setup-php-action#extensions-optional
| `false` | `mbstring, intl, json, pdo_sqlite, sqlite3` | -| `coverage` |Specify code-coverage driver, see https://github.com/marketplace/actions/setup-php-action#coverage-optional
| `false` | `none` | -| `token` |GitHub token for authentication
| `false` | `""` | - -### Outputs - -| name | description | -| --- | --- | -| `php-version` |The PHP version that was setup
| -| `php-version-file` |The PHP version file that was used
| -| `extensions` |The PHP extensions that were installed
| -| `coverage` |The code-coverage driver that was setup
| - -### Runs - -This action is a `composite` action. - -### Usage - -```yaml -- uses: ivuorinen/actions/php-laravel-phpunit@main - with: - php-version: - # PHP Version to use, see https://github.com/marketplace/actions/setup-php-action#php-version-optional - # - # Required: false - # Default: latest - - php-version-file: - # PHP Version file to use, see https://github.com/marketplace/actions/setup-php-action#php-version-file-optional - # - # Required: false - # Default: .php-version - - extensions: - # PHP extensions to install, see https://github.com/marketplace/actions/setup-php-action#extensions-optional - # - # Required: false - # Default: mbstring, intl, json, pdo_sqlite, sqlite3 - - coverage: - # Specify code-coverage driver, see https://github.com/marketplace/actions/setup-php-action#coverage-optional - # - # Required: false - # Default: none - - token: - # GitHub token for authentication - # - # Required: false - # Default: "" -``` diff --git a/php-laravel-phpunit/action.yml b/php-laravel-phpunit/action.yml deleted file mode 100644 index 87fd123..0000000 --- a/php-laravel-phpunit/action.yml +++ /dev/null @@ -1,243 +0,0 @@ -# yaml-language-server: $schema=https://json.schemastore.org/github-action.json -# permissions: -# - contents: read # Required for checking out repository ---- -name: Laravel Setup and Composer test -description: 'Setup PHP, install dependencies, generate key, create database and run composer test' -author: 'Ismo Vuorinen' - -branding: - icon: 'terminal' - color: 'blue' - -inputs: - php-version: - description: 'PHP Version to use, see https://github.com/marketplace/actions/setup-php-action#php-version-optional' - required: false - default: 'latest' - php-version-file: - description: 'PHP Version file to use, see https://github.com/marketplace/actions/setup-php-action#php-version-file-optional' - required: false - default: '.php-version' - extensions: - description: 'PHP extensions to install, see https://github.com/marketplace/actions/setup-php-action#extensions-optional' - required: false - default: 'mbstring, intl, json, pdo_sqlite, sqlite3' - coverage: - description: 'Specify code-coverage driver, see https://github.com/marketplace/actions/setup-php-action#coverage-optional' - required: false - default: 'none' - token: - description: 'GitHub token for authentication' - required: false - default: '' - -outputs: - php-version: - description: 'The PHP version that was setup' - value: ${{ steps.setup-php.outputs.php-version }} - php-version-file: - description: 'The PHP version file that was used' - value: ${{ steps.setup-php.outputs.php-version-file }} - extensions: - description: 'The PHP extensions that were installed' - value: ${{ steps.setup-php.outputs.extensions }} - coverage: - description: 'The code-coverage driver that was setup' - value: ${{ steps.setup-php.outputs.coverage }} - -runs: - using: composite - steps: - - name: Mask Secrets - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.token }} - run: | - if [ -n "$GITHUB_TOKEN" ]; then - echo "::add-mask::$GITHUB_TOKEN" - fi - - - name: Detect PHP Version - id: php-version - shell: sh - env: - DEFAULT_VERSION: "${{ inputs.php-version || '8.4' }}" - run: | - set -eu - - # Function to validate version format - validate_version() { - version=$1 - case "$version" in - [0-9]*.[0-9]* | [0-9]*.[0-9]*.[0-9]*) - return 0 - ;; - *) - return 1 - ;; - esac - } - - # Function to clean version string - clean_version() { - printf '%s' "$1" | sed 's/^[vV]//' | tr -d ' \n\r' - } - - detected_version="" - - # Parse .tool-versions file - if [ -f .tool-versions ]; then - echo "Checking .tool-versions for php..." >&2 - version=$(awk '/^php[[:space:]]/ {gsub(/#.*/, ""); print $2; exit}' .tool-versions 2>/dev/null || echo "") - if [ -n "$version" ]; then - version=$(clean_version "$version") - if validate_version "$version"; then - echo "Found PHP version in .tool-versions: $version" >&2 - detected_version="$version" - fi - fi - fi - - # Parse Dockerfile - if [ -z "$detected_version" ] && [ -f Dockerfile ]; then - echo "Checking Dockerfile for php..." >&2 - version=$(grep -iF "FROM" Dockerfile | grep -F "php:" | head -1 | \ - sed -n -E "s/.*php:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "") - if [ -n "$version" ]; then - version=$(clean_version "$version") - if validate_version "$version"; then - echo "Found PHP version in Dockerfile: $version" >&2 - detected_version="$version" - fi - fi - fi - - # Parse devcontainer.json - if [ -z "$detected_version" ] && [ -f .devcontainer/devcontainer.json ]; then - echo "Checking devcontainer.json for php..." >&2 - if command -v jq >/dev/null 2>&1; then - version=$(jq -r '.image // empty' .devcontainer/devcontainer.json 2>/dev/null | sed -n -E "s/.*php:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "") - if [ -n "$version" ]; then - version=$(clean_version "$version") - if validate_version "$version"; then - echo "Found PHP version in devcontainer: $version" >&2 - detected_version="$version" - fi - fi - else - echo "jq not found; skipping devcontainer.json parsing" >&2 - fi - fi - - # Parse .php-version file - if [ -z "$detected_version" ] && [ -f .php-version ]; then - echo "Checking .php-version..." >&2 - version=$(tr -d '\r' < .php-version | head -1) - if [ -n "$version" ]; then - version=$(clean_version "$version") - if validate_version "$version"; then - echo "Found PHP version in .php-version: $version" >&2 - detected_version="$version" - fi - fi - fi - - # Parse composer.json - if [ -z "$detected_version" ] && [ -f composer.json ]; then - echo "Checking composer.json..." >&2 - if command -v jq >/dev/null 2>&1; then - version=$(jq -r '.require.php // empty' composer.json 2>/dev/null | sed -n 's/[^0-9]*\\([0-9]\\+\\.[0-9]\\+\\(\\.[0-9]\\+\\)\\?\\).*/\\1/p') - if [ -z "$version" ]; then - version=$(jq -r '.config.platform.php // empty' composer.json 2>/dev/null | sed -n 's/[^0-9]*\\([0-9]\\+\\.[0-9]\\+\\(\\.[0-9]\\+\\)\\?\\).*/\\1/p') - fi - if [ -n "$version" ]; then - version=$(clean_version "$version") - if validate_version "$version"; then - echo "Found PHP version in composer.json: $version" >&2 - detected_version="$version" - fi - fi - else - echo "jq not found; skipping composer.json parsing" >&2 - fi - fi - - # Use default version if nothing detected - if [ -z "$detected_version" ]; then - detected_version="$DEFAULT_VERSION" - echo "Using default PHP version: $detected_version" >&2 - fi - - # Set output - printf 'detected-version=%s\n' "$detected_version" >> "$GITHUB_OUTPUT" - echo "Final detected PHP version: $detected_version" >&2 - - - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 - id: setup-php - with: - php-version: ${{ steps.php-version.outputs.detected-version }} - extensions: ${{ inputs.extensions }} - coverage: ${{ inputs.coverage }} - - - uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta - with: - token: ${{ inputs.token != '' && inputs.token || github.token }} - - - name: 'Check file existence' - id: check_files - uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 - with: - files: 'package.json, artisan' - - - name: Copy .env - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - run: | - set -euo pipefail - - php -r "file_exists('.env') || copy('.env.example', '.env');" - - - name: Install Dependencies - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - run: | - set -euo pipefail - - composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - - - name: Generate key - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - run: | - set -euo pipefail - - php artisan key:generate - - - name: Directory Permissions - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - run: | - set -euo pipefail - - chmod -R 777 storage bootstrap/cache - - - name: Create Database - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - run: | - set -euo pipefail - - mkdir -p database - touch database/database.sqlite - - - name: Execute composer test (Unit and Feature tests) - if: steps.check_files.outputs.files_exists == 'true' - shell: bash - env: - DB_CONNECTION: sqlite - DB_DATABASE: database/database.sqlite - run: |- - set -euo pipefail - - composer test diff --git a/php-laravel-phpunit/rules.yml b/php-laravel-phpunit/rules.yml deleted file mode 100644 index f7249ef..0000000 --- a/php-laravel-phpunit/rules.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Validation rules for php-laravel-phpunit action -# Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY -# Schema version: 1.0 -# Coverage: 100% (5/5 inputs) -# -# This file defines validation rules for the php-laravel-phpunit GitHub Action. -# Rules are automatically applied by validate-inputs action when this -# action is used. -# -schema_version: '1.0' -action: php-laravel-phpunit -description: Setup PHP, install dependencies, generate key, create database and run composer test -generator_version: 1.0.0 -required_inputs: [] -optional_inputs: - - coverage - - extensions - - php-version - - php-version-file - - token -conventions: - coverage: coverage_driver - extensions: php_extensions - php-version: semantic_version - php-version-file: file_path - token: github_token -overrides: {} -statistics: - total_inputs: 5 - validated_inputs: 5 - skipped_inputs: 0 - coverage_percentage: 100 -validation_coverage: 100 -auto_detected: true -manual_review_required: false -quality_indicators: - has_required_inputs: false - has_token_validation: true - has_version_validation: true - has_file_validation: true - has_security_validation: true diff --git a/php-tests/README.md b/php-tests/README.md index a3c6112..08d64f2 100644 --- a/php-tests/README.md +++ b/php-tests/README.md @@ -4,24 +4,33 @@ ### Description -Run PHPUnit tests on the repository +Run PHPUnit tests with optional Laravel setup and Composer dependency management ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `token` |GitHub token for authentication
| `false` | `""` | -| `username` |GitHub username for commits
| `false` | `github-actions` | -| `email` |GitHub email for commits
| `false` | `github-actions@github.com` | +| name | description | required | default | +|-----------------|----------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------------| +| `framework` |Framework detection mode (auto=detect Laravel via artisan, laravel=force Laravel, generic=no framework)
| `false` | `auto` | +| `php-version` |PHP Version to use (latest, 8.4, 8.3, etc.)
| `false` | `latest` | +| `extensions` |PHP extensions to install (comma-separated)
| `false` | `mbstring, intl, json, pdo_sqlite, sqlite3` | +| `coverage` |Code-coverage driver (none, xdebug, pcov)
| `false` | `none` | +| `composer-args` |Arguments to pass to Composer install
| `false` | `--no-progress --prefer-dist --optimize-autoloader` | +| `max-retries` |Maximum number of retry attempts for Composer commands
| `false` | `3` | +| `token` |GitHub token for authentication
| `false` | `""` | +| `username` |GitHub username for commits
| `false` | `github-actions` | +| `email` |GitHub email for commits
| `false` | `github-actions@github.com` | ### Outputs -| name | description | -| --- | --- | -| `test_status` |Test execution status (success/failure/skipped)
| -| `tests_run` |Number of tests executed
| -| `tests_passed` |Number of tests passed
| -| `coverage_path` |Path to coverage report
| +| name | description | +|--------------------|------------------------------------------------| +| `framework` |Detected framework (laravel or generic)
| +| `php-version` |The PHP version that was setup
| +| `composer-version` |Installed Composer version
| +| `cache-hit` |Indicates if there was a cache hit
| +| `test-status` |Test execution status (success/failure)
| +| `tests-run` |Number of tests executed
| +| `tests-passed` |Number of tests passed
| ### Runs @@ -32,6 +41,42 @@ This action is a `composite` action. ```yaml - uses: ivuorinen/actions/php-tests@main with: + framework: + # Framework detection mode (auto=detect Laravel via artisan, laravel=force Laravel, generic=no framework) + # + # Required: false + # Default: auto + + php-version: + # PHP Version to use (latest, 8.4, 8.3, etc.) + # + # Required: false + # Default: latest + + extensions: + # PHP extensions to install (comma-separated) + # + # Required: false + # Default: mbstring, intl, json, pdo_sqlite, sqlite3 + + coverage: + # Code-coverage driver (none, xdebug, pcov) + # + # Required: false + # Default: none + + composer-args: + # Arguments to pass to Composer install + # + # Required: false + # Default: --no-progress --prefer-dist --optimize-autoloader + + max-retries: + # Maximum number of retry attempts for Composer commands + # + # Required: false + # Default: 3 + token: # GitHub token for authentication # diff --git a/php-tests/action.yml b/php-tests/action.yml index 1fdeb40..18c83c3 100644 --- a/php-tests/action.yml +++ b/php-tests/action.yml @@ -3,7 +3,7 @@ # - contents: read # Required for checking out repository --- name: PHP Tests -description: Run PHPUnit tests on the repository +description: Run PHPUnit tests with optional Laravel setup and Composer dependency management author: Ismo Vuorinen branding: @@ -11,6 +11,30 @@ branding: color: green inputs: + framework: + description: 'Framework detection mode (auto=detect Laravel via artisan, laravel=force Laravel, generic=no framework)' + required: false + default: 'auto' + php-version: + description: 'PHP Version to use (latest, 8.4, 8.3, etc.)' + required: false + default: 'latest' + extensions: + description: 'PHP extensions to install (comma-separated)' + required: false + default: 'mbstring, intl, json, pdo_sqlite, sqlite3' + coverage: + description: 'Code-coverage driver (none, xdebug, pcov)' + required: false + default: 'none' + composer-args: + description: 'Arguments to pass to Composer install' + required: false + default: '--no-progress --prefer-dist --optimize-autoloader' + max-retries: + description: 'Maximum number of retry attempts for Composer commands' + required: false + default: '3' token: description: 'GitHub token for authentication' required: false @@ -25,56 +49,103 @@ inputs: default: 'github-actions@github.com' outputs: - test_status: - description: 'Test execution status (success/failure/skipped)' + framework: + description: 'Detected framework (laravel or generic)' + value: ${{ steps.detect-framework.outputs.framework }} + php-version: + description: 'The PHP version that was setup' + value: ${{ steps.setup-php.outputs.php-version }} + composer-version: + description: 'Installed Composer version' + value: ${{ steps.composer-config.outputs.version }} + cache-hit: + description: 'Indicates if there was a cache hit' + value: ${{ steps.composer-cache.outputs.cache-hit }} + test-status: + description: 'Test execution status (success/failure)' value: ${{ steps.test.outputs.status }} - tests_run: + tests-run: description: 'Number of tests executed' value: ${{ steps.test.outputs.tests_run }} - tests_passed: + tests-passed: description: 'Number of tests passed' value: ${{ steps.test.outputs.tests_passed }} - coverage_path: - description: 'Path to coverage report' - value: 'coverage.xml' runs: using: composite steps: + - name: Mask Secrets + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.token }} + run: | + set -euo pipefail + if [ -n "$GITHUB_TOKEN" ]; then + echo "::add-mask::$GITHUB_TOKEN" + fi + - name: Validate Inputs id: validate shell: bash env: - GITHUB_TOKEN: ${{ inputs.token }} + FRAMEWORK: ${{ inputs.framework }} + PHP_VERSION: ${{ inputs.php-version }} + COVERAGE: ${{ inputs.coverage }} + MAX_RETRIES: ${{ inputs.max-retries }} EMAIL: ${{ inputs.email }} USERNAME: ${{ inputs.username }} run: | set -euo pipefail - # Validate GitHub token format (basic validation) - if [[ -n "$GITHUB_TOKEN" ]]; then - # Skip validation for GitHub expressions (they'll be resolved at runtime) - if ! [[ "$GITHUB_TOKEN" =~ ^gh[efpousr]_[a-zA-Z0-9]{36}$ ]] && ! [[ "$GITHUB_TOKEN" =~ ^\$\{\{ ]]; then - echo "::warning::GitHub token format may be invalid. Expected format: gh*_36characters" + # Validate framework mode + case "$FRAMEWORK" in + auto|laravel|generic) + echo "Framework mode: $FRAMEWORK" + ;; + *) + echo "::error::Invalid framework: '$FRAMEWORK'. Must be 'auto', 'laravel', or 'generic'" + exit 1 + ;; + esac + + # Validate PHP version format + if [[ "$PHP_VERSION" != "latest" ]]; then + if ! [[ "$PHP_VERSION" =~ ^[0-9]+(\.[0-9]+)?(\.[0-9]+)?$ ]]; then + echo "::error::Invalid php-version format: '$PHP_VERSION'. Expected format: X.Y or X.Y.Z (e.g., 8.4, 8.3.0)" + exit 1 fi fi - # Validate email format (basic check) + # Validate coverage driver + case "$COVERAGE" in + none|xdebug|pcov) + ;; + *) + echo "::error::Invalid coverage driver: '$COVERAGE'. Must be 'none', 'xdebug', or 'pcov'" + exit 1 + ;; + esac + + # Validate max retries + if ! [[ "$MAX_RETRIES" =~ ^[0-9]+$ ]] || [ "$MAX_RETRIES" -le 0 ] || [ "$MAX_RETRIES" -gt 10 ]; then + echo "::error::Invalid max-retries: '$MAX_RETRIES'. Must be a positive integer between 1 and 10" + exit 1 + fi + + # Validate email format if [[ "$EMAIL" != *"@"* ]] || [[ "$EMAIL" != *"."* ]]; then echo "::error::Invalid email format: '$EMAIL'. Expected valid email address" exit 1 fi - # Validate username format (prevent command injection) + # Validate username format if [[ "$USERNAME" == *";"* ]] || [[ "$USERNAME" == *"&&"* ]] || [[ "$USERNAME" == *"|"* ]]; then echo "::error::Invalid username: '$USERNAME'. Command injection patterns not allowed" exit 1 fi - # Validate username length - username="$USERNAME" - if [ ${#username} -gt 39 ]; then - echo "::error::Username too long: ${#username} characters. GitHub usernames are max 39 characters" + if [ ${#USERNAME} -gt 39 ]; then + echo "::error::Username too long: ${#USERNAME} characters. GitHub usernames are max 39 characters" exit 1 fi @@ -85,18 +156,289 @@ runs: with: token: ${{ inputs.token || github.token }} - - name: Composer Install - uses: ivuorinen/actions/php-composer@0fa9a68f07a1260b321f814202658a6089a43d42 + - name: Detect Framework + id: detect-framework + shell: bash + env: + FRAMEWORK_MODE: ${{ inputs.framework }} + run: | + set -euo pipefail + + framework="generic" + + if [ "$FRAMEWORK_MODE" = "laravel" ]; then + framework="laravel" + echo "Framework mode forced to Laravel" + elif [ "$FRAMEWORK_MODE" = "auto" ]; then + if [ -f "artisan" ]; then + framework="laravel" + echo "Detected Laravel framework (artisan file found)" + else + echo "No Laravel framework detected (no artisan file)" + fi + else + echo "Framework mode set to generic" + fi + + printf 'framework=%s\n' "$framework" >> "$GITHUB_OUTPUT" + + - name: Detect PHP Version + id: detect-php-version + shell: sh + env: + DEFAULT_VERSION: ${{ inputs.php-version }} + run: | + set -eu + + # Function to validate version format + validate_version() { + version=$1 + case "$version" in + [0-9]*.[0-9]* | [0-9]*.[0-9]*.[0-9]*) + return 0 + ;; + *) + return 1 + ;; + esac + } + + # Function to clean version string + clean_version() { + printf '%s' "$1" | sed 's/^[vV]//' | tr -d ' \n\r' + } + + detected_version="" + + # Parse .tool-versions file + if [ -f .tool-versions ]; then + echo "Checking .tool-versions for php..." >&2 + version=$(awk '/^php[[:space:]]/ {gsub(/#.*/, ""); print $2; exit}' .tool-versions 2>/dev/null || echo "") + if [ -n "$version" ]; then + version=$(clean_version "$version") + if validate_version "$version"; then + echo "Found PHP version in .tool-versions: $version" >&2 + detected_version="$version" + fi + fi + fi + + # Parse Dockerfile + if [ -z "$detected_version" ] && [ -f Dockerfile ]; then + echo "Checking Dockerfile for php..." >&2 + version=$(grep -iF "FROM" Dockerfile | grep -F "php:" | head -1 | \ + sed -n -E "s/.*php:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "") + if [ -n "$version" ]; then + version=$(clean_version "$version") + if validate_version "$version"; then + echo "Found PHP version in Dockerfile: $version" >&2 + detected_version="$version" + fi + fi + fi + + # Parse devcontainer.json + if [ -z "$detected_version" ] && [ -f .devcontainer/devcontainer.json ]; then + echo "Checking devcontainer.json for php..." >&2 + if command -v jq >/dev/null 2>&1; then + version=$(jq -r '.image // empty' .devcontainer/devcontainer.json 2>/dev/null | sed -n -E "s/.*php:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "") + if [ -n "$version" ]; then + version=$(clean_version "$version") + if validate_version "$version"; then + echo "Found PHP version in devcontainer: $version" >&2 + detected_version="$version" + fi + fi + else + echo "jq not found; skipping devcontainer.json parsing" >&2 + fi + fi + + # Parse .php-version file + if [ -z "$detected_version" ] && [ -f .php-version ]; then + echo "Checking .php-version..." >&2 + version=$(tr -d '\r' < .php-version | head -1) + if [ -n "$version" ]; then + version=$(clean_version "$version") + if validate_version "$version"; then + echo "Found PHP version in .php-version: $version" >&2 + detected_version="$version" + fi + fi + fi + + # Parse composer.json + if [ -z "$detected_version" ] && [ -f composer.json ]; then + echo "Checking composer.json..." >&2 + if command -v jq >/dev/null 2>&1; then + version=$(jq -r '.require.php // empty' composer.json 2>/dev/null | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p') + if [ -z "$version" ]; then + version=$(jq -r '.config.platform.php // empty' composer.json 2>/dev/null | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p') + fi + if [ -n "$version" ]; then + version=$(clean_version "$version") + if validate_version "$version"; then + echo "Found PHP version in composer.json: $version" >&2 + detected_version="$version" + fi + fi + else + echo "jq not found; skipping composer.json parsing" >&2 + fi + fi + + # Use default version if nothing detected + if [ -z "$detected_version" ]; then + detected_version="$DEFAULT_VERSION" + echo "Using default PHP version: $detected_version" >&2 + fi + + # Set output + printf 'detected-version=%s\n' "$detected_version" >> "$GITHUB_OUTPUT" + echo "Final detected PHP version: $detected_version" >&2 + + - name: Setup PHP + id: setup-php + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + with: + php-version: ${{ steps.detect-php-version.outputs.detected-version }} + extensions: ${{ inputs.extensions }} + coverage: ${{ inputs.coverage }} + ini-values: memory_limit=1G, max_execution_time=600 + fail-fast: true + + - name: Configure Composer + id: composer-config + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.token || github.token }} + run: | + set -euo pipefail + + # Configure Composer environment + composer config --global process-timeout 600 + composer config --global allow-plugins true + composer config --global github-oauth.github.com "$GITHUB_TOKEN" + + # Verify Composer installation + composer_full_version=$(composer --version | grep -oP 'Composer version \K[0-9]+\.[0-9]+\.[0-9]+' || echo "") + if [ -z "$composer_full_version" ]; then + echo "::error::Failed to detect Composer version" + exit 1 + fi + + echo "Detected Composer version: $composer_full_version" + printf 'version=%s\n' "$composer_full_version" >> "$GITHUB_OUTPUT" + + # Log Composer configuration + echo "Composer Configuration:" + composer config --list + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: | + vendor + ~/.composer/cache + key: ${{ runner.os }}-php-${{ steps.setup-php.outputs.php-version }}-composer-${{ hashFiles('composer.lock', 'composer.json') }} + restore-keys: | + ${{ runner.os }}-php-${{ steps.setup-php.outputs.php-version }}-composer- + ${{ runner.os }}-php-${{ steps.setup-php.outputs.php-version }}- + ${{ runner.os }}-php- + + - name: Clear Composer Cache Before Install + if: steps.composer-cache.outputs.cache-hit != 'true' + shell: bash + run: | + set -euo pipefail + echo "Clearing Composer cache to ensure clean installation..." + composer clear-cache + + - name: Install Composer Dependencies + uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3 + with: + timeout_minutes: 10 + max_attempts: ${{ inputs.max-retries }} + retry_wait_seconds: 30 + command: composer install ${{ inputs.composer-args }} + + - name: Verify Composer Installation + shell: bash + run: | + set -euo pipefail + + # Verify vendor directory + if [ ! -d "vendor" ]; then + echo "::error::vendor directory not found" + exit 1 + fi + + # Verify autoloader + if [ ! -f "vendor/autoload.php" ]; then + echo "::error::autoload.php not found" + exit 1 + fi + + echo "โ Composer installation verified" + + - name: Laravel Setup - Copy .env + if: steps.detect-framework.outputs.framework == 'laravel' + shell: bash + run: | + set -euo pipefail + php -r "file_exists('.env') || copy('.env.example', '.env');" + echo "โ Laravel .env file configured" + + - name: Laravel Setup - Generate Key + if: steps.detect-framework.outputs.framework == 'laravel' + shell: bash + run: | + set -euo pipefail + php artisan key:generate + echo "โ Laravel application key generated" + + - name: Laravel Setup - Directory Permissions + if: steps.detect-framework.outputs.framework == 'laravel' + shell: bash + run: | + set -euo pipefail + chmod -R 777 storage bootstrap/cache + echo "โ Laravel directory permissions configured" + + - name: Laravel Setup - Create Database + if: steps.detect-framework.outputs.framework == 'laravel' + shell: bash + run: | + set -euo pipefail + mkdir -p database + touch database/database.sqlite + echo "โ Laravel SQLite database created" - name: Run PHPUnit Tests id: test shell: bash - run: |- + env: + IS_LARAVEL: ${{ steps.detect-framework.outputs.framework == 'laravel' }} + DB_CONNECTION: sqlite + DB_DATABASE: database/database.sqlite + run: | set -euo pipefail + echo "Running PHPUnit tests..." + # Run PHPUnit and capture results phpunit_exit_code=0 - phpunit_output=$(vendor/bin/phpunit --verbose 2>&1) || phpunit_exit_code=$? + if [ "$IS_LARAVEL" = "true" ] && [ -f "composer.json" ] && grep -q '"test"' composer.json; then + echo "Running Laravel tests via composer test..." + phpunit_output=$(composer test 2>&1) || phpunit_exit_code=$? + elif [ -f "vendor/bin/phpunit" ]; then + echo "Running PHPUnit directly..." + phpunit_output=$(vendor/bin/phpunit --verbose 2>&1) || phpunit_exit_code=$? + else + echo "::error::PHPUnit not found. Ensure Composer dependencies are installed." + exit 1 + fi echo "$phpunit_output" @@ -107,15 +449,16 @@ runs: # Determine status if [ $phpunit_exit_code -eq 0 ]; then status="success" + echo "โ Tests passed: $tests_passed/$tests_run" else status="failure" + echo "โ Tests failed" fi # Output results - echo "tests_run=$tests_run" >> $GITHUB_OUTPUT - echo "tests_passed=$tests_passed" >> $GITHUB_OUTPUT - echo "status=$status" >> $GITHUB_OUTPUT - echo "coverage_path=coverage.xml" >> $GITHUB_OUTPUT + printf 'tests_run=%s\n' "$tests_run" >> "$GITHUB_OUTPUT" + printf 'tests_passed=%s\n' "$tests_passed" >> "$GITHUB_OUTPUT" + printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT" # Exit with original code to maintain test failure behavior exit $phpunit_exit_code diff --git a/php-tests/rules.yml b/php-tests/rules.yml index 4eeb9fd..e5b66ec 100644 --- a/php-tests/rules.yml +++ b/php-tests/rules.yml @@ -1,37 +1,49 @@ +--- # Validation rules for php-tests action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 -# Coverage: 100% (3/3 inputs) +# Coverage: 78% (7/9 inputs) # # This file defines validation rules for the php-tests GitHub Action. # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: php-tests -description: Run PHPUnit tests on the repository +description: Run PHPUnit tests with optional Laravel setup and Composer dependency management generator_version: 1.0.0 required_inputs: [] optional_inputs: + - composer-args + - coverage - email + - extensions + - framework + - max-retries + - php-version - token - username conventions: + coverage: coverage_driver email: email + framework: boolean + max-retries: numeric_range_1_10 + php-version: semantic_version token: github_token username: username overrides: {} statistics: - total_inputs: 3 - validated_inputs: 3 + total_inputs: 9 + validated_inputs: 7 skipped_inputs: 0 - coverage_percentage: 100 -validation_coverage: 100 + coverage_percentage: 78 +validation_coverage: 78 auto_detected: true -manual_review_required: false +manual_review_required: true quality_indicators: has_required_inputs: false has_token_validation: true - has_version_validation: false + has_version_validation: true has_file_validation: false has_security_validation: true diff --git a/pr-lint/rules.yml b/pr-lint/rules.yml index 38d80a0..008f71c 100644 --- a/pr-lint/rules.yml +++ b/pr-lint/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for pr-lint action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: pr-lint description: Runs MegaLinter against pull requests diff --git a/pre-commit/rules.yml b/pre-commit/rules.yml index fa18a24..cf139d3 100644 --- a/pre-commit/rules.yml +++ b/pre-commit/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for pre-commit action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: pre-commit description: Runs pre-commit on the repository and pushes the fixes back to the repository diff --git a/prettier-lint/README.md b/prettier-lint/README.md index 2548f24..41f9316 100644 --- a/prettier-lint/README.md +++ b/prettier-lint/README.md @@ -8,32 +8,32 @@ Run Prettier in check or fix mode with advanced configuration and reporting ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `mode` |Mode to run (check or fix)
| `false` | `check` | -| `working-directory` |Directory containing files to format
| `false` | `.` | -| `prettier-version` |Prettier version to use
| `false` | `latest` | -| `config-file` |Path to Prettier config file
| `false` | `.prettierrc` | -| `ignore-file` |Path to Prettier ignore file
| `false` | `.prettierignore` | -| `file-pattern` |Files to include (glob pattern)
| `false` | `**/*.{js,jsx,ts,tsx,css,scss,json,md,yaml,yml}` | -| `cache` |Enable Prettier caching
| `false` | `true` | -| `fail-on-error` |Fail workflow if issues are found (check mode only)
| `false` | `true` | -| `report-format` |Output format for check mode (json, sarif)
| `false` | `sarif` | -| `max-retries` |Maximum number of retry attempts
| `false` | `3` | -| `plugins` |Comma-separated list of Prettier plugins to install
| `false` | `""` | -| `token` |GitHub token for authentication
| `false` | `""` | -| `username` |GitHub username for commits (fix mode only)
| `false` | `github-actions` | -| `email` |GitHub email for commits (fix mode only)
| `false` | `github-actions@github.com` | +| name | description | required | default | +|---------------------|------------------------------------------------------------|----------|--------------------------------------------------| +| `mode` |Mode to run (check or fix)
| `false` | `check` | +| `working-directory` |Directory containing files to format
| `false` | `.` | +| `prettier-version` |Prettier version to use
| `false` | `latest` | +| `config-file` |Path to Prettier config file
| `false` | `.prettierrc` | +| `ignore-file` |Path to Prettier ignore file
| `false` | `.prettierignore` | +| `file-pattern` |Files to include (glob pattern)
| `false` | `**/*.{js,jsx,ts,tsx,css,scss,json,md,yaml,yml}` | +| `cache` |Enable Prettier caching
| `false` | `true` | +| `fail-on-error` |Fail workflow if issues are found (check mode only)
| `false` | `true` | +| `report-format` |Output format for check mode (json, sarif)
| `false` | `sarif` | +| `max-retries` |Maximum number of retry attempts
| `false` | `3` | +| `plugins` |Comma-separated list of Prettier plugins to install
| `false` | `""` | +| `token` |GitHub token for authentication
| `false` | `""` | +| `username` |GitHub username for commits (fix mode only)
| `false` | `github-actions` | +| `email` |GitHub email for commits (fix mode only)
| `false` | `github-actions@github.com` | ### Outputs -| name | description | -| --- | --- | -| `status` |Overall status (success/failure)
| -| `files-checked` |Number of files checked (check mode only)
| +| name | description | +|---------------------|-----------------------------------------------------------------| +| `status` |Overall status (success/failure)
| +| `files-checked` |Number of files checked (check mode only)
| | `unformatted-files` |Number of files with formatting issues (check mode only)
| -| `sarif-file` |Path to SARIF report file (check mode only)
| -| `files-changed` |Number of files changed (fix mode only)
| +| `sarif-file` |Path to SARIF report file (check mode only)
| +| `files-changed` |Number of files changed (fix mode only)
| ### Runs diff --git a/prettier-lint/rules.yml b/prettier-lint/rules.yml index 531d3d4..f0b820e 100644 --- a/prettier-lint/rules.yml +++ b/prettier-lint/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for prettier-lint action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: prettier-lint description: Run Prettier in check or fix mode with advanced configuration and reporting diff --git a/python-lint-fix/README.md b/python-lint-fix/README.md index 3474bf2..3ee018a 100644 --- a/python-lint-fix/README.md +++ b/python-lint-fix/README.md @@ -8,25 +8,25 @@ Lints and fixes Python files, commits changes, and uploads SARIF report. ### Inputs -| name | description | required | default | -| --- | --- | --- | --- | -| `python-version` |Python version to use
| `false` | `3.11` | -| `flake8-version` |Flake8 version to use
| `false` | `7.0.0` | -| `autopep8-version` |Autopep8 version to use
| `false` | `2.0.4` | -| `max-retries` |Maximum number of retry attempts for installations and linting
| `false` | `3` | -| `working-directory` |Directory containing Python files to lint
| `false` | `.` | -| `fail-on-error` |Whether to fail the action if linting errors are found
| `false` | `true` | -| `token` |GitHub token for authentication
| `false` | `""` | -| `username` |GitHub username for commits
| `false` | `github-actions` | -| `email` |GitHub email for commits
| `false` | `github-actions@github.com` | +| name | description | required | default | +|---------------------|-----------------------------------------------------------------------|----------|-----------------------------| +| `python-version` |Python version to use
| `false` | `3.11` | +| `flake8-version` |Flake8 version to use
| `false` | `7.0.0` | +| `autopep8-version` |Autopep8 version to use
| `false` | `2.0.4` | +| `max-retries` |Maximum number of retry attempts for installations and linting
| `false` | `3` | +| `working-directory` |Directory containing Python files to lint
| `false` | `.` | +| `fail-on-error` |Whether to fail the action if linting errors are found
| `false` | `true` | +| `token` |GitHub token for authentication
| `false` | `""` | +| `username` |GitHub username for commits
| `false` | `github-actions` | +| `email` |GitHub email for commits
| `false` | `github-actions@github.com` | ### Outputs -| name | description | -| --- | --- | +| name | description | +|---------------|--------------------------------------------------------| | `lint-result` |Result of the linting process (success/failure)
| -| `fixed-files` |Number of files that were fixed
| -| `error-count` |Number of errors found
| +| `fixed-files` |Number of files that were fixed
| +| `error-count` |Number of errors found
| ### Runs diff --git a/python-lint-fix/rules.yml b/python-lint-fix/rules.yml index d093517..abf9f09 100644 --- a/python-lint-fix/rules.yml +++ b/python-lint-fix/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for python-lint-fix action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: python-lint-fix description: Lints and fixes Python files, commits changes, and uploads SARIF report. diff --git a/release-monthly/rules.yml b/release-monthly/rules.yml index 0816e10..338ecf6 100644 --- a/release-monthly/rules.yml +++ b/release-monthly/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for release-monthly action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: release-monthly description: Creates a release for the current month, incrementing patch number if necessary. diff --git a/stale/rules.yml b/stale/rules.yml index 1691a67..7f79dd0 100644 --- a/stale/rules.yml +++ b/stale/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for stale action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: stale description: A GitHub Action to close stale issues and pull requests. diff --git a/sync-labels/rules.yml b/sync-labels/rules.yml index 801f02b..ef90026 100644 --- a/sync-labels/rules.yml +++ b/sync-labels/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for sync-labels action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: sync-labels description: Sync labels from a YAML file to a GitHub repository diff --git a/terraform-lint-fix/rules.yml b/terraform-lint-fix/rules.yml index 1dddd4e..6f62212 100644 --- a/terraform-lint-fix/rules.yml +++ b/terraform-lint-fix/rules.yml @@ -1,3 +1,4 @@ +--- # Validation rules for terraform-lint-fix action # Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY # Schema version: 1.0 @@ -7,6 +8,7 @@ # Rules are automatically applied by validate-inputs action when this # action is used. # + schema_version: '1.0' action: terraform-lint-fix description: Lints and fixes Terraform files with advanced validation and security checks. diff --git a/validate-inputs/scripts/update-validators.py b/validate-inputs/scripts/update-validators.py index 0e784ab..9bf674f 100755 --- a/validate-inputs/scripts/update-validators.py +++ b/validate-inputs/scripts/update-validators.py @@ -331,9 +331,6 @@ class ValidationRuleGenerator: "file-pattern": "file_pattern", "plugins": "plugin_list", }, - "php-laravel-phpunit": { - "extensions": "php_extensions", - }, "codeql-analysis": { "language": "codeql_language", "queries": "codeql_queries", diff --git a/validate-inputs/tests/test_php-composer_custom.py b/validate-inputs/tests/test_php-composer_custom.py deleted file mode 100644 index 8d22626..0000000 --- a/validate-inputs/tests/test_php-composer_custom.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Tests for php-composer custom validator. - -Generated by generate-tests.py - Do not edit manually. -""" -# pylint: disable=invalid-name # Test file name matches action name - -import sys -from pathlib import Path - -# Add action directory to path to import custom validator -action_path = Path(__file__).parent.parent.parent / "php-composer" -sys.path.insert(0, str(action_path)) - -# pylint: disable=wrong-import-position -from CustomValidator import CustomValidator - - -class TestCustomPhpComposerValidator: - """Test cases for php-composer custom validator.""" - - def setup_method(self): - """Set up test fixtures.""" - self.validator = CustomValidator("php-composer") - - def teardown_method(self): - """Clean up after tests.""" - self.validator.clear_errors() - - def test_validate_inputs_valid(self): - """Test validation with valid inputs.""" - # TODO: Add specific valid inputs for php-composer - inputs = {} - result = self.validator.validate_inputs(inputs) - # Adjust assertion based on required inputs - assert isinstance(result, bool) - - def test_validate_inputs_invalid(self): - """Test validation with invalid inputs.""" - # TODO: Add specific invalid inputs for php-composer - inputs = {"invalid_key": "invalid_value"} - result = self.validator.validate_inputs(inputs) - # Custom validators may have specific validation rules - assert isinstance(result, bool) - - def test_required_inputs(self): - """Test required inputs detection.""" - required = self.validator.get_required_inputs() - assert isinstance(required, list) - # TODO: Assert specific required inputs for php-composer - - def test_validation_rules(self): - """Test validation rules.""" - rules = self.validator.get_validation_rules() - assert isinstance(rules, dict) - # TODO: Assert specific validation rules for php-composer - - def test_github_expressions(self): - """Test GitHub expression handling.""" - inputs = { - "test_input": "${{ github.token }}", - } - result = self.validator.validate_inputs(inputs) - assert isinstance(result, bool) - # GitHub expressions should generally be accepted - - def test_error_propagation(self): - """Test error propagation from sub-validators.""" - # Custom validators often use sub-validators - # Test that errors are properly propagated - inputs = {"test": "value"} - self.validator.validate_inputs(inputs) - # Check error handling - if self.validator.has_errors(): - assert len(self.validator.errors) > 0 diff --git a/validate-inputs/tests/test_php-laravel-phpunit_custom.py b/validate-inputs/tests/test_php-laravel-phpunit_custom.py deleted file mode 100644 index 39e6b5a..0000000 --- a/validate-inputs/tests/test_php-laravel-phpunit_custom.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Tests for php-laravel-phpunit custom validator. - -Generated by generate-tests.py - Do not edit manually. -""" -# pylint: disable=invalid-name # Test file name matches action name - -import sys -from pathlib import Path - -# Add action directory to path to import custom validator -action_path = Path(__file__).parent.parent.parent / "php-laravel-phpunit" -sys.path.insert(0, str(action_path)) - -# pylint: disable=wrong-import-position -from CustomValidator import CustomValidator - - -class TestCustomPhpLaravelPhpunitValidator: - """Test cases for php-laravel-phpunit custom validator.""" - - def setup_method(self): - """Set up test fixtures.""" - self.validator = CustomValidator("php-laravel-phpunit") - - def teardown_method(self): - """Clean up after tests.""" - self.validator.clear_errors() - - def test_validate_inputs_valid(self): - """Test validation with valid inputs.""" - # TODO: Add specific valid inputs for php-laravel-phpunit - inputs = {} - result = self.validator.validate_inputs(inputs) - # Adjust assertion based on required inputs - assert isinstance(result, bool) - - def test_validate_inputs_invalid(self): - """Test validation with invalid inputs.""" - # TODO: Add specific invalid inputs for php-laravel-phpunit - inputs = {"invalid_key": "invalid_value"} - result = self.validator.validate_inputs(inputs) - # Custom validators may have specific validation rules - assert isinstance(result, bool) - - def test_required_inputs(self): - """Test required inputs detection.""" - required = self.validator.get_required_inputs() - assert isinstance(required, list) - # TODO: Assert specific required inputs for php-laravel-phpunit - - def test_validation_rules(self): - """Test validation rules.""" - rules = self.validator.get_validation_rules() - assert isinstance(rules, dict) - # TODO: Assert specific validation rules for php-laravel-phpunit - - def test_github_expressions(self): - """Test GitHub expression handling.""" - inputs = { - "test_input": "${{ github.token }}", - } - result = self.validator.validate_inputs(inputs) - assert isinstance(result, bool) - # GitHub expressions should generally be accepted - - def test_error_propagation(self): - """Test error propagation from sub-validators.""" - # Custom validators often use sub-validators - # Test that errors are properly propagated - inputs = {"test": "value"} - self.validator.validate_inputs(inputs) - # Check error handling - if self.validator.has_errors(): - assert len(self.validator.errors) > 0