diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8c2d18a..6e6436e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,7 +7,7 @@ on:
pull_request:
jobs:
- plugin_test:
+ plugin-test:
name: asdf plugin test
strategy:
matrix:
@@ -16,7 +16,25 @@ jobs:
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- - name: asdf_plugin_test
+ - name: Run asdf plugin test
uses: asdf-vm/actions/plugin-test@v2
with:
- command: asdf-plugin-manager --version
+ command: asdf-plugin-manager version
+ - uses: actions/checkout@v3
+ - name: Install asdf-plugin-manager
+ run: |
+ asdf plugin add asdf-plugin-manager .
+ asdf install asdf-plugin-manager latest
+ asdf global asdf-plugin-manager latest
+ - name: Test asdf-plugin-manager
+ run: |
+ cd test
+ asdf-plugin-manager list
+ asdf-plugin-manager add-all
+ asdf plugin list --refs
+ - name: Validate installed plugins
+ run: |
+ set -euox pipefail
+ PLUGIN_GIT_REF=$(grep -oE "[^ ]\w{39}$" test/.plugin-versions)
+ asdf plugin list --refs | grep "${PLUGIN_GIT_REF}" &&
+ echo "[Passed] The plugin git ref in test/.plugin-versions matches the installed one."
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 454ce7a..a43fb53 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -6,6 +6,7 @@ on:
- main
permissions:
+ actions: write
contents: write
pull-requests: write
@@ -14,5 +15,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/release-please-action@v3
+ id: release
with:
release-type: simple
+ - uses: actions/checkout@v3
+ - name: Upload Release Artifact
+ if: ${{ steps.release.outputs.release_created }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ cp -a cli/asdf-plugin-manager.sh asdf-plugin-manager-${{ steps.release.outputs.tag_name }}.sh
+ gh release upload ${{ steps.release.outputs.tag_name }} asdf-plugin-manager-${{ steps.release.outputs.tag_name }}.sh
diff --git a/.github/workflows/semantic-pr.yml b/.github/workflows/semantic-pr.yml
index 8b26fa4..c32b2ae 100644
--- a/.github/workflows/semantic-pr.yml
+++ b/.github/workflows/semantic-pr.yml
@@ -1,4 +1,4 @@
-name: Lint
+name: Semantic PR
on:
pull_request_target:
diff --git a/LICENSE b/LICENSE
index de91979..7d8febb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,3 @@
-TODO: INSERT YOUR NAME COPYRIGHT YEAR (if applicable to your license)
-
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@@ -188,7 +186,7 @@ TODO: INSERT YOUR NAME COPYRIGHT YEAR (if applicable to your license)
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2023 Ahmed AbouZaid
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 29938f8..030fd45 100644
--- a/README.md
+++ b/README.md
@@ -1,59 +1,96 @@
+
# asdf-plugin-manager [![Build](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/build.yml/badge.svg)](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/build.yml) [![Lint](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/lint.yml/badge.svg)](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/lint.yml)
-[plugin-manager](https://github.com/aabouzaid/asdf-plugin-manager) plugin for the [asdf version manager](https://asdf-vm.com).
+Manage [asdf version manager](https://asdf-vm.com) plugins securely and declaratively. **(yes, this is an asdf plugin to manage asdf plugins!)**
+Using `asdf-plugin-manager`, you can set plugins Git URL and ref for security and integrity. So it's the only plugin you need to validate manually and the rest are validated via `.plugin-versions` file. Check [usage](#usage) for more details.
+
# Contents
+- [Why?](#why)
- [Dependencies](#dependencies)
- [Install](#install)
+- [Usage](#usage)
+- [Known Limitations](#known-limitations)
- [Contributing](#contributing)
- [License](#license)
-# Dependencies
+# Why?
+
+[Asdf is a great universal version manager](https://tech.aabouzaid.com/2022/01/asdf-vm-a-universal-version-manager-tools.html).
+However, it lacks a secure and declarative method to manage its plugins. For example, you cannot pin a specific asdf plugin version, which means you will be easily hacked if one of the asdf plugins you use is compromised!
+
+[Many exist requests asking to fix that](https://github.com/asdf-vm/asdf/issues/1577), but no solution has been proposed in `asdf` upstream yet! (Last check: Aug 2023)
+
+Hence, `asdf-plugin-manager` fills the gap to manage asdf plugins securely and declaratively via `.plugin-versions` file.
-**TODO: adapt this section**
-- `bash`, `curl`, `tar`: generic POSIX utilities.
-- `SOME_ENV_VAR`: set this environment variable in your shell config to load the correct version of tool x.
+# Dependencies
+
+- [asdf-vm](https://asdf-vm.com/)
+- `bash`, `cat`, `grep`: generic POSIX utilities.
+- `ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME`: Set default name for the file with the list of managed plugins.
+ Default: ".plugin-versions".
# Install
-Plugin:
+Setup plugin:
```shell
-asdf plugin add plugin-manager
-# or
-asdf plugin add plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git
+asdf plugin add asdf-plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git
+asdf update asdf-plugin-manager 1.0.0
```
-plugin-manager:
+Set asdf-plugin-manager version:
```shell
# Show all installable versions
-asdf list-all plugin-manager
+asdf list-all asdf-plugin-manager
# Install specific version
-asdf install plugin-manager latest
+asdf install asdf-plugin-manager latest
# Set a version globally (on your ~/.tool-versions file)
-asdf global plugin-manager latest
+asdf global asdf-plugin-manager latest
+
+# Now asdf-plugin-manager commands are available
+asdf-plugin-manager list
+```
+
+# Usage
+
+The `.plugin-versions` file syntax:
+
+```
+# Name Git URL Git ref (hash or version)
+venom https://github.com/aabouzaid/asdf-venom.git 2d94d17
+```
+
+And `asdf-plugin-manager` args:
-# Now plugin-manager commands are available
-asdf-plugin-manager --version
```
+asdf-plugin-manager help : Print this help message
+asdf-plugin-manager version : Print asdf-plugin-manager current version
+asdf-plugin-manager list : List managed plugins according to .plugin-versions file
+asdf-plugin-manager add : Add named plugin according to .plugin-versions file
+asdf-plugin-manager add-all : Add all plugins according to .plugin-versions file
+asdf-plugin-manager remove : Remove named plugin according to .plugin-versions file
+asdf-plugin-manager remove-all : Remove all plugins according to .plugin-versions file
+```
+
+# Known Limitations
-Check [asdf](https://github.com/asdf-vm/asdf) readme for more instructions on how to
-install & manage versions.
+Currently [asdf](https://github.com/asdf-vm/asdf) supports plugin's git-ref on the default branch only (e.g. `main`). So it's not possible to use a git-ref that's not in the default branch (this limitation will be fixed by [asdf-vm/asdf/pull/1204](https://github.com/asdf-vm/asdf/pull/1204)).
# Contributing
-Contributions of any kind welcome! See the [contributing guide](contributing.md).
+Contributions of any kind are welcome! See the [contributing guide](contributing.md).
-[Thanks goes to these contributors](https://github.com/aabouzaid/asdf-plugin-manager/graphs/contributors)!
+[Thanks go to these contributors](https://github.com/aabouzaid/asdf-plugin-manager/graphs/contributors)!
# License
diff --git a/bin/download b/bin/download
index c11ee53..068b789 100755
--- a/bin/download
+++ b/bin/download
@@ -10,14 +10,7 @@ source "${plugin_dir}/lib/utils.bash"
mkdir -p "$ASDF_DOWNLOAD_PATH"
-# TODO: Adapt this to proper extension and adapt extracting strategy.
-release_file="$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION.tar.gz"
+release_file="$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION"
-# Download tar.gz file to the download directory
+# Download release 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/latest-stable b/bin/latest-stable
index 818f26e..ea23ecd 100755
--- a/bin/latest-stable
+++ b/bin/latest-stable
@@ -11,7 +11,7 @@ plugin_dir=$(dirname "$(dirname "$current_script_path")")
curl_opts=(-sI)
if [ -n "${GITHUB_API_TOKEN:-}" ]; then
- curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
+ 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
@@ -21,9 +21,9 @@ redirect_url=$(curl "${curl_opts[@]}" "$GH_REPO/releases/latest" | sed -n -e "s|
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)"
+ version="$(list_all_versions | sort_versions | tail -n1 | xargs echo)"
else
- version="$(printf "%s\n" "$redirect_url" | sed 's|.*/tag/v\{0,1\}||')"
+ version="$(printf "%s\n" "$redirect_url" | sed 's|.*/tag/v\{0,1\}||')"
fi
printf "%s\n" "$version"
diff --git a/cli/asdf-plugin-manager.sh b/cli/asdf-plugin-manager.sh
new file mode 100755
index 0000000..f195c55
--- /dev/null
+++ b/cli/asdf-plugin-manager.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+
+set -eo pipefail
+
+VERSION=1.0.0
+PLUGIN_VERSIONS_FILENAME="${ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME:-.plugin-versions}"
+
+print_version() {
+ echo "${VERSION}"
+}
+
+print_plugin_versions_filename() {
+ echo "${PLUGIN_VERSIONS_FILENAME}"
+}
+
+print_help() {
+ cat < : Add named plugin according to .plugin-versions file
+ asdf-plugin-manager add-all : Add all plugins according to .plugin-versions file
+ asdf-plugin-manager remove : Remove named plugin according to .plugin-versions file
+ asdf-plugin-manager remove-all : Remove all plugins according to .plugin-versions file
+EOF
+}
+
+list_plugins() {
+ plugin_name=$1
+ if [[ -n ${plugin_name} ]]; then
+ grep "^${plugin_name} " "$(print_plugin_versions_filename)"
+ else
+ grep -v "^#" "$(print_plugin_versions_filename)"
+ fi
+}
+
+remove_plugins() {
+ local managed_plugins="$1"
+ echo "${managed_plugins}" | while read managed_plugin; do
+ read -r plugin_name _plugin_url _plugin_ref < <(echo ${managed_plugin})
+ echo "[INFO] Removing: ${plugin_name}"
+ asdf plugin remove "${plugin_name}" || true
+ done
+}
+
+add_plugins() {
+ local managed_plugins="$1"
+ echo "${managed_plugins}" | while read managed_plugin; do
+ read -r plugin_name plugin_url plugin_ref < <(echo ${managed_plugin})
+ echo "[INFO] Adding: ${plugin_name} ${plugin_url} ${plugin_ref}"
+ remove_plugins "$(list_plugins ${plugin_name})"
+ asdf plugin add "${plugin_name}" "${plugin_url}"
+ # TODO: Remove the plugin update once asdf supports adding plugin with git-ref.
+ # https://github.com/asdf-vm/asdf/pull/1204
+ asdf plugin update "${plugin_name}" "${plugin_ref}"
+ echo "[INFO] Done."
+ done
+}
+
+if [[ -z $1 ]]; then
+ print_help
+ exit 1
+fi
+
+while test -n "$1"; do
+ case "$1" in
+ help | -h)
+ print_help
+ exit 1
+ ;;
+ version | -v)
+ print_version
+ exit 0
+ ;;
+ list)
+ list_plugins
+ ;;
+ add)
+ add_plugins "$(list_plugins $2)"
+ ;;
+ add-all)
+ add_plugins "$(list_plugins)"
+ ;;
+ remove)
+ remove_plugins "$(list_plugins $2)"
+ ;;
+ remove-all)
+ remove_plugins "$(list_plugins)"
+ ;;
+ *)
+ echo "Unknown argument: $1"
+ print_help
+ exit 1
+ ;;
+ esac
+ shift
+done
diff --git a/contributing.md b/contributing.md
index ba5cd45..d7c4008 100644
--- a/contributing.md
+++ b/contributing.md
@@ -5,8 +5,7 @@ Testing Locally:
```shell
asdf plugin test [--asdf-tool-version ] [--asdf-plugin-gitref ] [test-command*]
-# TODO: adapt this
-asdf plugin test plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git "asdf-plugin-manager --version"
+asdf plugin test asdf-plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git "asdf-plugin-manager list"
```
Tests are automatically run in GitHub Actions on push and PR.
diff --git a/lib/utils.bash b/lib/utils.bash
index a064150..0a7e6b0 100644
--- a/lib/utils.bash
+++ b/lib/utils.bash
@@ -2,73 +2,66 @@
set -euo pipefail
-# TODO: Ensure this is the correct GitHub homepage where releases can be downloaded for plugin-manager.
GH_REPO="https://github.com/aabouzaid/asdf-plugin-manager"
-TOOL_NAME="plugin-manager"
-TOOL_TEST="asdf-plugin-manager --version"
+TOOL_NAME="asdf-plugin-manager"
+TOOL_TEST="asdf-plugin-manager list"
fail() {
- echo -e "asdf-$TOOL_NAME: $*"
- exit 1
+ echo -e "asdf-$TOOL_NAME: $*"
+ exit 1
}
curl_opts=(-fsSL)
-# NOTE: You might want to remove this if plugin-manager is not hosted on GitHub releases.
if [ -n "${GITHUB_API_TOKEN:-}" ]; then
- curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
+ 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}'
+ 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//' # NOTE: You might want to adapt this sed to remove non-version strings from tags
+ git ls-remote --tags --refs "$GH_REPO" |
+ grep -o 'refs/tags/.*' | cut -d/ -f3- | sed 's/^v//'
}
list_all_versions() {
- # TODO: Adapt this. By default we simply list the tag names from GitHub releases.
- # Change this function if plugin-manager has other means of determining installable versions.
- list_github_tags
+ list_github_tags
}
download_release() {
- local version filename url
- version="$1"
- filename="$2"
+ local version filename url
+ version="$1"
+ filename="$2"
+ url="$GH_REPO/releases/download/v${version}/asdf-plugin-manager-v${version}.sh"
- # TODO: Adapt the release URL convention for plugin-manager
- url="$GH_REPO/archive/v${version}.tar.gz"
-
- echo "* Downloading $TOOL_NAME release $version..."
- curl "${curl_opts[@]}" -o "$filename" -C - "$url" || fail "Could not download $url"
+ 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"
-
- # TODO: Assert plugin-manager executable exists.
- 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."
- )
+ 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"
+ chmod +x "$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION"
+ cp "$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION" "$install_path/$TOOL_NAME"
+
+ 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."
+ )
}
diff --git a/scripts/format.bash b/scripts/format.bash
index 1a216ea..1d1cce4 100755
--- a/scripts/format.bash
+++ b/scripts/format.bash
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
shfmt --language-dialect bash --write \
- ./**/*
+ ./**/*
diff --git a/scripts/lint.bash b/scripts/lint.bash
index 3451a05..9bb2080 100755
--- a/scripts/lint.bash
+++ b/scripts/lint.bash
@@ -1,9 +1,9 @@
#!/usr/bin/env bash
shellcheck --shell=bash --external-sources \
- bin/* --source-path=template/lib/ \
- lib/* \
- scripts/*
+ bin/* --source-path=template/lib/ \
+ lib/* \
+ scripts/*
-shfmt --language-dialect bash --diff \
- ./**/*
+shfmt -i 4 --language-dialect bash --diff \
+ ./**/*
diff --git a/test/.plugin-versions b/test/.plugin-versions
new file mode 100644
index 0000000..672b5b2
--- /dev/null
+++ b/test/.plugin-versions
@@ -0,0 +1,2 @@
+# name git-url git-ref
+venom https://github.com/aabouzaid/asdf-venom.git dea0c863f034c9935ebbfbfc0ead3c7bf90efae5