From 85755d38408fc8a77b414aa951ba5871ea55a6c3 Mon Sep 17 00:00:00 2001 From: Lucas FICHEUX Date: Tue, 24 Mar 2026 15:33:11 +0100 Subject: [PATCH 1/2] Support multiple values where the HCloud API supports it Changed inputs: * `network` => `networks` * `ssh_key` => `ssh_keys` * `volume` => `volumes` --- README.md | 8 +++--- action.sh | 75 ++++++++++++++++++++++++++++++++---------------------- action.yml | 18 ++++++------- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 9bf3f9b..e153445 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ jobs: ## Inputs > [!TIP] -> Use an SSH key ID (`ssh_key`) to disable root password generation and Hetzner Cloud email notifications. +> Use an SSH key ID (`ssh_keys`) to disable root password generation and Hetzner Cloud email notifications. | Name | Required | Description | Default | |---------------------|----------|-------------|---------| @@ -159,7 +159,7 @@ jobs: | `location` | | Name of Location to create Server in. | `nbg1` (Nürnberg 1) | | `mode` | ✓ (always) | Choose either `create` to create a new GitHub Actions Runner or `delete` to delete a previously created one. | | | `name` | ✓ (mode `delete`, optional for mode `create`) | The name for the server and label for the GitHub Actions Runner (must be unique within the project and conform to hostname rules: `^[a-zA-Z0-9_-]{1,64}`). | `gh-runner-[RANDOM-INT]` | -| `network` | | Network ID (integer) which should be attached to the Server private network interface at the creation time. | `null` | +| `networks` | | Comma separated Network IDs (integer) which should be attached to the Server private network interface at the creation time. | `null` | | `pre_runner_script` | | Specifies bash commands to run before the GitHub Actions Runner starts. It's useful for installing dependencies with apt-get, dnf, zypper etc. | | | `primary_ipv4` | | ID (integer) of the IPv4 Primary IP to use. If omitted and `enable_ipv4` is true, a new IPv4 Primary IP will automatically be created. | `null` | | `primary_ipv6` | | ID (integer) of the IPv6 Primary IP to use. If omitted and `enable_ipv6` is true, a new IPv6 Primary IP will automatically be created. | `null` | @@ -169,8 +169,8 @@ jobs: | `server_id` | ✓ (mode `stop`) | ID (integer) of Hetzner Cloud Server to delete. | | | `server_type` | | Name of the Server type this Server should be created with. | `cx23` (Intel x86, 2 vCPU, 4GB RAM, 40GB SSD) | | `server_wait` | | Wait up to `server_wait` retries (10 sec each) for the Hetzner Cloud Server to start. | `30` (5 min) | -| `ssh_key` | | SSH key ID (integer) which should be injected into the Server at creation time. | `null` | -| `volume` | | Specify a Volume ID (integer) to attach and mount to the Server during creation. The volume will be automatically mounted at `/mnt/HC_Volume_[VOLUME-ID]`. The volume must be in the same location as the Server. More details in [Volumes section](#Volumes). | `null` | +| `ssh_keys` | | Comma separated SSH key IDs (integer) which should be injected into the Server at creation time. | `null` | +| `volumes` | | Comma separated Volume IDs (integer) to attach and mount to the Server during creation. Volumes will be automatically mounted at `/mnt/HC_Volume_[VOLUME-ID]`. Volumes must be in the same location as the Server. More details in [Volumes section](#Volumes). | `null` | ## Outputs diff --git a/action.sh b/action.sh index 1c27e1c..a3dd6d5 100644 --- a/action.sh +++ b/action.sh @@ -23,6 +23,18 @@ function exit_with_failure() { exit 1 } +# Function to check all values of a comma separated list are integers +function check_all_integers() { + IFS=',' read -ra _values <<< "$1" + for value in "${_values[@]}"; do + if [[ ! "$value" =~ ^[0-9]+$ ]]; then + echo "$value" + return 1 + fi + done + return 0 +} + # Define required commands MY_COMMANDS=( base64 @@ -150,11 +162,12 @@ if [[ "$MY_NAME" == "hetzner" ]]; then fi # Set the network for the instance (default: null) -# If INPUT_NETWORK is set, use its value; otherwise, use "null". -MY_NETWORK=${INPUT_NETWORK:-"null"} -# Check if MY_NETWORK is an integer -if [[ "$MY_NETWORK" != "null" && ! "$MY_NETWORK" =~ ^[0-9]+$ ]]; then - exit_with_failure "The network ID must be 'null' or an integer!" +# If INPUT_NETWORKS is set, use its value; otherwise, use "null". +MY_NETWORKS=${INPUT_NETWORKS:-"null"} +if [[ "$MY_NETWORKS" != "null" ]]; then + invalid_value=$(check_all_integers "$MY_NETWORKS") || { + exit_with_failure "Invalid network ID: $invalid_value (must be 'null' or an integer)" + } fi # Set bash commands to run before the runner starts. @@ -219,19 +232,21 @@ if [[ ! "$MY_SERVER_WAIT" =~ ^[0-9]+$ ]]; then fi # Set the SSH key to use for the instance (default: null) -# If INPUT_SSH_KEY is set, use its value; otherwise, use "null". -MY_SSH_KEY=${INPUT_SSH_KEY:-"null"} -# Check if MY_SSH_KEY is an integer -if [[ "$MY_SSH_KEY" != "null" && ! "$MY_SSH_KEY" =~ ^[0-9]+$ ]]; then - exit_with_failure "The SSH key ID must be 'null' or an integer!" +# If INPUT_SSH_KEYS is set, use its value; otherwise, use "null". +MY_SSH_KEYS=${INPUT_SSH_KEYS:-"null"} +if [[ "$MY_SSH_KEYS" != "null" ]]; then + invalid_value=$(check_all_integers "$MY_SSH_KEYS") || { + exit_with_failure "Invalid SSH key ID: $invalid_value (must be 'null' or an integer)" + } fi # Set the volume ID which should be attached to the instance at the creation time (default: null) -# If INPUT_VOLUME is set, use its value; otherwise, use "null". -MY_VOLUME=${INPUT_VOLUME:-"null"} -# Check if MY_VOLUME is an integer -if [[ "$MY_VOLUME" != "null" && ! "$MY_VOLUME" =~ ^[0-9]+$ ]]; then - exit_with_failure "The volume ID must be 'null' or an integer!" +# If INPUT_VOLUMES is set, use its value; otherwise, use "null". +MY_VOLUMES=${INPUT_VOLUMES:-"null"} +if [[ "$MY_VOLUMES" != "null" ]]; then + invalid_value=$(check_all_integers "$MY_VOLUMES") || { + exit_with_failure "Invalid volume ID: $invalid_value (must be 'null' or an integer)" + } fi # @@ -292,7 +307,7 @@ if [[ "$MY_MODE" == "delete" ]]; then echo "GitHub Actions Runner deleted successfully." echo echo "The Hetzner Cloud Server and its associated GitHub Actions Runner have been deleted successfully." - # Add GitHub Action job summary + # Add GitHub Action job summary # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-job-summary echo "The Hetzner Cloud Server and its associated GitHub Actions Runner have been deleted successfully 🗑️" >> "$GITHUB_STEP_SUMMARY" exit 0 @@ -377,23 +392,23 @@ if [[ "$MY_PRIMARY_IPV6" != "null" ]]; then jq ".public_net.ipv6 = $MY_PRIMARY_IPV6" < create-server-ipv6.json > create-server.json && \ echo "Primary IPv6 ID added to create-server.json." fi -# Add network configuration to the create-server.json file if MY_NETWORK is not "null". -if [[ "$MY_NETWORK" != "null" ]]; then +# Add network configuration to the create-server.json file if MY_NETWORKS is not "null". +if [[ "$MY_NETWORKS" != "null" ]]; then cp create-server.json create-server-network.json && \ - jq ".networks += [$MY_NETWORK]" < create-server-network.json > create-server.json && \ - echo "Network added to create-server.json." + jq ".networks += [$MY_NETWORKS]" < create-server-network.json > create-server.json && \ + echo "Networks added to create-server.json." fi -# Add SSH key configuration to the create-server.json file if MY_SSH_KEY is not "null". -if [[ "$MY_SSH_KEY" != "null" ]]; then +# Add SSH key configuration to the create-server.json file if MY_SSH_KEYS is not "null". +if [[ "$MY_SSH_KEYS" != "null" ]]; then cp create-server.json create-server-ssh.json && \ - jq ".ssh_keys += [$MY_SSH_KEY]" < create-server-ssh.json > create-server.json && \ - echo "SSH key added to create-server.json." + jq ".ssh_keys += [$MY_SSH_KEYS]" < create-server-ssh.json > create-server.json && \ + echo "SSH keys added to create-server.json." fi -# Add volume configuration to the create-server.json file if MY_VOLUME is not "null". -if [[ "$MY_VOLUME" != "null" ]]; then +# Add volume configuration to the create-server.json file if MY_VOLUMES is not "null". +if [[ "$MY_VOLUMES" != "null" ]]; then cp create-server.json create-server-volume.json && \ - jq ".volumes += [$MY_VOLUME]" < create-server-volume.json > create-server.json && \ - echo "Volume added to create-server.json." + jq ".volumes += [$MY_VOLUMES]" < create-server-volume.json > create-server.json && \ + echo "Volumes added to create-server.json." fi # Send a POST request to the Hetzner Cloud API to create a server. @@ -508,9 +523,9 @@ if [[ ! "$MY_GITHUB_RUNNER_ID" =~ ^[0-9]+$ ]]; then fi echo -echo "The Hetzner Cloud Server and its associated GitHub Actions Runner are ready for use." +echo "The Hetzner Cloud Server and its associated GitHub Actions Runner are ready for use." echo "Runner: https://github.com/${MY_GITHUB_REPOSITORY}/settings/actions/runners/${MY_GITHUB_RUNNER_ID}" -# Add GitHub Action job summary +# Add GitHub Action job summary # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-job-summary echo "The Hetzner Cloud Server and its associated [GitHub Actions Runner](https://github.com/${MY_GITHUB_REPOSITORY}/settings/actions/runners/${MY_GITHUB_RUNNER_ID}) are ready for use 🚀" >> "$GITHUB_STEP_SUMMARY" exit 0 diff --git a/action.yml b/action.yml index 8c998e2..81af4af 100644 --- a/action.yml +++ b/action.yml @@ -54,9 +54,9 @@ inputs: description: >- The name for the server and label for the GitHub Actions Runner (must be unique within the project and conform to hostname rules: '[a-zA-Z0-9_-]'). required: false - network: + networks: description: >- - Network ID (integer) which should be attached to the Server private network interface at the creation time. + Comma separated Network IDs (integer) which should be attached to the Server private network interface at the creation time. required: false default: 'null' pre_runner_script: @@ -107,14 +107,14 @@ inputs: Wait up to 'server_wait' retries (10 sec each) for the Hetzner Cloud Server to start (default: 30 = 5 min). required: false default: '30' - ssh_key: + ssh_keys: description: >- - SSH key ID (integer) or name which should be injected into the Server at creation time. + Comma separated SSH key IDs (integer) which should be injected into the Server at creation time. required: false default: 'null' - volume: + volumes: description: >- - Volume ID (integer) which should be attached to the Server at the creation time. + Comma separated Volume IDs (integer) which should be attached to the Server at the creation time. required: false default: 'null' @@ -148,7 +148,7 @@ runs: INPUT_LOCATION: ${{ inputs.location }} INPUT_MODE: ${{ inputs.mode }} INPUT_NAME: ${{ inputs.name }} - INPUT_NETWORK: ${{ inputs.network }} + INPUT_NETWORKS: ${{ inputs.networks }} INPUT_PRE_RUNNER_SCRIPT: ${{ inputs.pre_runner_script }} INPUT_PRIMARY_IPV4: ${{ inputs.primary_ipv4 }} INPUT_PRIMARY_IPV6: ${{ inputs.primary_ipv6 }} @@ -158,5 +158,5 @@ runs: INPUT_SERVER_ID: ${{ inputs.server_id }} INPUT_SERVER_TYPE: ${{ inputs.server_type }} INPUT_SERVER_WAIT: ${{ inputs.server_wait }} - INPUT_SSH_KEY: ${{ inputs.ssh_key }} - INPUT_VOLUME: ${{ inputs.volume }} + INPUT_SSH_KEYS: ${{ inputs.ssh_keys }} + INPUT_VOLUMES: ${{ inputs.volumes }} From af074ef5fb1b1f9387bdd202d31dfd1819638c90 Mon Sep 17 00:00:00 2001 From: Lucas FICHEUX Date: Thu, 26 Mar 2026 10:19:13 +0100 Subject: [PATCH 2/2] Keep the old input names --- README.md | 8 ++++---- action.yml | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e153445..e518589 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ jobs: ## Inputs > [!TIP] -> Use an SSH key ID (`ssh_keys`) to disable root password generation and Hetzner Cloud email notifications. +> Use an SSH key ID (`ssh_key`) to disable root password generation and Hetzner Cloud email notifications. | Name | Required | Description | Default | |---------------------|----------|-------------|---------| @@ -159,7 +159,7 @@ jobs: | `location` | | Name of Location to create Server in. | `nbg1` (Nürnberg 1) | | `mode` | ✓ (always) | Choose either `create` to create a new GitHub Actions Runner or `delete` to delete a previously created one. | | | `name` | ✓ (mode `delete`, optional for mode `create`) | The name for the server and label for the GitHub Actions Runner (must be unique within the project and conform to hostname rules: `^[a-zA-Z0-9_-]{1,64}`). | `gh-runner-[RANDOM-INT]` | -| `networks` | | Comma separated Network IDs (integer) which should be attached to the Server private network interface at the creation time. | `null` | +| `network` | | Comma separated Network IDs (integer) which should be attached to the Server private network interface at the creation time. | `null` | | `pre_runner_script` | | Specifies bash commands to run before the GitHub Actions Runner starts. It's useful for installing dependencies with apt-get, dnf, zypper etc. | | | `primary_ipv4` | | ID (integer) of the IPv4 Primary IP to use. If omitted and `enable_ipv4` is true, a new IPv4 Primary IP will automatically be created. | `null` | | `primary_ipv6` | | ID (integer) of the IPv6 Primary IP to use. If omitted and `enable_ipv6` is true, a new IPv6 Primary IP will automatically be created. | `null` | @@ -169,8 +169,8 @@ jobs: | `server_id` | ✓ (mode `stop`) | ID (integer) of Hetzner Cloud Server to delete. | | | `server_type` | | Name of the Server type this Server should be created with. | `cx23` (Intel x86, 2 vCPU, 4GB RAM, 40GB SSD) | | `server_wait` | | Wait up to `server_wait` retries (10 sec each) for the Hetzner Cloud Server to start. | `30` (5 min) | -| `ssh_keys` | | Comma separated SSH key IDs (integer) which should be injected into the Server at creation time. | `null` | -| `volumes` | | Comma separated Volume IDs (integer) to attach and mount to the Server during creation. Volumes will be automatically mounted at `/mnt/HC_Volume_[VOLUME-ID]`. Volumes must be in the same location as the Server. More details in [Volumes section](#Volumes). | `null` | +| `ssh_key` | | Comma separated SSH key IDs (integer) which should be injected into the Server at creation time. | `null` | +| `volume` | | Comma separated Volume IDs (integer) to attach and mount to the Server during creation. Volumes will be automatically mounted at `/mnt/HC_Volume_[VOLUME-ID]`. Volumes must be in the same location as the Server. More details in [Volumes section](#Volumes). | `null` | ## Outputs diff --git a/action.yml b/action.yml index 81af4af..b156ec5 100644 --- a/action.yml +++ b/action.yml @@ -54,7 +54,7 @@ inputs: description: >- The name for the server and label for the GitHub Actions Runner (must be unique within the project and conform to hostname rules: '[a-zA-Z0-9_-]'). required: false - networks: + network: description: >- Comma separated Network IDs (integer) which should be attached to the Server private network interface at the creation time. required: false @@ -107,12 +107,12 @@ inputs: Wait up to 'server_wait' retries (10 sec each) for the Hetzner Cloud Server to start (default: 30 = 5 min). required: false default: '30' - ssh_keys: + ssh_key: description: >- Comma separated SSH key IDs (integer) which should be injected into the Server at creation time. required: false default: 'null' - volumes: + volume: description: >- Comma separated Volume IDs (integer) which should be attached to the Server at the creation time. required: false @@ -148,7 +148,7 @@ runs: INPUT_LOCATION: ${{ inputs.location }} INPUT_MODE: ${{ inputs.mode }} INPUT_NAME: ${{ inputs.name }} - INPUT_NETWORKS: ${{ inputs.networks }} + INPUT_NETWORKS: ${{ inputs.network }} INPUT_PRE_RUNNER_SCRIPT: ${{ inputs.pre_runner_script }} INPUT_PRIMARY_IPV4: ${{ inputs.primary_ipv4 }} INPUT_PRIMARY_IPV6: ${{ inputs.primary_ipv6 }} @@ -158,5 +158,5 @@ runs: INPUT_SERVER_ID: ${{ inputs.server_id }} INPUT_SERVER_TYPE: ${{ inputs.server_type }} INPUT_SERVER_WAIT: ${{ inputs.server_wait }} - INPUT_SSH_KEYS: ${{ inputs.ssh_keys }} - INPUT_VOLUMES: ${{ inputs.volumes }} + INPUT_SSH_KEYS: ${{ inputs.ssh_key }} + INPUT_VOLUMES: ${{ inputs.volume }}