diff --git a/.github/workflows/action.yaml b/.github/workflows/action.yaml index e19c3130..a3f3950e 100644 --- a/.github/workflows/action.yaml +++ b/.github/workflows/action.yaml @@ -27,3 +27,41 @@ jobs: uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Setup flux uses: ./action + + plugins: + runs-on: ubuntu-latest + name: action plugins on ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - name: Setup Go + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + with: + go-version-file: go.mod + cache-dependency-path: go.sum + - name: Build flux + shell: bash + run: | + set -euo pipefail + mkdir -p cmd/flux/manifests "$RUNNER_TEMP/flux-bin" + printf "apiVersion: v1\nkind: List\nitems: []\n" > cmd/flux/manifests/dummy.yaml + CGO_ENABLED=0 go build -ldflags="-s -w -X main.VERSION=0.0.0-pr" -o "$RUNNER_TEMP/flux-bin/flux" ./cmd/flux + - name: Setup flux with plugin + id: setup + uses: ./action + with: + version: 0.0.0-pr + bindir: ${{ runner.temp }}/flux-bin + plugins: | + mirror@sha256:91a1e04c2015ee66b1633e362cdb6d4550891b91bf3391a83414b9e9912e53f1 + - name: Assert plugin installation + shell: bash + env: + ACTION_PLUGIN_DIR: ${{ steps.setup.outputs['plugin-dir'] }} + run: | + set -euo pipefail + test -n "${FLUXCD_PLUGINS:-}" + test "$ACTION_PLUGIN_DIR" = "$FLUXCD_PLUGINS" + test -x "$FLUXCD_PLUGINS/flux-mirror" + flux plugin list + flux mirror --help diff --git a/action/README.md b/action/README.md index d511dc9c..0a09132f 100644 --- a/action/README.md +++ b/action/README.md @@ -12,6 +12,26 @@ steps: run: flux version --client ``` +To install Flux plugins alongside the CLI: + +```yaml +steps: + - name: Setup Flux CLI + uses: fluxcd/flux2/action@main + with: + plugins: | + mirror@0.0.1 + - name: Run Flux plugin + run: flux mirror --help +``` + +Installing plugins requires a Flux version with plugin support (v2.9.0 or later). +The `plugins` input accepts one plugin per line in ``, +`@`, or `@` format. Entries without a version or +digest install the latest version from the catalog. The `plugin-dir` input is +only used when `plugins` is set; when plugins are installed, the action exports +`FLUXCD_PLUGINS` for subsequent steps. + The Flux GitHub Action can be used to automate various tasks in CI, such as: - [Automate Flux upgrades on clusters via Pull Requests](https://fluxcd.io/flux/flux-gh-action/#automate-flux-updates) diff --git a/action/action.yml b/action/action.yml index 5642ccfd..330166f7 100644 --- a/action/action.yml +++ b/action/action.yml @@ -12,17 +12,36 @@ inputs: 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: ``, `@` or + `@`. Entries without a version or digest install the latest + version from the catalog. 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 }}" @@ -42,11 +61,13 @@ runs: 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 @@ -54,6 +75,7 @@ runs: elif [[ "$ARCH" == "x86" ]]; then ARCH="386" fi + echo "arch=$ARCH" >> "$GITHUB_OUTPUT" FLUX_EXEC_FILE="flux" if [[ "$OS" == "windows" ]]; then @@ -63,7 +85,7 @@ runs: 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 + if [[ ! -x "$FLUX_TOOL_DIR/$FLUX_EXEC_FILE" ]]; then DL_DIR="$(mktemp -dt flux2-XXXXXX)" trap 'rm -rf $DL_DIR' EXIT @@ -79,7 +101,7 @@ runs: 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 @@ -93,7 +115,7 @@ runs: 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 @@ -107,7 +129,7 @@ runs: exit 1 fi done - + echo "Verifying checksum" sum="" if command -v openssl > /dev/null; then @@ -129,7 +151,7 @@ runs: 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 @@ -146,3 +168,63 @@ runs: 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"