Skip to content

Commit

Permalink
Add configFile option (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrmarti authored Dec 15, 2023
1 parent ede49b4 commit 8b2e2d0
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 2 deletions.
15 changes: 15 additions & 0 deletions .azure-devops/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ jobs:
exit 1
fi
- job: test_config_file
displayName: Test configFile option
steps:
- task: DevcontainersCi@0
inputs:
subFolder: github-tests/Dockerfile/config-file
configFile: github-tests/Dockerfile/config-file/.devcontainer/subfolder/devcontainer.json
runCmd: echo $HOSTNAME && [[ $HOSTNAME == "my-host" ]]
- script: |
echo "'runCmdOutput' value: $runCmdOutput"
if [["$runCmdOutput" = *my-host*]]; then
echo "'runCmdOutput' output of test_config_file job doesn't contain expected value 'my-host'"
exit 1
fi
- job: test_build_args
displayName: Test build-args
steps:
Expand Down
9 changes: 9 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "1.0.11",
"resolved": "ghcr.io/devcontainers/features/github-cli@sha256:464564228ccdd6028f01f8a62a3cfbaf76e9ba7953b29ac0e53ba2c262604312",
"integrity": "sha256:464564228ccdd6028f01f8a62a3cfbaf76e9ba7953b29ac0e53ba2c262604312"
}
}
}
40 changes: 40 additions & 0 deletions .github/workflows/ci_common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ jobs:
- test-gh-docker-from-docker-root
- test-gh-skip-user-update
- test-compose-features
- test-config-file
- test-simple
- test-no-run
- test-platform-with-runcmd
Expand Down Expand Up @@ -452,6 +453,45 @@ jobs:
env:
runCmdOutput: ${{ steps.simpletest.outputs.runCmdOutput }}

test-config-file:
name: Run test with config file
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@v3
with:
persist-credentials: false
# if the following value is missing (i.e. not triggered via comment workflow)
# then the default checkout will apply
ref: ${{ inputs.prRef }}

# Published action contains compiled JS, but we need to compile it here
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Compile GH action
run: |
(cd common && npm install && npm run build)
(cd github-action/ && npm install && npm run build && npm run package)
- name: Run test
uses: ./
id: configfiletest
with:
subFolder: github-tests/Dockerfile/config-file
configFile: github-tests/Dockerfile/config-file/.devcontainer/subfolder/devcontainer.json
runCmd: echo $HOSTNAME && [[ $HOSTNAME == "my-host" ]]
- name: Validate runCmdOutput output
run: |
echo "'runCmdOutput' value: $runCmdOutput"
if [["$runCmdOutput" = *my-host*]]; then
echo "'runCmdOutput' output of configfiletest step doesn't contain expected value 'my-host'"
exit 1
fi
env:
runCmdOutput: ${{ steps.configfiletest.outputs.runCmdOutput }}

