Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
}
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/jsburckhardt/devcontainer-features/just:1": {}
},
"remoteUser": "node",
"updateContentCommand": "npm install -g @devcontainers/cli"
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ jobs:
strategy:
matrix:
features:
- color
- hello
- ohmyposh
baseImage:
- debian:latest
- ubuntu:latest
Expand All @@ -34,8 +33,7 @@ jobs:
strategy:
matrix:
features:
- color
- hello
- ohmyposh
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Feature tarballs for local testing
.devcontainer/*.tgz
125 changes: 44 additions & 81 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,111 +1,74 @@
# Dev Container Features: Self Authoring Template
# Dev Container Features

> This repo provides a starting point and example for creating your own custom [dev container Features](https://containers.dev/implementors/features/), hosted for free on GitHub Container Registry. The example in this repository follows the [dev container Feature distribution specification](https://containers.dev/implementors/features-distribution/).
>
> To provide feedback to the specification, please leave a comment [on spec issue #70](https://github.com/devcontainers/spec/issues/70). For more broad feedback regarding dev container Features, please see [spec issue #61](https://github.com/devcontainers/spec/issues/61).
Custom [dev container Features](https://containers.dev/implementors/features/) for enhancing development containers, hosted on GitHub Container Registry. This repository follows the [dev container Feature distribution specification](https://containers.dev/implementors/features-distribution/).

## Repo and Feature Structure
## Available Features

Similar to the [`devcontainers/features`](https://github.com/devcontainers/features) repo, this repository has a `src` folder. Each Feature has its own sub-folder, containing at least a `devcontainer-feature.json` and an entrypoint script `install.sh`.
### Oh My Posh

```
├── src
│ ├── my-feature
│ │ ├── devcontainer-feature.json
│ │ └── install.sh
│ ├── another-feature
│ │ ├── devcontainer-feature.json
│ │ └── install.sh
│ ├── ...
│ │ ├── devcontainer-feature.json
│ │ └── install.sh
...
```

An [implementing tool](https://containers.dev/supporting#tools) will composite [the documented dev container properties](https://containers.dev/implementors/features/#devcontainer-feature-json-properties) from the feature's `devcontainer-feature.json` file, and execute in the `install.sh` entrypoint script in the container during build time. Implementing tools are also free to process attributes under the `customizations` property as desired.
Installs [Oh My Posh](https://ohmyposh.dev/), a prompt theme engine for customizing your shell prompt across bash, zsh, and fish.

### Options
**Usage:**

All available options for a Feature should be declared in the `devcontainer-feature.json`. The syntax for the `options` property can be found in the [devcontainer Feature json properties reference](https://containers.dev/implementors/features/#devcontainer-feature-json-properties).

Options are exported as Feature-scoped environment variables. The option name is captialized and sanitized according to [option resolution](https://containers.dev/implementors/features/#option-resolution).
## Distributing Features
```json
{
"features": {
"ghcr.io/rosstaco/devcontainer-features/ohmyposh:1": {
"version": "latest",
"theme": "jandedobbeleer",
"installPath": "/usr/local/bin",
"shells": "bash,zsh"
}
}
}
```

### Versioning
**Options:**
- `version` - Oh My Posh version to install (default: "latest")
- `theme` - Built-in theme name to use (default: "jandedobbeleer")
- `installPath` - Installation directory (default: "/usr/local/bin")
- `shells` - Comma-separated list of shells to configure: bash, zsh, fish (default: "bash,zsh")

Features are individually versioned by the `version` attribute in a Feature's `devcontainer-feature.json`. Features are versioned according to the semver specification. More details can be found in [the dev container Feature specification](https://containers.dev/implementors/features/#versioning).
**Custom Themes:**

### Publishing
To use a custom theme file from your host machine, add a mount in your `devcontainer.json`:

> NOTE: The Distribution spec can be [found here](https://containers.dev/implementors/features-distribution/).
>
> While any registry [implementing the OCI Distribution spec](https://github.com/opencontainers/distribution-spec) can be used, this template will leverage GHCR (GitHub Container Registry) as the backing registry.
```json
{
"features": {
"ghcr.io/rosstaco/devcontainer-features/ohmyposh:1": {}
},
"mounts": [
"source=${localEnv:HOME}/path/to/theme.json,target=/home/vscode/.ohmyposh.json,type=bind"
]
}
```

Features are meant to be easily sharable units of dev container configuration and installation code.
The feature creates a placeholder file at `~/.ohmyposh.json` during installation. If you mount a custom theme to this location, it will be used automatically. Otherwise, the built-in theme specified in the options will be used.

This repo contains a **GitHub Action** [workflow](.github/workflows/release.yaml) that will publish each Feature to GHCR.
## Publishing

*Allow GitHub Actions to create and approve pull requests* should be enabled in the repository's `Settings > Actions > General > Workflow permissions` for auto generation of `src/<feature>/README.md` per Feature (which merges any existing `src/<feature>/NOTES.md`).
This repository uses a **GitHub Action** [workflow](.github/workflows/release.yaml) that publishes each Feature to GHCR (GitHub Container Registry).

By default, each Feature will be prefixed with the `<owner/<repo>` namespace. For example, Features in this repository can be referenced in a `devcontainer.json` with:
Features in this repository are referenced with:

```
ghcr.io/<owner>/<repo>/<feature>:1
ghcr.io/rosstaco/devcontainer-features/<feature>:1
```

The provided GitHub Action will also publish a third "metadata" package with just the namespace, eg: `ghcr.io/<owner>/<repo>`. This contains information useful for tools aiding in Feature discovery.

'`<owner>/<repo>`' is known as the feature collection namespace.

### Marking Feature Public

Note that by default, GHCR packages are marked as `private`. To stay within the free tier, Features need to be marked as `public`.

This can be done by navigating to the Feature's "package settings" page in GHCR, and setting the visibility to 'public`. The URL may look something like:
By default, GHCR packages are marked as `private`. To make them publicly accessible, navigate to the Feature's package settings page in GHCR and set the visibility to `public`:

```
https://github.com/users/<owner>/packages/container/<repo>%2F<featureName>/settings
https://github.com/users/rosstaco/packages/container/devcontainer-features%2F<featureName>/settings
```

<img width="669" alt="image" src="https://user-images.githubusercontent.com/23246594/185244705-232cf86a-bd05-43cb-9c25-07b45b3f4b04.png">

### Adding Features to the Index

If you'd like your Features to appear in our [public index](https://containers.dev/features) so that other community members can find them, you can do the following:
To add Features to the [public index](https://containers.dev/features):

* Go to [github.com/devcontainers/devcontainers.github.io](https://github.com/devcontainers/devcontainers.github.io)
* This is the GitHub repo backing the [containers.dev](https://containers.dev/) spec site
* Open a PR to modify the [collection-index.yml](https://github.com/devcontainers/devcontainers.github.io/blob/gh-pages/_data/collection-index.yml) file

This index is from where [supporting tools](https://containers.dev/supporting) like [VS Code Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and [GitHub Codespaces](https://github.com/features/codespaces) surface Features for their dev container creation UI.

#### Using private Features in Codespaces

For any Features hosted in GHCR that are kept private, the `GITHUB_TOKEN` access token in your environment will need to have `package:read` and `contents:read` for the associated repository.

Many implementing tools use a broadly scoped access token and will work automatically. GitHub Codespaces uses repo-scoped tokens, and therefore you'll need to add the permissions in `devcontainer.json`

An example `devcontainer.json` can be found below.

```jsonc
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/<owner>/<repo>/<feature>:1": {
"option": "value"
}
},
"customizations": {
"codespaces": {
"repositories": {
"<owner>/<repo>": {
"permissions": {
"packages": "read",
"contents": "read"
}
}
}
}
}
}
```
This allows tools like VS Code Dev Containers and GitHub Codespaces to surface your Features in their creation UI.
168 changes: 168 additions & 0 deletions docs/ohmyposh-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Oh My Posh devcontainer feature - Implementation Plan

## Overview

Create a devcontainer feature to install Oh My Posh with comprehensive configuration options. The installation will use GitHub releases API to download pre-compiled binaries directly for reliability and version control.

## Feature Structure

```
src/ohmyposh/
├── devcontainer-feature.json
└── install.sh
```

## Configuration Options

Define in `devcontainer-feature.json`:

- **`version`** (string, default: "latest")
- Oh My Posh version to install
- Supports: "latest" or specific version like "v19.0.0"

- **`theme`** (string, default: "jandedobbeleer")
- Built-in theme name to use as fallback
- Examples: "powerlevel10k_rainbow", "dracula", "agnoster", "pure"

- **`installPath`** (string, default: "/usr/local/bin")
- Binary installation location

- **`shells`** (string, default: "bash,zsh")
- Comma-separated list of shells to configure
- Options: "bash", "zsh", "fish"

## Installation Process (`install.sh`)

1. **Fetch binary from GitHub releases**
- Use GitHub API to get latest/specific release
- Detect architecture: amd64, arm64, arm
- Download appropriate binary for Linux

2. **Install binary**
- Move to specified `installPath`
- Set execute permissions
- Verify installation

3. **Create theme file placeholder**
```bash
touch /home/vscode/.ohmyposh.json
chown vscode:vscode /home/vscode/.ohmyposh.json
```

4. **Configure shells**
- Parse `shells` option
- Add init commands to respective rc files based on selected shells

## Shell Integration Logic

Add to shell rc files (`.bashrc`, `.zshrc`, `.config/fish/config.fish`):

```bash
# Check if user mounted a custom theme
if [ -s ~/.ohmyposh.json ]; then
# File has content, use custom theme
eval "$(oh-my-posh init <shell> --config ~/.ohmyposh.json)"
else
# Empty or invalid, use built-in theme from feature option
eval "$(oh-my-posh init <shell> --config <THEME>)"
fi
```

Where:
- `-s` checks if file exists and has content
- `<shell>` is replaced with actual shell (bash/zsh/fish)
- `<THEME>` is replaced with the theme option value

## Custom Theme Usage

### For Users

To use a custom Oh My Posh theme, add a mount to your `devcontainer.json`:

```jsonc
{
"features": {
"ghcr.io/rosstaco/devcontainer-features/ohmyposh:1": {
"theme": "jandedobbeleer",
"shells": "bash,zsh"
}
},
"mounts": [
"source=${localEnv:HOME}/path/to/your/theme.json,target=/home/vscode/.ohmyposh.json,type=bind"
]
}
```

### How It Works

1. Feature creates `~/.ohmyposh.json` during installation (empty file)
2. Mount target always exists, so mount operation succeeds
3. If user doesn't mount: file remains empty → feature uses built-in theme
4. If user mounts their theme: file has content → feature uses custom theme
5. User has full control over source path (can be anywhere on host)

## Key Design Decisions

### 1. Single Theme File Location
- **Path**: `~/.ohmyposh.json`
- **Rationale**: Simple, predictable, always exists
- **Benefit**: No mount failures, clear documentation

### 2. Graceful Fallback
- Empty file = use built-in theme from feature option
- Invalid JSON = use built-in theme
- Missing file = impossible (feature creates it)

### 3. User Flexibility
- Mount source path is user's choice
- Can point to anywhere on host system
- Not restricted to `.config` or specific locations

### 4. No `initializeCommand` Required
- Feature creates target file during build
- Mount succeeds even if source doesn't exist on host
- Simpler user setup

## Implementation Steps

1. Create `src/ohmyposh/devcontainer-feature.json` with options schema
2. Create `src/ohmyposh/install.sh` with:
- GitHub releases API integration
- Architecture detection
- Binary download and installation
- Theme file creation
- Shell configuration
3. Add error handling for:
- Network failures
- Architecture not supported
- Invalid version specified
4. Test on multiple base images (debian, ubuntu, alpine if supported)
5. Document in auto-generated README

## Testing Scenarios

1. **Default installation** - no options, uses latest + jandedobbeleer theme
2. **Specific version** - `"version": "v19.0.0"`
3. **Different theme** - `"theme": "dracula"`
4. **Custom shells** - `"shells": "zsh"` or `"shells": "bash,fish"`
5. **With custom theme mount** - user provides own theme file
6. **Without custom theme mount** - falls back to built-in

## Documentation Notes

Include in generated README:

- List of popular built-in themes
- Link to Oh My Posh themes gallery
- Example of mounting custom theme
- Note about Nerd Fonts requirement for most themes
- Shell configuration details
- Troubleshooting common issues

## Future Enhancements (Optional)

- Add `autoUpgrade` option for automatic updates
- Support for theme URLs (remote themes)
- Cache directory configuration
- Multiple theme files support
- Theme validation during build
24 changes: 24 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copy feature to .devcontainer for local testing
build-feature feature:
#!/usr/bin/env bash
set -e
echo "Copying {{feature}} feature to .devcontainer..."
rm -rf .devcontainer/{{feature}}
mkdir -p .devcontainer/{{feature}}
cp src/{{feature}}/devcontainer-feature.json .devcontainer/{{feature}}/
cp src/{{feature}}/install.sh .devcontainer/{{feature}}/
echo "✓ Feature copied to .devcontainer/{{feature}}"

# Build Oh My Posh feature
build-ohmyposh:
just build-feature ohmyposh

# Build all features
build-all:
just build-ohmyposh

# Clean copied features
clean:
rm -rf .devcontainer/ohmyposh
rm -f .devcontainer/*.tgz
echo "✓ Cleaned local features"
Empty file removed src/.gitkeep
Empty file.
Loading