Skip to content

Commit

Permalink
Fix #172 Add commands to fix unknown HEALTHCHECK flags
Browse files Browse the repository at this point in the history
Signed-off-by: Remy Suen <[email protected]>
  • Loading branch information
rcjsuen committed Sep 12, 2017
1 parent 999df0b commit 8739575
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased]
### Added
- textDocument/codeAction
- create commands for converting unknown HEALTHCHECK flags ([#172](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/172))
- docker.command.flagToHealthcheckInterval
- docker.command.flagToHealthcheckRetries
- docker.command.flagToHealthcheckStartPeriod
- docker.command.flagToHealthcheckTimeout
- textDocument/completion
- HEALTHCHECK's CMD and NONE arguments ([#169](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/169))

Expand Down
70 changes: 70 additions & 0 deletions src/dockerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export class CommandIds {
static readonly EXTRA_ARGUMENT = "docker.command.removeExtraArgument";
static readonly DIRECTIVE_TO_BACKTICK = "docker.command.directiveToBacktick";
static readonly DIRECTIVE_TO_BACKSLASH = "docker.command.directiveToBackslash";
static readonly FLAG_TO_HEALTHCHECK_INTERVAL = "docker.command.flagToHealthcheckInterval";
static readonly FLAG_TO_HEALTHCHECK_RETRIES = "docker.command.flagToHealthcheckRetries";
static readonly FLAG_TO_HEALTHCHECK_START_PERIOD = "docker.command.flagToHealthcheckStartPeriod";
static readonly FLAG_TO_HEALTHCHECK_TIMEOUT = "docker.command.flagToHealthcheckTimeout";
static readonly CONVERT_TO_AS = "docker.command.convertToAS";
}

Expand Down Expand Up @@ -69,6 +73,28 @@ export class DockerCommands {
arguments: [ textDocumentURI, diagnostics[i].range ]
});
break;
case ValidationCode.UNKNOWN_HEALTHCHECK_FLAG:
commands.push({
title: "Convert to --interval",
command: CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL,
arguments: [ textDocumentURI, diagnostics[i].range ]
});
commands.push({
title: "Convert to --retries",
command: CommandIds.FLAG_TO_HEALTHCHECK_RETRIES,
arguments: [ textDocumentURI, diagnostics[i].range ]
});
commands.push({
title: "Convert to --start-period",
command: CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD,
arguments: [ textDocumentURI, diagnostics[i].range ]
});
commands.push({
title: "Convert to --timeout",
command: CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT,
arguments: [ textDocumentURI, diagnostics[i].range ]
});
break;
}
}
return commands;
Expand Down Expand Up @@ -146,6 +172,50 @@ export class DockerCommands {
]
}
};
case CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL:
return {
changes: {
[
uri
]:
[
TextEdit.replace(range, "interval")
]
}
};
case CommandIds.FLAG_TO_HEALTHCHECK_RETRIES:
return {
changes: {
[
uri
]:
[
TextEdit.replace(range, "retries")
]
}
};
case CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD:
return {
changes: {
[
uri
]:
[
TextEdit.replace(range, "start-period")
]
}
};
case CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT:
return {
changes: {
[
uri
]:
[
TextEdit.replace(range, "timeout")
]
}
};
}
return null;
}
Expand Down
7 changes: 6 additions & 1 deletion src/dockerValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export enum ValidationCode {
MULTIPLE_INSTRUCTIONS,
UNKNOWN_INSTRUCTION,
UNKNOWN_FLAG,
UNKNOWN_HEALTHCHECK_FLAG,
DEPRECATED_MAINTAINER,
HEALTHCHECK_CMD_ARGUMENT_MISSING
}
Expand Down Expand Up @@ -385,7 +386,7 @@ export class Validator {
let flagName = flag.getName();
if (validFlags.indexOf(flagName) === -1) {
let nameRange = flag.getNameRange();
problems.push(Validator.createFlagUnknown(nameRange.start, nameRange.end, flag.getName()));
problems.push(Validator.createUnknownHealthcheckFlag(nameRange.start, nameRange.end, flag.getName()));
} else if (flagName === "retries") {
let value = flag.getValue();
if (value) {
Expand Down Expand Up @@ -1085,6 +1086,10 @@ export class Validator {
return Validator.createError(start, end, Validator.getDiagnosticMessage_FlagUnknown(flag), ValidationCode.UNKNOWN_FLAG);
}

static createUnknownHealthcheckFlag(start: Position, end: Position, flag: string): Diagnostic {
return Validator.createError(start, end, Validator.getDiagnosticMessage_FlagUnknown(flag), ValidationCode.UNKNOWN_HEALTHCHECK_FLAG);
}

private static createFlagUnknownUnit(range: Range, unit: string, duration: string): Diagnostic {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_FlagUnknownUnit(unit, duration), ValidationCode.FLAG_UNKNOWN_UNIT);
}
Expand Down
4 changes: 4 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ connection.onInitialize((params): InitializeResult => {
CommandIds.EXTRA_ARGUMENT,
CommandIds.DIRECTIVE_TO_BACKSLASH,
CommandIds.DIRECTIVE_TO_BACKTICK,
CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL,
CommandIds.FLAG_TO_HEALTHCHECK_RETRIES,
CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD,
CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT,
CommandIds.CONVERT_TO_AS
]
},
Expand Down
83 changes: 83 additions & 0 deletions test/dockerCommands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ function createInvalidEscapeDirective(): Diagnostic {
return Diagnostic.create(Range.create(Position.create(0, 0), Position.create(0, 0)), "", DiagnosticSeverity.Warning, ValidationCode.INVALID_ESCAPE_DIRECTIVE);
}

function createUnknownHealthcheckFlag(): Diagnostic {
return Diagnostic.create(Range.create(Position.create(0, 0), Position.create(0, 0)), "", DiagnosticSeverity.Error, ValidationCode.UNKNOWN_HEALTHCHECK_FLAG);
}

function createDirectiveUppercase(): Diagnostic {
return Diagnostic.create(Range.create(Position.create(0, 0), Position.create(0, 0)), "", DiagnosticSeverity.Warning, ValidationCode.CASING_DIRECTIVE);
}
Expand Down Expand Up @@ -139,6 +143,29 @@ describe("Dockerfile code actions", function () {
assert.equal(commands[0].arguments[0], uri);
assertRange(commands[0].arguments[1], diagnostic.range);
});

it("unknown HEALTHCHECK flags", function () {
let range = Range.create(Position.create(0, 0), Position.create(0, 4));
let diagnostic = createUnknownHealthcheckFlag();
let commands = dockerCommands.analyzeDiagnostics([ diagnostic ], uri, range);
assert.equal(commands.length, 4);
assert.equal(commands[0].command, CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL);
assert.equal(commands[0].arguments.length, 2);
assert.equal(commands[0].arguments[0], uri);
assertRange(commands[0].arguments[1], diagnostic.range);
assert.equal(commands[1].command, CommandIds.FLAG_TO_HEALTHCHECK_RETRIES);
assert.equal(commands[1].arguments.length, 2);
assert.equal(commands[1].arguments[0], uri);
assertRange(commands[1].arguments[1], diagnostic.range);
assert.equal(commands[2].command, CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD);
assert.equal(commands[2].arguments.length, 2);
assert.equal(commands[2].arguments[0], uri);
assertRange(commands[2].arguments[1], diagnostic.range);
assert.equal(commands[3].command, CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT);
assert.equal(commands[3].arguments.length, 2);
assert.equal(commands[3].arguments[0], uri);
assertRange(commands[3].arguments[1], diagnostic.range);
});
});

