diff --git a/.github/compute-feature-matrix.sh b/.github/compute-feature-matrix.sh new file mode 100755 index 0000000..ed78711 --- /dev/null +++ b/.github/compute-feature-matrix.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Usage: compute-feature-matrix.sh +# Outputs a JSON array of feature names to GITHUB_OUTPUT (or stdout when GITHUB_OUTPUT is unset). +set -euo pipefail + +event_name="${1:-}" +shift + +all_features=("cargo-lambda" "lambroll" "ngrok") +declare -A changed=( + ["cargo-lambda"]="${1:-false}" + ["lambroll"]="${2:-false}" + ["ngrok"]="${3:-false}" +) + +features=() +for feature in "${all_features[@]}"; do + if [ "$event_name" = "workflow_dispatch" ] || [ "${changed[$feature]}" = "true" ]; then + features+=("$feature") + fi +done + +if [ ${#features[@]} -eq 0 ]; then + json="[]" +else + json=$(printf '%s\n' "${features[@]}" | jq -R . | jq -sc .) +fi + +echo "features=$json" | tee -a "${GITHUB_OUTPUT:-/dev/stdout}" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fa62b5b..fb500c7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -6,15 +6,48 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + jobs: + compute-feature-matrix: + runs-on: ubuntu-latest + outputs: + features: ${{ steps.compute.outputs.features }} + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + cargo-lambda: + - 'src/cargo-lambda/**' + - 'test/cargo-lambda/**' + lambroll: + - 'src/lambroll/**' + - 'test/lambroll/**' + ngrok: + - 'src/ngrok/**' + - 'test/ngrok/**' + + - name: "Compute features matrix" + id: compute + run: | + bash .github/compute-feature-matrix.sh \ + "${{ github.event_name }}" \ + "${{ steps.filter.outputs.cargo-lambda }}" \ + "${{ steps.filter.outputs.lambroll }}" \ + "${{ steps.filter.outputs.ngrok }}" + test-autogenerated: + needs: compute-feature-matrix + if: needs.compute-feature-matrix.outputs.features != '[]' && needs.compute-feature-matrix.outputs.features != '' runs-on: ubuntu-latest continue-on-error: true strategy: matrix: - features: - - cargo-lambda - - lambroll + features: ${{ fromJson(needs.compute-feature-matrix.outputs.features) }} baseImage: - debian:latest - ubuntu:latest @@ -28,13 +61,13 @@ jobs: run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} . test-scenarios: + needs: compute-feature-matrix + if: needs.compute-feature-matrix.outputs.features != '[]' && needs.compute-feature-matrix.outputs.features != '' runs-on: ubuntu-latest continue-on-error: true strategy: matrix: - features: - - cargo-lambda - - lambroll + features: ${{ fromJson(needs.compute-feature-matrix.outputs.features) }} steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index 3ecb208..a3682e6 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ > > - [cargo-lambda](https://www.cargo-lambda.info/) > - [lambroll](https://github.com/fujiwara/lambroll) +> - [ngrok](https://ngrok.com/) # How to use @@ -13,4 +14,9 @@ note: - This will install zig to latest version via (ghcr.io/devcontainers-extra/features/zig:1) - `rust` and `binstall` when not available, will be downloaded -Lambroll: [Readme](src/lambroll/README.md) \ No newline at end of file +Lambroll: [Readme](src/lambroll/README.md) + +ngrok: [Readme](src/ngrok/README.md) + +- Supports `amd64` (x86_64) and `arm64` (aarch64) architectures +- Defaults to the latest stable release; a specific version can be pinned via the `version` option \ No newline at end of file diff --git a/src/ngrok/README.md b/src/ngrok/README.md new file mode 100644 index 0000000..bfcdc5a --- /dev/null +++ b/src/ngrok/README.md @@ -0,0 +1,33 @@ +# ngrok + +Installs [ngrok](https://ngrok.com/), a secure tunnel to localhost. Supports both `amd64` and `arm64` architectures. + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Version of ngrok to install (e.g. `latest`, `stable`, or a specific version like `3.5.0`) | string | latest | + +## Usage + +Add to your `devcontainer.json`: + +```jsonc +{ + "features": { + "ghcr.io/tokidoki11/devcontainer-feature/ngrok:1": {} + } +} +``` + +To install a specific version: + +```jsonc +{ + "features": { + "ghcr.io/tokidoki11/devcontainer-feature/ngrok:1": { + "version": "3.5.0" + } + } +} +``` diff --git a/src/ngrok/devcontainer-feature.json b/src/ngrok/devcontainer-feature.json new file mode 100644 index 0000000..39915bb --- /dev/null +++ b/src/ngrok/devcontainer-feature.json @@ -0,0 +1,13 @@ +{ + "name": "ngrok", + "id": "ngrok", + "version": "1.0.0", + "description": "Install ngrok - a secure tunnel to localhost. Supports amd64 and arm64 architectures.", + "options": { + "version": { + "type": "string", + "default": "latest", + "description": "Version of ngrok to install (e.g. 'latest', 'stable', or a specific version like '3.5.0')" + } + } +} diff --git a/src/ngrok/install.sh b/src/ngrok/install.sh new file mode 100755 index 0000000..a49eab5 --- /dev/null +++ b/src/ngrok/install.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e + +NGROK_VERSION="${VERSION:-"latest"}" + +# Detect architecture +ARCH=$(uname -m) +case "$ARCH" in + x86_64) NGROK_ARCH="amd64" ;; + aarch64 | arm64) NGROK_ARCH="arm64" ;; + *) echo "Unsupported architecture: $ARCH"; exit 1 ;; +esac + +# Map "latest" to "stable" for the equinox download URL +if [ "$NGROK_VERSION" = "latest" ]; then + NGROK_VERSION="stable" +fi + +# The equinox.io URL path 'bNyj1mQVY4c' is ngrok's stable channel identifier for v3. +# Supported values for NGROK_VERSION: 'stable', or specific versions like '3.5.0'. +DOWNLOAD_URL="https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-${NGROK_VERSION}-linux-${NGROK_ARCH}.tgz" + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi + apt-get -y install --no-install-recommends "$@" + fi +} + +export DEBIAN_FRONTEND=noninteractive + +check_packages curl ca-certificates + +echo "Downloading ngrok ${NGROK_VERSION} for ${NGROK_ARCH} from ${DOWNLOAD_URL}" + +TEMP_DIR=$(mktemp -d) +if ! curl -sSL --fail "${DOWNLOAD_URL}" -o "${TEMP_DIR}/ngrok.tgz"; then + echo "ERROR: Failed to download ngrok. Please verify the version '${NGROK_VERSION}' is valid and the URL is reachable: ${DOWNLOAD_URL}" + rm -rf "${TEMP_DIR}" + exit 1 +fi +if ! tar -xzf "${TEMP_DIR}/ngrok.tgz" -C "${TEMP_DIR}"; then + echo "ERROR: Failed to extract ngrok archive. The downloaded file may be corrupted." + rm -rf "${TEMP_DIR}" + exit 1 +fi +install -m 0755 "${TEMP_DIR}/ngrok" /usr/local/bin/ngrok + +rm -rf "${TEMP_DIR}" +rm -rf /var/lib/apt/lists/* + +echo "ngrok installed successfully" +ngrok version diff --git a/test/ngrok/install_latest.sh b/test/ngrok/install_latest.sh new file mode 100755 index 0000000..53124ce --- /dev/null +++ b/test/ngrok/install_latest.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +# Feature-specific tests +check "ngrok installed" bash -c "ngrok version" +check "ngrok is executable" which ngrok + +# Report results +reportResults diff --git a/test/ngrok/scenarios.json b/test/ngrok/scenarios.json new file mode 100644 index 0000000..6e908c0 --- /dev/null +++ b/test/ngrok/scenarios.json @@ -0,0 +1,8 @@ +{ + "install_latest": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ngrok": {} + } + } +} diff --git a/test/ngrok/test.sh b/test/ngrok/test.sh new file mode 100755 index 0000000..53124ce --- /dev/null +++ b/test/ngrok/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +# Feature-specific tests +check "ngrok installed" bash -c "ngrok version" +check "ngrok is executable" which ngrok + +# Report results +reportResults