diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..16bec6a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+root = true
+
+[*]
+indent_style = tab
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{md,yml,yaml}]
+indent_style = space
+indent_size = 2
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..83f93ac
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,27 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ""
+labels: bug
+assignees: ""
+---
+
+**Describe the bug**
+
+
+
+**Steps to reproduce**
+
+
+
+**Expected behavior**
+
+
+
+**Screenshots**
+
+
+
+**Additional context**
+
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..f52b3b9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,23 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ""
+labels: enhancement
+assignees: ""
+---
+
+**Is your feature request related to a problem? Please describe.**
+
+
+
+**Describe the solution you'd like**
+
+
+
+**Describe alternatives you've considered**
+
+
+
+**Additional context**
+
+
diff --git a/.github/PULL_REQUEST/pull_request_template.md b/.github/PULL_REQUEST/pull_request_template.md
new file mode 100644
index 0000000..a32de42
--- /dev/null
+++ b/.github/PULL_REQUEST/pull_request_template.md
@@ -0,0 +1,34 @@
+
+
+## Description
+
+
+
+## Motivation and Context
+
+
+
+
+## Types of changes
+
+
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to change)
+
+## Usage examples
+
+
+
+## How Has This Been Tested?
+
+
+
+## Checklist
+
+
+
+
+- [ ] I have updated the documentation accordingly.
+- [ ] I have added tests to cover my changes.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..5ace460
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..894f757
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,22 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ plugin_test:
+ name: asdf plugin test
+ strategy:
+ matrix:
+ os:
+ - ubuntu-latest
+ - macos-latest
+ runs-on: ${{ matrix.os }}
+ steps:
+ - name: asdf_plugin_test
+ uses: asdf-vm/actions/plugin-test@v2
+ with:
+ command: apko --help
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..5c3ffed
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,24 @@
+name: Lint
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: asdf-vm/actions/install@v2
+ - run: scripts/lint.bash
+
+ actionlint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Check workflow files
+ uses: docker://rhysd/actionlint:1.6.23
+ with:
+ args: -color
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..454ce7a
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,18 @@
+name: Release
+
+on:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ release-please:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: GoogleCloudPlatform/release-please-action@v3
+ with:
+ release-type: simple
diff --git a/.github/workflows/semantic-pr.yml b/.github/workflows/semantic-pr.yml
new file mode 100644
index 0000000..8b26fa4
--- /dev/null
+++ b/.github/workflows/semantic-pr.yml
@@ -0,0 +1,18 @@
+name: Lint
+
+on:
+ pull_request_target:
+ types:
+ - opened
+ - edited
+ - synchronize
+
+jobs:
+ semantic-pr:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: amannn/action-semantic-pull-request@v5.2.0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ validateSingleCommit: true
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 0000000..3d11f88
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1,2 @@
+shellcheck 0.9.0
+shfmt 3.6.0
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..aee1c60
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024-present Claudio Beatrice
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..162d2ba
--- /dev/null
+++ b/README.md
@@ -0,0 +1,57 @@
+
+
+# asdf-apko [![Build](https://github.com/omissis/asdf-apko/actions/workflows/build.yml/badge.svg)](https://github.com/omissis/asdf-apko/actions/workflows/build.yml) [![Lint](https://github.com/omissis/asdf-apko/actions/workflows/lint.yml/badge.svg)](https://github.com/omissis/asdf-apko/actions/workflows/lint.yml)
+
+[apko](https://github.com/chainguard-dev/apko/tree/main/docs) plugin for the [asdf version manager](https://asdf-vm.com).
+
+
+
+# Contents
+
+- [Dependencies](#dependencies)
+- [Install](#install)
+- [Contributing](#contributing)
+- [License](#license)
+
+# Dependencies
+
+- `melange`: while not strictly required, apko needs apks built by melange in order to package them into an image
+
+# Install
+
+Plugin:
+
+```shell
+asdf plugin add apko
+# or
+asdf plugin add apko https://github.com/omissis/asdf-apko.git
+```
+
+apko:
+
+```shell
+# Show all installable versions
+asdf list-all apko
+
+# Install specific version
+asdf install apko latest
+
+# Set a version globally (on your ~/.tool-versions file)
+asdf global apko latest
+
+# Now apko commands are available
+apko --help
+```
+
+Check [asdf](https://github.com/asdf-vm/asdf) readme for more instructions on how to
+install & manage versions.
+
+# Contributing
+
+Contributions of any kind welcome! See the [contributing guide](contributing.md).
+
+[Thanks goes to these contributors](https://github.com/omissis/asdf-apko/graphs/contributors)!
+
+# License
+
+See [LICENSE](LICENSE) © [Claudio Beatrice](https://github.com/omissis/)
diff --git a/bin/download b/bin/download
new file mode 100755
index 0000000..38c6411
--- /dev/null
+++ b/bin/download
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+current_script_path=${BASH_SOURCE[0]}
+plugin_dir=$(dirname "$(dirname "$current_script_path")")
+
+# shellcheck source=./lib/utils.bash
+source "${plugin_dir}/lib/utils.bash"
+
+mkdir -p "$ASDF_DOWNLOAD_PATH"
+
+release_file="$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION.tar.gz"
+
+# Download tar.gz file to the download directory
+download_release "$ASDF_INSTALL_VERSION" "$release_file"
+
+# Extract contents of tar.gz file into the download directory
+tar -xzf "$release_file" -C "$ASDF_DOWNLOAD_PATH" --strip-components=1 || fail "Could not extract $release_file"
+
+# Remove the tar.gz file since we don't need to keep it
+rm "$release_file"
diff --git a/bin/install b/bin/install
new file mode 100755
index 0000000..6ca759a
--- /dev/null
+++ b/bin/install
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+current_script_path=${BASH_SOURCE[0]}
+plugin_dir=$(dirname "$(dirname "$current_script_path")")
+
+# shellcheck source=./lib/utils.bash
+source "${plugin_dir}/lib/utils.bash"
+
+install_version "$ASDF_INSTALL_TYPE" "$ASDF_INSTALL_VERSION" "$ASDF_INSTALL_PATH"
diff --git a/bin/latest-stable b/bin/latest-stable
new file mode 100755
index 0000000..818f26e
--- /dev/null
+++ b/bin/latest-stable
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+current_script_path=${BASH_SOURCE[0]}
+plugin_dir=$(dirname "$(dirname "$current_script_path")")
+
+# shellcheck source=./lib/utils.bash
+. "${plugin_dir}/lib/utils.bash"
+
+curl_opts=(-sI)
+
+if [ -n "${GITHUB_API_TOKEN:-}" ]; then
+ curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
+fi
+
+# curl of REPO/releases/latest is expected to be a 302 to another URL
+# when no releases redirect_url="REPO/releases"
+# when there are releases redirect_url="REPO/releases/tag/v"
+redirect_url=$(curl "${curl_opts[@]}" "$GH_REPO/releases/latest" | sed -n -e "s|^location: *||p" | sed -n -e "s|\r||p")
+version=
+printf "redirect url: %s\n" "$redirect_url" >&2
+if [[ "$redirect_url" == "$GH_REPO/releases" ]]; then
+ version="$(list_all_versions | sort_versions | tail -n1 | xargs echo)"
+else
+ version="$(printf "%s\n" "$redirect_url" | sed 's|.*/tag/v\{0,1\}||')"
+fi
+
+printf "%s\n" "$version"
diff --git a/bin/list-all b/bin/list-all
new file mode 100755
index 0000000..9b8b666
--- /dev/null
+++ b/bin/list-all
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+current_script_path=${BASH_SOURCE[0]}
+plugin_dir=$(dirname "$(dirname "$current_script_path")")
+
+# shellcheck source=./lib/utils.bash
+source "${plugin_dir}/lib/utils.bash"
+
+list_all_versions | sort_versions | xargs echo
diff --git a/contributing.md b/contributing.md
new file mode 100644
index 0000000..61f4bbf
--- /dev/null
+++ b/contributing.md
@@ -0,0 +1,11 @@
+# Contributing
+
+Testing Locally:
+
+```shell
+asdf plugin test [--asdf-tool-version ] [--asdf-plugin-gitref ] [test-command*]
+
+asdf plugin test apko https://github.com/omissis/asdf-apko.git "apko --help"
+```
+
+Tests are automatically run in GitHub Actions on push and PR.
diff --git a/lib/utils.bash b/lib/utils.bash
new file mode 100644
index 0000000..e7b8faa
--- /dev/null
+++ b/lib/utils.bash
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+GH_REPO="https://github.com/chainguard-dev/apko"
+TOOL_NAME="apko"
+TOOL_TEST="apko --help"
+
+fail() {
+ echo -e "asdf-$TOOL_NAME: $*"
+ exit 1
+}
+
+curl_opts=(-fsSL)
+
+if [ -n "${GITHUB_API_TOKEN:-}" ]; then
+ curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
+fi
+
+sort_versions() {
+ sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z\1/; s/$/.z/; G; s/\n/ /' |
+ LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}'
+}
+
+list_github_tags() {
+ git ls-remote --tags --refs "$GH_REPO" |
+ grep -o 'refs/tags/.*' | cut -d/ -f3- |
+ sed 's/^v//'
+}
+
+list_all_versions() {
+ list_github_tags
+}
+
+download_release() {
+ local version filename url
+ version="$1"
+ filename="$2"
+
+ url="$GH_REPO/releases/download/v${version}/apko_${version}_$(get_platform)_$(get_arch).tar.gz"
+
+ echo "* Downloading $TOOL_NAME release $version..."
+ curl "${curl_opts[@]}" -o "$filename" -C - "$url" || fail "Could not download $url"
+}
+
+install_version() {
+ local install_type="$1"
+ local version="$2"
+ local install_path="${3%/bin}/bin"
+
+ if [ "$install_type" != "version" ]; then
+ fail "asdf-$TOOL_NAME supports release installs only"
+ fi
+
+ (
+ mkdir -p "$install_path"
+ cp -r "$ASDF_DOWNLOAD_PATH"/* "$install_path"
+
+ local tool_cmd
+ tool_cmd="$(echo "$TOOL_TEST" | cut -d' ' -f1)"
+ test -x "$install_path/$tool_cmd" || fail "Expected $install_path/$tool_cmd to be executable."
+
+ echo "$TOOL_NAME $version installation was successful!"
+ ) || (
+ rm -rf "$install_path"
+ fail "An error occurred while installing $TOOL_NAME $version."
+ )
+}
+
+get_platform() {
+ uname | tr '[:upper:]' '[:lower:]'
+}
+
+get_arch() {
+ local arch=""
+
+ case "$(uname -m)" in
+ x86_64|amd64) arch="amd64"; ;;
+ i686|i386) arch="386"; ;;
+ armv6l) arch="armv6"; ;;
+ armv7l) arch="armv7"; ;;
+ aarch64|arm64) arch="arm64"; ;;
+ ppc64le) arch="ppc64le"; ;;
+ *)
+ echo "Arch '$(uname -m)' not supported!" >&2
+ exit 1
+ ;;
+ esac
+
+ echo -n $arch
+}
diff --git a/scripts/format.bash b/scripts/format.bash
new file mode 100755
index 0000000..1a216ea
--- /dev/null
+++ b/scripts/format.bash
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+shfmt --language-dialect bash --write \
+ ./**/*
diff --git a/scripts/lint.bash b/scripts/lint.bash
new file mode 100755
index 0000000..3451a05
--- /dev/null
+++ b/scripts/lint.bash
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+shellcheck --shell=bash --external-sources \
+ bin/* --source-path=template/lib/ \
+ lib/* \
+ scripts/*
+
+shfmt --language-dialect bash --diff \
+ ./**/*
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..e69de29