Concourse: basic support for 'timeout' attribute

This commit is contained in:
Kris De Volder
2016-12-21 16:54:30 -08:00
parent 7bbdffbff5
commit 65451b0ff2
6 changed files with 124 additions and 2 deletions

View File

@@ -0,0 +1,36 @@
package org.springframework.ide.vscode.commons.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexpParser implements ValueParser {
final private Pattern pat;
final private String typeName; // used only for error message
final private String patternDescription; //Human readable description of the regexp pay
/**
* Create a RegexpParser which succeeds if the input string matches the given regexp
* and fail otherwise.
*
* @param regexp
* @param typeName Name of the type (used in error message for failing parses)
* @param patternDescription Human readable description of the regexp pattern (included in the error message for failing parses)
*/
public RegexpParser(String regexp, String typeName, String patternDescription) {
super();
this.pat = Pattern.compile(regexp);
this.typeName = typeName;
this.patternDescription = patternDescription;
}
@Override
public Object parse(String str) {
Matcher matcher = pat.matcher(str);
if (matcher.matches()) {
return matcher;
}
throw new IllegalArgumentException("'"+str+"' is not a valid '"+typeName+"'. "+patternDescription);
}
}

View File

@@ -52,6 +52,9 @@ public class PipelineYmlSchema implements YamlSchema {
YType t_params = f.ymap(t_string, t_any);
YType t_string_params = f.ymap(t_string, t_string);
YAtomicType t_duration = f.yatomic("Duration");
t_duration.parseWith(ValueParsers.DURATION);
YAtomicType t_version = f.yatomic("Version");
t_version.addHints("latest", "every");
@@ -142,6 +145,7 @@ public class PipelineYmlSchema implements YamlSchema {
prop(step, "ensure", step);
prop(step, "attempts", t_strictly_pos_integer);
prop(step, "tags", t_strings);
prop(step, "timeout", t_duration);
YBeanType resource = f.ybean("Resource");
prop(resource, "name", t_ne_string);

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.concourse;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.RegexpParser;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.ValueParser;
@@ -56,5 +57,16 @@ public class ValueParsers {
}
};
}
public static ValueParser DURATION = new RegexpParser(
"^(([0-9]+(.[0-9]+)?)(ns|us|µs|ms|s|h|m))+$",
"Duration",
" A duration string is a sequence of decimal numbers, each with "
+ "optional fraction and a unit suffix, such as '300ms', '1.5h' or"
+ " '2h45m'. Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', "
+ "'m', 'h'."
);
}

View File

@@ -0,0 +1,17 @@
Enforce a time limit on a step.
Any step can have a hard time limit enforced by attaching timeout and the number of seconds to limit it to.
timeout: duration
The amount of time to limit the step's execution to, e.g. `30m` for 30 minutes.
When exceeded, the step will be interrupted, with the same semantics as aborting the build (except the build will be `failed`, not `aborted`, to distinguish between human intervention and timeouts being enforced).
The following will run the task, and cancel it if it takes longer than 1 hour and 30 minutes:
plan:
- get: foo
- task: unit
file: foo/unit.yml
timeout: 1h30m

View File

@@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.ValueParser;
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.*;
public class DurationParserTest {
private ValueParser parser = ValueParsers.DURATION;
@Test
public void goodExamples() {
parser.parse("1h40m");
parser.parse("1.5h");
parser.parse("23h59m59s99ms200µs100ns");
}
@Test
public void badExamples() {
does_not_parse("1h:40m");
does_not_parse("15h 30m");
does_not_parse("23hours");
}
private void does_not_parse(String string) {
try {
parser.parse(string);
fail("Should have failed parsing!");
} catch (IllegalArgumentException e) {
assertContains("Duration", ExceptionUtil.getMessage(e));
}
}
}

View File

@@ -252,6 +252,7 @@ public class PipelineYamlEditorTest {
" config: some-config\n" +
" tags: [a, b, c]\n"+
" attempts: 10\n" +
" timeout: 1h30m\n" +
" ensure:\n" +
" bogus: bad\n" +
" on_failure:\n" +
@@ -267,6 +268,7 @@ public class PipelineYamlEditorTest {
editor.assertHoverContains("output_mapping", "A map from task output names to concrete names");
editor.assertHoverContains("config", "Use `config` to inline the task config");
editor.assertHoverContains("tags", "Any step can be directed at a pool of workers");
editor.assertHoverContains("timeout", "amount of time to limit the step's execution");
}
@Test
@@ -297,14 +299,16 @@ public class PipelineYamlEditorTest {
" plan:\n" +
" - get: git\n" +
" trigger: yohoho\n" +
" attempts: 0\n"
" attempts: 0\n" +
" timeout: 1h:30m\n"
);
editor.assertProblems(
"boohoo|boolean",
"-1|must be positive",
"git|resource does not exist",
"yohoho|boolean",
"0|must be at least 1"
"0|must be at least 1",
"1h:30m|Duration"
);
//check that correct values are indeed accepted
@@ -508,6 +512,7 @@ public class PipelineYamlEditorTest {
);
}
//////////////////////////////////////////////////////////////////////////////
private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {