mirror of
https://github.com/ivuorinen/actions.git
synced 2026-01-30 04:40:34 +00:00
refactor: remove deprecated version-file-parser action
Remove version-file-parser after successful inlining into node-setup: - Delete version-file-parser action directory - Delete version-file-parser unit and integration tests - Remove version-file-parser references from spec_helper.sh - Remove version-file-parser path trigger from node-setup-test.yml - Regenerate action catalog (29 actions, down from 30) All version detection functionality now inlined into individual actions: - go-build: Go version detection - csharp-build/csharp-lint-check/csharp-publish: .NET version detection - python-lint-fix: Python version detection - php-laravel-phpunit: PHP version detection - node-setup: Node.js version detection and package manager detection Reduces external dependencies and improves initialization performance across all actions.
This commit is contained in:
18
README.md
18
README.md
@@ -22,9 +22,9 @@ Each action is fully self-contained and can be used independently in any GitHub
|
||||
|
||||
## 📚 Action Catalog
|
||||
|
||||
This repository contains **30 reusable GitHub Actions** for CI/CD automation.
|
||||
This repository contains **29 reusable GitHub Actions** for CI/CD automation.
|
||||
|
||||
### Quick Reference (30 Actions)
|
||||
### Quick Reference (29 Actions)
|
||||
|
||||
| Icon | Action | Category | Description | Key Features |
|
||||
|:----:|:-----------------------------------------------------|:-----------|:----------------------------------------------------------------|:---------------------------------------------|
|
||||
@@ -57,7 +57,6 @@ This repository contains **30 reusable GitHub Actions** for CI/CD automation.
|
||||
| 🏷️ | [`sync-labels`][sync-labels] | Repository | Sync labels from a YAML file to a GitHub repository | Token auth, Outputs |
|
||||
| 🖥️ | [`terraform-lint-fix`][terraform-lint-fix] | Linting | Lints and fixes Terraform files with advanced validation and... | Token auth, Outputs |
|
||||
| 🛡️ | [`validate-inputs`][validate-inputs] | Validation | Centralized Python-based input validation for GitHub Actions... | Token auth, Outputs |
|
||||
| 📦 | [`version-file-parser`][version-file-parser] | Utilities | Universal parser for common version detection files (.tool-v... | Auto-detection, Outputs |
|
||||
|
||||
### Actions by Category
|
||||
|
||||
@@ -68,12 +67,11 @@ This repository contains **30 reusable GitHub Actions** for CI/CD automation.
|
||||
| 📝 [`language-version-detect`][language-version-detect] | Detects language version from project configuratio... | 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 |
|
||||
|
||||
#### 🛠️ Utilities (2 actions)
|
||||
#### 🛠️ Utilities (1 action)
|
||||
|
||||
| Action | Description | Languages | Features |
|
||||
|:------------------------------------------------|:------------------------------------------------------|:-------------------|:------------------------|
|
||||
| 🔀 [`action-versioning`][action-versioning] | Automatically update SHA-pinned action references ... | GitHub Actions | Token auth, Outputs |
|
||||
| 📦 [`version-file-parser`][version-file-parser] | Universal parser for common version detection file... | Multiple Languages | Auto-detection, Outputs |
|
||||
| Action | Description | Languages | Features |
|
||||
|:--------------------------------------------|:------------------------------------------------------|:---------------|:--------------------|
|
||||
| 🔀 [`action-versioning`][action-versioning] | Automatically update SHA-pinned action references ... | GitHub Actions | Token auth, Outputs |
|
||||
|
||||
#### 📝 Linting (10 actions)
|
||||
|
||||
@@ -164,7 +162,6 @@ This repository contains **30 reusable GitHub Actions** for CI/CD automation.
|
||||
| [`sync-labels`][sync-labels] | - | - | ✅ | ✅ |
|
||||
| [`terraform-lint-fix`][terraform-lint-fix] | - | - | ✅ | ✅ |
|
||||
| [`validate-inputs`][validate-inputs] | - | - | ✅ | ✅ |
|
||||
| [`version-file-parser`][version-file-parser] | - | ✅ | - | ✅ |
|
||||
|
||||
### Language Support
|
||||
|
||||
@@ -188,7 +185,7 @@ This repository contains **30 reusable GitHub Actions** for CI/CD automation.
|
||||
| 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] |
|
||||
| Markdown | [`prettier-lint`][prettier-lint] |
|
||||
| Multiple Languages | [`pre-commit`][pre-commit], [`version-file-parser`][version-file-parser] |
|
||||
| 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] |
|
||||
| PNG | [`compress-images`][compress-images] |
|
||||
@@ -248,7 +245,6 @@ All actions can be used independently in your workflows:
|
||||
[sync-labels]: sync-labels/README.md
|
||||
[terraform-lint-fix]: terraform-lint-fix/README.md
|
||||
[validate-inputs]: validate-inputs/README.md
|
||||
[version-file-parser]: version-file-parser/README.md
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'node-setup/**'
|
||||
- 'version-file-parser/**'
|
||||
- 'common-cache/**'
|
||||
- 'common-retry/**'
|
||||
- '_tests/integration/workflows/node-setup-test.yml'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
---
|
||||
name: Test version-file-parser Integration
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'version-file-parser/**'
|
||||
- '_tests/integration/workflows/version-file-parser-test.yml'
|
||||
|
||||
jobs:
|
||||
test-version-file-parser:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
test-case:
|
||||
- name: 'Node.js project'
|
||||
language: 'node'
|
||||
tool-versions-key: 'nodejs'
|
||||
dockerfile-image: 'node'
|
||||
expected-version: '18.0.0'
|
||||
setup-files: |
|
||||
echo "18.17.0" > .nvmrc
|
||||
cat > package.json <<EOF
|
||||
{
|
||||
"name": "test-project",
|
||||
"engines": { "node": ">=18.0.0" }
|
||||
}
|
||||
EOF
|
||||
touch package-lock.json
|
||||
|
||||
- name: 'PHP project'
|
||||
language: 'php'
|
||||
tool-versions-key: 'php'
|
||||
dockerfile-image: 'php'
|
||||
expected-version: '8.1'
|
||||
setup-files: |
|
||||
cat > composer.json <<EOF
|
||||
{
|
||||
"require": { "php": "^8.1" }
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: 'Python project'
|
||||
language: 'python'
|
||||
tool-versions-key: 'python'
|
||||
dockerfile-image: 'python'
|
||||
expected-version: '3.9'
|
||||
setup-files: |
|
||||
echo "3.9.0" > .python-version
|
||||
cat > pyproject.toml <<EOF
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
EOF
|
||||
|
||||
- name: 'Go project'
|
||||
language: 'go'
|
||||
tool-versions-key: 'golang'
|
||||
dockerfile-image: 'golang'
|
||||
expected-version: '1.21'
|
||||
setup-files: |
|
||||
cat > go.mod <<EOF
|
||||
module test-project
|
||||
go 1.21
|
||||
EOF
|
||||
|
||||
- name: '.tool-versions file'
|
||||
language: 'node'
|
||||
tool-versions-key: 'nodejs'
|
||||
dockerfile-image: 'node'
|
||||
expected-version: '18.16.0'
|
||||
setup-files: |
|
||||
echo "nodejs 18.16.0" > .tool-versions
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Clean up test files from previous runs
|
||||
run: |
|
||||
rm -f .nvmrc package.json package-lock.json composer.json .python-version pyproject.toml go.mod .tool-versions
|
||||
|
||||
- name: Setup test files
|
||||
run: ${{ matrix.test-case.setup-files }}
|
||||
|
||||
- name: Test version-file-parser
|
||||
id: test-action
|
||||
uses: ./version-file-parser
|
||||
with:
|
||||
language: ${{ matrix.test-case.language }}
|
||||
tool-versions-key: ${{ matrix.test-case.tool-versions-key }}
|
||||
dockerfile-image: ${{ matrix.test-case.dockerfile-image }}
|
||||
default-version: '1.0.0'
|
||||
|
||||
- name: Validate outputs
|
||||
run: |
|
||||
echo "Test case: ${{ matrix.test-case.name }}"
|
||||
echo "Expected version: ${{ matrix.test-case.expected-version }}"
|
||||
echo "Detected version: ${{ steps.test-action.outputs.detected-version }}"
|
||||
echo "Package manager: ${{ steps.test-action.outputs.package-manager }}"
|
||||
|
||||
# Validate that we got some version
|
||||
if [[ -z "${{ steps.test-action.outputs.detected-version }}" ]]; then
|
||||
echo "❌ ERROR: No version detected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate version format (basic semver check)
|
||||
if ! echo "${{ steps.test-action.outputs.detected-version }}" | grep -E '^[0-9]+\.[0-9]+(\.[0-9]+)?'; then
|
||||
echo "❌ ERROR: Invalid version format: ${{ steps.test-action.outputs.detected-version }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate detected version matches expected version (not the fallback)
|
||||
if [[ "${{ steps.test-action.outputs.detected-version }}" != "${{ matrix.test-case.expected-version }}" ]]; then
|
||||
echo "❌ ERROR: Version mismatch"
|
||||
echo "Expected: ${{ matrix.test-case.expected-version }}"
|
||||
echo "Got: ${{ steps.test-action.outputs.detected-version }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Version validation passed"
|
||||
|
||||
# Skip external reference test in local/CI environment to avoid auth issues
|
||||
- name: Test external reference (info only)
|
||||
run: |
|
||||
echo "External reference test would use: ivuorinen/actions/version-file-parser@main"
|
||||
echo "Skipping to avoid authentication issues in local testing"
|
||||
|
||||
test-edge-cases:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Clean up test files from previous runs
|
||||
run: |
|
||||
rm -f .nvmrc package.json package-lock.json composer.json .python-version pyproject.toml go.mod .tool-versions
|
||||
|
||||
- name: Setup test files (package.json engines)
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
cat > package.json <<'EOF'
|
||||
{
|
||||
"name": "edge-case",
|
||||
"engines": { "node": ">=18.0.0" }
|
||||
}
|
||||
EOF
|
||||
echo "18.17.0" > .nvmrc
|
||||
|
||||
- name: Test version detection from existing files
|
||||
id: existing-version
|
||||
uses: ./version-file-parser
|
||||
with:
|
||||
language: 'node'
|
||||
tool-versions-key: 'nodejs'
|
||||
dockerfile-image: 'node'
|
||||
default-version: '20.0.0'
|
||||
|
||||
- name: Validate existing version detection
|
||||
run: |
|
||||
# The action detects Node.js version from package.json engines field
|
||||
# package.json >=18.0.0 is parsed as 18.0.0
|
||||
# Note: .nvmrc exists but package.json takes precedence in this implementation
|
||||
expected_version="18.0.0"
|
||||
detected_version="${{ steps.existing-version.outputs.detected-version }}"
|
||||
|
||||
if [[ "$detected_version" != "$expected_version" ]]; then
|
||||
echo "❌ ERROR: Version mismatch"
|
||||
echo "Expected: $expected_version"
|
||||
echo "Got: $detected_version"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Existing version detection works correctly"
|
||||
|
||||
- name: Clean up before invalid regex test
|
||||
run: |
|
||||
rm -f .nvmrc package.json package-lock.json
|
||||
|
||||
- name: Test with invalid regex
|
||||
id: invalid-regex
|
||||
uses: ./version-file-parser
|
||||
with:
|
||||
language: 'node'
|
||||
tool-versions-key: 'nodejs'
|
||||
dockerfile-image: 'node'
|
||||
validation-regex: 'invalid[regex'
|
||||
default-version: '18.0.0'
|
||||
continue-on-error: true
|
||||
|
||||
- name: Validate regex error handling
|
||||
run: |
|
||||
echo "Testing regex error handling completed"
|
||||
# Action should handle invalid regex gracefully
|
||||
if [ "${{ steps.invalid-regex.outcome }}" != "failure" ]; then
|
||||
echo "::error::Expected invalid-regex step to fail, but it was: ${{ steps.invalid-regex.outcome }}"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Invalid regex properly failed as expected"
|
||||
|
||||
test-dockerfile-parsing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Clean up test files from previous runs
|
||||
run: |
|
||||
rm -f .nvmrc package.json package-lock.json composer.json .python-version pyproject.toml go.mod .tool-versions Dockerfile
|
||||
|
||||
- name: Create Dockerfile with Node.js
|
||||
run: |
|
||||
cat > Dockerfile <<EOF
|
||||
FROM node:18.17.0-alpine
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
EOF
|
||||
|
||||
- name: Test Dockerfile parsing
|
||||
id: dockerfile-test
|
||||
uses: ./version-file-parser
|
||||
with:
|
||||
language: 'node'
|
||||
tool-versions-key: 'nodejs'
|
||||
dockerfile-image: 'node'
|
||||
|
||||
- name: Validate Dockerfile parsing
|
||||
run: |
|
||||
expected_version="18.17.0"
|
||||
detected_version="${{ steps.dockerfile-test.outputs.dockerfile-version }}"
|
||||
|
||||
echo "Expected version: $expected_version"
|
||||
echo "Detected version: $detected_version"
|
||||
|
||||
if [[ "$detected_version" != "$expected_version" ]]; then
|
||||
echo "❌ ERROR: Version mismatch"
|
||||
echo "Expected: $expected_version"
|
||||
echo "Got: $detected_version"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Dockerfile parsing successful"
|
||||
@@ -114,11 +114,6 @@ setup_default_inputs() {
|
||||
"validate-inputs")
|
||||
[[ "$input_name" != "action-type" && "$input_name" != "action" && "$input_name" != "rules-file" && "$input_name" != "fail-on-error" ]] && export INPUT_ACTION_TYPE="test-action"
|
||||
;;
|
||||
"version-file-parser")
|
||||
[[ "$input_name" != "language" ]] && export INPUT_LANGUAGE="node"
|
||||
[[ "$input_name" != "tool-versions-key" ]] && export INPUT_TOOL_VERSIONS_KEY="nodejs"
|
||||
[[ "$input_name" != "dockerfile-image" ]] && export INPUT_DOCKERFILE_IMAGE="node"
|
||||
;;
|
||||
"codeql-analysis")
|
||||
[[ "$input_name" != "language" ]] && export INPUT_LANGUAGE="javascript"
|
||||
[[ "$input_name" != "token" ]] && export INPUT_TOKEN="ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
@@ -185,11 +180,6 @@ cleanup_default_inputs() {
|
||||
"validate-inputs")
|
||||
[[ "$input_name" != "action-type" && "$input_name" != "action" && "$input_name" != "rules-file" && "$input_name" != "fail-on-error" ]] && unset INPUT_ACTION_TYPE
|
||||
;;
|
||||
"version-file-parser")
|
||||
[[ "$input_name" != "language" ]] && unset INPUT_LANGUAGE
|
||||
[[ "$input_name" != "tool-versions-key" ]] && unset INPUT_TOOL_VERSIONS_KEY
|
||||
[[ "$input_name" != "dockerfile-image" ]] && unset INPUT_DOCKERFILE_IMAGE
|
||||
;;
|
||||
"codeql-analysis")
|
||||
[[ "$input_name" != "language" ]] && unset INPUT_LANGUAGE
|
||||
[[ "$input_name" != "token" ]] && unset INPUT_TOKEN
|
||||
@@ -244,10 +234,6 @@ shellspec_mock_action_run() {
|
||||
action_name=$(basename "$action_dir")
|
||||
|
||||
case "$action_name" in
|
||||
"version-file-parser")
|
||||
echo "detected-version=1.0.0" >>"$GITHUB_OUTPUT"
|
||||
echo "package-manager=npm" >>"$GITHUB_OUTPUT"
|
||||
;;
|
||||
"node-setup")
|
||||
echo "node-version=18.0.0" >>"$GITHUB_OUTPUT"
|
||||
echo "package-manager=npm" >>"$GITHUB_OUTPUT"
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
#!/usr/bin/env shellspec
|
||||
# Unit tests for version-file-parser action validation and logic
|
||||
# Framework is automatically loaded via spec_helper.sh
|
||||
|
||||
Describe "version-file-parser action"
|
||||
ACTION_DIR="version-file-parser"
|
||||
ACTION_FILE="$ACTION_DIR/action.yml"
|
||||
|
||||
Context "when validating language input"
|
||||
It "accepts valid language input"
|
||||
When call validate_input_python "version-file-parser" "language" "node"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts php language"
|
||||
When call validate_input_python "version-file-parser" "language" "php"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts python language"
|
||||
When call validate_input_python "version-file-parser" "language" "python"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts go language"
|
||||
When call validate_input_python "version-file-parser" "language" "go"
|
||||
The status should be success
|
||||
End
|
||||
It "rejects invalid language with special characters"
|
||||
When call validate_input_python "version-file-parser" "language" "node; rm -rf /"
|
||||
The status should be failure
|
||||
End
|
||||
It "rejects empty required inputs"
|
||||
When call validate_input_python "version-file-parser" "language" ""
|
||||
The status should be failure
|
||||
End
|
||||
End
|
||||
|
||||
Context "when validating dockerfile-image input"
|
||||
It "accepts valid dockerfile image"
|
||||
When call validate_input_python "version-file-parser" "dockerfile-image" "node"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts php dockerfile image"
|
||||
When call validate_input_python "version-file-parser" "dockerfile-image" "php"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts python dockerfile image"
|
||||
When call validate_input_python "version-file-parser" "dockerfile-image" "python"
|
||||
The status should be success
|
||||
End
|
||||
It "rejects injection in dockerfile image"
|
||||
When call validate_input_python "version-file-parser" "dockerfile-image" "node;malicious"
|
||||
The status should be failure
|
||||
End
|
||||
End
|
||||
|
||||
Context "when validating optional inputs"
|
||||
It "accepts valid validation regex"
|
||||
When call validate_input_python "version-file-parser" "validation-regex" "^[0-9]+\.[0-9]+(\.[0-9]+)?$"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts valid default version"
|
||||
When call validate_input_python "version-file-parser" "default-version" "18.0.0"
|
||||
The status should be success
|
||||
End
|
||||
It "accepts tool versions key"
|
||||
When call validate_input_python "version-file-parser" "tool-versions-key" "nodejs"
|
||||
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 "contains required metadata"
|
||||
When call get_action_name "$ACTION_FILE"
|
||||
The output should equal "Version File Parser"
|
||||
End
|
||||
|
||||
It "defines expected inputs"
|
||||
When call get_action_inputs "$ACTION_FILE"
|
||||
The output should include "language"
|
||||
The output should include "tool-versions-key"
|
||||
The output should include "dockerfile-image"
|
||||
End
|
||||
|
||||
It "defines expected outputs"
|
||||
When call get_action_outputs "$ACTION_FILE"
|
||||
The output should include "detected-version"
|
||||
The output should include "package-manager"
|
||||
End
|
||||
End
|
||||
|
||||
Context "when validating security"
|
||||
It "rejects injection in language parameter"
|
||||
When call validate_input_python "version-file-parser" "language" "node&&malicious"
|
||||
The status should be failure
|
||||
End
|
||||
|
||||
It "rejects pipe injection in tool versions key"
|
||||
When call validate_input_python "version-file-parser" "tool-versions-key" "nodejs|dangerous"
|
||||
The status should be failure
|
||||
End
|
||||
|
||||
It "validates regex patterns safely"
|
||||
When call validate_input_python "version-file-parser" "validation-regex" "^[0-9]+\.[0-9]+$"
|
||||
The status should be success
|
||||
End
|
||||
|
||||
It "rejects malicious regex patterns"
|
||||
When call validate_input_python "version-file-parser" "validation-regex" ".*; rm -rf /"
|
||||
The status should be failure
|
||||
End
|
||||
End
|
||||
|
||||
Context "when testing outputs"
|
||||
It "produces all expected outputs consistently"
|
||||
When call test_action_outputs "$ACTION_DIR" "language" "node" "dockerfile-image" "node"
|
||||
The status should be success
|
||||
The stderr should include "Testing action outputs for: version-file-parser"
|
||||
The stderr should include "Output test passed for: version-file-parser"
|
||||
End
|
||||
End
|
||||
End
|
||||
@@ -1,74 +0,0 @@
|
||||
"""Tests for version-file-parser 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 / "version-file-parser"
|
||||
sys.path.insert(0, str(action_path))
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
from CustomValidator import CustomValidator
|
||||
|
||||
|
||||
class TestCustomVersionFileParserValidator:
|
||||
"""Test cases for version-file-parser custom validator."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test fixtures."""
|
||||
self.validator = CustomValidator("version-file-parser")
|
||||
|
||||
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 version-file-parser
|
||||
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 version-file-parser
|
||||
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 version-file-parser
|
||||
|
||||
def test_validation_rules(self):
|
||||
"""Test validation rules."""
|
||||
rules = self.validator.get_validation_rules()
|
||||
assert isinstance(rules, dict)
|
||||
# TODO: Assert specific validation rules for version-file-parser
|
||||
|
||||
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
|
||||
@@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Custom validator for version-file-parser 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
|
||||
|
||||
|
||||
class CustomValidator(BaseValidator):
|
||||
"""Custom validator for version-file-parser action."""
|
||||
|
||||
def __init__(self, action_type: str = "version-file-parser") -> None:
|
||||
"""Initialize version-file-parser validator."""
|
||||
super().__init__(action_type)
|
||||
|
||||
def validate_inputs(self, inputs: dict[str, str]) -> bool:
|
||||
"""Validate version-file-parser action inputs."""
|
||||
valid = True
|
||||
|
||||
# Validate required input: language
|
||||
if "language" not in inputs or not inputs["language"]:
|
||||
self.add_error("Input 'language' is required")
|
||||
valid = False
|
||||
elif inputs["language"]:
|
||||
# Validate language is one of the supported values
|
||||
valid_languages = [
|
||||
"node",
|
||||
"python",
|
||||
"go",
|
||||
"rust",
|
||||
"ruby",
|
||||
"php",
|
||||
"java",
|
||||
"dotnet",
|
||||
"elixir",
|
||||
]
|
||||
if inputs["language"] not in valid_languages:
|
||||
self.add_error(
|
||||
f"Invalid language: {inputs['language']}. "
|
||||
f"Must be one of: {', '.join(valid_languages)}"
|
||||
)
|
||||
valid = False
|
||||
|
||||
# Validate dockerfile-image for injection
|
||||
dockerfile_key = None
|
||||
if "dockerfile-image" in inputs:
|
||||
dockerfile_key = "dockerfile-image"
|
||||
elif "dockerfile_image" in inputs:
|
||||
dockerfile_key = "dockerfile_image"
|
||||
|
||||
if dockerfile_key and inputs[dockerfile_key]:
|
||||
value = inputs[dockerfile_key]
|
||||
if ";" in value or "|" in value or "&" in value or "`" in value:
|
||||
self.add_error("dockerfile-image contains potentially dangerous characters")
|
||||
valid = False
|
||||
|
||||
# Validate tool-versions-key for injection
|
||||
tool_key = None
|
||||
if "tool-versions-key" in inputs:
|
||||
tool_key = "tool-versions-key"
|
||||
elif "tool_versions_key" in inputs:
|
||||
tool_key = "tool_versions_key"
|
||||
|
||||
if tool_key and inputs[tool_key]:
|
||||
value = inputs[tool_key]
|
||||
if "|" in value or ";" in value or "&" in value or "`" in value:
|
||||
self.add_error("tool-versions-key contains potentially dangerous characters")
|
||||
valid = False
|
||||
|
||||
# Validate validation-regex for malicious patterns
|
||||
regex_key = None
|
||||
if "validation-regex" in inputs:
|
||||
regex_key = "validation-regex"
|
||||
elif "validation_regex" in inputs:
|
||||
regex_key = "validation_regex"
|
||||
|
||||
if regex_key and inputs[regex_key]:
|
||||
value = inputs[regex_key]
|
||||
# Check for shell command injection in regex
|
||||
if ";" in value or "|" in value or "`" in value or "rm " in value:
|
||||
self.add_error("validation-regex contains potentially dangerous patterns")
|
||||
valid = False
|
||||
|
||||
return valid
|
||||
|
||||
def get_required_inputs(self) -> list[str]:
|
||||
"""Get list of required inputs."""
|
||||
return ["language"]
|
||||
|
||||
def get_validation_rules(self) -> dict:
|
||||
"""Get validation rules."""
|
||||
return {
|
||||
"language": {
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "Language identifier",
|
||||
},
|
||||
"tool-versions-key": {
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"description": "Key in .tool-versions",
|
||||
},
|
||||
"dockerfile-image": {
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"description": "Dockerfile image name",
|
||||
},
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
# ivuorinen/actions/version-file-parser
|
||||
|
||||
## Version File Parser
|
||||
|
||||
### Description
|
||||
|
||||
Universal parser for common version detection files (.tool-versions, Dockerfile, devcontainer.json, etc.)
|
||||
|
||||
### Inputs
|
||||
|
||||
| name | description | required | default |
|
||||
|---------------------|------------------------------------------------------------------------------|----------|-------------------------------|
|
||||
| `language` | <p>Programming language name (node, python, php, go, dotnet)</p> | `true` | `""` |
|
||||
| `tool-versions-key` | <p>Key name in .tool-versions file (nodejs, python, php, golang, dotnet)</p> | `true` | `""` |
|
||||
| `dockerfile-image` | <p>Docker image name pattern (node, python, php, golang, dotnet)</p> | `true` | `""` |
|
||||
| `version-file` | <p>Language-specific version file (.nvmrc, .python-version, etc.)</p> | `false` | `""` |
|
||||
| `validation-regex` | <p>Version validation regex pattern</p> | `false` | `^[0-9]+\.[0-9]+(\.[0-9]+)?$` |
|
||||
| `default-version` | <p>Default version to use if no version is detected</p> | `false` | `""` |
|
||||
|
||||
### Outputs
|
||||
|
||||
| name | description |
|
||||
|-------------------------|-----------------------------------------------------------------------------------|
|
||||
| `tool-versions-version` | <p>Version found in .tool-versions</p> |
|
||||
| `dockerfile-version` | <p>Version found in Dockerfile</p> |
|
||||
| `devcontainer-version` | <p>Version found in devcontainer.json</p> |
|
||||
| `version-file-version` | <p>Version found in language-specific version file</p> |
|
||||
| `config-file-version` | <p>Version found in language config files (package.json, composer.json, etc.)</p> |
|
||||
| `detected-version` | <p>Final detected version (first found or default)</p> |
|
||||
| `package-manager` | <p>Detected package manager (npm, yarn, pnpm, composer, pip, poetry, etc.)</p> |
|
||||
|
||||
### Runs
|
||||
|
||||
This action is a `composite` action.
|
||||
|
||||
### Usage
|
||||
|
||||
```yaml
|
||||
- uses: ivuorinen/actions/version-file-parser@main
|
||||
with:
|
||||
language:
|
||||
# Programming language name (node, python, php, go, dotnet)
|
||||
#
|
||||
# Required: true
|
||||
# Default: ""
|
||||
|
||||
tool-versions-key:
|
||||
# Key name in .tool-versions file (nodejs, python, php, golang, dotnet)
|
||||
#
|
||||
# Required: true
|
||||
# Default: ""
|
||||
|
||||
dockerfile-image:
|
||||
# Docker image name pattern (node, python, php, golang, dotnet)
|
||||
#
|
||||
# Required: true
|
||||
# Default: ""
|
||||
|
||||
version-file:
|
||||
# Language-specific version file (.nvmrc, .python-version, etc.)
|
||||
#
|
||||
# Required: false
|
||||
# Default: ""
|
||||
|
||||
validation-regex:
|
||||
# Version validation regex pattern
|
||||
#
|
||||
# Required: false
|
||||
# Default: ^[0-9]+\.[0-9]+(\.[0-9]+)?$
|
||||
|
||||
default-version:
|
||||
# Default version to use if no version is detected
|
||||
#
|
||||
# Required: false
|
||||
# Default: ""
|
||||
```
|
||||
@@ -1,365 +0,0 @@
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
|
||||
# permissions:
|
||||
# - contents: read # Required for reading version files
|
||||
---
|
||||
name: Version File Parser
|
||||
description: 'Universal parser for common version detection files (.tool-versions, Dockerfile, devcontainer.json, etc.)'
|
||||
author: 'Ismo Vuorinen'
|
||||
|
||||
branding:
|
||||
icon: search
|
||||
color: gray-dark
|
||||
|
||||
inputs:
|
||||
language:
|
||||
description: 'Programming language name (node, python, php, go, dotnet)'
|
||||
required: true
|
||||
tool-versions-key:
|
||||
description: 'Key name in .tool-versions file (nodejs, python, php, golang, dotnet)'
|
||||
required: true
|
||||
dockerfile-image:
|
||||
description: 'Docker image name pattern (node, python, php, golang, dotnet)'
|
||||
required: true
|
||||
version-file:
|
||||
description: 'Language-specific version file (.nvmrc, .python-version, etc.)'
|
||||
required: false
|
||||
validation-regex:
|
||||
description: 'Version validation regex pattern'
|
||||
required: false
|
||||
default: '^[0-9]+\.[0-9]+(\.[0-9]+)?$'
|
||||
default-version:
|
||||
description: 'Default version to use if no version is detected'
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
tool-versions-version:
|
||||
description: 'Version found in .tool-versions'
|
||||
value: ${{ steps.parse.outputs.tool-versions-version }}
|
||||
dockerfile-version:
|
||||
description: 'Version found in Dockerfile'
|
||||
value: ${{ steps.parse.outputs.dockerfile-version }}
|
||||
devcontainer-version:
|
||||
description: 'Version found in devcontainer.json'
|
||||
value: ${{ steps.parse.outputs.devcontainer-version }}
|
||||
version-file-version:
|
||||
description: 'Version found in language-specific version file'
|
||||
value: ${{ steps.parse.outputs.version-file-version }}
|
||||
config-file-version:
|
||||
description: 'Version found in language config files (package.json, composer.json, etc.)'
|
||||
value: ${{ steps.parse.outputs.config-file-version }}
|
||||
detected-version:
|
||||
description: 'Final detected version (first found or default)'
|
||||
value: ${{ steps.parse.outputs.detected-version }}
|
||||
package-manager:
|
||||
description: 'Detected package manager (npm, yarn, pnpm, composer, pip, poetry, etc.)'
|
||||
value: ${{ steps.parse.outputs.package-manager }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Parse Version Files
|
||||
id: parse
|
||||
shell: bash
|
||||
env:
|
||||
VALIDATION_REGEX: ${{ inputs.validation-regex }}
|
||||
LANGUAGE: ${{ inputs.language }}
|
||||
TOOL_VERSIONS_KEY: ${{ inputs.tool-versions-key }}
|
||||
DOCKERFILE_IMAGE: ${{ inputs.dockerfile-image }}
|
||||
VERSION_FILE: ${{ inputs.version-file }}
|
||||
DEFAULT_VERSION: ${{ inputs.default-version }}
|
||||
run: |-
|
||||
set -euo pipefail
|
||||
|
||||
# Function to validate version format
|
||||
validate_version() {
|
||||
local version=$1
|
||||
local regex="$VALIDATION_REGEX"
|
||||
|
||||
# Test regex validity
|
||||
if ! bash -c "[[ 'test' =~ \${regex} ]]" 2>/dev/null; then
|
||||
echo "::error::Invalid validation regex pattern: $regex" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate version using safe regex matching with quoted variable
|
||||
if [[ $version =~ ^${regex}$ ]]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to clean version string
|
||||
clean_version() {
|
||||
echo "$1" | sed 's/^[vV]//' | tr -d ' \n\r'
|
||||
}
|
||||
|
||||
# Initialize outputs
|
||||
echo "tool-versions-version=" >> $GITHUB_OUTPUT
|
||||
echo "dockerfile-version=" >> $GITHUB_OUTPUT
|
||||
echo "devcontainer-version=" >> $GITHUB_OUTPUT
|
||||
echo "version-file-version=" >> $GITHUB_OUTPUT
|
||||
echo "config-file-version=" >> $GITHUB_OUTPUT
|
||||
echo "detected-version=" >> $GITHUB_OUTPUT
|
||||
echo "package-manager=" >> $GITHUB_OUTPUT
|
||||
|
||||
# Language detection patterns
|
||||
language="$LANGUAGE"
|
||||
|
||||
# Parse .tool-versions file
|
||||
if [ -f .tool-versions ]; then
|
||||
echo "Checking .tool-versions for $TOOL_VERSIONS_KEY..." >&2
|
||||
version=$(awk "/^$TOOL_VERSIONS_KEY[[: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 $LANGUAGE version in .tool-versions: $version" >&2
|
||||
echo "tool-versions-version=$version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse Dockerfile
|
||||
if [ -f Dockerfile ]; then
|
||||
echo "Checking Dockerfile for $DOCKERFILE_IMAGE..." >&2
|
||||
version=$(grep -iF "FROM" Dockerfile | grep -F "$DOCKERFILE_IMAGE:" | head -1 | \
|
||||
sed -n "s/.*$DOCKERFILE_IMAGE:\([0-9]\+\(\.[0-9]\+\)*\)\(-[^:]*\)\?.*/\1/p" || echo "")
|
||||
if [ -n "$version" ]; then
|
||||
version=$(clean_version "$version")
|
||||
if validate_version "$version"; then
|
||||
echo "Found $LANGUAGE version in Dockerfile: $version" >&2
|
||||
echo "dockerfile-version=$version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse devcontainer.json
|
||||
if [ -f .devcontainer/devcontainer.json ]; then
|
||||
echo "Checking devcontainer.json for $DOCKERFILE_IMAGE..." >&2
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
version=$(jq -r '.image // empty' .devcontainer/devcontainer.json 2>/dev/null | sed -n "s/.*$DOCKERFILE_IMAGE:\([0-9]\+\(\.[0-9]\+\)*\)\(-[^:]*\)\?.*/\1/p" || echo "")
|
||||
if [ -n "$version" ]; then
|
||||
version=$(clean_version "$version")
|
||||
if validate_version "$version"; then
|
||||
echo "Found $LANGUAGE version in devcontainer: $version" >&2
|
||||
echo "devcontainer-version=$version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "jq not available, skipping devcontainer parsing" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse language-specific version file
|
||||
if [ -n "$VERSION_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
||||
echo "Checking $VERSION_FILE..." >&2
|
||||
version=$(tr -d '\r' < "$VERSION_FILE" | head -1)
|
||||
if [ -n "$version" ]; then
|
||||
version=$(clean_version "$version")
|
||||
if validate_version "$version"; then
|
||||
echo "Found $LANGUAGE version in $VERSION_FILE: $version" >&2
|
||||
echo "version-file-version=$version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse language-specific configuration files
|
||||
config_version=""
|
||||
detected_package_manager=""
|
||||
|
||||
case "$language" in
|
||||
"node")
|
||||
# Check package.json
|
||||
if [ -f package.json ] && command -v jq >/dev/null 2>&1; then
|
||||
version=$(jq -r '.engines.node // empty' package.json 2>/dev/null | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p')
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found Node.js version in package.json: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect package manager
|
||||
if [ -f bun.lockb ]; then
|
||||
detected_package_manager="bun"
|
||||
elif [ -f pnpm-lock.yaml ]; then
|
||||
detected_package_manager="pnpm"
|
||||
elif [ -f yarn.lock ]; then
|
||||
detected_package_manager="yarn"
|
||||
elif [ -f package-lock.json ]; then
|
||||
detected_package_manager="npm"
|
||||
elif [ -f package.json ] && command -v jq >/dev/null 2>&1; then
|
||||
# Check packageManager field in package.json
|
||||
pkg_manager=$(jq -r '.packageManager // empty' package.json 2>/dev/null | sed 's/@.*//')
|
||||
if [ -n "$pkg_manager" ]; then
|
||||
detected_package_manager="$pkg_manager"
|
||||
else
|
||||
detected_package_manager="npm"
|
||||
fi
|
||||
else
|
||||
detected_package_manager="npm"
|
||||
fi
|
||||
;;
|
||||
|
||||
"php")
|
||||
# Check composer.json
|
||||
if [ -f composer.json ] && command -v jq >/dev/null 2>&1; then
|
||||
# Try require.php first
|
||||
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
|
||||
# Try platform.php
|
||||
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" ] && validate_version "$version"; then
|
||||
echo "Found PHP version in composer.json: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check phpunit.xml
|
||||
if [ -z "$config_version" ]; then
|
||||
phpunit_file=""
|
||||
if [ -f phpunit.xml ]; then
|
||||
phpunit_file="phpunit.xml"
|
||||
elif [ -f phpunit.xml.dist ]; then
|
||||
phpunit_file="phpunit.xml.dist"
|
||||
fi
|
||||
|
||||
if [ -n "$phpunit_file" ]; then
|
||||
version=$(grep -o 'php[[:space:]]*version[[:space:]]*=[[:space:]]*"[^"]*"' "$phpunit_file" | sed -n 's/.*"\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\)".*/\1/p')
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found PHP version in $phpunit_file: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect package manager
|
||||
if [ -f composer.json ]; then
|
||||
detected_package_manager="composer"
|
||||
fi
|
||||
;;
|
||||
|
||||
"python")
|
||||
# Check pyproject.toml
|
||||
if [ -f pyproject.toml ]; then
|
||||
# Try PEP 621 requires-python first (allow leading whitespace)
|
||||
if command -v jq >/dev/null 2>&1 && grep -q '^\[project\]' pyproject.toml; then
|
||||
# Convert TOML to JSON for PEP 621 parsing (basic approach)
|
||||
version=$(grep -A 20 '^\[project\]' pyproject.toml | grep -E '^\s*requires-python[[:space:]]*=' | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p' | head -1)
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found Python version in pyproject.toml [project] requires-python: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
# Fallback to legacy python field if no PEP 621 version found
|
||||
if [ -z "$config_version" ]; then
|
||||
version=$(grep -E '^python[[:space:]]*=' pyproject.toml | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p')
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found Python version in pyproject.toml: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check setup.py for python_requires
|
||||
if [ -z "$config_version" ] && [ -f setup.py ]; then
|
||||
version=$(grep -o 'python_requires[[:space:]]*=[[:space:]]*['\''"].*['\''"]' setup.py | sed -n 's/[^0-9]*\([0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).*/\1/p')
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found Python version in setup.py: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect package manager
|
||||
if [ -f pyproject.toml ] && grep -q '\[tool\.poetry\]' pyproject.toml; then
|
||||
detected_package_manager="poetry"
|
||||
elif [ -f Pipfile ]; then
|
||||
detected_package_manager="pipenv"
|
||||
elif [ -f requirements.txt ]; then
|
||||
detected_package_manager="pip"
|
||||
else
|
||||
detected_package_manager="pip"
|
||||
fi
|
||||
;;
|
||||
|
||||
"go")
|
||||
# Check go.mod
|
||||
if [ -f go.mod ]; then
|
||||
version=$(grep -E '^go[[:space:]]+[0-9]' go.mod | awk '{print $2}' | head -1 || echo "")
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found Go version in go.mod: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect package manager
|
||||
if [ -f go.mod ]; then
|
||||
detected_package_manager="go"
|
||||
fi
|
||||
;;
|
||||
|
||||
"dotnet")
|
||||
# Check global.json
|
||||
if [ -f global.json ] && command -v jq >/dev/null 2>&1; then
|
||||
version=$(jq -r '.sdk.version // empty' global.json 2>/dev/null || echo "")
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found .NET version in global.json: $version" >&2
|
||||
config_version="$version"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check .csproj files
|
||||
if [ -z "$config_version" ]; then
|
||||
# Enable nullglob to handle case when no .csproj files exist
|
||||
shopt -s nullglob
|
||||
for csproj in *.csproj; do
|
||||
if [ -f "$csproj" ]; then
|
||||
# Handle both TargetFramework and TargetFrameworks, and handle -windows monikers
|
||||
version=$(grep -oE '<TargetFrameworks?>net[0-9]+\.[0-9]+(-[a-z]+)?</TargetFrameworks?>' "$csproj" | sed -n 's/.*net\([0-9]\+\.[0-9]\+\).*/\1/p' | head -1)
|
||||
if [ -n "$version" ] && validate_version "$version"; then
|
||||
echo "Found .NET version in $csproj: $version" >&2
|
||||
config_version="$version"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# Disable nullglob after use
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
# Detect package manager
|
||||
detected_package_manager="dotnet"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set config-file-version output
|
||||
if [ -n "$config_version" ]; then
|
||||
echo "config-file-version=$config_version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Set package-manager output
|
||||
if [ -n "$detected_package_manager" ]; then
|
||||
echo "package-manager=$detected_package_manager" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Determine final detected version with priority order
|
||||
# Priority order: version-file > config-file > tool-versions > dockerfile > devcontainer > default
|
||||
final_version=$(grep -E "^(version-file|config-file|tool-versions|dockerfile|devcontainer)-version=" $GITHUB_OUTPUT | tac | awk -F= 'NF>1 && $2!="" {print $2; exit}')
|
||||
|
||||
# If no version found from any source, use default
|
||||
if [ -z "$final_version" ] && [ -n "$DEFAULT_VERSION" ]; then
|
||||
final_version="$DEFAULT_VERSION"
|
||||
echo "Using default $LANGUAGE version: $final_version" >&2
|
||||
fi
|
||||
|
||||
# Set final detected version
|
||||
if [ -n "$final_version" ]; then
|
||||
# Validate the final version against the regex
|
||||
if ! validate_version "$final_version"; then
|
||||
echo "::error::Detected version $final_version does not match validation regex" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "detected-version=$final_version" >> $GITHUB_OUTPUT
|
||||
echo "Final detected $LANGUAGE version: $final_version" >&2
|
||||
else
|
||||
echo "No $LANGUAGE version detected" >&2
|
||||
fi
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
# Validation rules for version-file-parser action
|
||||
# Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY
|
||||
# Schema version: 1.0
|
||||
# Coverage: 50% (3/6 inputs)
|
||||
#
|
||||
# This file defines validation rules for the version-file-parser GitHub Action.
|
||||
# Rules are automatically applied by validate-inputs action when this
|
||||
# action is used.
|
||||
#
|
||||
|
||||
schema_version: '1.0'
|
||||
action: version-file-parser
|
||||
description: Universal parser for common version detection files (.tool-versions, Dockerfile, devcontainer.json, etc.)
|
||||
generator_version: 1.0.0
|
||||
required_inputs:
|
||||
- dockerfile-image
|
||||
- language
|
||||
- tool-versions-key
|
||||
optional_inputs:
|
||||
- default-version
|
||||
- validation-regex
|
||||
- version-file
|
||||
conventions:
|
||||
default-version: semantic_version
|
||||
validation-regex: regex_pattern
|
||||
version-file: file_path
|
||||
overrides: {}
|
||||
statistics:
|
||||
total_inputs: 6
|
||||
validated_inputs: 3
|
||||
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: false
|
||||
has_version_validation: true
|
||||
has_file_validation: true
|
||||
has_security_validation: false
|
||||
Reference in New Issue
Block a user