Skip to content

Commit

Permalink
Validation failure tests and SYNTAX.md update.
Browse files Browse the repository at this point in the history
Also added missing descriptions for job properties, triggers and build
parameters, and removed the not-actually-existing "use script" section.
  • Loading branch information
abayer committed Oct 11, 2016
1 parent 9c1d145 commit f4fffa2
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 24 deletions.
60 changes: 37 additions & 23 deletions SYNTAX.md
Expand Up @@ -10,8 +10,9 @@
These are sections that are specified directly within the `pipeline` argument closure.

### agent
* *Description*: Specifies where the build will run.
* *Required*: Yes
* *Description*: Specifies where the build or stage will run.
* *Required*: Yes for the top-level `pipeline` closure, optional for individual `stage` closures.
* *Allowed In*: Top-level `pipeline` closure and individual `stage` closures.
* *Parameters*: Either a `Map` of one or more arguments or one of two constants - `none` or `any`.
* *Map Keys*:
* Note that this will be an `ExtensionPoint`, so plugins will be able to add to the available image providers.
Expand Down Expand Up @@ -41,6 +42,7 @@ These are sections that are specified directly within the `pipeline` argument cl
* *Description*: A sequence of `key = value` pairs, which will be passed to the `withEnv` step the build will be
executed within.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: One or more lines with `foo = 'bar'` variable name/value pairs.
Expand All @@ -59,6 +61,7 @@ environment {
### stages
* *Description*: A sequence of one or more Pipeline `stage`s, each of which consist of a sequence of steps.
* *Required*: Yes
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: one or more `stage` blocks, as described below.
Expand All @@ -69,27 +72,35 @@ to-be-released block-scoped `stage` syntax in base Pipeline.
* *Required*: At least one is required.
* *Parameters*: A single `String`, the name for the `stage`.
* *Takes a Closure*: Yes
* *Closure Contents*: One or more Pipeline steps, including block-scoped steps and the special `script` block described below.
* *Closure Contents*: A `steps` block containing one or more Pipeline steps, including block-scoped steps and the
special `script` block described below, and optionally, certain configuration sections that allow being set on a
per-stage basis.
* *NOTE*: Currently only the `agent` section can be configured per-stage.
* *NOTE*: Only the "declarative subset" of Groovy is allowed by default. See below for details on that subset.
* *NOTE*: The `parallel` step is a special case - it can only be used if it's the sole step in the `stage`.
* *Examples*:

```
stages {
stage('foo') {
echo 'bar'
steps {
echo 'bar'
}
}
}
stages {
stage('first') {
timeout(time:5, unit:'MINUTES') {
sh "mvn clean install -DskipTests"
steps {
timeout(time:5, unit:'MINUTES') {
sh "mvn clean install -DskipTests"
}
}
}
stage('second') {
node('some-node') {
agent label:'some-node'
steps {
checkout scm
sh "mvn clean install"
}
Expand All @@ -98,14 +109,16 @@ stages {
stages {
stage('parallel-stage') {
parallel(
firstBlock: {
echo "First block of the parallel"
},
secondBlock: {
echo "Second block of the parallel"
}
)
steps {
parallel(
firstBlock: {
echo "First block of the parallel"
},
secondBlock: {
echo "Second block of the parallel"
}
)
}
}
}
```
Expand Down Expand Up @@ -136,6 +149,7 @@ stages {
* *Description*: A top-level section defining tools to auto-install and put on the PATH. This is ignored if `image none`
is specified.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: Names and versions of tools configured in Jenkins to install.
Expand All @@ -155,6 +169,7 @@ tools {
### notifications
* *Description*: Defines notifications to be sent after build completion, assuming build status conditions are met.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: A sequence of one or more build conditions containing Pipeline steps to run. See below for
Expand All @@ -164,6 +179,7 @@ definition of build conditions and their contents.
* *Description*: Defines post build actions to be run after build completion, assuming build status conditions are met.
Note that `postBuild` steps are run *before* `notifications`.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: A sequence of one or more build conditions containing Pipeline steps to run. See below for
Expand Down Expand Up @@ -205,8 +221,9 @@ postBuild {
```

### Triggers
* *Description*:
* *Description*: Triggers for this job, as used in other Jenkins jobs.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: A sequence of one or more trigger configurations, using `@Symbol` names for constructors.
Expand All @@ -221,8 +238,9 @@ triggers {
```

### Build Parameters
* *Description*:
* *Description*: Build parameters that will be prompted for at build time.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: A sequence of one or more parameter definition configurations, using `@Symbol` names for constructors.
Expand All @@ -237,8 +255,9 @@ parameters {
```

### Job Properties
* *Description*:
* *Description*: Other job properties, such as build discarding, limiting concurrent builds, and more.
* *Required*: No
* *Allowed In*: Top-level `pipeline` closure only.
* *Parameters*: None
* *Takes a Closure*: Yes
* *Closure Contents*: A sequence of one or more job property configurations, using `@Symbol` names for constructors.
Expand Down Expand Up @@ -272,8 +291,3 @@ jobProperties {
* Method calls where the left hand side is a variable reference or a sequence of property references: `x.y.z(...)`
* Method calls (including `@Symbol` constructors like used above in job properties, triggers and build parameters) where there is no left hand side.
* Closure without parameters: `{ ... }`

## Script mode
* *Description*: A flag which, when set, allows usage of standard non-declarative-subset Pipeline code throughout the Jenkinsfile.
* *Usage*: Set by putting `use script` at the beginning of the Jenkinsfile
* *Examples*: (hard to figure out a good example here since we've moved to the `pipeline` step?)
Expand Up @@ -288,7 +288,7 @@ class ModelParser {
eachStatement(((ClosureExpression)bodyExp).code) { s ->
def mc = matchMethodCall(s);
if (mc == null) {
errorCollector.error(stage, "Not a valid section definition: '${getSourceText(s)}'. Some extra configuration is required.")
errorCollector.error(stage, "Not a valid stage section definition: '${getSourceText(s)}'. Some extra configuration is required.")
} else {
def name = parseMethodName(mc);

Expand Down
Expand Up @@ -139,6 +139,10 @@ public static Iterable<Object[]> configsWithErrors() {
result.add(new Object[]{"wrongParameterNameMethodCall", "Invalid parameter 'namd', did you mean 'name'?"});
result.add(new Object[]{"invalidParameterTypeMethodCall", "Expecting class java.lang.String for parameter 'name' but got '1234' instead"});

result.add(new Object[]{"perStageConfigEmptySteps", "At /pipeline/stages/0/branches/0/steps: Array has 0 entries, requires minimum of 1"});
result.add(new Object[]{"perStageConfigMissingSteps", "At /pipeline/stages/0/branches/0: Missing one or more required properties: 'steps'"});
result.add(new Object[]{"perStageConfigUnknownSection", "At /pipeline/stages/0: additional properties are not allowed"});

result.add(new Object[]{"malformed", "Expected a ',' or '}' at character 243 of {\"pipeline\": {\n" +
" \"stages\": [ {\n" +
" \"name\": \"foo\",\n" +
Expand Down
Expand Up @@ -212,6 +212,27 @@ public void unknownStepParameter() throws Exception {
failWithError("Invalid parameter 'banana', did you mean 'unit'?");
}

@Test
public void perStageConfigEmptySteps() throws Exception {
prepRepoWithJenkinsfile("errors", "perStageConfigEmptySteps");

failWithError("No steps specified for branch");
}

@Test
public void perStageConfigMissingSteps() throws Exception {
prepRepoWithJenkinsfile("errors", "perStageConfigMissingSteps");

failWithError("Nothing to execute within stage");
}

@Test
public void perStageConfigUnknownSection() throws Exception {
prepRepoWithJenkinsfile("errors", "perStageConfigUnknownSection");

failWithError("Unknown stage section 'banana'");
}

@Test
public void invalidMetaStepSyntax() throws Exception {
prepRepoWithJenkinsfile("errors", "invalidMetaStepSyntax");
Expand Down Expand Up @@ -254,6 +275,13 @@ public void emptyAgent() throws Exception {
failWithError("Not a valid section definition: 'agent'. Some extra configuration is required.");
}

@Test
public void perStageConfigEmptyAgent() throws Exception {
prepRepoWithJenkinsfile("errors", "perStageConfigEmptyAgent");

failWithError("Not a valid stage section definition: 'agent'. Some extra configuration is required.");
}

@Test
public void invalidBuildCondition() throws Exception {
prepRepoWithJenkinsfile("errors", "invalidBuildCondition");
Expand Down
38 changes: 38 additions & 0 deletions src/test/resources/errors/perStageConfigEmptyAgent.groovy
@@ -0,0 +1,38 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

pipeline {
agent none
stages {
stage("foo") {
agent
steps {
echo "Hi"
}
}
}
}



37 changes: 37 additions & 0 deletions src/test/resources/errors/perStageConfigEmptySteps.groovy
@@ -0,0 +1,37 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

pipeline {
agent none
stages {
stage("foo") {
agent label:'some-label'
steps {
}
}
}
}



35 changes: 35 additions & 0 deletions src/test/resources/errors/perStageConfigMissingSteps.groovy
@@ -0,0 +1,35 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

pipeline {
agent none
stages {
stage("foo") {
agent label:'some-label'
}
}
}



41 changes: 41 additions & 0 deletions src/test/resources/errors/perStageConfigUnknownSection.groovy
@@ -0,0 +1,41 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

pipeline {
agent none
stages {
stage("foo") {
banana {
echo "monkey"
}
agent label:'some-label'
steps {
echo "hi"
}
}
}
}



20 changes: 20 additions & 0 deletions src/test/resources/json/errors/perStageConfigEmptySteps.json
@@ -0,0 +1,20 @@
{"pipeline": {
"stages": [ {
"name": "foo",
"branches": [ {
"name": "default",
"steps": []
}],
"agent": [ {
"key": "label",
"value": {
"isLiteral": true,
"value": "some-label"
}
}]
}],
"agent": {
"isLiteral": true,
"value": "none"
}
}}

0 comments on commit f4fffa2

Please sign in to comment.