diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a5f0386..660e137 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -34,5 +34,7 @@ ], // Mount the parent as /workspaces so we can pip install peers as editable "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind", - "initializeCommand": "mkdir -p ${localEnv:HOME}/.config/devcontainer_rc" + // Create the config folder for the bash-config feature + "initializeCommand": "mkdir -p ${localEnv:HOME}/.config/bash-config", + "remoteUser": "root" } \ No newline at end of file diff --git a/.devcontainer/features/bash-config/README.md b/.devcontainer/features/bash-config/README.md index e164739..beeb168 100644 --- a/.devcontainer/features/bash-config/README.md +++ b/.devcontainer/features/bash-config/README.md @@ -1,26 +1,47 @@ -# Lightweight, Configurable BASH Eternal History +# Lightweight, Configurable BASH Config with Eternal History -## Defaults +Intended as a lightweight alternative to common-utils. -When this feature is first called, onCreateCommand.sh is created and called in `devcontainer-feature`. -This creates and installs a default bash terminal configuration from `feature_settings_rc` which contains opinionated default BASH terminal settings such as: -* A minimalist, blue bash prompt. -* Eternal, shared history between containers using this feature. +## Installation -## Customisation +To use this feature in an individual devcontainer, add the following to your `.devcontainer/devcontainer.json`: + +```json + "features": { + "ghcr.io/diamondlightsource/devcontainer-features/bash-config:1": {} + }, + "initializeCommand": "mkdir -p ${localEnv:HOME}/.config/bash-config", +``` + +The initializeCommand is required to create the directory for the bash-config folder in your home folder on the host, the very first time this is executed. Features do not have an InitializeCommand, so the devcontainer.json must do this. + +## Global Installation + +To use this feature in all devcontainers on your workstation, add the following to User setting.json: + +```json + "dev.containers.defaultFeatures": { + "ghcr.io/gilesknap/devcontainer-features/bash-config:1.1.0" + } +``` -The user can specify their own terminal preferences in `$CONFIG_STAGING/bashrc`, which defaults to `/devcontainer_staging/bashrc`. -Then the container is rebuilt, if `bashrc` already exists it won't be overwritten, preserving changes. If the container has been built once already, the existing bashrc must be deleted in order for your changes to be applied. +Also, one time only, make sure the host folder for bash-config is created: +```bash +mkdir -p $HOME/.config/bash-config +``` -creates staging folder in container -creates onCreateCommand.sh in the staging folder -inputrc and bashrc are also created in the staging folder, containing incremental history searching and user customisations respectively -feature_settings_rc is created in the staging fodler, which contains a PS1 setup and opinionated terminal features -"onCreateCommand" is then exectuted inside the container during finalisation of container setup. - - This copies the contents of feature_settings_rc into devcontainer_rc - - then copies bashrc and inputrc into the container, unless they exist already to prevent overwriting user edits - - then adds root permissions. -A symbolic link to /root/ is created The items in the CONFIG_FOLDER -our bashrc is called by /root/.bashrc \ No newline at end of file +## features + +The default, opinionated configuration can be found in `$HOME/.config/bash-config/bash-config-rc` and includes the following: + +- Persistent history across all devcontainers that use this feature +- The MS devcontainer bash prompt with git branch and status +- history search with up/down arrows (.inputrc) +- ctrl-left or right arrow for word navigation (.inputrc) +- git autocomplete + +## Customisation + +Can be customized by editing `$HOME/.config/bash-config/bashrc` \ No newline at end of file diff --git a/.devcontainer/features/bash-config/config/README.md b/.devcontainer/features/bash-config/config/README.md new file mode 100644 index 0000000..762966e --- /dev/null +++ b/.devcontainer/features/bash-config/config/README.md @@ -0,0 +1,23 @@ +# bash-config configuration files + +## introduction + +The files in this folder are copied out of the bash-config feature and +into the users config folder on the host at ~/.config/bash-config + +## files + +- bashrc: The entry point for the bash-config feature. User editable +- inputrc: The readline configuration file. User editable +- bash-config-rc: The configuration file for the bash-config feature. Not + user editable. Replaced with the latest version on each rebuild of the + developer container. + +## Stages + +1. At build time all the files in this folder are copied to a staging folder +in the container filesystem. +1. At container runtime the files are copied from the staging folder to the +users config folder on the host. +1. The file onCreateCommand.sh is executed at container creation time in order +to facilitate the above copy. diff --git a/.devcontainer/features/bash-config/config/bash-config-rc b/.devcontainer/features/bash-config/config/bash-config-rc new file mode 100644 index 0000000..d2a96a4 --- /dev/null +++ b/.devcontainer/features/bash-config/config/bash-config-rc @@ -0,0 +1,46 @@ +#!/bin/bash + +# default opinioned bash configuration + +# set the prompt +export PS1="\[\033[1;34m\]\W \[\033[0m\]# " + +# enable enternal shared history +export HISTCONTROL=ignoreboth:erasedups +export HISTSIZE=-1 +export HISTFILESIZE=-1 +export SAVEHIST=-1 +export HISTFILE=$CONFIG_FOLDER/.bash_eternal_history + +# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme +# from https://github.com/devcontainers/features/blob/main/src/common-utils/scripts/bash_theme_snippet.sh +__bash_prompt() { + local userpart='`export XIT=$? \ + && [ ! -z "${GITHUB_USER:-}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER:-} " || echo -n "\[\033[0;32m\]\u " \ + && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' + local gitbranch='`\ + if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ + export BRANCH="$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null)"; \ + if [ "${BRANCH:-}" != "" ]; then \ + echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH:-}" \ + && if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \ + git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ + echo -n " \[\033[1;33m\]✗"; \ + fi \ + && echo -n "\[\033[0;36m\]) "; \ + fi; \ + fi`' + local lightblue='\[\033[1;34m\]' + local removecolor='\[\033[0m\]' + PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " + unset -f __bash_prompt +} +__bash_prompt +export PROMPT_DIRTRIM=4 + +# enable bash completion for git +if [[ -f /usr/share/bash-completion/completions/git ]]; then + source /usr/share/bash-completion/completions/git +elif [[ -f /etc/bash_completion.d/git ]]; then + source /etc/bash_completion.d/git +fi diff --git a/.devcontainer/features/bash-config/config/bashrc b/.devcontainer/features/bash-config/config/bashrc new file mode 100644 index 0000000..21f98d6 --- /dev/null +++ b/.devcontainer/features/bash-config/config/bashrc @@ -0,0 +1,19 @@ +#!/bin/bash + +# This bashrc will be source from /root/.bashrc upon launch of every terminal +# in a devcontainer that uses the bash-config feature from +# https://github.com/DiamondLightSource/devcontainer-features + +# This file is initialized by bash-config, but you are then free to edit it + +# execute default, opinionated settings - delete this line to remove defaults +source $CONFIG_FOLDER/bash-config-rc + +if [ ! -f /one-time ]; then + + # add your personal one time only (container creation) commands here + + touch /one-time +fi + +# add your personal settings for every shell below diff --git a/.devcontainer/features/bash-config/config/inputrc b/.devcontainer/features/bash-config/config/inputrc new file mode 100644 index 0000000..e44e17b --- /dev/null +++ b/.devcontainer/features/bash-config/config/inputrc @@ -0,0 +1,10 @@ +# Readline configuration for bash shell. + +# Incremental history searching with up and down arrows (C-P and C-N for old +# style navigation). +"\e[A": history-search-backward +"\e[B": history-search-forward + +# Control left and right for word movement +"\e[5C": forward-word +"\e[5D": backward-word \ No newline at end of file diff --git a/.devcontainer/features/bash-config/config/onCreateCommand.sh b/.devcontainer/features/bash-config/config/onCreateCommand.sh new file mode 100644 index 0000000..b1cbed8 --- /dev/null +++ b/.devcontainer/features/bash-config/config/onCreateCommand.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# this script is run once inside the developer container at creation time + +# copy in the opinionated default settings from the feature +cp $CONFIG_STAGING/bash-config-rc $CONFIG_FOLDER + +# copy in the user editable settings unless they already exist +if [[ ! -f $CONFIG_FOLDER/bashrc ]] ; then + cp $CONFIG_STAGING/bashrc $CONFIG_FOLDER + cp $CONFIG_STAGING/inputrc $CONFIG_FOLDER +fi + +# hook in the config to the root account +ln -s $CONFIG_FOLDER/inputrc /root/.inputrc +echo "source $CONFIG_FOLDER/bashrc" >> /root/.bashrc \ No newline at end of file diff --git a/.devcontainer/features/bash-config/devcontainer-feature.json b/.devcontainer/features/bash-config/devcontainer-feature.json index 4cc68e6..dcd52bb 100644 --- a/.devcontainer/features/bash-config/devcontainer-feature.json +++ b/.devcontainer/features/bash-config/devcontainer-feature.json @@ -2,19 +2,20 @@ "name": "Lightweight and configurable BASH eternal history", //ID *must* match parent folder name *exactly* "id": "bash-config", - "version": "1.0.0", + // a default beta version that is replaced by CI when doing tagged releases + "version": "0.0.1-b1", "description": "Lightweight BASH setup with eternal history and PS1 tweaks. Fully configurable.", - "documentationURL": "https://raw.githubusercontent.com/DiamondRC/devcontainer-features/refs/heads/main/.devcontainer/features/bash-config/README.md", + "documentationURL": "https://raw.githubusercontent.com/DiamondLightSource/devcontainer-features/refs/heads/main/.devcontainer/features/bash-config/README.md", "containerEnv": { - "CONFIG_FOLDER": "/devcontainer_rc", - "CONFIG_STAGING": "/devcontainer_staging" + "CONFIG_FOLDER": "/bash-config", + "CONFIG_STAGING": "/bash-config-staging" }, "mounts": [ { - "source": "${localEnv:HOME}/.config/devcontainer_rc", - "target": "/devcontainer_rc", + "source": "${localEnv:HOME}/.config/bash-config", + "target": "/bash-config", "type": "bind" } ], - "onCreateCommand": "bash /devcontainer_staging/onCreateCommand.sh" -} + "onCreateCommand": "bash /bash-config-staging/onCreateCommand.sh" +} \ No newline at end of file diff --git a/.devcontainer/features/bash-config/install.sh b/.devcontainer/features/bash-config/install.sh index 95db35a..e71b846 100644 --- a/.devcontainer/features/bash-config/install.sh +++ b/.devcontainer/features/bash-config/install.sh @@ -1,71 +1,24 @@ #!/bin/bash -set -e - -echo "Activating feature 'terminal-history'" -echo "User: ${_REMOTE_USER} User home: ${_REMOTE_USER_HOME}" - -mkdir -p $CONFIG_STAGING - -# ------------------------------------------------------------------------------- -cat > $CONFIG_STAGING/onCreateCommand.sh \ -<< EOF -#!/bin/bash - -# copy in the opinionated default settings from the feature -cp $CONFIG_STAGING/feature_settings_rc $CONFIG_FOLDER/feature_settings_rc - -# copy in the user editable settings unless they already exist -if [[ ! -f $CONFIG_FOLDER/bashrc ]] ; then - cp $CONFIG_STAGING/bashrc $CONFIG_FOLDER - cp $CONFIG_STAGING/inputrc $CONFIG_FOLDER -fi -# hook in the config to the root account -ln -s $CONFIG_FOLDER/inputrc /root/.inputrc -echo "source $CONFIG_FOLDER/bashrc" >> /root/.bashrc -EOF - -# ------------------------------------------------------------------------------- -cat > $CONFIG_STAGING/inputrc \ -<< EOF -# Readline configuration for bash shell. - -# Incremental history searching with up and down arrows (C-P and C-N for old -# style navigation). -"\e[A": history-search-backward -"\e[B": history-search-forward - -# Control left and right for word movement -"\e[5C": forward-word -"\e[5D": backward-word -EOF - -# ------------------------------------------------------------------------------- -cat > $CONFIG_STAGING/bashrc \ -<< EOF -#!/bin/bash +# abort on error +set -e -# execute default opinionated settings - delete this line to remove defaults -source $CONFIG_FOLDER/feature_settings_rc +# discover where this install.sh and its peers have been extracted to +this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# add your personal custom settings below -EOF -# ------------------------------------------------------------------------------- -cat > $CONFIG_STAGING/feature_settings_rc \ -<< EOF -#!/bin/bash +echo "Activating feature 'bash-config'" +echo "User: ${_REMOTE_USER} User home: ${_REMOTE_USER_HOME}" -# default opinioned bash configuration +# This script is run at container build time. +# +# Here we place all the configuration files in a staging area. +# +# Then at container runtime, when the hosts' config folder is mounted in, we +# can copy from the staging area to the mounted host folder +# +# The runtime copy to host folder is performed once only by onCreateCommand.sh -# set the prompt -export PS1="\[\033[1;34m\]\W \[\033[0m\]# " +mkdir -p "$CONFIG_STAGING" +cp -r "$this_dir"/config/* "$CONFIG_STAGING" -# enable enternal shared history -export HISTCONTROL=ignoreboth:erasedups -export HISTSIZE=-1 -export HISTFILESIZE=-1 -export SAVEHIST=-1 -export HISTFILE=$CONFIG_FOLDER/.bash_eternal_history -PROMPT_COMMAND="history -a; $PROMPT_COMMAND" -EOF diff --git a/.github/workflows/_check.yml b/.github/workflows/_check.yml new file mode 100644 index 0000000..a6139c1 --- /dev/null +++ b/.github/workflows/_check.yml @@ -0,0 +1,27 @@ +on: + workflow_call: + outputs: + branch-pr: + description: The PR number if the branch is in one + value: ${{ jobs.pr.outputs.branch-pr }} + +jobs: + pr: + runs-on: "ubuntu-latest" + outputs: + branch-pr: ${{ steps.script.outputs.result }} + steps: + - uses: actions/github-script@v7 + id: script + if: github.event_name == 'push' + with: + script: | + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: context.repo.owner + ':${{ github.ref_name }}' + }) + if (prs.data.length) { + console.log(`::notice ::Skipping CI on branch push as it is already run in PR #${prs.data[0]["number"]}`) + return prs.data[0]["number"] + } diff --git a/.github/workflows/release.yaml b/.github/workflows/_release.yml similarity index 66% rename from .github/workflows/release.yaml rename to .github/workflows/_release.yml index 8f7c58b..6fc1efd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/_release.yml @@ -1,28 +1,41 @@ name: "Release dev container features & Generate Documentation" on: + # use this to test releasing of the devcontainer features in a branch workflow_dispatch: + workflow_call: jobs: deploy: - if: ${{ github.ref == 'refs/heads/main' }} runs-on: ubuntu-latest permissions: contents: write - pull-requests: write packages: write steps: - uses: actions/checkout@v4 + - name: patch in version tag + # patch the version tag if the version is a valid semver. If not then + # default to 0.0.1-b1 (only when using workflow_dispatch for tests) + run: | + if [[ ${{ github.ref_name }} =~ ^[0-9]+\.[0-9]+.+ ]] ; then + sed -i s/0\.0\.1-b1/${{ github.ref_name }}/ $(find .devcontainer -name devcontainer-feature.json) + # dump the modified json for debugging + cat $(find .devcontainer -name devcontainer-feature.json) + fi + - name: "Publish Features" uses: devcontainers/action@v1 with: publish-features: "true" base-path-to-features: "./src" generate-docs: "true" - + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # the example features publishes docs like below - I believe this is only + # relevant if publishing to the marketplace? + # - name: Create PR for Documentation # id: push_image_info # env: diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml new file mode 100644 index 0000000..1ed3f44 --- /dev/null +++ b/.github/workflows/_test.yml @@ -0,0 +1,26 @@ +name: "CI - Test Features" +on: + workflow_call: + +jobs: + test-autogenerated: + runs-on: ubuntu-latest + continue-on-error: true + strategy: + matrix: + features: + - bash-config + baseImage: + - debian:latest + - ubuntu:latest + steps: + - uses: actions/checkout@v4 + + - name: "Install latest devcontainer CLI" + run: | + npm install -g @devcontainers/cli + mkdir -p ~/.config/bash-config + + - name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'" + run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} . + diff --git a/.github/workflows/validate.yml b/.github/workflows/_validate.yml similarity index 95% rename from .github/workflows/validate.yml rename to .github/workflows/_validate.yml index 1109b17..666b5dc 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/_validate.yml @@ -1,6 +1,6 @@ name: "Validate devcontainer-feature.json files" on: - pull_request: + workflow_call: jobs: validate: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2194778 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: CI + +on: + push: + pull_request: + +jobs: + check: + uses: ./.github/workflows/_check.yml + + validate: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_validate.yml + + test: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_test.yml + + release: + if: github.ref_type == 'tag' + needs: test + uses: ./.github/workflows/_release.yml + permissions: + contents: write + packages: write + diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml deleted file mode 100644 index 80017c1..0000000 --- a/.github/workflows/test.yaml +++ /dev/null @@ -1,58 +0,0 @@ -name: "CI - Test Features" -on: - push: - branches: - - main - pull_request: - workflow_dispatch: - -jobs: - test-autogenerated: - runs-on: ubuntu-latest - continue-on-error: true - strategy: - matrix: - features: - - terminal-history - baseImage: - - debian:latest - - ubuntu:latest - steps: - - uses: actions/checkout@v4 - - - name: "Install latest devcontainer CLI" - run: | - npm install -g @devcontainers/cli - mkdir -p ~/.config/devcontainer_rc - - - name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'" - run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} . - -# test-scenarios: -# runs-on: ubuntu-latest -# continue-on-error: true -# strategy: -# matrix: -# features: -# - color -# - hello -# steps: -# - uses: actions/checkout@v4 -# -# - name: "Install latest devcontainer CLI" -# run: npm install -g @devcontainers/cli -# -# - name: "Generating tests for '${{ matrix.features }}' scenarios" -# run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated --skip-duplicated . -# -# test-global: -# runs-on: ubuntu-latest -# continue-on-error: true -# steps: -# - uses: actions/checkout@v4 -# -# - name: "Install latest devcontainer CLI" -# run: npm install -g @devcontainers/cli -# -# - name: "Testing global scenarios" -# run: devcontainer features test --global-scenarios-only . diff --git a/README.md b/README.md index 1a1cea8..b5d09c2 100644 --- a/README.md +++ b/README.md @@ -1,188 +1,25 @@ -# 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). +Devcontainer features for use in Python Copier Template or any other devcontainer. -## Example Contents +## bash-config -This repository contains a _collection_ of two Features - `hello` and `color`. These Features serve as simple feature implementations. Each sub-section below shows a sample `devcontainer.json` alongside example usage of the Feature. +Adds customizations to the the bash shell that can be shared across all developer containers using the feature. -### `hello` +See details in the [bash-config README](.devcontainer/features/bash-config/README.md). -Running `hello` inside the built container will print the greeting provided to it via its `greeting` option. +## other -```jsonc -{ - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers/feature-starter/hello:1": { - "greeting": "Hello" - } - } -} -``` +Further features may be added here in future. -```bash -$ hello +## Testing -Hello, user. -``` +This repo has it's own devcontainer which can be used to do local testing and development of the features. -### `color` +## Publishing Features -Running `color` inside the built container will print your favorite color to standard out. +CI verifies and publishes the feature(s) as follows:- -```jsonc -{ - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers/feature-starter/color:1": { - "favorite": "green" - } - } -} -``` +- bash-config: ghcr.io/diamondlightsource/devcontainer-features/bash-config:1 -```bash -$ color - -my favorite color is green -``` - -## Repo and Feature Structure - -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`. - -``` -├── src -│ ├── hello -│ │ ├── devcontainer-feature.json -│ │ └── install.sh -│ ├── color -│ │ ├── 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. - -### Options - -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). - -For example, the `color` feature provides an enum of three possible options (`red`, `gold`, `green`). If no option is provided in a user's `devcontainer.json`, the value is set to "red". - -```jsonc -{ - // ... - "options": { - "favorite": { - "type": "string", - "enum": [ - "red", - "gold", - "green" - ], - "default": "red", - "description": "Choose your favorite color." - } - } -} -``` - -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). - -```bash -#!/bin/bash - -echo "Activating feature 'color'" -echo "The provided favorite color is: ${FAVORITE}" - -... -``` - -## Distributing Features - -### Versioning - -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). - -### Publishing - -> 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. - -Features are meant to be easily sharable units of dev container configuration and installation code. - -This repo contains a **GitHub Action** [workflow](.github/workflows/release.yaml) that will publish each Feature to GHCR. - -*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//README.md` per Feature (which merges any existing `src//NOTES.md`). - -By default, each Feature will be prefixed with the `` namespace. For example, the two Features in this repository can be referenced in a `devcontainer.json` with: - -``` -ghcr.io/devcontainers/feature-starter/color:1 -ghcr.io/devcontainers/feature-starter/hello:1 -``` - -The provided GitHub Action will also publish a third "metadata" package with just the namespace, eg: `ghcr.io/devcontainers/feature-starter`. This contains information useful for tools aiding in Feature discovery. - -'`devcontainers/feature-starter`' 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: - -``` -https://github.com/users//packages/container/%2F/settings -``` - -image - -### 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: - -* 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/my-org/private-features/hello:1": { - "greeting": "Hello" - } - }, - "customizations": { - "codespaces": { - "repositories": { - "my-org/private-features": { - "permissions": { - "packages": "read", - "contents": "read" - } - } - } - } - } -} -``` +(the tag can be major, major.minor, major.minor.patch, or latest) diff --git a/test/bash-config/scenarios.json b/test/bash-config/scenarios.json new file mode 100644 index 0000000..484e02a --- /dev/null +++ b/test/bash-config/scenarios.json @@ -0,0 +1,8 @@ +{ + "hello": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "bash-config": {} + } + } +} \ No newline at end of file diff --git a/test/bash-config/test.sh b/test/bash-config/test.sh new file mode 100644 index 0000000..2886eb3 --- /dev/null +++ b/test/bash-config/test.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +# 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 +# The 'check' command comes from the dev-container-features-test-lib. Syntax is... +# check