From 6ee6ae901952e59a2570e58d8d453afcac27b892 Mon Sep 17 00:00:00 2001 From: rosstaco Date: Wed, 1 Jul 2026 04:24:47 +0000 Subject: [PATCH 1/2] feat: add atlassian-jira-confluence-cli (acli) dev container feature Installs the official Atlassian CLI (acli command) for Jira and Confluence Cloud. The feature is published as `atlassian-jira-confluence-cli` for discoverability; the installed binary and internals remain `acli`. - Downloads the static binary from acli.atlassian.com (latest rolling release or a pinned -stable archive), supporting amd64 and arm64 - Installs an xdg-open shim (configureBrowser, default true) that prefers $BROWSER so `acli auth login` opens OAuth on the host instead of failing inside the container - Adds autogenerated + scenario tests (version pinning, custom install path, browser-shim opt-out) and wires the feature into the CI test matrix and justfile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/test.yaml | 2 + README.md | 38 ++++++ justfile | 6 + src/atlassian-jira-confluence-cli/NOTES.md | 42 +++++++ src/atlassian-jira-confluence-cli/README.md | 68 +++++++++++ .../devcontainer-feature.json | 41 +++++++ src/atlassian-jira-confluence-cli/install.sh | 113 ++++++++++++++++++ .../custom-install-path.sh | 15 +++ .../no-browser-shim.sh | 14 +++ .../scenarios.json | 26 ++++ test/atlassian-jira-confluence-cli/test.sh | 44 +++++++ test/atlassian-jira-confluence-cli/version.sh | 15 +++ 12 files changed, 424 insertions(+) create mode 100644 src/atlassian-jira-confluence-cli/NOTES.md create mode 100644 src/atlassian-jira-confluence-cli/README.md create mode 100644 src/atlassian-jira-confluence-cli/devcontainer-feature.json create mode 100644 src/atlassian-jira-confluence-cli/install.sh create mode 100644 test/atlassian-jira-confluence-cli/custom-install-path.sh create mode 100644 test/atlassian-jira-confluence-cli/no-browser-shim.sh create mode 100644 test/atlassian-jira-confluence-cli/scenarios.json create mode 100644 test/atlassian-jira-confluence-cli/test.sh create mode 100644 test/atlassian-jira-confluence-cli/version.sh diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f9f0be1..007d47c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -19,6 +19,7 @@ jobs: - copilot-persistence - gitlab-ci-local - copilot-metrics-lgtm + - atlassian-jira-confluence-cli baseImage: - debian:latest - ubuntu:latest @@ -44,6 +45,7 @@ jobs: - copilot-persistence - gitlab-ci-local - copilot-metrics-lgtm + - atlassian-jira-confluence-cli steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index 95b0ec7..44eebe5 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,44 @@ Persists GitHub Copilot CLI settings and chat history across container rebuilds - Command history - Trusted folders +### Atlassian CLI for Jira & Confluence + +Installs the [Atlassian CLI](https://developer.atlassian.com/cloud/acli/) (`acli`) for working with Jira and Confluence Cloud from the command line. + +**Usage:** + +```json +{ + "features": { + "ghcr.io/rosstaco/devcontainer-features/atlassian-jira-confluence-cli:1": { + "version": "latest" + } + } +} +``` + +**Options:** +- `version` - Version of acli to install (default: "latest"). Use "latest" or a specific version like "1.3.21" +- `installPath` - Directory where the acli binary will be installed (default: "/usr/local/bin") +- `configureBrowser` - Install an `xdg-open` shim that prefers `$BROWSER` so `acli auth login` opens on your host (default: `true`) + +**Supported Architectures:** +- amd64 (x86_64) +- arm64 (aarch64) + +**Getting Started:** + +After the container starts, authenticate once and then use the Jira and Confluence commands: + +```bash +acli auth login +acli jira project list +``` + +**Browser Login:** + +`acli auth login` opens an OAuth page via `xdg-open`, which doesn't honor `$BROWSER` inside a dev container. With `configureBrowser` enabled (the default), the feature installs a small `xdg-open` shim at `/usr/local/bin/xdg-open` that prefers `$BROWSER` (such as the VS Code browser helper) so the login page opens on your host machine. Set `configureBrowser` to `false` to skip it. + ## Publishing This repository uses a **GitHub Action** [workflow](.github/workflows/release.yaml) that publishes each Feature to GHCR (GitHub Container Registry). diff --git a/justfile b/justfile index 1668f54..81208a3 100644 --- a/justfile +++ b/justfile @@ -21,11 +21,16 @@ build-microsoft-security-devops-cli: build-gitlab-ci-local: just build-feature gitlab-ci-local +# Build Atlassian CLI (acli) feature +build-atlassian-jira-confluence-cli: + just build-feature atlassian-jira-confluence-cli + # Build all features build-all: just build-ohmyposh just build-microsoft-security-devops-cli just build-gitlab-ci-local + just build-atlassian-jira-confluence-cli # Generate feature README.md files from devcontainer-feature.json and NOTES.md generate-docs: @@ -35,5 +40,6 @@ generate-docs: clean: rm -rf .devcontainer/ohmyposh rm -rf .devcontainer/gitlab-ci-local + rm -rf .devcontainer/atlassian-jira-confluence-cli rm -f .devcontainer/*.tgz echo "✓ Cleaned local features" diff --git a/src/atlassian-jira-confluence-cli/NOTES.md b/src/atlassian-jira-confluence-cli/NOTES.md new file mode 100644 index 0000000..f9e7be1 --- /dev/null +++ b/src/atlassian-jira-confluence-cli/NOTES.md @@ -0,0 +1,42 @@ +## About + +The [Atlassian CLI](https://developer.atlassian.com/cloud/acli/) (`acli`) is Atlassian's official command line tool for working with **Jira** and **Confluence** Cloud (plus Atlassian Guard and Rovo Dev) directly from your terminal. + +For more information, see: https://developer.atlassian.com/cloud/acli/ + +## How It Works + +1. **Downloads the official binary** from `acli.atlassian.com` (the same rolling `latest` and versioned `-stable` archives Atlassian publishes) +2. **Installs to** `/usr/local/bin/acli` by default (configurable via `installPath`) +3. **Supports** both `amd64` and `arm64` architectures +4. **Installs an `xdg-open` shim** (when `configureBrowser` is `true`, the default) so the OAuth login opens in your host browser — see below + +## Browser Login in a Dev Container + +`acli auth login` opens an OAuth page by shelling out to `xdg-open`, which doesn't +honor `$BROWSER` and fails (or tries to launch a browser inside the container). +With `configureBrowser` enabled, this feature installs a small `xdg-open` shim at +`/usr/local/bin/xdg-open` that prefers `$BROWSER` (for example the VS Code browser +helper) and falls back to the real `xdg-open` otherwise, so the login page opens on +your host. Set `configureBrowser` to `false` to skip installing the shim. + +## Usage + +Authenticate once (interactive OAuth login): + +```bash +acli auth login +``` + +Then work with Jira and Confluence, for example: + +```bash +# List your Jira projects +acli jira project list + +# View a Jira work item +acli jira workitem view --key PROJ-123 + +# Confluence commands +acli confluence --help +``` diff --git a/src/atlassian-jira-confluence-cli/README.md b/src/atlassian-jira-confluence-cli/README.md new file mode 100644 index 0000000..ea3501d --- /dev/null +++ b/src/atlassian-jira-confluence-cli/README.md @@ -0,0 +1,68 @@ + +# Atlassian CLI for Jira & Confluence (atlassian-jira-confluence-cli) + +Installs the Atlassian CLI (acli) for working with Jira and Confluence Cloud from the command line + +## Example Usage + +```json +"features": { + "ghcr.io/rosstaco/devcontainer-features/atlassian-jira-confluence-cli:1": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Version of acli to install. Use 'latest' or a specific version like '1.3.21' | string | latest | +| installPath | Directory where the acli binary will be installed | string | /usr/local/bin | +| configureBrowser | Install an xdg-open shim in /usr/local/bin that prefers $BROWSER (e.g. the VS Code browser helper) so 'acli auth login' opens the OAuth page on your host instead of failing inside the container | boolean | true | + +## About + +The [Atlassian CLI](https://developer.atlassian.com/cloud/acli/) (`acli`) is Atlassian's official command line tool for working with **Jira** and **Confluence** Cloud (plus Atlassian Guard and Rovo Dev) directly from your terminal. + +For more information, see: https://developer.atlassian.com/cloud/acli/ + +## How It Works + +1. **Downloads the official binary** from `acli.atlassian.com` (the same rolling `latest` and versioned `-stable` archives Atlassian publishes) +2. **Installs to** `/usr/local/bin/acli` by default (configurable via `installPath`) +3. **Supports** both `amd64` and `arm64` architectures +4. **Installs an `xdg-open` shim** (when `configureBrowser` is `true`, the default) so the OAuth login opens in your host browser — see below + +## Browser Login in a Dev Container + +`acli auth login` opens an OAuth page by shelling out to `xdg-open`, which doesn't +honor `$BROWSER` and fails (or tries to launch a browser inside the container). +With `configureBrowser` enabled, this feature installs a small `xdg-open` shim at +`/usr/local/bin/xdg-open` that prefers `$BROWSER` (for example the VS Code browser +helper) and falls back to the real `xdg-open` otherwise, so the login page opens on +your host. Set `configureBrowser` to `false` to skip installing the shim. + +## Usage + +Authenticate once (interactive OAuth login): + +```bash +acli auth login +``` + +Then work with Jira and Confluence, for example: + +```bash +# List your Jira projects +acli jira project list + +# View a Jira work item +acli jira workitem view --key PROJ-123 + +# Confluence commands +acli confluence --help +``` + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/rosstaco/devcontainer-features/blob/main/src/atlassian-jira-confluence-cli/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/src/atlassian-jira-confluence-cli/devcontainer-feature.json b/src/atlassian-jira-confluence-cli/devcontainer-feature.json new file mode 100644 index 0000000..0d394bd --- /dev/null +++ b/src/atlassian-jira-confluence-cli/devcontainer-feature.json @@ -0,0 +1,41 @@ +{ + "id": "atlassian-jira-confluence-cli", + "version": "1.0.0", + "name": "Atlassian CLI for Jira & Confluence", + "description": "Installs the Atlassian CLI (acli) for working with Jira and Confluence Cloud from the command line", + "documentationURL": "https://github.com/rosstaco/devcontainer-features/tree/main/src/atlassian-jira-confluence-cli", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest" + ], + "default": "latest", + "description": "Version of acli to install. Use 'latest' or a specific version like '1.3.21'" + }, + "installPath": { + "type": "string", + "default": "/usr/local/bin", + "description": "Directory where the acli binary will be installed" + }, + "configureBrowser": { + "type": "boolean", + "default": true, + "description": "Install an xdg-open shim in /usr/local/bin that prefers $BROWSER (e.g. the VS Code browser helper) so 'acli auth login' opens the OAuth page on your host instead of failing inside the container" + } + }, + "customizations": { + "vscode": { + "settings": { + "github.copilot.chat.codeGeneration.instructions": [ + { + "text": "This dev container includes `acli`, the Atlassian CLI, pre-installed and available on the `PATH`. Use it to work with Jira and Confluence Cloud from the command line. Authenticate with `acli auth login` before running commands." + } + ] + } + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} diff --git a/src/atlassian-jira-confluence-cli/install.sh b/src/atlassian-jira-confluence-cli/install.sh new file mode 100644 index 0000000..06ecc51 --- /dev/null +++ b/src/atlassian-jira-confluence-cli/install.sh @@ -0,0 +1,113 @@ +#!/bin/bash +set -e + +# Atlassian CLI (acli) installation script for devcontainer features +# https://developer.atlassian.com/cloud/acli/ + +CLI_VERSION="${VERSION:-latest}" +INSTALL_PATH="${INSTALLPATH:-/usr/local/bin}" +CONFIGURE_BROWSER="${CONFIGUREBROWSER:-true}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}Script must be run as root. Use sudo, su, or add \"USER root\" to your Dockerfile before running this script.${NC}" + exit 1 +fi + +apt_get_update() { + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +echo -e "${GREEN}Installing Atlassian CLI (acli)...${NC}" + +check_packages curl ca-certificates tar +echo "Finished setting up dependencies" + +# Detect architecture using dpkg (acli publishes amd64 and arm64 builds) +arch=$(dpkg --print-architecture) +if [ "${arch}" != "amd64" ] && [ "${arch}" != "arm64" ]; then + echo -e "${RED}Unsupported architecture: ${arch}${NC}" >&2 + echo -e "${RED}Only amd64 and arm64 are supported.${NC}" >&2 + exit 1 +fi +echo "Detected architecture: ${arch}" + +# Build the download URL. 'latest' uses the rolling release path; a pinned +# version resolves to the versioned '-stable' archive. +if [ "${CLI_VERSION}" = "latest" ]; then + download_url="https://acli.atlassian.com/linux/latest/acli_linux_${arch}.tar.gz" +else + # Normalize the version: drop any leading 'v' and ensure the '-stable' suffix + release="${CLI_VERSION#v}" + case "${release}" in + *-stable) ;; + *) release="${release}-stable" ;; + esac + download_url="https://acli.atlassian.com/linux/${release}/acli_${release}_linux_${arch}.tar.gz" +fi + +echo "Downloading acli from ${download_url}..." + +tmp_dir="$(mktemp -d)" +cleanup() { rm -rf "${tmp_dir}"; } +trap cleanup EXIT + +if ! curl -fsSL "${download_url}" -o "${tmp_dir}/acli.tar.gz"; then + echo -e "${RED}Failed to download acli from ${download_url}${NC}" >&2 + echo -e "${RED}Check that the requested version '${CLI_VERSION}' exists.${NC}" >&2 + exit 1 +fi + +# The archive contains a single '/acli' entry; strip the top-level dir +tar -xzf "${tmp_dir}/acli.tar.gz" --strip-components=1 -C "${tmp_dir}" + +if [ ! -f "${tmp_dir}/acli" ]; then + echo -e "${RED}acli binary not found in downloaded archive${NC}" >&2 + exit 1 +fi + +mkdir -p "${INSTALL_PATH}" +install -m 0755 "${tmp_dir}/acli" "${INSTALL_PATH}/acli" + +# Verify installation +if ! command -v acli &> /dev/null && [ ! -x "${INSTALL_PATH}/acli" ]; then + echo -e "${RED}acli installation failed - binary not found${NC}" >&2 + exit 1 +fi + +INSTALLED_VERSION=$("${INSTALL_PATH}/acli" --version 2>&1 | head -n 1 || true) +echo -e "${GREEN}acli installed successfully to ${INSTALL_PATH}/acli: ${INSTALLED_VERSION}${NC}" + +# acli's OAuth login shells out to 'xdg-open' rather than honoring $BROWSER, +# which fails (or pops an in-container browser) inside a dev container. Install a +# shim on the PATH that prefers $BROWSER (e.g. VS Code's browser helper) and +# falls back to the real xdg-open otherwise. +if [ "${CONFIGURE_BROWSER}" = "true" ]; then + echo "Installing xdg-open shim that prefers \$BROWSER..." + cat > /usr/local/bin/xdg-open <<'SHIM' +#!/bin/sh +[ -n "$BROWSER" ] && [ -x "$BROWSER" ] && exec "$BROWSER" "$@" +exec /usr/bin/xdg-open "$@" +SHIM + chmod 0755 /usr/local/bin/xdg-open +fi + +echo "" +echo "The 'acli' command is now available." +echo "Authenticate with 'acli auth login' to start working with Jira and Confluence." +echo "For more information: https://developer.atlassian.com/cloud/acli/" diff --git a/test/atlassian-jira-confluence-cli/custom-install-path.sh b/test/atlassian-jira-confluence-cli/custom-install-path.sh new file mode 100644 index 0000000..9edd5bb --- /dev/null +++ b/test/atlassian-jira-confluence-cli/custom-install-path.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# This test verifies that acli can be installed to a custom directory + +set -e + +source dev-container-features-test-lib + +check "acli binary in custom install path" test -x /usr/bin/acli + +check "acli is on PATH" command -v acli + +check "acli version command works" bash -c "acli --version 2>&1 | grep -q '[0-9]\+\.[0-9]\+\.[0-9]\+'" + +reportResults diff --git a/test/atlassian-jira-confluence-cli/no-browser-shim.sh b/test/atlassian-jira-confluence-cli/no-browser-shim.sh new file mode 100644 index 0000000..e9a649c --- /dev/null +++ b/test/atlassian-jira-confluence-cli/no-browser-shim.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# This test verifies that the xdg-open shim is NOT installed when +# configureBrowser is set to false. + +set -e + +source dev-container-features-test-lib + +check "acli is installed" command -v acli + +check "xdg-open shim not installed" bash -c "! test -e /usr/local/bin/xdg-open" + +reportResults diff --git a/test/atlassian-jira-confluence-cli/scenarios.json b/test/atlassian-jira-confluence-cli/scenarios.json new file mode 100644 index 0000000..e48726b --- /dev/null +++ b/test/atlassian-jira-confluence-cli/scenarios.json @@ -0,0 +1,26 @@ +{ + "version": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "atlassian-jira-confluence-cli": { + "version": "1.3.21" + } + } + }, + "custom-install-path": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "atlassian-jira-confluence-cli": { + "installPath": "/usr/bin" + } + } + }, + "no-browser-shim": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "atlassian-jira-confluence-cli": { + "configureBrowser": false + } + } + } +} diff --git a/test/atlassian-jira-confluence-cli/test.sh b/test/atlassian-jira-confluence-cli/test.sh new file mode 100644 index 0000000..8cac49a --- /dev/null +++ b/test/atlassian-jira-confluence-cli/test.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# This test file will be executed against an auto-generated devcontainer.json that +# includes the 'acli' Feature with no options. +# +# Thus, the value of all options will fall back to the default value in the +# Feature's 'devcontainer-feature.json'. +# +# These scripts are run as 'root' by default. Although that can be changed +# with the '--remote-user' flag. + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +check "acli is executable" command -v acli + +check "acli binary exists" test -x /usr/local/bin/acli + +check "acli version command works" bash -c "acli --version 2>&1 | grep -q '[0-9]\+\.[0-9]\+\.[0-9]\+'" + +check "acli reports itself as acli" bash -c "acli --version 2>&1 | grep -q 'acli'" + +check "acli jira command available" bash -c "acli jira --help 2>&1 | grep -q 'Jira'" + +check "acli confluence command available" bash -c "acli confluence --help 2>&1 | grep -q 'Confluence'" + +# The feature installs an xdg-open shim (configureBrowser defaults to true) so +# 'acli auth login' opens the OAuth page via $BROWSER instead of in-container. +check "xdg-open shim installed" test -x /usr/local/bin/xdg-open + +check "xdg-open shim prefers \$BROWSER" bash -c ' + marker="$(mktemp)" + fake="$(mktemp)" + printf "#!/bin/sh\necho \"\$1\" > \"%s\"\n" "$marker" > "$fake" + chmod +x "$fake" + BROWSER="$fake" /usr/local/bin/xdg-open "https://example.com/oauth" >/dev/null 2>&1 + grep -q "https://example.com/oauth" "$marker" +' + +# Report results +reportResults diff --git a/test/atlassian-jira-confluence-cli/version.sh b/test/atlassian-jira-confluence-cli/version.sh new file mode 100644 index 0000000..6763dbf --- /dev/null +++ b/test/atlassian-jira-confluence-cli/version.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# This test verifies that a specific version can be installed + +set -e + +source dev-container-features-test-lib + +check "acli is installed" command -v acli + +check "acli binary exists" test -x /usr/local/bin/acli + +check "acli reports pinned version 1.3.21" bash -c "acli --version 2>&1 | grep -q '1\.3\.21'" + +reportResults From 81ad71b5c629305c8aeacfcb18b8da0c087eb639 Mon Sep 17 00:00:00 2001 From: rosstaco Date: Fri, 24 Jul 2026 06:15:47 +0000 Subject: [PATCH 2/2] switch to ubuntu base image. --- .devcontainer/devcontainer-lock.json | 19 +++++++++++++++++++ .devcontainer/devcontainer.json | 8 +++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .devcontainer/devcontainer-lock.json diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..1de7f99 --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,19 @@ +{ + "features": { + "ghcr.io/devcontainers/features/common-utils": { + "version": "2.5.9", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a", + "integrity": "sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a" + }, + "ghcr.io/devcontainers/features/docker-in-docker:2": { + "version": "2.17.0", + "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c", + "integrity": "sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c" + }, + "ghcr.io/jsburckhardt/devcontainer-features/just:1": { + "version": "1.0.0", + "resolved": "ghcr.io/jsburckhardt/devcontainer-features/just@sha256:5c90013b36669270be21c69e7d8e5b6148b4b0b34fca9e104a599edf0d7c11af", + "integrity": "sha256:5c90013b36669270be21c69e7d8e5b6148b4b0b34fca9e104a599edf0d7c11af" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0ca3a58..2ae80b2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bookworm", + "image": "mcr.microsoft.com/devcontainers/base:noble", "customizations": { "vscode": { "settings": { @@ -18,13 +18,15 @@ } }, "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/docker-in-docker:4": {}, + "ghcr.io/devcontainers/features/node:2": { + "version": "20" + }, "ghcr.io/jsburckhardt/devcontainer-features/just:1": {}, "ghcr.io/devcontainers/features/common-utils": { "installOhMyZsh": true, "configureZshAsDefaultShell": true } }, - "remoteUser": "node", "updateContentCommand": "npm install -g @devcontainers/cli" }