From febce9c0b07fbb9e97149253bd3605d26d777fad Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner Date: Thu, 12 Mar 2026 14:26:28 +0100 Subject: [PATCH] Cleanup unneded workflows --- .../runner/docker/gh-runner-self.dockerfile | 68 ----- .../workflows/bak/close_template_issue.yml | 55 ---- .github/workflows/bak/crawl-versions.yaml | 126 --------- .github/workflows/bak/script-test.yml | 175 ------------ .github/workflows/bak/script_format.yml | 243 ---------------- .github/workflows/bak/validate-filenames.yml | 158 ----------- .github/workflows/push-to-gitea.yaml | 48 ---- .../scripts/app-test/pr-alpine-install.func | 85 ------ .../workflows/scripts/app-test/pr-build.func | 260 ------------------ .../scripts/app-test/pr-create-lxc.sh | 163 ----------- .../scripts/app-test/pr-install.func | 93 ------- .github/workflows/scripts/update-json.sh | 20 -- .github/workflows/scripts/update_json_date.sh | 23 -- .github/workflows/update-json-date.yml | 152 ---------- .github/workflows/update-versions-github.yml | 236 ---------------- 15 files changed, 1905 deletions(-) delete mode 100644 .github/runner/docker/gh-runner-self.dockerfile delete mode 100644 .github/workflows/bak/close_template_issue.yml delete mode 100644 .github/workflows/bak/crawl-versions.yaml delete mode 100644 .github/workflows/bak/script-test.yml delete mode 100644 .github/workflows/bak/script_format.yml delete mode 100644 .github/workflows/bak/validate-filenames.yml delete mode 100644 .github/workflows/push-to-gitea.yaml delete mode 100644 .github/workflows/scripts/app-test/pr-alpine-install.func delete mode 100644 .github/workflows/scripts/app-test/pr-build.func delete mode 100644 .github/workflows/scripts/app-test/pr-create-lxc.sh delete mode 100644 .github/workflows/scripts/app-test/pr-install.func delete mode 100644 .github/workflows/scripts/update-json.sh delete mode 100644 .github/workflows/scripts/update_json_date.sh delete mode 100644 .github/workflows/update-json-date.yml delete mode 100644 .github/workflows/update-versions-github.yml diff --git a/.github/runner/docker/gh-runner-self.dockerfile b/.github/runner/docker/gh-runner-self.dockerfile deleted file mode 100644 index e5ae072ab..000000000 --- a/.github/runner/docker/gh-runner-self.dockerfile +++ /dev/null @@ -1,68 +0,0 @@ -FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy as build - -ARG TARGETOS -ARG TARGETARCH -ARG DOCKER_VERSION=27.5.1 -ARG BUILDX_VERSION=0.20.1 -ARG RUNNER_ARCH="x64" - -RUN apt update -y && apt install sudo curl unzip -y - -WORKDIR /actions-runner - -RUN RUNNER_VERSION=$(curl -s https://api.github.com/repos/actions/runner/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \ - && curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \ - && tar xzf ./runner.tar.gz \ - && rm runner.tar.gz - -RUN RUNNER_CONTAINER_HOOKS_VERSION=$(curl -s https://api.github.com/repos/actions/runner-container-hooks/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \ - && curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \ - && unzip ./runner-container-hooks.zip -d ./k8s \ - && rm runner-container-hooks.zip - -RUN export RUNNER_ARCH=${TARGETARCH} \ - && if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \ - && if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \ - && curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \ - && tar zxvf docker.tgz \ - && rm -rf docker.tgz \ - && mkdir -p /usr/local/lib/docker/cli-plugins \ - && curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \ - "https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \ - && chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx - -FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy - -ENV DEBIAN_FRONTEND=noninteractive -ENV RUNNER_MANUALLY_TRAP_SIG=1 -ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1 -ENV ImageOS=ubuntu22 - -RUN apt update -y \ - && apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \ - && rm -rf /var/lib/apt/lists/* - -RUN add-apt-repository ppa:git-core/ppa \ - && apt update -y \ - && apt install -y git \ - && rm -rf /var/lib/apt/lists/* - -RUN adduser --disabled-password --gecos "" --uid 1001 runner \ - && groupadd docker --gid 123 \ - && usermod -aG sudo runner \ - && usermod -aG docker runner \ - && echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \ - && echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers - -# Install own dependencies in final image -RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y nodejs \ - && apt-get install -y gh jq git - -WORKDIR /home/runner - -COPY --chown=runner:docker --from=build /actions-runner . -COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx -RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker - -USER runner diff --git a/.github/workflows/bak/close_template_issue.yml b/.github/workflows/bak/close_template_issue.yml deleted file mode 100644 index b87923bc4..000000000 --- a/.github/workflows/bak/close_template_issue.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Auto-Close Wrong Template Issues -on: - issues: - types: [opened] - -jobs: - close_tteck_issues: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: ubuntu-latest - steps: - - name: Auto-close if wrong Template issue detected - uses: actions/github-script@v7 - with: - script: | - const issue = context.payload.issue; - const content = `${issue.title}\n${issue.body}`; - const issueNumber = issue.number; - - // Regex patterns (case-insensitive, flexible versioning) - const patterns = [ - /Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s*\[(online|local)\]/i, - /Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s+is\s+missing\s+or\s+corrupted/i, - /Container\s+creation\s+failed\.?\s+Checking\s+if\s+template\s+is\s+corrupted\s+or\s+incomplete/i, - /Template\s+is\s+valid,\s+but\s+container\s+creation\s+still\s+failed/i, - /exit\s+code\s+0:\s+while\s+executing\s+command\s+bash\s+-c\s+"\$?\(curl\s+-fsSL\s+https:\/\/raw\.githubusercontent\.com\/[\w/-]+\/create_lxc\.sh\)"/i - ]; - - const matched = patterns.some((regex) => regex.test(content)); - - if (matched) { - const message = "πŸ‘‹ Hello!\n\n" + - "It looks like you are referencing a **container creation issue with a Debian 13 template** (e.g. `debian-13-standard_13.x-x_amd64.tar.zst`).\n\n" + - "We receive many similar reports about this, and it's not related to the scripts themselves but to **a Proxmox base template bug**.\n\n" + - "Please refer to [discussion #8126](https://github.com/community-scripts/ProxmoxVE/discussions/8126) for details.\n" + - "If your issue persists after following the guidance there, feel free to reopen this issue.\n\n" + - "_This issue was automatically closed by a bot._"; - - await github.rest.issues.createComment({ - ...context.repo, - issue_number: issueNumber, - body: message - }); - - await github.rest.issues.addLabels({ - ...context.repo, - issue_number: issueNumber, - labels: ["not planned"] - }); - - await github.rest.issues.update({ - ...context.repo, - issue_number: issueNumber, - state: "closed" - }); - } diff --git a/.github/workflows/bak/crawl-versions.yaml b/.github/workflows/bak/crawl-versions.yaml deleted file mode 100644 index 4f8e9a003..000000000 --- a/.github/workflows/bak/crawl-versions.yaml +++ /dev/null @@ -1,126 +0,0 @@ -name: Crawl Versions from newreleases.io - -on: - workflow_dispatch: - schedule: - # Runs at 12:00 AM and 12:00 PM UTC - - cron: "0 0,12 * * *" - -permissions: - contents: write - pull-requests: write - -jobs: - crawl-versions: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - with: - repository: community-scripts/ProxmoxVE - ref: main - - - name: Generate a token - id: generate-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Crawl from newreleases.io - env: - token: ${{ secrets.NEWRELEASES_TOKEN }} - run: | - page=1 - projects_file="project_json" - output_file="frontend/public/json/versions.json" - - echo "[]" > $output_file - - while true; do - - echo "Start loop on page: $page" - - projects=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects?page=$page") - total_pages=$(echo "$projects" | jq -r '.total_pages') - - if [ -z "$total_pages" ] || [ "$total_pages" -eq 0 ]; then - echo "No pages available. Exiting." - exit 1 - fi - if [ $page == $total_pages ]; then - break - fi - - if [ -z "$projects" ] || ! echo "$projects" | jq -e '.projects' > /dev/null; then - echo "No more projects or invalid response. Exiting." - break - fi - - echo "$projects" > "$projects_file" - - jq -r '.projects[] | "\(.id) \(.name)"' "$projects_file" | while read -r id name; do - version=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects/$id/latest-release") - version_data=$(echo "$version" | jq -r '.version // empty') - date=$(echo "$version" | jq -r '.date // empty') - if [ -n "$version_data" ]; then - jq --arg name "$name" --arg version "$version_data" --arg date "$date" \ - '. += [{"name": $name, "version": $version, "date": $date}]' "$output_file" > "$output_file.tmp" && mv "$output_file.tmp" "$output_file" - fi - done - ((page++)) - done - - - name: Commit JSON - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "GitHub Actions[bot]" - git checkout -b update_versions || git checkout update_versions - git add frontend/public/json/versions.json - if git diff --cached --quiet; then - echo "No changes detected." - echo "changed=false" >> "$GITHUB_ENV" - exit 0 - else - echo "Changes detected:" - git diff --stat --cached - echo "changed=true" >> "$GITHUB_ENV" - fi - git commit -m "Update versions.json" - git push origin update_versions --force - gh pr create --title "[Github Action] Update versions.json" --body "Update versions.json, crawled from newreleases.io" --base main --head update_versions --label "automated pr" - - - name: Approve pull request - if: env.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - fi - - - name: Approve pull request and merge - if: env.changed == 'true' - env: - GH_TOKEN: ${{ secrets.PAT_AUTOMERGE }} - run: | - PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - gh pr merge $PR_NUMBER --squash --admin - fi - - - name: Re-approve pull request after update - if: env.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - fi diff --git a/.github/workflows/bak/script-test.yml b/.github/workflows/bak/script-test.yml deleted file mode 100644 index eb53c366d..000000000 --- a/.github/workflows/bak/script-test.yml +++ /dev/null @@ -1,175 +0,0 @@ -name: Run Scripts on PVE Node for testing -permissions: - pull-requests: write -on: - pull_request_target: - branches: - - main - paths: - - "install/**.sh" - - "ct/**.sh" - -jobs: - run-install-script: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: pvenode - steps: - - name: Checkout PR branch - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - fetch-depth: 0 - - - name: Add Git safe directory - run: | - git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE - - - name: Set up GH_TOKEN - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV - - - name: Get Changed Files - run: | - CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only) - CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ') - echo "Changed files: $CHANGED_FILES" - echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get scripts - id: check-install-script - run: | - ALL_FILES=() - ADDED_FILES=() - for FILE in ${{ env.SCRIPT }}; do - if [[ $FILE =~ ^install/.*-install\.sh$ ]] || [[ $FILE =~ ^ct/.*\.sh$ ]]; then - STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') - if [[ ! " ${ADDED_FILES[@]} " =~ " $STRIPPED_NAME " ]]; then - ALL_FILES+=("$FILE") - ADDED_FILES+=("$STRIPPED_NAME") # Mark this base file as added (without the path) - fi - fi - done - ALL_FILES=$(echo "${ALL_FILES[@]}" | xargs) - echo "$ALL_FILES" - echo "ALL_FILES=$ALL_FILES" >> $GITHUB_ENV - - - name: Run scripts - id: run-install - continue-on-error: true - run: | - set +e - #run for each files in /ct - for FILE in ${{ env.ALL_FILES }}; do - STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') - echo "Running Test for: $STRIPPED_NAME" - if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "$FILE"; then - echo "The script contains an interactive prompt. Skipping execution." - continue - fi - if [[ $FILE =~ ^install/.*-install\.sh$ ]]; then - CT_SCRIPT="ct/$STRIPPED_NAME.sh" - if [[ ! -f $CT_SCRIPT ]]; then - echo "No CT script found for $STRIPPED_NAME" - ERROR_MSG="No CT script found for $FILE" - echo "$ERROR_MSG" > result_$STRIPPED_NAME.log - continue - fi - if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "install/$STRIPPED_NAME-install.sh"; then - echo "The script contains an interactive prompt. Skipping execution." - continue - fi - echo "Found CT script for $STRIPPED_NAME" - chmod +x "$CT_SCRIPT" - RUNNING_FILE=$CT_SCRIPT - elif [[ $FILE =~ ^ct/.*\.sh$ ]]; then - INSTALL_SCRIPT="install/$STRIPPED_NAME-install.sh" - if [[ ! -f $INSTALL_SCRIPT ]]; then - echo "No install script found for $STRIPPED_NAME" - ERROR_MSG="No install script found for $FILE" - echo "$ERROR_MSG" > result_$STRIPPED_NAME.log - continue - fi - echo "Found install script for $STRIPPED_NAME" - chmod +x "$INSTALL_SCRIPT" - RUNNING_FILE=$FILE - if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "ct/$STRIPPED_NAME.sh"; then - echo "The script contains an interactive prompt. Skipping execution." - continue - fi - fi - git remote add community-scripts https://github.com/community-scripts/ProxmoxVE.git - git fetch community-scripts - rm -f .github/workflows/scripts/app-test/pr-build.func || true - rm -f .github/workflows/scripts/app-test/pr-install.func || true - rm -f .github/workflows/scripts/app-test/pr-alpine-install.func || true - rm -f .github/workflows/scripts/app-test/pr-create-lxc.sh || true - git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-build.func - git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-install.func - git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-alpine-install.func - git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-create-lxc.sh - chmod +x $RUNNING_FILE - chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh - chmod +x .github/workflows/scripts/app-test/pr-install.func - chmod +x .github/workflows/scripts/app-test/pr-alpine-install.func - chmod +x .github/workflows/scripts/app-test/pr-build.func - sed -i 's|source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)|source .github/workflows/scripts/app-test/pr-build.func|g' "$RUNNING_FILE" - echo "Executing $RUNNING_FILE" - ERROR_MSG=$(./$RUNNING_FILE 2>&1 > /dev/null) - echo "Finished running $FILE" - if [ -n "$ERROR_MSG" ]; then - echo "ERROR in $STRIPPED_NAME: $ERROR_MSG" - echo "$ERROR_MSG" > result_$STRIPPED_NAME.log - fi - done - set -e # Restore exit-on-error - - - name: Cleanup PVE Node - run: | - containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}' | awk '{print $1}') - - for container_id in $containers; do - status=$(pct status $container_id | awk '{print $2}') - if [[ $status == "running" ]]; then - pct stop $container_id - pct destroy $container_id - fi - done - - - name: Post error comments - run: | - ERROR="false" - SEARCH_LINE=".github/workflows/scripts/app-test/pr-build.func: line 255:" - - # Get all existing comments on the PR - EXISTING_COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '.comments[].body') - - for FILE in ${{ env.ALL_FILES }}; do - STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') - if [[ ! -f result_$STRIPPED_NAME.log ]]; then - continue - fi - ERROR_MSG=$(cat result_$STRIPPED_NAME.log) - - if [ -n "$ERROR_MSG" ]; then - CLEANED_ERROR_MSG=$(echo "$ERROR_MSG" | sed "s|$SEARCH_LINE.*||") - COMMENT_BODY=":warning: The script _**$FILE**_ failed with the following message:
${CLEANED_ERROR_MSG}
" - - # Check if the comment already exists - if echo "$EXISTING_COMMENTS" | grep -qF "$COMMENT_BODY"; then - echo "Skipping duplicate comment for $FILE" - else - echo "Posting error message for $FILE" - gh pr comment ${{ github.event.pull_request.number }} \ - --repo ${{ github.repository }} \ - --body "$COMMENT_BODY" - ERROR="true" - fi - fi - done - - echo "ERROR=$ERROR" >> $GITHUB_ENV diff --git a/.github/workflows/bak/script_format.yml b/.github/workflows/bak/script_format.yml deleted file mode 100644 index 64a2eda42..000000000 --- a/.github/workflows/bak/script_format.yml +++ /dev/null @@ -1,243 +0,0 @@ -name: Script Format Check -permissions: - pull-requests: write -on: - pull_request_target: - branches: - - main - paths: - - "install/*.sh" - - "ct/*.sh" - -jobs: - run-install-script: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: pvenode - steps: - - name: Checkout PR branch (supports forks) - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - fetch-depth: 0 - - - name: Add Git safe directory - run: | - git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE - - - name: Set up GH_TOKEN - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV - - - name: Get Changed Files - run: | - CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only) - CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ') - echo "Changed files: $CHANGED_FILES" - echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Check scripts - id: run-install - continue-on-error: true - run: | - for FILE in ${{ env.SCRIPT }}; do - STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//') - echo "Running Test for: $STRIPPED_NAME" - FILE_STRIPPED="${FILE##*/}" - LOG_FILE="result_$FILE_STRIPPED.log" - - if [[ $FILE =~ ^ct/.*\.sh$ ]]; then - - FIRST_LINE=$(sed -n '1p' "$FILE") - [[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE" - SECOND_LINE=$(sed -n '2p' "$FILE") - [[ "$SECOND_LINE" != "source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" ]] && - echo "Line 2 was $SECOND_LINE | Should be: source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" >> "$LOG_FILE" - THIRD_LINE=$(sed -n '3p' "$FILE") - if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then - echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE" - fi - - EXPECTED_AUTHOR="# Author:" - EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE" - EXPECTED_SOURCE="# Source:" - EXPECTED_EMPTY="" - - for i in {4..7}; do - LINE=$(sed -n "${i}p" "$FILE") - - case $i in - 4) - [[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE - ;; - 5) - [[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE - ;; - 6) - [[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE - ;; - 7) - [[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE - ;; - esac - done - - - EXPECTED_PREFIXES=( - "APP=" - "var_tags=" - "var_cpu=" # Must be a number - "var_ram=" # Must be a number - "var_disk=" # Must be a number - "var_os=" # Must be debian, alpine, or ubuntu - "var_version=" - "var_unprivileged=" # Must be 0 or 1 - ) - - - for i in {8..15}; do - LINE=$(sed -n "${i}p" "$FILE") - INDEX=$((i - 8)) - - case $INDEX in - 2|3|4) # var_cpu, var_ram, var_disk (must be numbers) - if [[ "$LINE" =~ ^${EXPECTED_PREFIXES[$INDEX]}([0-9]+)$ ]]; then - continue # Valid - else - echo "Line $i was '$LINE' | Should be: '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE" - fi - ;; - 5) # var_os (must be debian, alpine, or ubuntu) - if [[ "$LINE" =~ ^var_os=(debian|alpine|ubuntu)$ ]]; then - continue # Valid - else - echo "Line $i was '$LINE' | Should be: 'var_os=[debian|alpine|ubuntu]'" >> "$LOG_FILE" - fi - ;; - 7) # var_unprivileged (must be 0 or 1) - if [[ "$LINE" =~ ^var_unprivileged=[01]$ ]]; then - continue # Valid - else - echo "Line $i was '$LINE' | Should be: 'var_unprivileged=[0|1]'" >> "$LOG_FILE" - fi - ;; - *) # Other lines (must start with expected prefix) - if [[ "$LINE" == ${EXPECTED_PREFIXES[$INDEX]}* ]]; then - continue # Valid - else - echo "Line $i was '$LINE' | Should start with '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE" - fi - ;; - esac - done - - for i in {16..20}; do - LINE=$(sed -n "${i}p" "$FILE") - EXPECTED=( - "header_info \"$APP\"" - "variables" - "color" - "catch_errors" - "function update_script() {" - ) - [[ "$LINE" != "${EXPECTED[$((i-16))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-16))]}" >> "$LOG_FILE" - done - cat "$LOG_FILE" - elif [[ $FILE =~ ^install/.*-install\.sh$ ]]; then - - FIRST_LINE=$(sed -n '1p' "$FILE") - [[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE" - - SECOND_LINE=$(sed -n '2p' "$FILE") - [[ -n "$SECOND_LINE" ]] && echo "Line 2 should be empty" >> "$LOG_FILE" - - THIRD_LINE=$(sed -n '3p' "$FILE") - if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then - echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE" - fi - - EXPECTED_AUTHOR="# Author:" - EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE" - EXPECTED_SOURCE="# Source:" - EXPECTED_EMPTY="" - - for i in {4..7}; do - LINE=$(sed -n "${i}p" "$FILE") - - case $i in - 4) - [[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE - ;; - 5) - [[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE - ;; - 6) - [[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE - ;; - 7) - [[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE - ;; - esac - done - - [[ "$(sed -n '8p' "$FILE")" != 'source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' ]] && echo 'Line 8 should be: source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' >> "$LOG_FILE" - - for i in {9..14}; do - LINE=$(sed -n "${i}p" "$FILE") - EXPECTED=( - "color" - "verb_ip6" - "catch_errors" - "setting_up_container" - "network_check" - "update_os" - ) - [[ "$LINE" != "${EXPECTED[$((i-9))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-9))]}" >> "$LOG_FILE" - done - - [[ -n "$(sed -n '15p' "$FILE")" ]] && echo "Line 15 should be empty" >> "$LOG_FILE" - [[ "$(sed -n '16p' "$FILE")" != 'msg_info "Installing Dependencies"' ]] && echo 'Line 16 should be: msg_info "Installing Dependencies"' >> "$LOG_FILE" - - LAST_3_LINES=$(tail -n 3 "$FILE") - [[ "$LAST_3_LINES" != *"$STD apt-get -y autoremove"* ]] && echo 'Third to last line should be: $STD apt-get -y autoremove' >> "$LOG_FILE" - [[ "$LAST_3_LINES" != *"$STD apt-get -y autoclean"* ]] && echo 'Second to last line should be: $STD apt-get -y clean' >> "$LOG_FILE" - [[ "$LAST_3_LINES" != *'msg_ok "Cleaned"'* ]] && echo 'Last line should be: msg_ok "Cleaned"' >> "$LOG_FILE" - cat "$LOG_FILE" - fi - - done - - - name: Post error comments - run: | - ERROR="false" - for FILE in ${{ env.SCRIPT }}; do - FILE_STRIPPED="${FILE##*/}" - LOG_FILE="result_$FILE_STRIPPED.log" - echo $LOG_FILE - if [[ ! -f $LOG_FILE ]]; then - continue - fi - ERROR_MSG=$(cat $LOG_FILE) - - if [ -n "$ERROR_MSG" ]; then - echo "Posting error message for $FILE" - echo ${ERROR_MSG} - gh pr comment ${{ github.event.pull_request.number }} \ - --repo ${{ github.repository }} \ - --body ":warning: The script _**$FILE**_ has the following formatting errors:
${ERROR_MSG}
" - - - ERROR="true" - fi - done - echo "ERROR=$ERROR" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Fail if error - if: ${{ env.ERROR == 'true' }} - run: exit 1 diff --git a/.github/workflows/bak/validate-filenames.yml b/.github/workflows/bak/validate-filenames.yml deleted file mode 100644 index 211be06df..000000000 --- a/.github/workflows/bak/validate-filenames.yml +++ /dev/null @@ -1,158 +0,0 @@ -name: Validate filenames - -on: - pull_request_target: - paths: - - "ct/*.sh" - - "install/*.sh" - - "frontend/public/json/*.json" - -jobs: - check-files: - if: github.repository == 'community-scripts/ProxmoxVE' - name: Check changed files - runs-on: ubuntu-latest - permissions: - pull-requests: write - - steps: - - name: Get pull request information - if: github.event_name == 'pull_request_target' - uses: actions/github-script@v7 - id: pr - with: - script: | - const { data: pullRequest } = await github.rest.pulls.get({ - ...context.repo, - pull_number: context.payload.pull_request.number, - }); - return pullRequest; - - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Ensure the full history is fetched for accurate diffing - ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} - - - name: Get changed files - id: changed-files - run: | - if ${{ github.event_name == 'pull_request_target' }}; then - echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT - else - echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT - fi - - - name: "Validate filenames in ct and install directory" - if: always() && steps.changed-files.outputs.files != '' - id: check-scripts - run: | - CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; }) - - NON_COMPLIANT_FILES="" - for FILE in $CHANGED_FILES; do - BASENAME=$(echo "$(basename "${FILE%.*}")") - if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then - NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" - fi - done - - if [ -n "$NON_COMPLIANT_FILES" ]; then - echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT - echo "Non-compliant filenames found, change to lowercase:" - for FILE in $NON_COMPLIANT_FILES; do - echo "$FILE" - done - exit 1 - fi - - - name: "Validate filenames in json directory." - if: always() && steps.changed-files.outputs.files != '' - id: check-json - run: | - CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; }) - - NON_COMPLIANT_FILES="" - for FILE in $CHANGED_FILES; do - BASENAME=$(echo "$(basename "${FILE%.*}")") - if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then - NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" - fi - done - - if [ -n "$NON_COMPLIANT_FILES" ]; then - echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT - echo "Non-compliant filenames found, change to lowercase:" - for FILE in $NON_COMPLIANT_FILES; do - echo "$FILE" - done - exit 1 - fi - - - name: Post results and comment - if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target' - uses: actions/github-script@v7 - with: - script: | - const result = "${{ job.status }}" === "success" ? "success" : "failure"; - const nonCompliantFiles = { - script: "${{ steps.check-scripts.outputs.files }}", - JSON: "${{ steps.check-json.outputs.files }}", - }; - - const issueNumber = context.payload.pull_request - ? context.payload.pull_request.number - : null; - const commentIdentifier = "validate-filenames"; - let newCommentBody = `\n### Filename validation\n\n`; - - if (result === "failure") { - newCommentBody += ":x: We found issues in the following changed files:\n\n"; - for (const [check, files] of Object.entries(nonCompliantFiles)) { - if (files) { - newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files - .trim() - .split(" ") - .map((file) => `- ${file}`) - .join("\n")}\n\n`; - } - } - newCommentBody += - "Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n"; - } else { - newCommentBody += `:rocket: All files passed filename validation!\n`; - } - - newCommentBody += `\n\n`; - - if (issueNumber) { - const { data: comments } = await github.rest.issues.listComments({ - ...context.repo, - issue_number: issueNumber, - }); - - const existingComment = comments.find( - (comment) => comment.user.login === "github-actions[bot]", - ); - - if (existingComment) { - if (existingComment.body.includes(commentIdentifier)) { - const re = new RegExp(String.raw`[\s\S]*?`, ""); - newCommentBody = existingComment.body.replace(re, newCommentBody); - } else { - newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody; - } - - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: existingComment.id, - body: newCommentBody, - }); - } else { - await github.rest.issues.createComment({ - ...context.repo, - issue_number: issueNumber, - body: newCommentBody, - }); - } - } diff --git a/.github/workflows/push-to-gitea.yaml b/.github/workflows/push-to-gitea.yaml deleted file mode 100644 index bd927f4a4..000000000 --- a/.github/workflows/push-to-gitea.yaml +++ /dev/null @@ -1,48 +0,0 @@ -name: Sync to Gitea - -on: - push: - branches: - - main - -jobs: - sync: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: ubuntu-latest - - steps: - - name: Checkout source repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Change all links to git.community-scripts.org - run: | - echo "Searching for files containing raw.githubusercontent.com URLs..." - - # Find all files containing GitHub raw URLs, excluding certain directories - files_with_github_urls=$(grep -r "https://raw.githubusercontent.com/community-scripts/ProxmoxVE" . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.github/workflows --files-with-matches || true) - - if [ -n "$files_with_github_urls" ]; then - echo "$files_with_github_urls" | while read file; do - if [ -f "$file" ]; then - sed -i 's|https://raw\.githubusercontent\.com/community-scripts/ProxmoxVE/|https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/|g' "$file" - fi - done - else - echo "No files found containing GitHub raw URLs" - fi - - - - - name: Push to Gitea - run: | - git config --global user.name "Push From Github" - git config --global user.email "actions@github.com" - git remote add gitea https://$GITEA_USER:$GITEA_TOKEN@git.community-scripts.org/community-scripts/ProxmoxVE.git - git add . - git commit -m "Sync to Gitea" - git push gitea --all --force - env: - GITEA_USER: ${{ secrets.GITEA_USERNAME }} - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} diff --git a/.github/workflows/scripts/app-test/pr-alpine-install.func b/.github/workflows/scripts/app-test/pr-alpine-install.func deleted file mode 100644 index 89c57dcf5..000000000 --- a/.github/workflows/scripts/app-test/pr-alpine-install.func +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-2026 community-scripts ORG -# Author: Michel Roegl-Brunner (michelroegl-brunner) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE - -color() { - return -} -catch_errors() { - set -Eeuo pipefail - trap 'error_handler $LINENO "$BASH_COMMAND"' ERR -} - -# This function handles errors -error_handler() { - local line_number="$1" - local command="$2" - SCRIPT_NAME=$(basename "$0") - local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command" - echo -e "\n$error_message" - exit 0 -} -verb_ip6() { - STD="" - return -} - -msg_info() { - local msg="$1" - echo -ne "${msg}\n" -} - -msg_ok() { - local msg="$1" - echo -e "${msg}\n" -} - -msg_error() { - - local msg="$1" - echo -e "${msg}\n" -} - -RETRY_NUM=10 -RETRY_EVERY=3 -i=$RETRY_NUM - -setting_up_container() { - while [ $i -gt 0 ]; do - if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then - break - fi - echo 1>&2 -en "No Network! " - sleep $RETRY_EVERY - i=$((i - 1)) - done - - if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then - echo 1>&2 -e "\n No Network After $RETRY_NUM Tries" - echo -e "Check Network Settings" - exit 1 - fi - msg_ok "Set up Container OS" - msg_ok "Network Connected: $(hostname -i)" -} - -network_check() { - RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') - if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi - set -e -} - -update_os() { - msg_info "Updating Container OS" - $STD apk -U upgrade - msg_ok "Updated Container OS" -} - -motd_ssh() { - return -} - -customize() { - return -} diff --git a/.github/workflows/scripts/app-test/pr-build.func b/.github/workflows/scripts/app-test/pr-build.func deleted file mode 100644 index 6eadfb60d..000000000 --- a/.github/workflows/scripts/app-test/pr-build.func +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-2026 community-scripts ORG -# Author: Michel Roegl-Brunner (michelroegl-brunner) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE - -variables() { - NSAPP=$(echo ${APP,,} | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces. - var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP. - -} - -NEXTID=$(pvesh get /cluster/nextid) -timezone=$(cat /etc/timezone) -header_info() { - return -} - -base_settings() { - # Default Settings - CT_TYPE="1" - DISK_SIZE="4" - CORE_COUNT="1" - RAM_SIZE="1024" - VERBOSE="no" - PW="" - CT_ID=$NEXTID - HN=$NSAPP - BRG="vmbr0" - NET="dhcp" - GATE="" - APT_CACHER="" - APT_CACHER_IP="" - DISABLEIP6="no" - MTU="" - SD="" - NS="" - MAC="" - VLAN="" - SSH="no" - SSH_AUTHORIZED_KEY="" - TAGS="community-script;" - - # Override default settings with variables from ct script - CT_TYPE=${var_unprivileged:-$CT_TYPE} - DISK_SIZE=${var_disk:-$DISK_SIZE} - CORE_COUNT=${var_cpu:-$CORE_COUNT} - RAM_SIZE=${var_ram:-$RAM_SIZE} - VERB=${var_verbose:-$VERBOSE} - TAGS="${TAGS}${var_tags:-}" - - # Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts - if [ -z "$var_os" ]; then - var_os="debian" - fi - if [ -z "$var_version" ]; then - var_version="12" - fi -} - -color() { - # Colors - YW=$(echo "\033[33m") - YWB=$(echo "\033[93m") - BL=$(echo "\033[36m") - RD=$(echo "\033[01;31m") - BGN=$(echo "\033[4;92m") - GN=$(echo "\033[1;92m") - DGN=$(echo "\033[32m") - - # Formatting - CL=$(echo "\033[m") - UL=$(echo "\033[4m") - BOLD=$(echo "\033[1m") - BFR="\\r\\033[K" - HOLD=" " - TAB=" " - - # Icons - CM="${TAB}βœ”οΈ${TAB}${CL}" - CROSS="${TAB}βœ–οΈ${TAB}${CL}" - INFO="${TAB}πŸ’‘${TAB}${CL}" - OS="${TAB}πŸ–₯️${TAB}${CL}" - OSVERSION="${TAB}🌟${TAB}${CL}" - CONTAINERTYPE="${TAB}πŸ“¦${TAB}${CL}" - DISKSIZE="${TAB}πŸ’Ύ${TAB}${CL}" - CPUCORE="${TAB}🧠${TAB}${CL}" - RAMSIZE="${TAB}πŸ› οΈ${TAB}${CL}" - SEARCH="${TAB}πŸ”${TAB}${CL}" - VERIFYPW="${TAB}πŸ”${TAB}${CL}" - CONTAINERID="${TAB}πŸ†”${TAB}${CL}" - HOSTNAME="${TAB}🏠${TAB}${CL}" - BRIDGE="${TAB}πŸŒ‰${TAB}${CL}" - NETWORK="${TAB}πŸ“‘${TAB}${CL}" - GATEWAY="${TAB}🌐${TAB}${CL}" - DISABLEIPV6="${TAB}🚫${TAB}${CL}" - DEFAULT="${TAB}βš™οΈ${TAB}${CL}" - MACADDRESS="${TAB}πŸ”—${TAB}${CL}" - VLANTAG="${TAB}🏷️${TAB}${CL}" - ROOTSSH="${TAB}πŸ”‘${TAB}${CL}" - CREATING="${TAB}πŸš€${TAB}${CL}" - ADVANCED="${TAB}🧩${TAB}${CL}" -} - -catch_errors() { - set -Eeuo pipefail - trap 'error_handler $LINENO "$BASH_COMMAND"' ERR -} - -# This function handles errors -error_handler() { - local line_number="$1" - local command="$2" - SCRIPT_NAME=$(basename "$0") - local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command" - echo -e "\n$error_message" - exit 100 -} - -msg_info() { - local msg="$1" - echo -ne "${msg}\n" -} - -msg_ok() { - local msg="$1" - echo -e "${msg}\n" -} - -msg_error() { - - local msg="$1" - echo -e "${msg}\n" -} -start() { - base_settings - return -} - -build_container() { - # if [ "$VERB" == "yes" ]; then set -x; fi - - if [ "$CT_TYPE" == "1" ]; then - FEATURES="keyctl=1,nesting=1" - else - FEATURES="nesting=1" - fi - TEMP_DIR=$(mktemp -d) - pushd $TEMP_DIR >/dev/null - if [ "$var_os" == "alpine" ]; then - export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-alpine-install.func)" - else - export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-install.func)" - fi - - export CACHER="$APT_CACHER" - export CACHER_IP="$APT_CACHER_IP" - export tz="" - export DISABLEIPV6="$DISABLEIP6" - export APPLICATION="$APP" - export app="$NSAPP" - export PASSWORD="$PW" - export VERBOSE="$VERB" - export SSH_ROOT="${SSH}" - export SSH_AUTHORIZED_KEY - export CTID="$CT_ID" - export CTTYPE="$CT_TYPE" - export PCT_OSTYPE="$var_os" - export PCT_OSVERSION="$var_version" - export PCT_DISK_SIZE="$DISK_SIZE" - export tz="$timezone" - export PCT_OPTIONS=" - -features $FEATURES - -hostname $HN - -tags $TAGS - $SD - $NS - -net0 name=eth0,bridge=$BRG$MAC,ip=$NET$GATE$VLAN$MTU - -onboot 1 - -cores $CORE_COUNT - -memory $RAM_SIZE - -unprivileged $CT_TYPE - $PW - " - echo "Container ID: $CTID" - - # This executes create_lxc.sh and creates the container and .conf file - bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-create-lxc.sh)" - - LXC_CONFIG=/etc/pve/lxc/${CTID}.conf - if [ "$CT_TYPE" == "0" ]; then - cat <>$LXC_CONFIG -# USB passthrough -lxc.cgroup2.devices.allow: a -lxc.cap.drop: -lxc.cgroup2.devices.allow: c 188:* rwm -lxc.cgroup2.devices.allow: c 189:* rwm -lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir -lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file -lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file -lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file -lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file -EOF - fi - - if [ "$CT_TYPE" == "0" ]; then - if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then - cat <>$LXC_CONFIG -# VAAPI hardware transcoding -lxc.cgroup2.devices.allow: c 226:0 rwm -lxc.cgroup2.devices.allow: c 226:128 rwm -lxc.cgroup2.devices.allow: c 29:0 rwm -lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file -lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir -lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file -EOF - fi - else - if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then - if [[ -e "/dev/dri/renderD128" ]]; then - if [[ -e "/dev/dri/card0" ]]; then - cat <>$LXC_CONFIG -# VAAPI hardware transcoding -dev0: /dev/dri/card0,gid=44 -dev1: /dev/dri/renderD128,gid=104 -EOF - else - cat <>$LXC_CONFIG -# VAAPI hardware transcoding -dev0: /dev/dri/card1,gid=44 -dev1: /dev/dri/renderD128,gid=104 -EOF - fi - fi - fi - fi - - # This starts the container and executes -install.sh - msg_info "Starting LXC Container" - pct start "$CTID" - msg_ok "Started LXC Container" - - if [[ ! -f "/root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh" ]]; then - msg_error "No install script found for $APP" - exit 1 - fi - if [ "$var_os" == "alpine" ]; then - sleep 3 - pct exec "$CTID" -- /bin/sh -c 'cat </etc/apk/repositories -http://dl-cdn.alpinelinux.org/alpine/latest-stable/main -http://dl-cdn.alpinelinux.org/alpine/latest-stable/community -EOF' - pct exec "$CTID" -- ash -c "apk add bash >/dev/null" - fi - lxc-attach -n "$CTID" -- bash -c "$(cat /root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh)" - -} - -description() { - IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1) -} diff --git a/.github/workflows/scripts/app-test/pr-create-lxc.sh b/.github/workflows/scripts/app-test/pr-create-lxc.sh deleted file mode 100644 index 4012599c9..000000000 --- a/.github/workflows/scripts/app-test/pr-create-lxc.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-2026 community-scripts ORG -# Author: Michel Roegl-Brunner (michelroegl-brunner) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE - -color() { - return -} -catch_errors() { - set -Eeuo pipefail - trap 'error_handler $LINENO "$BASH_COMMAND"' ERR -} - -# This function handles errors -error_handler() { - local exit_code="$?" - local line_number="$1" - local command="$2" - local error_message="Failure in line $line_number: exit code $exit_code: while executing command $command" - echo -e "\n$error_message" - exit 100 -} -verb_ip6() { - return -} - -msg_info() { - local msg="$1" - echo -ne "${msg}\n" -} - -msg_ok() { - local msg="$1" - echo -e "${msg}\n" -} - -msg_error() { - - local msg="$1" - echo -e "${msg}\n" -} - -VALIDCT=$(pvesm status -content rootdir | awk 'NR>1') -if [ -z "$VALIDCT" ]; then - msg_error "Unable to detect a valid Container Storage location." - exit 1 -fi -VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1') -if [ -z "$VALIDTMP" ]; then - msg_error "Unable to detect a valid Template Storage location." - exit 1 -fi - -function select_storage() { - local CLASS=$1 - local CONTENT - local CONTENT_LABEL - case $CLASS in - container) - CONTENT='rootdir' - CONTENT_LABEL='Container' - ;; - template) - CONTENT='vztmpl' - CONTENT_LABEL='Container template' - ;; - *) false || { - msg_error "Invalid storage class." - exit 201 - } ;; - esac - - # This Queries all storage locations - local -a MENU - while read -r line; do - local TAG=$(echo $line | awk '{print $1}') - local TYPE=$(echo $line | awk '{printf "%-10s", $2}') - local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') - local ITEM="Type: $TYPE Free: $FREE " - local OFFSET=2 - if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then - local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) - fi - MENU+=("$TAG" "$ITEM" "OFF") - done < <(pvesm status -content $CONTENT | awk 'NR>1') - - # Select storage location - if [ $((${#MENU[@]} / 3)) -eq 1 ]; then - printf ${MENU[0]} - else - msg_error "STORAGE ISSUES!" - exit 202 - fi -} - -[[ "${CTID:-}" ]] || { - msg_error "You need to set 'CTID' variable." - exit 203 -} -[[ "${PCT_OSTYPE:-}" ]] || { - msg_error "You need to set 'PCT_OSTYPE' variable." - exit 204 -} - -# Test if ID is valid -[ "$CTID" -ge "100" ] || { - msg_error "ID cannot be less than 100." - exit 205 -} - -# Test if ID is in use -if pct status $CTID &>/dev/null; then - echo -e "ID '$CTID' is already in use." - unset CTID - msg_error "Cannot use ID that is already in use." - exit 206 -fi - -TEMPLATE_STORAGE=$(select_storage template) || exit - -CONTAINER_STORAGE=$(select_storage container) || exit - -pveam update >/dev/null - -TEMPLATE_SEARCH=${PCT_OSTYPE}-${PCT_OSVERSION:-} -mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V) -[ ${#TEMPLATES[@]} -gt 0 ] || { - msg_error "Unable to find a template when searching for '$TEMPLATE_SEARCH'." - exit 207 -} -TEMPLATE="${TEMPLATES[-1]}" - -TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" - -if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then - [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH" - pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null || - { - msg_error "A problem occurred while downloading the LXC template." - exit 208 - } -fi - -grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid -grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid - -PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}}) -[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}") - -if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then - [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH" - - pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null || - { - msg_error "A problem occurred while re-downloading the LXC template." - exit 208 - } - - if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then - msg_error "A problem occurred while trying to create container after re-downloading template." - exit 200 - fi -fi diff --git a/.github/workflows/scripts/app-test/pr-install.func b/.github/workflows/scripts/app-test/pr-install.func deleted file mode 100644 index 1709a1c16..000000000 --- a/.github/workflows/scripts/app-test/pr-install.func +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-2026 community-scripts ORG -# Author: Michel Roegl-Brunner (michelroegl-brunner) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE - -color() { - return -} - -catch_errors() { - set -Euo pipefail - trap 'error_handler $LINENO "$BASH_COMMAND"' ERR -} - -error_handler() { - local line_number="$1" - local command="$2" - local error_message="Failure in line $line_number while executing command '$command'" - echo -e "\n$error_message\n" >&2 - exit 1 -} - -verb_ip6() { - STD="silent" - silent() { - "$@" >/dev/null 2>&1 || error_handler "${BASH_LINENO[0]}" "$*" - } - return -} - -msg_info() { - local msg="$1" - echo -ne "${msg}\n" -} - -msg_ok() { - local msg="$1" - echo -e "${msg}\n" -} - -msg_error() { - - local msg="$1" - echo -e "${msg}\n" -} - -RETRY_NUM=10 -RETRY_EVERY=3 -setting_up_container() { - - sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen - locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1) - echo "LANG=${locale_line}" >/etc/default/locale - locale-gen >/dev/null - export LANG=${locale_line} - echo $tz >/etc/timezone - ln -sf /usr/share/zoneinfo/$tz /etc/localtime - - for ((i = RETRY_NUM; i > 0; i--)); do - if [ "$(hostname -I)" != "" ]; then - break - fi - sleep $RETRY_EVERY - done - if [ "$(hostname -I)" = "" ]; then - echo 1>&2 -e "\nNo Network After $RETRY_NUM Tries" - echo -e "Check Network Settings" - exit 101 - fi - rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED - systemctl disable -q --now systemd-networkd-wait-online.service -} - -network_check() { - RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }') - if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi - set -e -} - -update_os() { - export DEBIAN_FRONTEND=noninteractive - apt-get update >/dev/null 2>&1 - apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade >/dev/null - rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED -} - -motd_ssh() { - return -} - -customize() { - return -} diff --git a/.github/workflows/scripts/update-json.sh b/.github/workflows/scripts/update-json.sh deleted file mode 100644 index 1711f7550..000000000 --- a/.github/workflows/scripts/update-json.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -FILE=$1 -TODAY=$(date -u +"%Y-%m-%d") - -if [[ -z "$FILE" ]]; then - echo "No file specified. Exiting." - exit 1 -fi - -if [[ ! -f "$FILE" ]]; then - echo "File $FILE not found. Exiting." - exit 1 -fi - -DATE_IN_JSON=$(jq -r '.date_created' "$FILE" 2>/dev/null || echo "") - -if [[ "$DATE_IN_JSON" != "$TODAY" ]]; then - jq --arg date "$TODAY" '.date_created = $date' "$FILE" >tmp.json && mv tmp.json "$FILE" -fi diff --git a/.github/workflows/scripts/update_json_date.sh b/.github/workflows/scripts/update_json_date.sh deleted file mode 100644 index 13305de83..000000000 --- a/.github/workflows/scripts/update_json_date.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# Verzeichnis, das die JSON-Dateien enthΓ€lt -json_dir="./json/*.json" - -current_date=$(date +"%Y-%m-%d") - -for json_file in $json_dir; do - if [[ -f "$json_file" ]]; then - current_json_date=$(jq -r '.date_created' "$json_file") - - if [[ "$current_json_date" != "$current_date" ]]; then - echo "Updating $json_file with date $current_date" - jq --arg date "$current_date" '.date_created = $date' "$json_file" >temp.json && mv temp.json "$json_file" - - git add "$json_file" - git commit -m "Update date_created to $current_date in $json_file" - else - echo "Date in $json_file is already up to date." - fi - fi -done -git push origin HEAD diff --git a/.github/workflows/update-json-date.yml b/.github/workflows/update-json-date.yml deleted file mode 100644 index 7e4824052..000000000 --- a/.github/workflows/update-json-date.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: Update JSON Date - -on: - push: - branches: - - main - paths: - - "json/**.json" - workflow_dispatch: - -jobs: - update-app-files: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: ubuntu-latest - - permissions: - contents: write - pull-requests: write - - steps: - - name: Generate a token - id: generate-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Generate a token for PR approval and merge - id: generate-token-merge - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }} - private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }} - - - name: Generate dynamic branch name - id: timestamp - run: echo "BRANCH_NAME=pr-update-json-$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV - - - name: Set up GH_TOKEN - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV - - - name: Checkout Repository - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Ensure we have the last two commits - - - name: Get Previous Commit - id: prev_commit - run: | - PREV_COMMIT=$(git rev-parse HEAD^) - echo "Previous commit: $PREV_COMMIT" - echo "prev_commit=$PREV_COMMIT" >> $GITHUB_ENV - - - name: Get Newly Added JSON Files - id: new_json_files - run: | - git diff --name-only --diff-filter=A ${{ env.prev_commit }} HEAD | grep '^json/.*\.json$' > new_files.txt || true - echo "New files detected:" - cat new_files.txt || echo "No new files." - - - name: Disable file mode changes - run: git config core.fileMode false - - - name: Set up Git - run: | - git config --global user.name "GitHub Actions" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - - name: Change JSON Date - id: change-json-date - run: | - current_date=$(date +"%Y-%m-%d") - while IFS= read -r file; do - # Skip empty lines - [[ -z "$file" ]] && continue - - if [[ -f "$file" ]]; then - echo "Processing $file..." - current_json_date=$(jq -r '.date_created // empty' "$file") - if [[ -z "$current_json_date" || "$current_json_date" != "$current_date" ]]; then - echo "Updating $file with date $current_date" - jq --arg date "$current_date" '.date_created = $date' "$file" > temp.json && mv temp.json "$file" - else - echo "Date in $file is already up to date." - fi - else - echo "Warning: File $file not found!" - fi - done < new_files.txt - rm new_files.txt - - - name: Check if there are any changes - run: | - echo "Checking for changes..." - git add -A - git status - if git diff --cached --quiet; then - echo "No changes detected." - echo "changed=false" >> "$GITHUB_ENV" - else - echo "Changes detected:" - git diff --stat --cached - echo "changed=true" >> "$GITHUB_ENV" - fi - - # Step 7: Commit and create PR if changes exist - - name: Commit and create PR if changes exist - if: env.changed == 'true' - run: | - - - git commit -m "Update date in json" - git checkout -b ${{ env.BRANCH_NAME }} - git push origin ${{ env.BRANCH_NAME }} - - gh pr create --title "[core] update date in json" \ - --body "This PR is auto-generated by a GitHub Action to update the date in json." \ - --head ${{ env.BRANCH_NAME }} \ - --base main \ - --label "automated pr" - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - - - name: Approve pull request - if: env.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - fi - - - name: Approve pull request and merge - if: env.changed == 'true' - env: - GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }} - run: | - git config --global user.name "github-actions-automege[bot]" - git config --global user.email "github-actions-automege[bot]@users.noreply.github.com" - PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - gh pr merge $PR_NUMBER --squash --admin - fi - - - name: No changes detected - if: env.changed == 'false' - run: echo "No changes to commit. Workflow completed successfully." diff --git a/.github/workflows/update-versions-github.yml b/.github/workflows/update-versions-github.yml deleted file mode 100644 index 31d7f7af8..000000000 --- a/.github/workflows/update-versions-github.yml +++ /dev/null @@ -1,236 +0,0 @@ -name: Update GitHub Versions (New) - -on: - workflow_dispatch: - schedule: - # Runs 4x daily: 00:00, 06:00, 12:00, 18:00 UTC - - cron: "0 0,6,12,18 * * *" - -permissions: - contents: write - pull-requests: write - -env: - VERSIONS_FILE: json/github-versions.json - BRANCH_NAME: automated/update-github-versions - AUTOMATED_PR_LABEL: "automated pr" - -jobs: - update-github-versions: - if: github.repository == 'community-scripts/ProxmoxVE' - runs-on: ubuntu-latest - - steps: - - name: Generate a token - id: generate-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Generate a token for PR approval and merge - id: generate-token-merge - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }} - private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }} - - - name: Checkout Repository - uses: actions/checkout@v4 - with: - ref: main - - - name: Extract GitHub versions from install scripts - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -euo pipefail - - echo "=========================================" - echo " Extracting GitHub versions from scripts" - echo "=========================================" - - # Initialize versions array - versions_json="[]" - - # Function to add a version entry - add_version() { - local slug="$1" - local repo="$2" - local version="$3" - local pinned="$4" - local date="$5" - - versions_json=$(echo "$versions_json" | jq \ - --arg slug "$slug" \ - --arg repo "$repo" \ - --arg version "$version" \ - --argjson pinned "$pinned" \ - --arg date "$date" \ - '. += [{"slug": $slug, "repo": $repo, "version": $version, "pinned": $pinned, "date": $date}]') - } - - # Get list of slugs from JSON files - echo "" - echo "=== Scanning JSON files for slugs ===" - - for json_file in json/*.json; do - [[ ! -f "$json_file" ]] && continue - - # Skip non-app JSON files - basename_file=$(basename "$json_file") - case "$basename_file" in - metadata.json|versions.json|github-versions.json|dependency-check.json|update-apps.json) - continue - ;; - esac - - # Extract slug from JSON - slug=$(jq -r '.slug // empty' "$json_file" 2>/dev/null) - [[ -z "$slug" ]] && continue - - # Find corresponding script (install script or addon script) - install_script="" - if [[ -f "install/${slug}-install.sh" ]]; then - install_script="install/${slug}-install.sh" - elif [[ -f "tools/addon/${slug}.sh" ]]; then - install_script="tools/addon/${slug}.sh" - else - continue - fi - - # Look for fetch_and_deploy_gh_release calls - # Pattern: fetch_and_deploy_gh_release "app" "owner/repo" ["mode"] ["version"] - while IFS= read -r line; do - # Skip commented lines - [[ "$line" =~ ^[[:space:]]*# ]] && continue - - # Extract repo and version from fetch_and_deploy_gh_release - if [[ "$line" =~ fetch_and_deploy_gh_release[[:space:]]+\"[^\"]*\"[[:space:]]+\"([^\"]+)\"([[:space:]]+\"([^\"]+)\")?([[:space:]]+\"([^\"]+)\")? ]]; then - repo="${BASH_REMATCH[1]}" - mode="${BASH_REMATCH[3]:-tarball}" - pinned_version="${BASH_REMATCH[5]:-latest}" - - # Check if version is pinned (not "latest" and not empty) - is_pinned=false - target_version="" - - if [[ -n "$pinned_version" && "$pinned_version" != "latest" ]]; then - is_pinned=true - target_version="$pinned_version" - fi - - # Fetch version from GitHub - if [[ "$is_pinned" == "true" ]]; then - # For pinned versions, verify it exists and get date - response=$(gh api "repos/${repo}/releases/tags/${target_version}" 2>/dev/null || echo '{}') - if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then - version=$(echo "$response" | jq -r '.tag_name') - date=$(echo "$response" | jq -r '.published_at // empty') - add_version "$slug" "$repo" "$version" "true" "$date" - echo "[$slug] βœ“ $version (pinned)" - else - echo "[$slug] ⚠ pinned version $target_version not found" - fi - else - # Fetch latest release - response=$(gh api "repos/${repo}/releases/latest" 2>/dev/null || echo '{}') - if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then - version=$(echo "$response" | jq -r '.tag_name') - date=$(echo "$response" | jq -r '.published_at // empty') - add_version "$slug" "$repo" "$version" "false" "$date" - echo "[$slug] βœ“ $version" - else - # Try tags as fallback - version=$(gh api "repos/${repo}/tags" --jq '.[0].name // empty' 2>/dev/null || echo "") - if [[ -n "$version" ]]; then - add_version "$slug" "$repo" "$version" "false" "" - echo "[$slug] βœ“ $version (from tags)" - else - echo "[$slug] ⚠ no version found" - fi - fi - fi - - break # Only first match per script - fi - done < <(grep 'fetch_and_deploy_gh_release' "$install_script" 2>/dev/null || true) - - done - - # Save versions file - echo "$versions_json" | jq --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - '{generated: $date, versions: (. | sort_by(.slug))}' > "$VERSIONS_FILE" - - total=$(echo "$versions_json" | jq 'length') - echo "" - echo "=========================================" - echo " Total versions extracted: $total" - echo "=========================================" - - - name: Check for changes - id: check-changes - run: | - # Check if file is new (untracked) or has changes - if [[ ! -f "$VERSIONS_FILE" ]]; then - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "Versions file was not created" - elif ! git ls-files --error-unmatch "$VERSIONS_FILE" &>/dev/null; then - # File exists but is not tracked - it's new - echo "changed=true" >> "$GITHUB_OUTPUT" - echo "New file created: $VERSIONS_FILE" - elif git diff --quiet "$VERSIONS_FILE" 2>/dev/null; then - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "No changes detected" - else - echo "changed=true" >> "$GITHUB_OUTPUT" - echo "Changes detected:" - git diff --stat "$VERSIONS_FILE" 2>/dev/null || true - fi - - - name: Commit and push changes - if: steps.check-changes.outputs.changed == 'true' - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git add "$VERSIONS_FILE" - git commit -m "chore: update github-versions.json" - git checkout -b $BRANCH_NAME || git checkout $BRANCH_NAME - git push origin $BRANCH_NAME --force - - - name: Create pull request if not exists - if: steps.check-changes.outputs.changed == 'true' - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - run: | - PR_EXISTS=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') - if [ -z "$PR_EXISTS" ]; then - gh pr create --title "[Github Action] Update github-versions.json" \ - --body "This PR is auto-generated by a Github Action to update the github-versions.json file." \ - --head $BRANCH_NAME \ - --base main \ - --label "$AUTOMATED_PR_LABEL" - fi - - - name: Approve pull request - if: steps.check-changes.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - fi - - - name: Approve pull request and merge - if: steps.check-changes.outputs.changed == 'true' - env: - GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }} - run: | - git config --global user.name "github-actions-automege[bot]" - git config --global user.email "github-actions-automege[bot]@users.noreply.github.com" - PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number') - if [ -n "$PR_NUMBER" ]; then - gh pr review $PR_NUMBER --approve - gh pr merge $PR_NUMBER --squash --admin - fi