diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..fb4a596 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,26 @@ +name: "Release" + +on: + push: + branches: + - main + +jobs: + deploy: + name: "Release to GHCR" + if: ${{ github.ref == 'refs/heads/main' }} + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + packages: write + steps: + - uses: actions/checkout@v6 + + - name: "Publish features" + uses: devcontainers/action@v1 + with: + publish-features: "true" + base-path-to-features: "./src" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..8a74390 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,65 @@ +name: "Test" + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +jobs: + docs: + name: "Ensure documentation has been generated" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: "Install devcontainer CLI" + run: npm install -g @devcontainers/cli + + - name: "Generate docs" + run: devcontainer features generate-docs -p src -n csutter/devcontainer-features + + - name: "Verify docs are up to date" + run: git diff --quiet -- */**/README.md + + shellcheck: + name: Shellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 + + test: + name: "Test ${{ matrix.feature }} on ${{ matrix.baseImage }}" + runs-on: ubuntu-latest + continue-on-error: true + strategy: + matrix: + feature: + - personal-setup + baseImage: + # Vanilla distribution images + - docker.io/library/debian:latest + - docker.io/library/ubuntu:latest + - quay.io/fedora/fedora-toolbox:latest + # Microsoft devcontainer base image + - mcr.microsoft.com/devcontainers/base:ubuntu + steps: + - uses: actions/checkout@v4 + + # The personal-setup feature requires my dotfiles folders to be present in the expected + # location, so clone the public repo to simulate this, and fake the private repo mount. + - name: "Prepare demo dotfiles mounts" + run: | + mkdir -p $HOME/src/csutter + mkdir $HOME/src/csutter/dotfiles-private + git clone https://github.com/csutter/dotfiles.git $HOME/src/csutter/dotfiles + + - name: "Install devcontainer CLI" + run: npm install -g @devcontainers/cli + + - name: "Test feature: ${{ matrix.feature }} on ${{ matrix.baseImage }}" + run: devcontainer features test --features ${{ matrix.feature }} --base-image ${{ matrix.baseImage }} diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..29c2f95 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +# Don't follow external sources +disable=SC1091 diff --git a/README.md b/README.md index abf7858..406cd20 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ # devcontainer-features Feature definitions for my containerised development environments + +> [!CAUTION] +> This repository contains assorted devcontainer features meant to be used by _me_ personally: +> * as default features for all (own and third party) devcontainers I run, or +> * as features in specific devcontainers for my own personal projects +> +> You may or may not get much mileage out of using them directly, and any or all features may not be +> stable, continue to provide the same functionality in the long run, always be available on +> `ghcr.io`, or even work on anyone else's machine! +> +> I therefore recommend that you use this repository as inspiration for your own features, and do +> not rely on them directly. + +## Features +* [`personal-setup`](src/personal-setup/): Sets up tooling and dotfiles for any arbitrary devcontainer diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..1a2920c --- /dev/null +++ b/mise.toml @@ -0,0 +1,23 @@ +[tools] +node = "24" +"npm:@devcontainers/cli" = "0.80" +"github:koalaman/shellcheck" = "v0.11.0" + +[tasks.docs] +description = "Generate documentation for all features" +# Note: The `generate-docs` command documentation wrongly suggests -p should be the root of the +# repo, but it should be the src/ directory. +run = "devcontainer features generate-docs -p src -n csutter/devcontainer-features" + +[tasks.lint-shell] +description = "Lint all shell scripts using ShellCheck" +run = "find . -name '*.sh' -print0 | xargs -0 shellcheck" + +[tasks.test] +description = "Run tests for all features" +run = [ + "devcontainer features test -i docker.io/library/debian:latest", + "devcontainer features test -i docker.io/library/ubuntu:latest", + "devcontainer features test -i quay.io/fedora/fedora-toolbox:latest", + "devcontainer features test -i mcr.microsoft.com/devcontainers/base:ubuntu", +] diff --git a/src/personal-setup/NOTES.md b/src/personal-setup/NOTES.md new file mode 100644 index 0000000..904ce7e --- /dev/null +++ b/src/personal-setup/NOTES.md @@ -0,0 +1,19 @@ +I have a set of preferred tools that I want available in any devcontainer, as well as several +dotfiles repositories to configure my desired development environment. + +I've previously (ab)used the _Dev Containers_ extension's built in dotfiles support, but it: +- doesn't allow multiple dotfiles repositories (a key use case for me) +- relies on an install script in the repository (which feels like an unsuitable concern for a + repository of configuration files) +- clones the repository from origin every time (which requires SSH agent confirmation and needs + "human in the loop" during setup, and means changes on the host don't get picked up until push and + a full container rebuild) + +This feature: +- Installs a set of packages in the container (including `rcm` for dotfiles management) +- Mounts my dotfiles repositories into the container +- Installs the dotfiles (with appropriate tags) + +This feature is intended to be configured as part of my personal user settings as a default feature +for all devcontainers (through `dev.containers.defaultFeatures`). It's obviously specific to me, +and coupled to my canonical directory layout and dotfiles repositories. diff --git a/src/personal-setup/README.md b/src/personal-setup/README.md new file mode 100644 index 0000000..2a05015 --- /dev/null +++ b/src/personal-setup/README.md @@ -0,0 +1,39 @@ + +# Personal Setup (personal-setup) + +Sets up my desired software and configuration for any devcontainer environment. + +## Example Usage + +```json +"features": { + "ghcr.io/csutter/devcontainer-features/personal-setup:1": {} +} +``` + + + +I have a set of preferred tools that I want available in any devcontainer, as well as several +dotfiles repositories to configure my desired development environment. + +I've previously (ab)used the _Dev Containers_ extension's built in dotfiles support, but it: +- doesn't allow multiple dotfiles repositories (a key use case for me) +- relies on an install script in the repository (which feels like an unsuitable concern for a + repository of configuration files) +- clones the repository from origin every time (which requires SSH agent confirmation and needs + "human in the loop" during setup, and means changes on the host don't get picked up until push and + a full container rebuild) + +This feature: +- Installs a set of packages in the container (including `rcm` for dotfiles management) +- Mounts my dotfiles repositories into the container +- Installs the dotfiles (with appropriate tags) + +This feature is intended to be configured as part of my personal user settings as a default feature +for all devcontainers (through `dev.containers.defaultFeatures`). It's obviously specific to me, +and coupled to my canonical directory layout and dotfiles repositories. + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/src/personal-setup/devcontainer-feature.json b/src/personal-setup/devcontainer-feature.json new file mode 100644 index 0000000..cd6950b --- /dev/null +++ b/src/personal-setup/devcontainer-feature.json @@ -0,0 +1,22 @@ +{ + "id": "personal-setup", + "version": "1.0.0", + "name": "Personal Setup", + "description": "Sets up my desired software and configuration for any devcontainer environment.", + "mounts": [ + { + "type": "bind", + "source": "${localEnv:HOME}/src/csutter/dotfiles", + "target": "/mnt/dotfiles" + }, + { + "type": "bind", + "source": "${localEnv:HOME}/src/csutter/dotfiles-private", + "target": "/mnt/dotfiles-private" + } + ], + "containerEnv": { + "RCRC": "/mnt/dotfiles/tag-devcontainer/rcrc" + }, + "postCreateCommand": "rcup -vf" +} diff --git a/src/personal-setup/install.sh b/src/personal-setup/install.sh new file mode 100755 index 0000000..70076fe --- /dev/null +++ b/src/personal-setup/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/bash +set -e + +if [ -f /etc/os-release ]; then + . /etc/os-release +else + echo "Error: Cannot detect distribution (no /etc/os-release)" + exit 1 +fi + +echo "Installing packages for distribution: $ID" +case "$ID" in + debian|ubuntu) + apt-get update + apt-get install -y rcm + ;; + fedora) + dnf install -y rcm + ;; + *) + echo "Error: Unsupported distribution: $ID" + echo "This feature supports: debian, ubuntu, fedora" + exit 1 + ;; +esac diff --git a/test/personal-setup/test.sh b/test/personal-setup/test.sh new file mode 100755 index 0000000..56b7a92 --- /dev/null +++ b/test/personal-setup/test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +source dev-container-features-test-lib + +check "rcm is available" bash -c "which rcup" +# Use a dotfile that should _always_ be present on any system +check "dotfiles are installed" bash -c "test -f $HOME/.config/fish/config.fish" + +reportResults