name: Setup Flux CLI description: A GitHub Action for installing the Flux CLI author: Flux project branding: color: blue icon: command inputs: version: description: "Flux version e.g. 2.0.0 (defaults to latest stable release)" required: false arch: description: "arch can be amd64, arm64 or arm" required: false deprecationMessage: "No longer required, action will now detect runner arch." plugins: description: > Plugins to install alongside Flux. One per line: `@`. Example: `mirror@0.0.1` required: false plugin-dir: description: > Directory where requested plugins are installed. This input is only used when `plugins` is set. When plugins are installed, the action exports `FLUXCD_PLUGINS` for subsequent steps. Defaults to a `plugins` directory alongside the Flux binary in $RUNNER_TOOL_CACHE. required: false bindir: description: "Alternative location for the Flux binary, defaults to path relative to $RUNNER_TOOL_CACHE." required: false token: description: "Token used to authenticate against the GitHub.com API." required: false outputs: plugin-dir: description: > Directory where the plugins were installed by the action. value: ${{ steps.set-outputs.outputs.plugin-dir }} runs: using: composite steps: - name: "Download the binary to the runner's cache dir" shell: bash id: setup-flux-bin env: VERSION: "${{ inputs.version }}" FLUX_TOOL_DIR: "${{ inputs.bindir }}" TOKEN: "${{ inputs.token }}" run: | if [[ -z "$VERSION" ]] || [[ "$VERSION" = "latest" ]]; then if [[ "${TOKEN}" != '' ]]; then VERSION=$(curl -fsSL -H "Authorization: token ${TOKEN}" https://api.github.com/repos/fluxcd/flux2/releases/latest | grep tag_name | cut -d '"' -f 4) else VERSION=$(curl -w "%{url_effective}\n" -IsSL https://github.com/fluxcd/flux2/releases/latest -o /dev/null | sed 's$^.*/$$') fi fi if [[ -z "$VERSION" ]]; then echo "Unable to determine Flux CLI version" exit 1 fi if [[ $VERSION = v* ]]; then VERSION="${VERSION:1}" fi echo "installed-flux-version=$VERSION" >> "$GITHUB_OUTPUT" OS=$(echo "${RUNNER_OS}" | tr '[:upper:]' '[:lower:]') if [[ "$OS" == "macos" ]]; then OS="darwin" fi echo "os=$OS" >> "$GITHUB_OUTPUT" ARCH=$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]') if [[ "$ARCH" == "x64" ]]; then ARCH="amd64" elif [[ "$ARCH" == "x86" ]]; then ARCH="386" fi echo "arch=$ARCH" >> "$GITHUB_OUTPUT" FLUX_EXEC_FILE="flux" if [[ "$OS" == "windows" ]]; then FLUX_EXEC_FILE="${FLUX_EXEC_FILE}.exe" fi if [[ -z "$FLUX_TOOL_DIR" ]]; then FLUX_TOOL_DIR="${RUNNER_TOOL_CACHE}/flux2/${VERSION}/${OS}/${ARCH}" fi if [[ ! -x "$FLUX_TOOL_DIR/$FLUX_EXEC_FILE" ]]; then DL_DIR="$(mktemp -dt flux2-XXXXXX)" trap 'rm -rf $DL_DIR' EXIT echo "Downloading flux ${VERSION} for ${OS}/${ARCH}" FLUX_TARGET_FILE="flux_${VERSION}_${OS}_${ARCH}.tar.gz" if [[ "$OS" == "windows" ]]; then FLUX_TARGET_FILE="flux_${VERSION}_${OS}_${ARCH}.zip" fi FLUX_CHECKSUMS_FILE="flux_${VERSION}_checksums.txt" FLUX_DOWNLOAD_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/" MAX_RETRIES=5 RETRY_DELAY=5 for i in $(seq 1 $MAX_RETRIES); do echo "Downloading flux binary (attempt $i/$MAX_RETRIES)" if curl -fsSL -o "$DL_DIR/$FLUX_TARGET_FILE" "$FLUX_DOWNLOAD_URL/$FLUX_TARGET_FILE"; then break fi if [ $i -lt $MAX_RETRIES ]; then echo "Download failed, retrying in ${RETRY_DELAY} seconds..." sleep $RETRY_DELAY else echo "Failed to download flux binary after $MAX_RETRIES attempts" exit 1 fi done for i in $(seq 1 $MAX_RETRIES); do echo "Downloading checksums file (attempt $i/$MAX_RETRIES)" if curl -fsSL -o "$DL_DIR/$FLUX_CHECKSUMS_FILE" "$FLUX_DOWNLOAD_URL/$FLUX_CHECKSUMS_FILE"; then break fi if [ $i -lt $MAX_RETRIES ]; then echo "Download failed, retrying in ${RETRY_DELAY} seconds..." sleep $RETRY_DELAY else echo "Failed to download checksums file after $MAX_RETRIES attempts" exit 1 fi done echo "Verifying checksum" sum="" if command -v openssl > /dev/null; then sum=$(openssl sha256 "$DL_DIR/$FLUX_TARGET_FILE" | awk '{print $2}') elif command -v sha256sum > /dev/null; then sum=$(sha256sum "$DL_DIR/$FLUX_TARGET_FILE" | awk '{print $1}') fi if [[ -z "$sum" ]]; then echo "Neither openssl nor sha256sum found. Cannot calculate checksum." exit 1 fi expected_sum=$(grep " $FLUX_TARGET_FILE\$" "$DL_DIR/$FLUX_CHECKSUMS_FILE" | awk '{print $1}') if [ "$sum" != "$expected_sum" ]; then echo "SHA sum of ${FLUX_TARGET_FILE} does not match. Aborting." exit 1 fi echo "Installing flux to ${FLUX_TOOL_DIR}" mkdir -p "$FLUX_TOOL_DIR" if [[ "$OS" == "windows" ]]; then unzip "$DL_DIR/$FLUX_TARGET_FILE" "$FLUX_EXEC_FILE" -d "$FLUX_TOOL_DIR" else tar xzf "$DL_DIR/$FLUX_TARGET_FILE" -C "$FLUX_TOOL_DIR" $FLUX_EXEC_FILE fi chmod +x "$FLUX_TOOL_DIR/$FLUX_EXEC_FILE" fi echo "Adding flux to path" echo "$FLUX_TOOL_DIR" >> "$GITHUB_PATH" - name: "Print installed flux version" shell: bash run: | flux -v - name: "Plugin support gate" id: plugin-support-gate shell: bash if: inputs.plugins != '' run: | flux_version="$(flux -v 2>/dev/null | awk '{print $3}')" if flux plugin --help >/dev/null 2>&1; then echo "plugin-support=yes" >> "$GITHUB_OUTPUT" exit 0 else echo "plugin-support=no" >> "$GITHUB_OUTPUT" msg="Installed Flux version ${flux_version:-unknown} does not support plugins; need >= 2.9.0. Requested plugins cannot be installed." echo "::error title=Unsupported Flux version::$msg" echo "> [!CAUTION]" >> $GITHUB_STEP_SUMMARY echo "> $msg" >> $GITHUB_STEP_SUMMARY exit 1 fi - name: "Setup Plugins Dir" shell: bash if: steps.plugin-support-gate.outputs.plugin-support == 'yes' env: FLUXCD_PLUGINS: ${{ inputs.plugin-dir }} VERSION: ${{ steps.setup-flux-bin.outputs.installed-flux-version }} OS: ${{ steps.setup-flux-bin.outputs.os }} ARCH: ${{ steps.setup-flux-bin.outputs.arch }} run: | # Use a default plugin directory when plugin-dir was not provided. if [[ -z "$FLUXCD_PLUGINS" ]]; then FLUXCD_PLUGINS="${RUNNER_TOOL_CACHE}/flux2/${VERSION}/${OS}/${ARCH}/plugins/" fi # Export it so subsequent steps can discover the installed plugins. echo "FLUXCD_PLUGINS=$FLUXCD_PLUGINS" >> "$GITHUB_ENV" # Create the directory if it does not exist. mkdir -p "$FLUXCD_PLUGINS" - name: "Install Plugins" shell: bash id: install-plugins if: steps.plugin-support-gate.outputs.plugin-support == 'yes' env: PLUGINS: ${{ inputs.plugins }} run: | echo "$PLUGINS" | while read -r PLUGIN; do trimmed="${PLUGIN//[[:space:]]/}" if [[ -n "$trimmed" ]]; then echo Installing: "$PLUGIN" flux plugin install "$PLUGIN" fi done - name: "Set Output" id: set-outputs if: steps.plugin-support-gate.outputs.plugin-support == 'yes' shell: bash run: | echo "plugin-dir=$FLUXCD_PLUGINS" >> "$GITHUB_OUTPUT"