test-gh-run-args:
name: Run GitHub run-args test
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ inputs:
required: false
description: Specify a child folder (containing a .devcontainer) instead of using the repository root
default:
configFile:
required: false
description: Specify the path to a devcontainer.json file instead of using `./.devcontainer/devcontainer.json` or `./.devcontainer.json`
default:
checkoutPath:
required: false
description: Specify path to checked out folder if not using default (or for testing with nektos/act)
Expand Down
6 changes: 6 additions & 0 deletions azdo-task/DevcontainersCi/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export async function runMain(): Promise<void> {
const imageTag = task.getInput('imageTag');
const platform = task.getInput('platform');
const subFolder = task.getInput('subFolder') ?? '.';
const relativeConfigFile = task.getInput('configFile');
const runCommand = task.getInput('runCmd');
const envs = task.getInput('env')?.split('\n') ?? [];
const inputEnvsWithDefaults = populateDefaults(envs);
Expand All @@ -62,6 +63,8 @@ export async function runMain(): Promise<void> {

const log = (message: string): void => console.log(message);
const workspaceFolder = path.resolve(checkoutPath, subFolder);
const configFile =
relativeConfigFile && path.resolve(checkoutPath, relativeConfigFile);

const resolvedImageTag = imageTag ?? 'latest';
const imageTagArray = resolvedImageTag.split(',');
Expand Down Expand Up @@ -91,6 +94,7 @@ export async function runMain(): Promise<void> {
}
const buildArgs: DevContainerCliBuildArgs = {
workspaceFolder,
configFile,
imageName: fullImageNameArray,
platform,
additionalCacheFroms: cacheFrom,
Expand Down Expand Up @@ -120,6 +124,7 @@ export async function runMain(): Promise<void> {
console.log('***');
const upArgs: DevContainerCliUpArgs = {
workspaceFolder,
configFile,
additionalCacheFroms: cacheFrom,
skipContainerUserIdUpdate,
env: inputEnvsWithDefaults,
Expand All @@ -141,6 +146,7 @@ export async function runMain(): Promise<void> {
console.log('***');
const execArgs: DevContainerCliExecArgs = {
workspaceFolder,
configFile,
command: ['bash', '-c', runCommand],
env: inputEnvsWithDefaults,
};
Expand Down
6 changes: 6 additions & 0 deletions azdo-task/DevcontainersCi/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
"label": "Specify a child folder (containing a .devcontainer) instead of using the repository root",
"required": false
},
{
"name": "configFile",
"type": "string",
"label": "Specify the path to a devcontainer.json file instead of using `./.devcontainer/devcontainer.json` or `./.devcontainer.json`",
"required": false
},
{
"name": "env",
"type": "multiLine",
Expand Down
1 change: 1 addition & 0 deletions azdo-task/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ In the example above, the devcontainer-build-run will perform the following step
| imageName | true | Image name to use when building the dev container image (including registry) |
| imageTag | false | One or more comma-separated image tags (defaults to `latest`) |
| subFolder | false | Use this to specify the repo-relative path to the folder containing the dev container (i.e. the folder that contains the `.devcontainer` folder). Defaults to repo root |
| configFile | false | Use this to specify the repo-relative path to the devcontainer.json file. Defaults to `./.devcontainer/devcontainer.json` and `./.devcontainer.json`. |
| runCmd | true | The command to run after building the dev container image |
| env | false | Specify environment variables to pass to the dev container when run |
| push | false | One of: `never`, `filter`, `always`. When set to `filter`, the image if pushed if the `sourceBranchFilterForPush`, `buildReasonsForPush`, and `pushOnFailedBuild` conditions are met. Defaults to `filter` if `imageName` is set, `never` otherwise. |
Expand Down
16 changes: 14 additions & 2 deletions common/src/dev-container-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export interface DevContainerCliBuildResult
extends DevContainerCliSuccessResult {}
export interface DevContainerCliBuildArgs {
workspaceFolder: string;
configFile: string | undefined;
imageName?: string[];
platform?: string;
additionalCacheFroms?: string[];
Expand All @@ -168,6 +169,9 @@ async function devContainerBuild(
'--workspace-folder',
args.workspaceFolder,
];
if (args.configFile) {
commandArgs.push('--config', args.configFile);
}
if (args.imageName) {
args.imageName.forEach(iName =>
commandArgs.push('--image-name', iName),
Expand Down Expand Up @@ -203,6 +207,7 @@ export interface DevContainerCliUpResult extends DevContainerCliSuccessResult {
}
export interface DevContainerCliUpArgs {
workspaceFolder: string;
configFile: string | undefined;
additionalCacheFroms?: string[];
skipContainerUserIdUpdate?: boolean;
env?: string[];
Expand All @@ -220,6 +225,9 @@ async function devContainerUp(
args.workspaceFolder,
...remoteEnvArgs,
];
if (args.configFile) {
commandArgs.push('--config', args.configFile);
}
if (args.additionalCacheFroms) {
args.additionalCacheFroms.forEach(cacheFrom =>
commandArgs.push('--cache-from', cacheFrom),
Expand All @@ -245,6 +253,7 @@ async function devContainerUp(

export interface DevContainerCliExecArgs {
workspaceFolder: string;
configFile: string | undefined;
command: string[];
env?: string[];
userDataFolder?: string;
Expand All @@ -255,12 +264,15 @@ async function devContainerExec(
): Promise<number | null> {
// const remoteEnvArgs = args.env ? args.env.flatMap(e=> ["--remote-env", e]): []; // TODO - test flatMap again
const remoteEnvArgs = getRemoteEnvArray(args.env);
const commandArgs = ["exec", "--workspace-folder", args.workspaceFolder, ...remoteEnvArgs, ...args.command];
const commandArgs = ["exec", "--workspace-folder", args.workspaceFolder, ...remoteEnvArgs];
if (args.configFile) {
commandArgs.push('--config', args.configFile);
}
if (args.userDataFolder) {
commandArgs.push("--user-data-folder", args.userDataFolder);
}
return await runSpecCliNonJsonCommand({
args: commandArgs,
args: commandArgs.concat(args.command),
log,
env: {DOCKER_BUILDKIT: '1', COMPOSE_DOCKER_CLI_BUILD: '1'},
});
Expand Down
1 change: 1 addition & 0 deletions docs/azure-devops-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ In the example above, the devcontainer-build-run will perform the following step
| imageName | true | Image name to use when building the dev container image (including registry) |
| imageTag | false | One or more comma-separated image tags (defaults to `latest`) |
| subFolder | false | Use this to specify the repo-relative path to the folder containing the dev container (i.e. the folder that contains the `.devcontainer` folder). Defaults to repo root |
| configFile | false | Use this to specify the repo-relative path to the devcontainer.json file. Defaults to `./.devcontainer/devcontainer.json` and `./.devcontainer.json`. |
| runCmd | true | The command to run after building the dev container image |
| env | false | Specify environment variables to pass to the dev container when run |
| push | false | One of: `never`, `filter`, `always`. When set to `filter`, the image if pushed if the `sourceBranchFilterForPush`, `buildReasonsForPush`, and `pushOnFailedBuild` conditions are met. Defaults to `filter` if `imageName` is set, `never` otherwise. |
Expand Down
1 change: 1 addition & 0 deletions docs/github-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ The [`devcontainers/ci` action](https://github.com/marketplace/actions/devcontai
| imageName | true | Image name to use when building the dev container image (including registry) |
| imageTag | false | One or more comma-separated image tags (defaults to `latest`) |
| subFolder | false | Use this to specify the repo-relative path to the folder containing the dev container (i.e. the folder that contains the `.devcontainer` folder). Defaults to repo root |
| configFile | false | Use this to specify the repo-relative path to the devcontainer.json file. Defaults to `./.devcontainer/devcontainer.json` and `./.devcontainer.json`. |
| runCmd | true | The command to run after building the dev container image |
| env | false | Specify environment variables to pass to the dev container when run |
| checkoutPath | false | Only used for development/testing |
Expand Down
8 changes: 8 additions & 0 deletions github-action/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export async function runMain(): Promise<void> {
const imageTag = emptyStringAsUndefined(core.getInput('imageTag'));
const platform = emptyStringAsUndefined(core.getInput('platform'));
const subFolder: string = core.getInput('subFolder');
const relativeConfigFile = emptyStringAsUndefined(
core.getInput('configFile'),
);
const runCommand = core.getInput('runCmd');
const inputEnvs: string[] = core.getMultilineInput('env');
const inputEnvsWithDefaults = populateDefaults(inputEnvs);
Expand All @@ -72,6 +75,8 @@ export async function runMain(): Promise<void> {

const log = (message: string): void => core.info(message);
const workspaceFolder = path.resolve(checkoutPath, subFolder);
const configFile =
relativeConfigFile && path.resolve(checkoutPath, relativeConfigFile);

const resolvedImageTag = imageTag ?? 'latest';
const imageTagArray = resolvedImageTag.split(',');
Expand Down Expand Up @@ -108,6 +113,7 @@ export async function runMain(): Promise<void> {
const buildResult = await core.group('🏗️ build container', async () => {
const args: DevContainerCliBuildArgs = {
workspaceFolder,
configFile,
imageName: fullImageNameArray,
platform,
additionalCacheFroms: cacheFrom,
Expand Down Expand Up @@ -142,6 +148,7 @@ export async function runMain(): Promise<void> {
const upResult = await core.group('🏃 start container', async () => {
const args: DevContainerCliUpArgs = {
workspaceFolder,
configFile,
additionalCacheFroms: cacheFrom,
skipContainerUserIdUpdate,
env: inputEnvsWithDefaults,
Expand All @@ -166,6 +173,7 @@ export async function runMain(): Promise<void> {
async () => {
const args: DevContainerCliExecArgs = {
workspaceFolder,
configFile,
command: ['bash', '-c', runCommand],
env: inputEnvsWithDefaults,
userDataFolder,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "config-file",
"image": "mcr.microsoft.com/devcontainers/base:jammy",
"runArgs": [
"--hostname", "my-host"
]}

0 comments on commit 8b2e2d0

Please sign in to comment.