Skip to content

Commit

Permalink
Fix #101 Suggest HEALTHCHECK flags after an ONBUILD
Browse files Browse the repository at this point in the history
When an ONBUILD's trigger instruction is a HEALTHCHECK, it should be
possible to get the HEALTHCHECK flags suggested as completion items.

Signed-off-by: Remy Suen <[email protected]>
  • Loading branch information
rcjsuen committed Jul 25, 2017
1 parent bdc2e36 commit 99d7705
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 75 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ All notable changes to this project will be documented in this file.
- suggest build stage names in a COPY instruction ([#44](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/44))
- add '=' as a trigger character
- include the --start-period flag in HEALTHCHECK CMD items ([#78](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/78))
- HEALTHCHECK CMD flags ([#69](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/69))
- HEALTHCHECK CMD flags ([#69](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/69), [#101](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/101))
- suggest $ variables ([#93](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/93))
- ARG and ENV variables
- default Docker ARG variables
Expand Down
45 changes: 38 additions & 7 deletions src/dockerAssist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { DockerHover } from './dockerHover';
import { DockerfileParser } from './parser/dockerfileParser';
import { Copy } from './parser/instructions/copy';
import { Healthcheck } from './parser/instructions/healthcheck';
import { Onbuild } from './parser/instructions/onbuild';
import { Instruction } from './parser/instruction';

export class DockerAssist {
Expand Down Expand Up @@ -117,9 +118,44 @@ export class DockerAssist {
case "COPY":
return this.createBuildStageProposals(dockerfile, instruction as Copy, position, offset);
case "HEALTHCHECK":
return this.createHealthcheckProposals(dockerfile, instruction as Healthcheck, position, offset, prefix);
let subcommand = (instruction as Healthcheck).getSubcommand();
if (subcommand && subcommand.isBefore(position)) {
return [];
}
return this.createHealthcheckProposals(dockerfile, position, offset, prefix);
case "ONBUILD":
let onbuildArgs = instruction.getArguments();
if (onbuildArgs.length === 0 || Util.isInsideRange(position, onbuildArgs[0].getRange())) {
// no trigger instructions or the cursor is in the trigger instruction
previousWord = "ONBUILD";
break instructionsCheck;
} else {
let trigger = (instruction as Onbuild).getTriggerInstruction();
if (trigger === "HEALTHCHECK") {
if (onbuildArgs.length === 1) {
// suggest HEALTHCHECK flags
return this.createHealthcheckProposals(dockerfile, position, offset, prefix);
}
for (let i = 1; i < onbuildArgs.length; i++) {
let arg = onbuildArgs[i].getValue().toUpperCase();
if (arg === "CMD" || arg === "NONE") {
return [];
} else if (Util.isInsideRange(position, onbuildArgs[i].getRange())) {
return this.createHealthcheckProposals(dockerfile, position, offset, prefix);
}
}
}
}
switch (onbuildArgs.length) {
case 0:
previousWord = "ONBUILD";
break instructionsCheck;
case 1:
previousWord = "ONBUILD";
break instructionsCheck;
default:
break;
}
if (onbuildArgs.length === 0 || Util.isInsideRange(position, onbuildArgs[0].getRange())) {
previousWord = "ONBUILD";
break instructionsCheck;
Expand Down Expand Up @@ -207,12 +243,7 @@ export class DockerAssist {
return [];
}

private createHealthcheckProposals(dockerfile: Dockerfile, healthcheck: Healthcheck, position: Position, offset: number, prefix: string) {
let subcommand = healthcheck.getSubcommand();
if (subcommand && subcommand.isBefore(position)) {
return [];
}

private createHealthcheckProposals(dockerfile: Dockerfile, position: Position, offset: number, prefix: string) {
let items: CompletionItem[] = [];
if ("--interval".indexOf(prefix) === 0) {
items.push(this.createHEALTHCHECK_FlagInterval(prefix, offset));
Expand Down
5 changes: 5 additions & 0 deletions src/parser/instructions/onbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export class Onbuild extends Instruction {
super(document, range, escapeChar, instruction, instructionRange);
}

public getTriggerInstruction(): string | null {
let trigger = this.getTrigger();
return trigger === null ? null : trigger.toUpperCase();
}

public getTrigger(): string | null {
return this.getRangeContent(this.getTriggerRange());
}
Expand Down
141 changes: 74 additions & 67 deletions test/dockerAssist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1382,99 +1382,104 @@ describe('Docker Content Assist Tests', function() {
});
});

describe("HEALTHCHECK", function() {
function testHealthcheck(snippetSupport: boolean) {
describe("arguments", function() {
it("full", function() {
var items = computePosition("FROM busybox\nHEALTHCHECK ", 1, 12, snippetSupport);
assertHealthcheckItems(items, 1, 12, 1, 12, snippetSupport);
});
function testHealthcheck(trigger: boolean) {
describe("HEALTHCHECK", function() {
let onbuild = trigger ? "ONBUILD " : "";
let triggerOffset = onbuild.length;
function testFlags(snippetSupport: boolean) {
describe("arguments", function() {
it("full", function() {
var items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK ", 1, triggerOffset + 12, snippetSupport);
assertHealthcheckItems(items, 1, triggerOffset + 12, 1, triggerOffset + 12, snippetSupport);
});

it("prefix", function() {
var items = computePosition("FROM busybox\nHEALTHCHECK -", 1, 13, snippetSupport);
assertHealthcheckItems(items, 1, 12, 1, 13, snippetSupport);
it("prefix", function() {
var items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK -", 1, triggerOffset + 13, snippetSupport);
assertHealthcheckItems(items, 1, triggerOffset + 12, 1, triggerOffset + 13, snippetSupport);

items = computePosition("FROM busybox\nHEALTHCHECK --", 1, 14, snippetSupport);
assertHealthcheckItems(items, 1, 12, 1, 14, snippetSupport);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK --", 1, triggerOffset + 14, snippetSupport);
assertHealthcheckItems(items, 1, triggerOffset + 12, 1, triggerOffset + 14, snippetSupport);

items = computePosition("FROM busybox\nHEALTHCHECK --inter", 1, 19, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagInterval(items[0], 1, 12, 1, 19, snippetSupport);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK --inter", 1, triggerOffset + 19, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagInterval(items[0], 1, triggerOffset + 12, 1, triggerOffset + 19, snippetSupport);

items = computePosition("FROM busybox\nHEALTHCHECK --ret", 1, 17, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagRetries(items[0], 1, 12, 1, 17, snippetSupport);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK --ret", 1, triggerOffset + 17, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagRetries(items[0], 1, triggerOffset + 12, 1, triggerOffset + 17, snippetSupport);

items = computePosition("FROM busybox\nHEALTHCHECK --start", 1, 19, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagStartPeriod(items[0], 1, 12, 1, 19, snippetSupport);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK --start", 1, triggerOffset + 19, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagStartPeriod(items[0], 1, triggerOffset + 12, 1, triggerOffset + 19, snippetSupport);

items = computePosition("FROM busybox\nHEALTHCHECK --time", 1, 18, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagTimeout(items[0], 1, 12, 1, 18, snippetSupport);
});
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK --time", 1, triggerOffset + 18, snippetSupport);
assert.equal(items.length, 1);
assertHEALTHCHECK_FlagTimeout(items[0], 1, triggerOffset + 12, 1, triggerOffset + 18, snippetSupport);
});

it("after command", function() {
var items = computePosition("FROM busybox\nHEALTHCHECK CMD", 1, 15, snippetSupport);
assert.equal(items.length, 0);
it("after command", function() {
var items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK CMD", 1, triggerOffset + 15, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK cmd", 1, 15, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK cmd", 1, triggerOffset + 15, snippetSupport);
assert.equal(items.length, 0);

var items = computePosition("FROM busybox\nHEALTHCHECK CMD ", 1, 16, snippetSupport);
assert.equal(items.length, 0);
var items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK CMD ", 1, triggerOffset + 16, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK cmd ", 1, 16, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK cmd ", 1, triggerOffset + 16, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK CMD\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK CMD\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK cmd\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK cmd\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK CMD \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK CMD \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK cmd \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK cmd \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK NONE", 1, 16, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK NONE", 1, triggerOffset + 16, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK none", 1, 16, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK none", 1, triggerOffset + 16, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK NONE ", 1, 17, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK NONE ", 1, triggerOffset + 17, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK none ", 1, 17, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK none ", 1, triggerOffset + 17, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK NONE \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK NONE \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK none \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK none \\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK NONE\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK NONE\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);

items = computePosition("FROM busybox\nHEALTHCHECK none\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
items = computePosition("FROM busybox\n" + onbuild + "HEALTHCHECK none\\\n", 2, 0, snippetSupport);
assert.equal(items.length, 0);
});
});
});
}
}

describe("snippets", function() {
testHealthcheck(true);
});

describe("snippets", function() {
testFlags(true);
});

describe("plain text", function() {
testHealthcheck(false);
describe("plain text", function() {
testFlags(true);
});
});
});
}
testHealthcheck(false);

describe('ONBUILD nesting', function() {
it('all', function() {
Expand Down Expand Up @@ -1599,6 +1604,8 @@ describe('Docker Content Assist Tests', function() {
assert.equal(proposals.length, 0);
});
});

testHealthcheck(true);
});

describe("variables", function() {
Expand Down

0 comments on commit 99d7705

Please sign in to comment.