describe("Dockerfile execute commands", function () {
Expand Down Expand Up @@ -225,4 +252,60 @@ describe("Dockerfile execute commands", function () {
assert.equal(edits[0].newText, "AS");
assert.equal(edits[0].range, range);
});

it("HEALTHCHECK flag to --interval", function () {
let range = Range.create(Position.create(0, 0), Position.create(0, 4));
let document = createDocument("");
let edit = dockerCommands.createWorkspaceEdit(document, {
command: CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL,
arguments: [ uri, range ]
});
assert.equal(edit.documentChanges, undefined);
let edits = edit.changes[uri];
assert.equal(edits.length, 1);
assert.equal(edits[0].newText, "interval");
assert.equal(edits[0].range, range);
});

it("HEALTHCHECK flag to --retries", function () {
let range = Range.create(Position.create(0, 0), Position.create(0, 4));
let document = createDocument("");
let edit = dockerCommands.createWorkspaceEdit(document, {
command: CommandIds.FLAG_TO_HEALTHCHECK_RETRIES,
arguments: [ uri, range ]
});
assert.equal(edit.documentChanges, undefined);
let edits = edit.changes[uri];
assert.equal(edits.length, 1);
assert.equal(edits[0].newText, "retries");
assert.equal(edits[0].range, range);
});

it("HEALTHCHECK flag to --start-period", function () {
let range = Range.create(Position.create(0, 0), Position.create(0, 4));
let document = createDocument("");
let edit = dockerCommands.createWorkspaceEdit(document, {
command: CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD,
arguments: [ uri, range ]
});
assert.equal(edit.documentChanges, undefined);
let edits = edit.changes[uri];
assert.equal(edits.length, 1);
assert.equal(edits[0].newText, "start-period");
assert.equal(edits[0].range, range);
});

it("HEALTHCHECK flag to --timeout", function () {
let range = Range.create(Position.create(0, 0), Position.create(0, 4));
let document = createDocument("");
let edit = dockerCommands.createWorkspaceEdit(document, {
command: CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT,
arguments: [ uri, range ]
});
assert.equal(edit.documentChanges, undefined);
let edits = edit.changes[uri];
assert.equal(edits.length, 1);
assert.equal(edits[0].newText, "timeout");
assert.equal(edits[0].range, range);
});
});
31 changes: 21 additions & 10 deletions test/dockerValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ function assertFlagUnknownUnit(diagnostic: Diagnostic, unit: string, duration: s
assert.equal(diagnostic.range.end.character, endCharacter);
}

