From f1cd1be14d6dc0dd8566304af2cb1c52bfdd86b1 Mon Sep 17 00:00:00 2001 From: Maximilian Jugl Date: Wed, 22 Apr 2026 09:36:58 +0200 Subject: [PATCH] feat: initial --- .forgejo/workflows/test.yaml | 30 ++++++ .gitignore | 201 +++++++++++++++++++++++++++++++++++ .prettierrc | 3 + .vscode/settings.json | 5 + README.md | 29 +++++ action.yml | 143 +++++++++++++++++++++++++ package-lock.json | 28 +++++ package.json | 5 + 8 files changed, 444 insertions(+) create mode 100644 .forgejo/workflows/test.yaml create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 action.yml create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml new file mode 100644 index 0000000..3fdbae6 --- /dev/null +++ b/.forgejo/workflows/test.yaml @@ -0,0 +1,30 @@ +name: Test action + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + - reopened + +jobs: + test: + name: Test on ${{ matrix.image }} + runs-on: stackit-docker + strategy: + fail-fast: false + matrix: + image: + - registry.onstackit.cloud/devex-images/ubuntu:act-latest + - registry.onstackit.cloud/devex-images/alpine:latest + container: + image: ${{ matrix.image }} + steps: + - uses: actions/checkout@v6 + - name: Test action + uses: ./ + with: + version: "v0.61.0" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3596329 --- /dev/null +++ b/.gitignore @@ -0,0 +1,201 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.* +!.env.example + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist +.output + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp directory +.temp + +# Sveltekit cache directory +.svelte-kit/ + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Firebase cache directory +.firebase/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# pnpm +.pnpm-store + +# yarn v3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Vite files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +.vite/ + +# General +.DS_Store +.localized +__MACOSX/ +.AppleDouble +.LSOverride +Icon[ ] + +# Resource forks +._* + +# Files and directories that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.com.apple.timemachine.supported +.PKInstallSandboxManager +.PKInstallSandboxManager-SystemSoftware +.hotfiles.btree +.vol +.file +.disk_label* +lost+found +.HFS+ Private Directory Data[ ] + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Mac OS 6 to 9 +Desktop DB +Desktop DF +TheFindByContentFolder +TheVolumeSettingsFolder +.FBCIndex +.FBCSemaphoreFile +.FBCLockFolder + +# Quota system +.quota.group +.quota.user +.quota.ops.group +.quota.ops.user + +# TimeMachine +Backups.backupdb +.MobileBackups +.MobileBackups.trash +MobileBackups.trash +tmbootpicker.efi diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..963354f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 120 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..100de18 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.tabSize": 2 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e20448f --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Install STACKIT CLI Action + +This GitHub Action installs the STACKIT CLI on a GitHub Actions runner. It is designed to be compatible with both Ubuntu (apt-get) and Alpine Linux (apk) environments. + +## Usage + +To use this action in your workflow, reference it as a step. You can optionally specify a version. + +### Simple usage + +```yaml +- name: Install STACKIT CLI + uses: https://stackit-solutions.git.onstackit.cloud/actions/install-stackit-cli@v1 +``` + +### Usage with a specific version + +```yaml +- name: Install STACKIT CLI + uses: https://stackit-solutions.git.onstackit.cloud/actions/install-stackit-cli@v1 + with: + version: "v0.61.0" +``` + +## Inputs + +| Name | Description | Required | Default | +| ------- | --------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | +| version | The specific version of STACKIT CLI to install (e.g., v0.61.0). If left empty, the latest stable version will be installed. | No | "" | diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..0ef3142 --- /dev/null +++ b/action.yml @@ -0,0 +1,143 @@ +name: "Install STACKIT CLI" +description: "Installs the STACKIT CLI application." +inputs: + version: + description: "Version of STACKIT CLI to install, e.g. v0.59.0. If left empty, the latest version will be installed." + required: false + default: "" + +runs: + using: "composite" + steps: + - name: Install requirements + shell: sh # alpine may not have bash pre-installed + run: | + set -e + + if command -v curl >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then + echo "curl and jq are already installed, skipping installation." + else + if command -v apt-get >/dev/null 2>&1; then + apt-get -y update + apt-get -y install curl jq + elif command -v apk >/dev/null 2>&1; then + apk add --no-cache curl jq bash + else + echo "::error::No supported package manager (apt-get, apk) found." + exit 1 + fi + fi + - name: Install STACKIT CLI + shell: bash + env: + STACKIT_CLI_VERSION: ${{ inputs.version }} + run: | + set -eo pipefail + + REPO="stackitcloud/stackit-cli" + + OS="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + + if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then + ARCH="amd64" + elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then + ARCH="arm64" + fi + + CACHE_BASE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}/stackit-cli" + + # try to load stackit cli from hosted tools cache + if [ -n "$STACKIT_CLI_VERSION" ]; then + TOOL_CACHE_FILE="$CACHE_BASE/$STACKIT_CLI_VERSION/$ARCH/stackit" + + # if file exists in hosted tools cache, symlink it + if [ -x "$TOOL_CACHE_FILE" ]; then + echo "::group::Linking from hosted tool cache" + ln -sf "$TOOL_CACHE_FILE" /usr/local/bin/stackit + echo "::endgroup::" + exit 0 + fi + fi + + echo "::group::Determining STACKIT CLI version" + # if no version is provided, use latest + if [ -z "$STACKIT_CLI_VERSION" ]; then + API_URL="https://api.github.com/repos/$REPO/releases/latest" + else + API_URL="https://api.github.com/repos/$REPO/releases/tags/$STACKIT_CLI_VERSION" + fi + + RELEASES_JSON="$(curl -s "$API_URL")" + VERSION="$(echo "$RELEASES_JSON" | jq -r '.tag_name')" + + if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then + echo "Failed to fetch release information. Please check if the version exists." + exit 1 + fi + + echo "Installing STACKIT CLI $VERSION" + echo "::endgroup::" + + # check if latest binary is already present on this runner + TOOL_CACHE_DIR="$CACHE_BASE/$VERSION/$ARCH" + TOOL_CACHE_FILE="$TOOL_CACHE_DIR/stackit" + + if [ -x "$TOOL_CACHE_FILE" ]; then + echo "::group::Linking from hosted tool cache" + ln -sf "$TOOL_CACHE_FILE" /usr/local/bin/stackit + echo "::endgroup::" + exit 0 + fi + + # prepare binary download + DOWNLOAD_DIR="$(mktemp -d)" + + # always delete download dir when script exits + trap 'rm -rf "$DOWNLOAD_DIR"' EXIT + + cd "$DOWNLOAD_DIR" + + RELEASE_ASSET="$(echo "$RELEASES_JSON" | jq -r --arg os "$OS" --arg arch "$ARCH" \ + '.assets[] | select(.name | endswith($os + "_" + $arch + ".tar.gz"))')" + + if [ -z "$RELEASE_ASSET" ] || [ "$RELEASE_ASSET" = "null" ]; then + echo "No matching release found for OS=$OS, ARCH=$ARCH." + exit 1 + fi + + ARCHIVE_NAME="$(echo "$RELEASE_ASSET" | jq -r '.name')" + ARCHIVE_DOWNLOAD_URL="$(echo "$RELEASE_ASSET" | jq -r '.browser_download_url')" + + CHECKSUMS_DOWNLOAD_URL="$(echo "$RELEASES_JSON" | jq -r '.assets[] | select(.name | contains("checksums.txt")) | .browser_download_url')" + CHECKSUMS="checksums.txt" + + if [ -z "$CHECKSUMS_DOWNLOAD_URL" ] || [ "$CHECKSUMS_DOWNLOAD_URL" = "null" ]; then + echo "No checksum file available in release assets." + exit 1 + fi + + echo "::group::Downloading assets and verifying integrity" + # download binary and checksums (-f for fail fast) + curl -fLO "$ARCHIVE_DOWNLOAD_URL" + curl -fLo "$CHECKSUMS" "$CHECKSUMS_DOWNLOAD_URL" + + grep "$ARCHIVE_NAME" "$CHECKSUMS" | sha256sum -c - + echo "::endgroup::" + + echo "::group::Installing into hosted tool cache" + mkdir stackit-cli + tar -xzvf "$ARCHIVE_NAME" -C stackit-cli + + # save to tool cache + mkdir -p "$TOOL_CACHE_DIR" + mv ./stackit-cli/stackit "$TOOL_CACHE_FILE" + + # symlink + ln -sf "$TOOL_CACHE_FILE" /usr/local/bin/stackit + echo "::endgroup::" + + cd "$GITHUB_WORKSPACE" + - name: Print version + shell: sh + run: stackit --version diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0d1ebb1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "install-stackit-cli", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "prettier": "^3.8.3" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c689305 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "prettier": "^3.8.3" + } +}