From f8f2bd75b10772722c2798dd52e7d726cf5c9503 Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Tue, 3 Feb 2026 09:46:43 +0100 Subject: [PATCH] feat: add some scripts --- scripts/actions-to-mirror.txt | 32 ++++++++ scripts/clone-actions.sh | 86 +++++++++++++++++++++ scripts/migrate-actions.sh | 139 ++++++++++++++++++++++++++++++++++ scripts/scan-actions.sh | 57 ++++++++++++++ scripts/test-configuration | 6 ++ 5 files changed, 320 insertions(+) create mode 100644 scripts/actions-to-mirror.txt create mode 100755 scripts/clone-actions.sh create mode 100755 scripts/migrate-actions.sh create mode 100755 scripts/scan-actions.sh diff --git a/scripts/actions-to-mirror.txt b/scripts/actions-to-mirror.txt new file mode 100644 index 0000000..2e986ac --- /dev/null +++ b/scripts/actions-to-mirror.txt @@ -0,0 +1,32 @@ +# GitHub Actions to mirror +# Format: org/repo@version +# Lines starting with # are comments + +actions/cache@v3 +actions/cache@v4 +actions/checkout@v2 +actions/checkout@v3 +actions/checkout@v4 +actions/download-artifact@v3 +actions/setup-go@v2 +actions/setup-go@v4 +actions/setup-java@v4 +actions/setup-node@v2 +actions/setup-node@v3 +actions/setup-node@v4 +actions/stale@v4 +actions/upload-artifact@v3 +actions/upload-artifact@v4 +android-actions/setup-android@v3 +andstor/file-existence-action@v1 +appleboy/ssh-action@v1 +dawidd6/action-download-artifact@v3 +deployphp/action@v1 +docker/setup-buildx-action@v1 +easingthemes/ssh-deploy@v5.1.1 +github/codeql-action@v1 +github/codeql-action@v2 +shivammathur/setup-php@v2 +softprops/action-gh-release@v1 +subosito/flutter-action@v2 +up9cloud/action-rsync@v1 diff --git a/scripts/clone-actions.sh b/scripts/clone-actions.sh new file mode 100755 index 0000000..f338da4 --- /dev/null +++ b/scripts/clone-actions.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Clone GitHub Actions to a local mirror directory +# Usage: ./clone-actions.sh + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ACTIONS_LIST="${SCRIPT_DIR}/actions-to-mirror.txt" + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 " + echo "Example: $0 ./actions-mirror" + exit 1 +fi + +OUTPUT_DIR="$1" + +if [[ ! -f "$ACTIONS_LIST" ]]; then + echo "Error: Actions list not found at $ACTIONS_LIST" + exit 1 +fi + +mkdir -p "$OUTPUT_DIR" + +clone_action() { + local entry="$1" + local org repo version target_dir + + # Parse org/repo@version + org="${entry%%/*}" + local repo_version="${entry#*/}" + repo="${repo_version%%@*}" + version="${repo_version#*@}" + + # Target directory: org/repo-version (e.g., actions/checkout-v4) + target_dir="${OUTPUT_DIR}/${org}/${repo}-${version}" + + if [[ -d "$target_dir" ]]; then + echo "Skipping ${org}/${repo}@${version} (already exists)" + return 0 + fi + + echo "Cloning ${org}/${repo}@${version}..." + + mkdir -p "$(dirname "$target_dir")" + + # Clone with specific tag/branch, depth 1 for speed + if ! git clone --depth 1 --branch "$version" \ + "https://github.com/${org}/${repo}.git" "$target_dir" 2>/dev/null; then + echo "Warning: Failed to clone ${org}/${repo}@${version}" + return 1 + fi + + # Remove .git directory (we don't want submodules) + rm -rf "${target_dir}/.git" + + echo "Done: ${org}/${repo}@${version} -> ${target_dir}" +} + +echo "Reading actions from $ACTIONS_LIST" +echo "Output directory: $OUTPUT_DIR" +echo "" + +success=0 +failed=0 + +while IFS= read -r line || [[ -n "$line" ]]; do + # Skip empty lines and comments + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + # Trim whitespace + line="$(echo "$line" | xargs)" + + if clone_action "$line"; then + ((++success)) + else + ((++failed)) + fi +done < "$ACTIONS_LIST" + +echo "" +echo "Complete: $success succeeded, $failed failed" + +if [[ $failed -gt 0 ]]; then + exit 1 +fi diff --git a/scripts/migrate-actions.sh b/scripts/migrate-actions.sh new file mode 100755 index 0000000..3603c8e --- /dev/null +++ b/scripts/migrate-actions.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash +# Migrate GitHub Actions in workflow files to use mirrored actions +# Usage: ./migrate-actions.sh + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ACTIONS_LIST="${SCRIPT_DIR}/actions-to-mirror.txt" + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 " + echo "Example: $0 /path/to/repo" + exit 1 +fi + +REPO_PATH="$1" + +if [[ ! -d "$REPO_PATH" ]]; then + echo "Error: Repository path not found: $REPO_PATH" + exit 1 +fi + +if [[ ! -f "$ACTIONS_LIST" ]]; then + echo "Error: Actions list not found at $ACTIONS_LIST" + exit 1 +fi + +# Build lookup table of mirrored actions +declare -A MIRRORED_ACTIONS +while IFS= read -r line || [[ -n "$line" ]]; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + line="$(echo "$line" | xargs)" + # Store as key for quick lookup (e.g., "actions/checkout@v4") + MIRRORED_ACTIONS["$line"]=1 +done < "$ACTIONS_LIST" + +# Find workflow files +WORKFLOW_DIR="${REPO_PATH}/.github/workflows" +if [[ ! -d "$WORKFLOW_DIR" ]]; then + echo "Error: No .github/workflows directory found in $REPO_PATH" + exit 1 +fi + +# Track unmirrored actions +declare -A UNMIRRORED_ACTIONS + +# Convert action reference to mirrored path +# e.g., "actions/checkout@v4" -> "infrastructure/actions/actions/checkout-v4" +convert_action() { + local action="$1" + local org repo version + + # Parse org/repo@version + org="${action%%/*}" + local repo_version="${action#*/}" + repo="${repo_version%%@*}" + version="${repo_version#*@}" + + echo "infrastructure/actions/${org}/${repo}-${version}" +} + +# Process a single workflow file +process_workflow() { + local file="$1" + local modified=false + local temp_file + temp_file=$(mktemp) + + while IFS= read -r line || [[ -n "$line" ]]; do + # Check if line contains a uses: statement + if [[ "$line" =~ ^([[:space:]]*)uses:[[:space:]]*([^[:space:]]+) ]]; then + local indent="${BASH_REMATCH[1]}" + local action="${BASH_REMATCH[2]}" + + # Remove quotes if present + action="${action#\"}" + action="${action%\"}" + action="${action#\'}" + action="${action%\'}" + + # Check if this is a GitHub action reference (org/repo@version format) + if [[ "$action" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+@[a-zA-Z0-9._-]+$ ]]; then + if [[ -n "${MIRRORED_ACTIONS[$action]:-}" ]]; then + # Replace with mirrored version + local new_action + new_action=$(convert_action "$action") + echo "${indent}uses: ${new_action}" >> "$temp_file" + modified=true + echo " Replaced: $action -> $new_action" + else + # Not in our mirror list + UNMIRRORED_ACTIONS["$action"]+="${file##*/} " + echo "$line" >> "$temp_file" + fi + else + # Not a standard action reference (could be local action, docker, etc.) + echo "$line" >> "$temp_file" + fi + else + echo "$line" >> "$temp_file" + fi + done < "$file" + + if [[ "$modified" == true ]]; then + cp "$temp_file" "$file" + echo " Updated: $file" + fi + + rm -f "$temp_file" +} + +echo "Migrating workflows in: $REPO_PATH" +echo "Using actions list: $ACTIONS_LIST" +echo "" + +# Process all workflow files +for workflow in "$WORKFLOW_DIR"/*.yml "$WORKFLOW_DIR"/*.yaml; do + [[ -f "$workflow" ]] || continue + echo "Processing: ${workflow##*/}" + process_workflow "$workflow" + echo "" +done + +# Report unmirrored actions +if [[ ${#UNMIRRORED_ACTIONS[@]} -gt 0 ]]; then + echo "========================================" + echo "UNMIRRORED ACTIONS (not replaced):" + echo "========================================" + for action in "${!UNMIRRORED_ACTIONS[@]}"; do + echo "" + echo " $action" + echo " Used in: ${UNMIRRORED_ACTIONS[$action]}" + done + echo "" + echo "Add these to $ACTIONS_LIST and re-run clone-actions.sh to mirror them." +fi + +echo "" +echo "Migration complete." diff --git a/scripts/scan-actions.sh b/scripts/scan-actions.sh new file mode 100755 index 0000000..590826a --- /dev/null +++ b/scripts/scan-actions.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Scan git repositories for GitHub/Gitea/Forgejo Actions used in workflows +# Usage: ./scripts/scan-actions.sh /var/lib/gitea/repositories + +set -euo pipefail + +# Wrapper to handle safe.directory issues when running as root +git_cmd() { + git -c safe.directory='*' "$@" +} + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " >&2 + echo "Example: $0 /var/lib/gitea/repositories" >&2 + exit 1 +fi + +BASE_DIR="$1" + +if [[ ! -d "$BASE_DIR" ]]; then + echo "Error: Directory '$BASE_DIR' does not exist" >&2 + exit 1 +fi + +# Find all bare git repositories +find "$BASE_DIR" -type d -name "*.git" -print0 2>/dev/null | while IFS= read -r -d '' repo; do + # Get all branch refs + branches=$(git_cmd -C "$repo" for-each-ref --format='%(refname:short)' refs/heads/ 2>/dev/null || true) + + if [[ -z "$branches" ]]; then + continue + fi + + for branch in $branches; do + # Check all workflow directories + for workflow_dir in ".github/workflows" ".gitea/workflows" ".forgejo/workflows"; do + # List files in the workflow directory + files=$(git_cmd -C "$repo" ls-tree --name-only "$branch":"$workflow_dir" 2>/dev/null || true) + + for file in $files; do + # Only process .yml and .yaml files + case "$file" in + *.yml|*.yaml) + # Read the file content and extract uses: statements + git_cmd -C "$repo" show "$branch:$workflow_dir/$file" 2>/dev/null || true + ;; + esac + done + done + done +done | \ + # Extract uses: values - match owner/repo@ref or owner/repo/path@ref pattern + grep -oE 'uses:\s*["'"'"']?[a-zA-Z0-9_.-]+/[a-zA-Z0-9_./-]+@[a-zA-Z0-9_.-]+' | \ + # Remove the uses: prefix and any quotes + sed -E 's/uses:\s*["'"'"']?//' | \ + # Sort and deduplicate + sort -u diff --git a/scripts/test-configuration b/scripts/test-configuration index b0d2ed5..386f6bf 100755 --- a/scripts/test-configuration +++ b/scripts/test-configuration @@ -66,6 +66,12 @@ NIX_EXIT_STATUS=$? # Check the exit status if [ "$NIX_EXIT_STATUS" -eq 0 ]; then echo "INFO: Dry-build for host '$HOSTNAME' completed successfully." + # Extract and display warnings even on success + WARNINGS=$(echo "$NIX_OUTPUT_ERR" | grep -E "^(warning:|trace:)" || true) + if [ -n "$WARNINGS" ]; then + echo "WARNINGS from nix-instantiate:" + echo "$WARNINGS" + fi if [ "$VERBOSE" = true ]; then echo "Output from nix-instantiate:" echo "$NIX_OUTPUT_ERR"