detect-versions-action/action.yml
Tom Foster d0e72af7f3 feat(action): optimise metadata for GitHub Marketplace compatibility
Shorten description to 100 characters to meet GitHub Marketplace
requirements. Change icon from 'monitor' to 'search' to better
represent the detection and discovery functionality of the action.
2025-09-22 14:27:40 +01:00

436 lines
18 KiB
YAML

name: 'Detect OS and Runtime Versions'
description: 'Detect OS and runtime versions with semantic versioning outputs for GitHub/Forgejo workflows'
branding:
icon: 'search'
color: 'blue'
outputs:
name:
description: 'OS name (e.g. Ubuntu, Debian, CentOS, macOS, Windows)'
value: ${{ steps.os.outputs.name }}
version:
description: 'OS version (e.g. 22.04, 11, 2022)'
value: ${{ steps.os.outputs.version }}
slug:
description: 'Combined OS slug (e.g. Ubuntu-22.04, macOS-13, Windows-2022)'
value: ${{ steps.os.outputs.slug }}
arch:
description: 'System architecture (e.g. x64, arm64)'
value: ${{ steps.os.outputs.arch }}
cmake_major:
description: 'Major version of CMake if available (e.g. 3)'
value: ${{ steps.cmake.outputs.cmake_major }}
cmake_minor:
description: 'Minor version of CMake if available (e.g. 28)'
value: ${{ steps.cmake.outputs.cmake_minor }}
cmake_patch:
description: 'Patch version of CMake if available (e.g. 1)'
value: ${{ steps.cmake.outputs.cmake_patch }}
cmake_version:
description: 'Full CMake version if available (e.g. 3.28.1)'
value: ${{ steps.cmake.outputs.cmake_version }}
docker_major:
description: 'Major version of Docker if available (e.g. 24)'
value: ${{ steps.docker.outputs.docker_major }}
docker_minor:
description: 'Minor version of Docker if available (e.g. 0)'
value: ${{ steps.docker.outputs.docker_minor }}
docker_patch:
description: 'Patch version of Docker if available (e.g. 7)'
value: ${{ steps.docker.outputs.docker_patch }}
docker_version:
description: 'Full Docker version if available (e.g. 24.0.7)'
value: ${{ steps.docker.outputs.docker_version }}
git_major:
description: 'Major version of Git if available (e.g. 2)'
value: ${{ steps.git.outputs.git_major }}
git_minor:
description: 'Minor version of Git if available (e.g. 43)'
value: ${{ steps.git.outputs.git_minor }}
git_patch:
description: 'Patch version of Git if available (e.g. 0)'
value: ${{ steps.git.outputs.git_patch }}
git_version:
description: 'Full Git version if available (e.g. 2.43.0)'
value: ${{ steps.git.outputs.git_version }}
go_major:
description: 'Major version of Go if available (e.g. 1)'
value: ${{ steps.go.outputs.go_major }}
go_minor:
description: 'Minor version of Go if available (e.g. 21)'
value: ${{ steps.go.outputs.go_minor }}
go_patch:
description: 'Patch version of Go if available (e.g. 5)'
value: ${{ steps.go.outputs.go_patch }}
go_version:
description: 'Full Go version if available (e.g. 1.21.5)'
value: ${{ steps.go.outputs.go_version }}
java_major:
description: 'Major version of Java if available (e.g. 21)'
value: ${{ steps.java.outputs.java_major }}
java_minor:
description: 'Minor version of Java if available (e.g. 0)'
value: ${{ steps.java.outputs.java_minor }}
java_patch:
description: 'Patch version of Java if available (e.g. 1)'
value: ${{ steps.java.outputs.java_patch }}
java_version:
description: 'Full Java version if available (e.g. 21.0.1)'
value: ${{ steps.java.outputs.java_version }}
node_major:
description: 'Major version of Node.js if available (e.g. 22)'
value: ${{ steps.nodejs.outputs.node_major }}
node_minor:
description: 'Minor version of Node.js if available (e.g. 19)'
value: ${{ steps.nodejs.outputs.node_minor }}
node_patch:
description: 'Patch version of Node.js if available (e.g. 0)'
value: ${{ steps.nodejs.outputs.node_patch }}
node_version:
description: 'Full Node.js version if available (e.g. 22.19.0)'
value: ${{ steps.nodejs.outputs.node_version }}
python_major:
description: 'Major version of Python if available (e.g. 3)'
value: ${{ steps.python.outputs.python_major }}
python_minor:
description: 'Minor version of Python if available (e.g. 11)'
value: ${{ steps.python.outputs.python_minor }}
python_patch:
description: 'Patch version of Python if available (e.g. 5)'
value: ${{ steps.python.outputs.python_patch }}
python_version:
description: 'Full Python version if available (e.g. 3.11.5)'
value: ${{ steps.python.outputs.python_version }}
rust_major:
description: 'Major version of Rust if available (e.g. 1)'
value: ${{ steps.rust.outputs.rust_major }}
rust_minor:
description: 'Minor version of Rust if available (e.g. 75)'
value: ${{ steps.rust.outputs.rust_minor }}
rust_patch:
description: 'Patch version of Rust if available (e.g. 0)'
value: ${{ steps.rust.outputs.rust_patch }}
rust_version:
description: 'Full Rust version if available (e.g. 1.75.0)'
value: ${{ steps.rust.outputs.rust_version }}
runs:
using: composite
steps:
- name: Detect OS and architecture
id: os
shell: bash
run: |
# Detect system architecture
if [[ "$RUNNER_ARCH" != "" ]]; then
ARCH="$RUNNER_ARCH"
elif command -v uname >/dev/null 2>&1; then
case "$(uname -m)" in
x86_64|amd64) ARCH="x64" ;;
aarch64|arm64) ARCH="arm64" ;;
armv7l) ARCH="arm" ;;
*) ARCH="$(uname -m)" ;;
esac
else
ARCH="unknown"
fi
# Detect OS and version based on runner OS
if [[ "$RUNNER_OS" == "Linux" ]]; then
# Try multiple methods for Linux detection
if command -v lsb_release >/dev/null 2>&1; then
# Use lsb_release if available
OS_NAME=$(lsb_release -is 2>/dev/null)
OS_VERSION=$(lsb_release -rs 2>/dev/null)
elif [[ -f /etc/os-release ]]; then
# Parse /etc/os-release
OS_NAME=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
elif [[ -f /etc/redhat-release ]]; then
# Red Hat family detection
if grep -q "CentOS" /etc/redhat-release; then
OS_NAME="CentOS"
OS_VERSION=$(grep -oE '[0-9]+\.[0-9]+' /etc/redhat-release | head -1)
elif grep -q "Red Hat" /etc/redhat-release; then
OS_NAME="RHEL"
OS_VERSION=$(grep -oE '[0-9]+\.[0-9]+' /etc/redhat-release | head -1)
elif grep -q "Fedora" /etc/redhat-release; then
OS_NAME="Fedora"
OS_VERSION=$(grep -oE '[0-9]+' /etc/redhat-release | head -1)
fi
elif [[ -f /etc/debian_version ]]; then
# Debian family fallback
OS_NAME="Debian"
OS_VERSION=$(cat /etc/debian_version | cut -d'.' -f1)
else
# Final fallback
OS_NAME="Linux"
OS_VERSION="unknown"
fi
# Capitalise OS name for consistency
OS_NAME=$(echo "$OS_NAME" | sed 's/\b\(.\)/\u\1/g')
elif [[ "$RUNNER_OS" == "macOS" ]]; then
OS_NAME="macOS"
# Get macOS version
if command -v sw_vers >/dev/null 2>&1; then
OS_VERSION=$(sw_vers -productVersion | cut -d'.' -f1-2)
else
OS_VERSION="unknown"
fi
elif [[ "$RUNNER_OS" == "Windows" ]]; then
OS_NAME="Windows"
# Detect Windows version
if command -v systeminfo >/dev/null 2>&1; then
# Extract Windows version from systeminfo
WIN_VERSION=$(systeminfo | grep "OS Name" | grep -oE "Windows [0-9]+" | grep -oE "[0-9]+")
if [[ -n "$WIN_VERSION" ]]; then
OS_VERSION="$WIN_VERSION"
else
# Fallback to common runner versions
OS_VERSION="2022"
fi
else
OS_VERSION="2022"
fi
else
# Unknown runner OS
OS_NAME="$RUNNER_OS"
OS_VERSION="unknown"
fi
# Ensure we have values
if [[ -z "$OS_NAME" ]]; then
OS_NAME="Unknown"
fi
if [[ -z "$OS_VERSION" ]]; then
OS_VERSION="unknown"
fi
# Create combined slug
OS_SLUG="${OS_NAME}-${OS_VERSION}"
# Set outputs
echo "name=${OS_NAME}" >> $GITHUB_OUTPUT
echo "version=${OS_VERSION}" >> $GITHUB_OUTPUT
echo "slug=${OS_SLUG}" >> $GITHUB_OUTPUT
echo "arch=${ARCH}" >> $GITHUB_OUTPUT
# Log detection results
echo "🔍 Detected Runner: ${OS_NAME} ${OS_VERSION} (${ARCH})"
- name: Detect CMake
id: cmake
shell: bash
run: |
if command -v cmake >/dev/null 2>&1; then
CMAKE_VERSION=$(cmake --version | head -1 | sed 's/cmake version //' | cut -d' ' -f1)
CMAKE_MAJOR=$(echo "$CMAKE_VERSION" | cut -d. -f1)
CMAKE_MINOR=$(echo "$CMAKE_VERSION" | cut -d. -f2)
CMAKE_PATCH=$(echo "$CMAKE_VERSION" | cut -d. -f3)
echo "cmake_version=${CMAKE_VERSION}" >> $GITHUB_OUTPUT
echo "cmake_major=${CMAKE_MAJOR}" >> $GITHUB_OUTPUT
echo "cmake_minor=${CMAKE_MINOR}" >> $GITHUB_OUTPUT
echo "cmake_patch=${CMAKE_PATCH}" >> $GITHUB_OUTPUT
echo "🔧 Detected CMake: ${CMAKE_VERSION}"
else
echo "cmake_version=" >> $GITHUB_OUTPUT
echo "cmake_major=" >> $GITHUB_OUTPUT
echo "cmake_minor=" >> $GITHUB_OUTPUT
echo "cmake_patch=" >> $GITHUB_OUTPUT
echo "🔧 CMake not found"
fi
- name: Detect Docker
id: docker
shell: bash
run: |
if command -v docker >/dev/null 2>&1; then
DOCKER_VERSION=$(docker --version | sed 's/Docker version //' | cut -d',' -f1)
DOCKER_MAJOR=$(echo "$DOCKER_VERSION" | cut -d. -f1)
DOCKER_MINOR=$(echo "$DOCKER_VERSION" | cut -d. -f2)
DOCKER_PATCH=$(echo "$DOCKER_VERSION" | cut -d. -f3)
echo "docker_version=${DOCKER_VERSION}" >> $GITHUB_OUTPUT
echo "docker_major=${DOCKER_MAJOR}" >> $GITHUB_OUTPUT
echo "docker_minor=${DOCKER_MINOR}" >> $GITHUB_OUTPUT
echo "docker_patch=${DOCKER_PATCH}" >> $GITHUB_OUTPUT
echo "🐳 Detected Docker: ${DOCKER_VERSION}"
else
echo "docker_version=" >> $GITHUB_OUTPUT
echo "docker_major=" >> $GITHUB_OUTPUT
echo "docker_minor=" >> $GITHUB_OUTPUT
echo "docker_patch=" >> $GITHUB_OUTPUT
echo "🐳 Docker not found"
fi
- name: Detect Git
id: git
shell: bash
run: |
if command -v git >/dev/null 2>&1; then
GIT_VERSION=$(git --version | sed 's/git version //')
GIT_MAJOR=$(echo "$GIT_VERSION" | cut -d. -f1)
GIT_MINOR=$(echo "$GIT_VERSION" | cut -d. -f2)
GIT_PATCH=$(echo "$GIT_VERSION" | cut -d. -f3)
echo "git_version=${GIT_VERSION}" >> $GITHUB_OUTPUT
echo "git_major=${GIT_MAJOR}" >> $GITHUB_OUTPUT
echo "git_minor=${GIT_MINOR}" >> $GITHUB_OUTPUT
echo "git_patch=${GIT_PATCH}" >> $GITHUB_OUTPUT
echo "📦 Detected Git: ${GIT_VERSION}"
else
echo "git_version=" >> $GITHUB_OUTPUT
echo "git_major=" >> $GITHUB_OUTPUT
echo "git_minor=" >> $GITHUB_OUTPUT
echo "git_patch=" >> $GITHUB_OUTPUT
echo "📦 Git not found"
fi
- name: Detect Go
id: go
shell: bash
run: |
if command -v go >/dev/null 2>&1; then
GO_VERSION=$(go version | sed 's/go version go//' | cut -d' ' -f1)
GO_MAJOR=$(echo "$GO_VERSION" | cut -d. -f1)
GO_MINOR=$(echo "$GO_VERSION" | cut -d. -f2)
GO_PATCH=$(echo "$GO_VERSION" | cut -d. -f3)
echo "go_version=${GO_VERSION}" >> $GITHUB_OUTPUT
echo "go_major=${GO_MAJOR}" >> $GITHUB_OUTPUT
echo "go_minor=${GO_MINOR}" >> $GITHUB_OUTPUT
echo "go_patch=${GO_PATCH}" >> $GITHUB_OUTPUT
echo "🐹 Detected Go: ${GO_VERSION}"
else
echo "go_version=" >> $GITHUB_OUTPUT
echo "go_major=" >> $GITHUB_OUTPUT
echo "go_minor=" >> $GITHUB_OUTPUT
echo "go_patch=" >> $GITHUB_OUTPUT
echo "🐹 Go not found"
fi
- name: Detect Java
id: java
shell: bash
run: |
if command -v java >/dev/null 2>&1; then
# Java version parsing is complex due to different formats
JAVA_RAW=$(java -version 2>&1 | head -1)
if [[ "$JAVA_RAW" =~ \"([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
# Modern format: "21.0.1"
JAVA_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
JAVA_MAJOR="${BASH_REMATCH[1]}"
JAVA_MINOR="${BASH_REMATCH[2]}"
JAVA_PATCH="${BASH_REMATCH[3]}"
elif [[ "$JAVA_RAW" =~ \"1\.([0-9]+)\.([0-9]+)_([0-9]+) ]]; then
# Legacy format: "1.8.0_392"
JAVA_VERSION="1.${BASH_REMATCH[1]}.${BASH_REMATCH[2]}_${BASH_REMATCH[3]}"
JAVA_MAJOR="${BASH_REMATCH[1]}"
JAVA_MINOR="${BASH_REMATCH[2]}"
JAVA_PATCH="${BASH_REMATCH[3]}"
else
# Fallback parsing
JAVA_VERSION=$(echo "$JAVA_RAW" | sed 's/.*version \"//' | sed 's/\".*//' | head -1)
JAVA_MAJOR=$(echo "$JAVA_VERSION" | cut -d. -f1 | sed 's/^1\.//')
JAVA_MINOR=$(echo "$JAVA_VERSION" | cut -d. -f2)
JAVA_PATCH=$(echo "$JAVA_VERSION" | cut -d. -f3 | cut -d_ -f1)
fi
echo "java_version=${JAVA_VERSION}" >> $GITHUB_OUTPUT
echo "java_major=${JAVA_MAJOR}" >> $GITHUB_OUTPUT
echo "java_minor=${JAVA_MINOR}" >> $GITHUB_OUTPUT
echo "java_patch=${JAVA_PATCH}" >> $GITHUB_OUTPUT
echo "☕ Detected Java: ${JAVA_VERSION}"
else
echo "java_version=" >> $GITHUB_OUTPUT
echo "java_major=" >> $GITHUB_OUTPUT
echo "java_minor=" >> $GITHUB_OUTPUT
echo "java_patch=" >> $GITHUB_OUTPUT
echo "☕ Java not found"
fi
- name: Detect Node.js
id: nodejs
shell: bash
run: |
if command -v node >/dev/null 2>&1; then
NODE_VERSION=$(node --version | sed 's/v//')
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
NODE_MINOR=$(echo "$NODE_VERSION" | cut -d. -f2)
NODE_PATCH=$(echo "$NODE_VERSION" | cut -d. -f3)
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
echo "node_major=${NODE_MAJOR}" >> $GITHUB_OUTPUT
echo "node_minor=${NODE_MINOR}" >> $GITHUB_OUTPUT
echo "node_patch=${NODE_PATCH}" >> $GITHUB_OUTPUT
echo "🟢 Detected Node.js: v${NODE_VERSION}"
else
echo "node_version=" >> $GITHUB_OUTPUT
echo "node_major=" >> $GITHUB_OUTPUT
echo "node_minor=" >> $GITHUB_OUTPUT
echo "node_patch=" >> $GITHUB_OUTPUT
echo "🟢 Node.js not found"
fi
- name: Detect Python
id: python
shell: bash
run: |
if command -v python3 >/dev/null 2>&1; then
PYTHON_VERSION=$(python3 --version 2>&1 | sed 's/Python //')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
PYTHON_PATCH=$(echo "$PYTHON_VERSION" | cut -d. -f3)
echo "python_version=${PYTHON_VERSION}" >> $GITHUB_OUTPUT
echo "python_major=${PYTHON_MAJOR}" >> $GITHUB_OUTPUT
echo "python_minor=${PYTHON_MINOR}" >> $GITHUB_OUTPUT
echo "python_patch=${PYTHON_PATCH}" >> $GITHUB_OUTPUT
echo "🐍 Detected Python: ${PYTHON_VERSION}"
elif command -v python >/dev/null 2>&1; then
PYTHON_VERSION=$(python --version 2>&1 | sed 's/Python //')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
PYTHON_PATCH=$(echo "$PYTHON_VERSION" | cut -d. -f3)
echo "python_version=${PYTHON_VERSION}" >> $GITHUB_OUTPUT
echo "python_major=${PYTHON_MAJOR}" >> $GITHUB_OUTPUT
echo "python_minor=${PYTHON_MINOR}" >> $GITHUB_OUTPUT
echo "python_patch=${PYTHON_PATCH}" >> $GITHUB_OUTPUT
echo "🐍 Detected Python: ${PYTHON_VERSION}"
else
echo "python_version=" >> $GITHUB_OUTPUT
echo "python_major=" >> $GITHUB_OUTPUT
echo "python_minor=" >> $GITHUB_OUTPUT
echo "python_patch=" >> $GITHUB_OUTPUT
echo "🐍 Python not found"
fi
- name: Detect Rust
id: rust
shell: bash
run: |
if command -v rustc >/dev/null 2>&1; then
# Try to get rustc version, but handle rustup cases where no default toolchain is set
if RUST_VERSION=$(rustc --version 2>/dev/null | sed 's/rustc //' | cut -d' ' -f1); then
RUST_MAJOR=$(echo "$RUST_VERSION" | cut -d. -f1)
RUST_MINOR=$(echo "$RUST_VERSION" | cut -d. -f2)
RUST_PATCH=$(echo "$RUST_VERSION" | cut -d. -f3)
echo "rust_version=${RUST_VERSION}" >> $GITHUB_OUTPUT
echo "rust_major=${RUST_MAJOR}" >> $GITHUB_OUTPUT
echo "rust_minor=${RUST_MINOR}" >> $GITHUB_OUTPUT
echo "rust_patch=${RUST_PATCH}" >> $GITHUB_OUTPUT
echo "🦀 Detected Rust: ${RUST_VERSION}"
else
# rustc command exists but failed (likely rustup without default toolchain)
echo "rust_version=" >> $GITHUB_OUTPUT
echo "rust_major=" >> $GITHUB_OUTPUT
echo "rust_minor=" >> $GITHUB_OUTPUT
echo "rust_patch=" >> $GITHUB_OUTPUT
echo "🦀 Rust not found (rustup installed but no default toolchain)"
fi
else
echo "rust_version=" >> $GITHUB_OUTPUT
echo "rust_major=" >> $GITHUB_OUTPUT
echo "rust_minor=" >> $GITHUB_OUTPUT
echo "rust_patch=" >> $GITHUB_OUTPUT
echo "🦀 Rust not found"
fi