function assertUnknownHealthcheckFlag(diagnostic: Diagnostic, flag: string, startLine: number, startCharacter: number, endLine: number, endCharacter: number) {
assert.equal(diagnostic.code, ValidationCode.UNKNOWN_HEALTHCHECK_FLAG);
assert.equal(diagnostic.severity, DiagnosticSeverity.Error);
assert.equal(diagnostic.source, source);
assert.equal(diagnostic.message, Validator.getDiagnosticMessage_FlagUnknown(flag));
assert.equal(diagnostic.range.start.line, startLine);
assert.equal(diagnostic.range.start.character, startCharacter);
assert.equal(diagnostic.range.end.line, endLine);
assert.equal(diagnostic.range.end.character, endCharacter);
}

function assertInvalidAs(diagnostic: Diagnostic, startLine: number, startCharacter: number, endLine: number, endCharacter: number) {
assert.equal(diagnostic.code, ValidationCode.INVALID_AS);
assert.equal(diagnostic.severity, DiagnosticSeverity.Error);
Expand Down Expand Up @@ -1954,34 +1965,34 @@ describe("Docker Validator Tests", function() {
it("unknown flag", function() {
let diagnostics = validate("FROM alpine\nHEALTHCHECK --interva=30s CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);

// empty value
diagnostics = validate("FROM alpine\nHEALTHCHECK --interva= CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);

// no equals sign
diagnostics = validate("FROM alpine\nHEALTHCHECK --interva CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);

// flags are case-sensitive
diagnostics = validate("FROM alpine\nHEALTHCHECK --INTERVAL=30s CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "INTERVAL", 1, 14, 1, 22);
assertUnknownHealthcheckFlag(diagnostics[0], "INTERVAL", 1, 14, 1, 22);

diagnostics = validate("FROM alpine\nHEALTHCHECK --RETRIES=3 CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "RETRIES", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "RETRIES", 1, 14, 1, 21);

diagnostics = validate("FROM alpine\nHEALTHCHECK --START-PERIOD=0s CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "START-PERIOD", 1, 14, 1, 26);
assertUnknownHealthcheckFlag(diagnostics[0], "START-PERIOD", 1, 14, 1, 26);

diagnostics = validate("FROM alpine\nHEALTHCHECK --TIMEOUT=30s CMD ls");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "TIMEOUT", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "TIMEOUT", 1, 14, 1, 21);
});

it("flag no value", function() {
Expand Down Expand Up @@ -2246,17 +2257,17 @@ describe("Docker Validator Tests", function() {
// no equals sign
let diagnostics = validate("FROM alpine\nHEALTHCHECK --interva");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);

// empty value
diagnostics = validate("FROM alpine\nHEALTHCHECK --interva=");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);

// value specified
diagnostics = validate("FROM alpine\nHEALTHCHECK --interva=30s");
assert.equal(diagnostics.length, 1);
assertFlagUnknown(diagnostics[0], "interva", 1, 14, 1, 21);
assertUnknownHealthcheckFlag(diagnostics[0], "interva", 1, 14, 1, 21);
});
});
});
Expand Down

0 comments on commit 8739575

Please sign in to comment.