From eb70e7802074588a0918318a4bc8c2d858314f39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:47:30 +0000 Subject: [PATCH 1/2] Initial plan From 6911d02813e690a8d288d52302ad1e6baa843d4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:52:22 +0000 Subject: [PATCH 2/2] Add avivsinai/bitbucket-cli feature Agent-Logs-Url: https://github.com/devcontainer-community/devcontainer-features/sessions/c85ba519-c205-460a-be94-69ea5e7d2180 Co-authored-by: sebst <592313+sebst@users.noreply.github.com> --- README.md | 1 + src/avivsinai-bitbucket-cli/NOTES.md | 17 ++ .../devcontainer-feature.json | 17 ++ src/avivsinai-bitbucket-cli/install.sh | 161 ++++++++++++++++++ test/avivsinai-bitbucket-cli/test.sh | 14 ++ 5 files changed, 210 insertions(+) create mode 100644 src/avivsinai-bitbucket-cli/NOTES.md create mode 100644 src/avivsinai-bitbucket-cli/devcontainer-feature.json create mode 100755 src/avivsinai-bitbucket-cli/install.sh create mode 100755 test/avivsinai-bitbucket-cli/test.sh diff --git a/README.md b/README.md index 86ebc87..2540050 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ | [asdf-vm.com](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/asdf-vm.com) | `asdf` — multi-runtime version manager | gh release | 1.0.2 | | [astral.sh/uv](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/astral.sh-uv) | `uv`/`uvx` — fast Python package and project manager | gh release | 1.0.4 | | [atuin.sh](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/atuin.sh) | `atuin` — shell history sync and search | gh release | 1.0.3 | +| [avivsinai/bitbucket-cli](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/avivsinai-bitbucket-cli) | `bkt` — CLI for Bitbucket | gh release | 1.0.0 | | [AWS CLI](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/aws-cli) | `aws` — official AWS command-line interface | curl | 1.1.2 | | [basecamp/fizzy-cli](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/basecamp-fizzy-cli) | `fizzy` — CLI for Basecamp | gh release | 1.0.1 | | [bat](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/bat) | `bat` — cat with syntax highlighting and git integration | gh release | 1.0.1 | diff --git a/src/avivsinai-bitbucket-cli/NOTES.md b/src/avivsinai-bitbucket-cli/NOTES.md new file mode 100644 index 0000000..5291370 --- /dev/null +++ b/src/avivsinai-bitbucket-cli/NOTES.md @@ -0,0 +1,17 @@ +# avivsinai/bitbucket-cli + +## Project + +- [avivsinai/bitbucket-cli](https://github.com/avivsinai/bitbucket-cli) + +## Description + +`bkt` is a command-line interface for Bitbucket. It allows developers to interact with Bitbucket repositories, pull requests, and other resources directly from the terminal. + +## Installation Method + +Downloaded as a pre-compiled binary from the [GitHub releases page](https://github.com/avivsinai/bitbucket-cli/releases) and placed in `/usr/local/bin`. + +## Other Notes + +_No additional notes._ diff --git a/src/avivsinai-bitbucket-cli/devcontainer-feature.json b/src/avivsinai-bitbucket-cli/devcontainer-feature.json new file mode 100644 index 0000000..1cedbb5 --- /dev/null +++ b/src/avivsinai-bitbucket-cli/devcontainer-feature.json @@ -0,0 +1,17 @@ +{ + "name": "avivsinai/bitbucket-cli", + "id": "avivsinai-bitbucket-cli", + "version": "1.0.0", + "description": "bkt — CLI for Bitbucket", + "documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/avivsinai-bitbucket-cli", + "options": { + "version": { + "type": "string", + "default": "latest", + "proposals": [ + "latest" + ], + "description": "Version of \"bkt\" to install." + } + } +} diff --git a/src/avivsinai-bitbucket-cli/install.sh b/src/avivsinai-bitbucket-cli/install.sh new file mode 100755 index 0000000..9262fdc --- /dev/null +++ b/src/avivsinai-bitbucket-cli/install.sh @@ -0,0 +1,161 @@ +#!/bin/bash +set -o errexit +set -o pipefail +set -o noclobber +set -o nounset +set -o allexport +readonly githubRepository='avivsinai/bitbucket-cli' +readonly binaryName='bkt' +readonly versionArgument='--version' +readonly binaryTargetFolder='/usr/local/bin' +readonly name="${githubRepository##*/}" +apt_get_update() { + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} +apt_get_checkinstall() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + apt_get_update + DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends --no-install-suggests --option 'Debug::pkgProblemResolver=true' --option 'Debug::pkgAcquire::Worker=1' "$@" + fi +} +apt_get_cleanup() { + apt-get clean + rm -rf /var/lib/apt/lists/* +} +check_curl_envsubst_file_tar_installed() { + declare -a requiredAptPackagesMissing=() + if ! [ -r '/etc/ssl/certs/ca-certificates.crt' ]; then + requiredAptPackagesMissing+=('ca-certificates') + fi + if ! command -v curl >/dev/null 2>&1; then + requiredAptPackagesMissing+=('curl') + fi + if ! command -v envsubst >/dev/null 2>&1; then + requiredAptPackagesMissing+=('gettext-base') + fi + if ! command -v file >/dev/null 2>&1; then + requiredAptPackagesMissing+=('file') + fi + if ! command -v tar >/dev/null 2>&1; then + requiredAptPackagesMissing+=('tar') + fi + declare -i requiredAptPackagesMissingCount=${#requiredAptPackagesMissing[@]} + if [ $requiredAptPackagesMissingCount -gt 0 ]; then + apt_get_update + apt_get_checkinstall "${requiredAptPackagesMissing[@]}" + apt_get_cleanup + fi +} +curl_check_url() { + local url=$1 + local status_code + status_code=$(curl -s -o /dev/null -w '%{http_code}' "$url") + if [ "$status_code" -ne 200 ] && [ "$status_code" -ne 302 ]; then + echo "Failed to download '$url'. Status code: $status_code." + return 1 + fi +} +curl_download_stdout() { + local url=$1 + curl \ + --silent \ + --location \ + --output '-' \ + --connect-timeout 5 \ + "$url" +} +curl_download_untar() { + local url=$1 + local strip=$2 + local target=$3 + local bin_path=$4 + curl_download_stdout "$url" | tar \ + -xz \ + -f '-' \ + --strip-components="$strip" \ + -C "$target" \ + "$bin_path" +} +debian_get_arch() { + echo "$(dpkg --print-architecture)" +} +debian_get_target_arch() { + case $(debian_get_arch) in + amd64) echo 'x86_64' ;; + arm64) echo 'arm64' ;; + armhf) echo 'armv7' ;; + i386) echo 'i686' ;; + *) echo 'unknown' ;; + esac +} +echo_banner() { + local text="$1" + echo -e "\e[1m\e[97m\e[41m$text\e[0m" +} +github_list_releases() { + if [ -z "$1" ]; then + echo "Usage: list_github_releases " + return 1 + fi + local repo="$1" + local url="https://api.github.com/repos/$repo/releases" + curl -s "$url" | grep -Po '"tag_name": "\K.*?(?=")' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' +} +github_get_latest_release() { + if [ -z "$1" ]; then + echo "Usage: get_latest_github_release " + return 1 + fi + github_list_releases "$1" | head -n 1 +} +github_get_tag_for_version() { + if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: github_get_tag_for_version " + return 1 + fi + local repo="$1" + local _version="$2" + local url="https://api.github.com/repos/$repo/releases" + local escaped_version + escaped_version="$(printf '%s' "$_version" | sed 's/\./\\./g')" + curl -s "$url" | grep -Po '"tag_name": "\K.*?(?=")' | grep -E "^v?${escaped_version}$" | head -n 1 +} +utils_check_version() { + local version=$1 + if ! [[ "${version:-}" =~ ^(latest|[0-9]+\.[0-9]+\.[0-9]+)$ ]]; then + printf >&2 '=== [ERROR] Option "version" (value: "%s") is not "latest" or valid semantic version format "X.Y.Z" !\n' \ + "$version" + exit 1 + fi +} +install() { + utils_check_version "$VERSION" + check_curl_envsubst_file_tar_installed + readonly architecture="$(debian_get_target_arch)" + readonly binaryTargetPathTemplate='${binaryTargetFolder}/${binaryName}' + if [ "$VERSION" == 'latest' ] || [ -z "$VERSION" ]; then + VERSION=$(github_get_latest_release "$githubRepository") + fi + readonly version="${VERSION:?}" + readonly releaseTag="$(github_get_tag_for_version "$githubRepository" "$version")" + if [ -z "$releaseTag" ]; then + printf >&2 '=== [ERROR] Could not find release tag for version "%s" in "%s"!\n' "$version" "$githubRepository" + exit 1 + fi + readonly downloadUrlTemplate='https://github.com/${githubRepository}/releases/download/${releaseTag}/bkt_${version}_linux_${architecture}.tar.gz' + readonly downloadUrl="$(echo -n "$downloadUrlTemplate" | envsubst)" + curl_check_url "$downloadUrl" + readonly binaryPathInArchive="$binaryName" + readonly stripComponents="$(echo -n "$binaryPathInArchive" | awk -F'/' '{print NF-1}')" + readonly binaryTargetPath="$(echo -n "$binaryTargetPathTemplate" | envsubst)" + curl_download_untar "$downloadUrl" "$stripComponents" "$binaryTargetFolder" "$binaryPathInArchive" + chmod 755 "$binaryTargetPath" + apt_get_cleanup +} +echo_banner "devcontainer.community" +echo "Installing $name..." +install "$@" +echo "(*) Done!" diff --git a/test/avivsinai-bitbucket-cli/test.sh b/test/avivsinai-bitbucket-cli/test.sh new file mode 100755 index 0000000..e5843b9 --- /dev/null +++ b/test/avivsinai-bitbucket-cli/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib +# Provides the 'check' and 'reportResults' commands. +source dev-container-features-test-lib + +# Feature-specific tests +check "execute command" bash -c "bkt --version | grep 'bkt version'" + +# Report results +reportResults