├── yaml_junit.png
├── junit_pipeline.png
├── pipeline
├── templates
│ ├── steps
│ │ ├── template-script.yml
│ │ ├── template-mock.yml
│ │ └── template-steps.yml
│ ├── jobs
│ │ └── template-jobs.yml
│ └── stages
│ │ └── template-stages.yml
├── simple-pipeline.yml
├── simple-deployment.yml
├── external-resources-pipeline.yml
├── powershell-mock.yml
├── bash-mock.yml
├── pipeline-test.yml
└── junit-pipeline.yml
├── src
├── main
│ ├── java
│ │ └── azdo
│ │ │ ├── hook
│ │ │ ├── Hook.java
│ │ │ ├── DeleteTargetFile.java
│ │ │ ├── FindReplaceInFile.java
│ │ │ └── DeleteJUnitPipelineDependency.java
│ │ │ ├── yaml
│ │ │ ├── ActionResult.java
│ │ │ ├── RepositoryResource.java
│ │ │ └── YamlTemplate.java
│ │ │ ├── action
│ │ │ ├── Action.java
│ │ │ ├── ActionDeleteSection.java
│ │ │ ├── ActionUpdateSectionByProperty.java
│ │ │ ├── ActionUpdateSection.java
│ │ │ ├── ActionDeleteSectionByProperty.java
│ │ │ ├── ActionInsertSection.java
│ │ │ ├── ActionInsertSectionByProperty.java
│ │ │ ├── ActionResetTrigger.java
│ │ │ ├── ActionReturnPropertyValue.java
│ │ │ ├── ActionInsertLineInSection.java
│ │ │ ├── ActionAddPropertyToSection.java
│ │ │ ├── ActionOverrideElement.java
│ │ │ ├── ActionOnSection.java
│ │ │ ├── ActionInsertLineInInnerSection.java
│ │ │ └── ActionOnSectionByProperty.java
│ │ │ ├── utils
│ │ │ ├── Constants.java
│ │ │ ├── Log.java
│ │ │ ├── PomUtils.java
│ │ │ ├── GitUtils.java
│ │ │ ├── Utils.java
│ │ │ └── PropertyUtils.java
│ │ │ └── junit
│ │ │ ├── TimelineRecord.java
│ │ │ └── RunResult.java
│ └── resources
│ │ ├── log4j.properties
│ │ ├── log4j2.xml
│ │ └── junit_pipeline.properties
└── test
│ └── java
│ └── PipelineUnit.java
├── LICENSE
└── pom.xml
/yaml_junit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hvmerode/junit-pipeline/HEAD/yaml_junit.png
--------------------------------------------------------------------------------
/junit_pipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hvmerode/junit-pipeline/HEAD/junit_pipeline.png
--------------------------------------------------------------------------------
/pipeline/templates/steps/template-script.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) Henry van Merode.
2 | # Licensed under the MIT License.
3 |
4 | steps:
5 | - script: |
6 | echo 'This is script step'
7 | displayName: This is script step
8 |
--------------------------------------------------------------------------------
/src/main/java/azdo/hook/Hook.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) Henry van Merode.
2 | // Licensed under the MIT License.
3 |
4 | package azdo.hook;
5 |
6 | public class Hook {
7 | public void executeHook ()
8 | {
9 | throw new UnsupportedOperationException();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/pipeline/templates/steps/template-mock.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) Henry van Merode.
2 | # Licensed under the MIT License.
3 |
4 | parameters:
5 | - name: param_1
6 | type: string
7 | - name: param_2
8 | type: string
9 |
10 | steps:
11 | - script: |
12 | echo 'This is mock template file'
13 | displayName: template-mock.yml script
14 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Root logger option
2 | log4j.rootLogger=DEBUG, stdout
3 |
4 | # Direct log messages to stdout
5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stdout.Target=System.out
7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
--------------------------------------------------------------------------------
/pipeline/templates/steps/template-steps.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: param_1
3 | type: string
4 | default: xxx
5 | - name: param_2
6 | type: string
7 | default: param_2_value
8 | steps:
9 | - script: |
10 | echo 'This is parameter ${{ parameters.param_1 }}'
11 | displayName: template-steps.yml script
12 | - script: |
13 | echo 'This is step 2 of file template-steps.yml'
14 | displayName: template-steps.yml script
15 |
--------------------------------------------------------------------------------
/src/main/java/azdo/yaml/ActionResult.java:
--------------------------------------------------------------------------------
1 | package azdo.yaml;
2 |
3 | /******************************************************************************************
4 | Use in the execution of an Action instance.
5 | *******************************************************************************************/
6 | public class ActionResult {
7 | public Object l1 = null;
8 | public Object l2 = null;
9 | public Object l3 = null;
10 | public boolean actionExecuted = false;
11 | }
12 |
--------------------------------------------------------------------------------
/pipeline/templates/jobs/template-jobs.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: param_1
3 | type: string
4 | default: xxx
5 | jobs:
6 | - job: Job_A
7 | displayName: template-jobs.yml job
8 | variables:
9 | - name: jobVar
10 | value: 'jobVarInTemplate'
11 | pool:
12 | vmImage: ubuntu-latest
13 | steps:
14 | - script: |
15 | echo 'This is job: Job_A with parameter ${{ parameters.param_1 }}'
16 | displayName: template-jobs.yml script
17 | - template: ../steps/template-steps.yml
18 |
--------------------------------------------------------------------------------
/pipeline/templates/stages/template-stages.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: aNiceParam
3 | type: string
4 | default: aNiceDefault
5 | - name: template
6 | type: string
7 | default: "default_name_of_template_param"
8 | stages:
9 | - stage: Stage_B
10 | displayName: template-stages.yml stage
11 | jobs:
12 | - job: Job_B
13 | displayName: template-stages.yml job
14 | pool:
15 | vmImage: ubuntu-latest
16 | steps:
17 | - script: |
18 | echo 'This is job: Job_B with parameter ${{ parameters.aNiceParam }}'
19 | displayName: template-stages.yml script
20 | - template: ../jobs/template-jobs.yml
21 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/Action.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import azdo.yaml.ActionResult;
4 |
5 | import java.util.Map;
6 |
7 | public interface Action {
8 | public enum ACTION {INSERT_SECTION, UPDATE_SECTION, DELETE_SECTION, INSERT_SECTION_LINE, GET_PROPERTY};
9 | // Executes the action
10 | void execute (ActionResult actionResult);
11 |
12 | // You can ask a question to the action; does it need a section name to be executed or is a section type sufficient
13 | boolean needsSectionIdentifier ();
14 |
15 | // A custom action does not follow the pattern of regular actions
16 | boolean isCustomAction ();
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/azdo/yaml/RepositoryResource.java:
--------------------------------------------------------------------------------
1 | package azdo.yaml;
2 |
3 | /******************************************************************************************
4 | Details of a repository.
5 | *******************************************************************************************/
6 | public class RepositoryResource {
7 | public String repository;
8 | public String endpoint;
9 | public String trigger;
10 | public String name;
11 | public String project;
12 | public String ref;
13 | public String type;
14 | public String localBase; // Base location on the local file system
15 | public static final String LOCAL_SOURCE_POSTFIX = "_source"; // Prefix added to the cloned source directory to prevent mixing up with the local target directory
16 | }
17 |
--------------------------------------------------------------------------------
/pipeline/simple-pipeline.yml:
--------------------------------------------------------------------------------
1 | # Build numbering format
2 | name: $(Date:yyyyMMdd)$(Rev:.r)
3 |
4 | trigger:
5 | branches:
6 | include:
7 | - master
8 | - myFeature
9 | exclude:
10 | - releases/*
11 |
12 | variables:
13 | - name: testVar
14 | value: test
15 |
16 | parameters:
17 | - name: param_1
18 | type: string
19 | default: 'default'
20 |
21 | stages:
22 | - stage: simpleStage
23 | displayName: simple_stage
24 | jobs:
25 | - job: simpleJob
26 | displayName: simple_job
27 | pool:
28 | vmImage: 'ubuntu-latest'
29 | steps:
30 | - script: |
31 | echo 'This is a simple test'
32 | displayName: 'Testing, testing'
33 | - template: templates/steps/template-script.yml
34 |
--------------------------------------------------------------------------------
/pipeline/simple-deployment.yml:
--------------------------------------------------------------------------------
1 | # Build numbering format
2 | name: $(Date:yyyyMMdd)$(Rev:.r)
3 |
4 | trigger: none
5 |
6 | stages:
7 | - stage: simpleDeployment
8 | displayName: Deploy stage
9 | jobs:
10 | - deployment: Deploy
11 | displayName: Deploy my app
12 | pool:
13 | vmImage: 'ubuntu-latest'
14 | environment: 'dev'
15 | strategy:
16 | runOnce:
17 | deploy:
18 | steps:
19 | - checkout: self
20 | - script: echo "This is a deployment"
21 | displayName: 'This is a deployment'
22 | on:
23 | failure:
24 | steps:
25 | - script: echo "This is on failure"
26 | success:
27 | steps:
28 | - script: echo "This is on success"
29 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionDeleteSection.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | /******************************************************************************************
4 | This class is used to delete a section. This section is searched using 'sectionType'
5 | and 'sectionIdentifier'. For example:
6 | Assume, that 'sectionType' has the value "stage", and 'sectionIdentifier' has the
7 | value "mystage".
8 | The stage with the identifier "mystage" is searched in the yaml pipeline.
9 | If found, the stage section is deleted from the yaml.
10 | ******************************************************************************************/
11 | public class ActionDeleteSection extends ActionOnSection {
12 |
13 | public ActionDeleteSection(String sectionType, String sectionIdentifier)
14 | {
15 | super(ACTION.DELETE_SECTION,
16 | sectionType,
17 | sectionIdentifier,
18 | null,
19 | false);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionUpdateSectionByProperty.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import java.util.Map;
4 |
5 | /******************************************************************************************
6 | This class is used to replace a section. This section is searched using 'sectionType'
7 | and 'property'.
8 | If the section is found, it is replaced by 'newSection'.
9 | ******************************************************************************************/
10 | public class ActionUpdateSectionByProperty extends ActionOnSectionByProperty {
11 |
12 | public ActionUpdateSectionByProperty(String sectionType,
13 | String property,
14 | String propertyValue,
15 | Map newSection) {
16 | super(ACTION.UPDATE_SECTION,
17 | sectionType,
18 | property,
19 | propertyValue,
20 | newSection,
21 | false);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Henry van Merode.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE
20 |
--------------------------------------------------------------------------------
/pipeline/external-resources-pipeline.yml:
--------------------------------------------------------------------------------
1 | # Build numbering format
2 | name: $(Date:yyyyMMdd)$(Rev:.r)
3 |
4 | trigger: none
5 |
6 | # Define 2 repositories, one is an Azure DevOps repo and the other a GitHub repo.
7 | # Note, that the 'endpoint' parameter is mandatory for a GitHub repository.
8 | # Both repos must exist, otherwise test no. 11 and 12 fail.
9 | resources:
10 | repositories:
11 | - repository: external
12 | name: Templates/Templates
13 | type: git
14 | ref: refs/heads/develop
15 | - repository: external2
16 | name: hvmerode/azdo-templates
17 | type: github
18 | endpoint: GitHubEndpoint
19 |
20 | stages:
21 | - stage: externalResourcesStage
22 | displayName: stage
23 | jobs:
24 | - job: externalResourcesJob
25 | displayName: job
26 | pool:
27 | vmImage: 'ubuntu-latest'
28 | steps:
29 | - script: |
30 | echo 'External resources test'
31 | displayName: 'External resources'
32 | - template: test-template.yml@external
33 | - template: test-template.yml@external2
34 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionUpdateSection.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import java.util.Map;
4 |
5 | /******************************************************************************************
6 | This class is used to replace a section. This section is searched using 'sectionType'
7 | and 'sectionIdentifier'. For example:
8 | Assume, that 'sectionType' has the value "task", and 'sectionIdentifier' has the
9 | value "AWSShellScript@1".
10 | The stage with the identifier "AWSShellScript@1" is searched in the yaml pipeline.
11 | If the task is found, it is replaced by 'newSection'.
12 | ******************************************************************************************/
13 | public class ActionUpdateSection extends ActionOnSection {
14 |
15 | public ActionUpdateSection(String sectionType,
16 | String sectionIdentifier,
17 | Map newSection)
18 | {
19 | super(ACTION.UPDATE_SECTION,
20 | sectionType,
21 | sectionIdentifier,
22 | newSection,
23 | false);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionDeleteSectionByProperty.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | /******************************************************************************************
4 | This class is used to delete a section. This section is searched using 'sectionType'
5 | and 'property'. For example:
6 | Assume, that 'sectionType' has the value "stage", 'property' has the value "displayName",
7 | and 'propertyValue' has the value "Execute this stage".
8 | The stage with the displaName "Execute this stage" is searched in the yaml pipeline.
9 | If found, the stage section is deleted from the yaml.
10 | ******************************************************************************************/
11 | public class ActionDeleteSectionByProperty extends ActionOnSectionByProperty {
12 | public ActionDeleteSectionByProperty(String sectionType,
13 | String property,
14 | String propertyValue) {
15 | super(ACTION.DELETE_SECTION,
16 | sectionType,
17 | property,
18 | propertyValue,
19 | null,
20 | false);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/azdo/hook/DeleteTargetFile.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) Henry van Merode.
2 | // Licensed under the MIT License.
3 |
4 | package azdo.hook;
5 |
6 | import azdo.utils.Log;
7 | import azdo.utils.Utils;
8 | import java.nio.file.Path;
9 | import java.nio.file.Paths;
10 |
11 | /******************************************************************************************
12 | Hook, to delete a file from the target path.
13 | *******************************************************************************************/
14 | public class DeleteTargetFile extends Hook {
15 | private String fullQualifiedFileName;
16 | private static final Log logger = Log.getLogger();
17 | public DeleteTargetFile(String fullQualifiedFileName) {
18 | logger.debug("==> Class: DeleteTargetFile");
19 |
20 | this.fullQualifiedFileName = fullQualifiedFileName;
21 | }
22 |
23 | @Override
24 | public void executeHook (){
25 | logger.debug("==> Method: DeleteTargetFile.executeHook");
26 | Path path = Paths.get(fullQualifiedFileName);
27 | path = path.normalize();
28 | fullQualifiedFileName = path.toString();
29 | Utils.deleteFile(fullQualifiedFileName);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionInsertSection.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import java.util.Map;
4 |
5 | /******************************************************************************************
6 | This class is used to insert a section before or after another section. This section is
7 | searched using the 'sectionType' and 'sectionIdentifier'. For example:
8 | Assume, that 'sectionType' has the value "stage" and 'sectionIdentifier' has the value
9 | "mystage". The stage with the name (identifier) "mystage" is searched in the yaml pipeline.
10 | If found, a section - defined by 'sectionToInsert' - is inserted before or after "mystage",
11 | depending on the value of 'insertBefore'.
12 |
13 | The variable 'sectionToInsert' is of type Map, because this is the way how a section is
14 | represented in a yaml object in Snakeyaml.
15 | ******************************************************************************************/
16 | public class ActionInsertSection extends ActionOnSection {
17 | public ActionInsertSection(String sectionType,
18 | String sectionIdentifier,
19 | Map sectionToInsert,
20 | boolean insertBefore)
21 | {
22 | super(ACTION.INSERT_SECTION,
23 | sectionType,
24 | sectionIdentifier,
25 | sectionToInsert,
26 | insertBefore);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/azdo/hook/FindReplaceInFile.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) Henry van Merode.
2 | // Licensed under the MIT License.
3 |
4 | package azdo.hook;
5 |
6 | import azdo.utils.Log;
7 | import azdo.utils.Utils;
8 |
9 | /******************************************************************************************
10 | Hook, to find and replace all literals in a given file.
11 | *******************************************************************************************/
12 | public class FindReplaceInFile extends Hook {
13 | private String fullQualifiedFileName;
14 | private String findString;
15 | private String replaceString;
16 | private boolean replaceAll;
17 | private static final Log logger = Log.getLogger();
18 | public FindReplaceInFile(String fullQualifiedFileName,
19 | String findString,
20 | String replaceString,
21 | boolean replaceAll) {
22 | logger.debug("==> Class: FindReplaceInFile");
23 |
24 | this.fullQualifiedFileName = fullQualifiedFileName;
25 | this.findString = findString;
26 | this.replaceString = replaceString;
27 | this.replaceAll = replaceAll;
28 | }
29 |
30 | @Override
31 | public void executeHook (){
32 | logger.debug("==> Method: FindReplaceInFile.executeHook");
33 | Utils.findReplaceInFile(fullQualifiedFileName, findString, replaceString, true);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionInsertSectionByProperty.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import java.util.Map;
4 |
5 | /******************************************************************************************
6 | This class is used to insert a section before or after another section. This section is
7 | searched using the 'sectionType'
8 | and 'property'. For example:
9 | Assume, that 'sectionType' has the value "stage", 'property' has the value "displayName",
10 | and 'propertyValue' has the value "Execute this stage".
11 | If found, a section - defined by 'sectionToInsert' - is inserted before or after "mystage",
12 | depending on the value of 'insertBefore'.
13 |
14 | The variable 'sectionToInsert' is of type Map, because this is the way how a section is
15 | represented in a yaml object in Snakeyaml.
16 |
17 | ******************************************************************************************/
18 | public class ActionInsertSectionByProperty extends ActionOnSectionByProperty {
19 |
20 | public ActionInsertSectionByProperty(String sectionType,
21 | String property,
22 | String propertyValue,
23 | Map sectionToInsert,
24 | boolean insertBefore) {
25 | super(ACTION.INSERT_SECTION,
26 | sectionType,
27 | property,
28 | propertyValue,
29 | sectionToInsert,
30 | insertBefore);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/main/java/azdo/hook/DeleteJUnitPipelineDependency.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) Henry van Merode.
2 | // Licensed under the MIT License.
3 |
4 | package azdo.hook;
5 |
6 | import azdo.junit.AzDoPipeline;
7 | import azdo.utils.Log;
8 | import azdo.utils.PomUtils;
9 | import azdo.utils.Utils;
10 |
11 | /******************************************************************************************
12 | Hook, to remove the dependency to the 'junit-pipeline' jar, before it is deployed to the
13 | AzDo test project. Normally, this dependency is stored in a repository or in
14 | Azure DevOps artifacts. When building the Maven artifact, the location of this dependency
15 | is configured and the Maven build will not fail.
16 | The dependency is removed from the pom.xml to prevent build errors (cannot find library).
17 | ******************************************************************************************/
18 | public class DeleteJUnitPipelineDependency extends Hook {
19 | private String pom;
20 | private String groupId;
21 | private String artifactId;
22 | private static final Log logger = Log.getLogger();
23 | public DeleteJUnitPipelineDependency (String pom, String groupId, String artifactId) {
24 | logger.debug("==> Class: DeleteJUnitPipelineDependency");
25 |
26 | this.pom = Utils.fixPath(pom);
27 | this.groupId = groupId;
28 | this.artifactId = artifactId;
29 | }
30 |
31 | @Override
32 | public void executeHook (){
33 | try {
34 | logger.debug("==> Method: DeleteJUnitPipelineDependency.executeHook");
35 | PomUtils.deleteDependency(pom, groupId, artifactId);
36 | }
37 | catch (Exception e) {}
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionResetTrigger.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import azdo.utils.Log;
4 | import azdo.yaml.ActionResult;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Map;
8 |
9 | import static azdo.utils.Constants.SECTION_TRIGGER;
10 |
11 | public class ActionResetTrigger implements Action {
12 | private static final Log logger = Log.getLogger();
13 |
14 | public ActionResetTrigger() {}
15 |
16 | /******************************************************************************************
17 | Perform an action on the 'trigger' section (replace with new trigger section).
18 | @param actionResult Contains parts of the YAML structure. It is used to search for the
19 | section in the l3 structure.
20 | ******************************************************************************************/
21 | public void execute (ActionResult actionResult) {
22 | logger.debug("==> Method ActionResetTrigger.execute");
23 | logger.debug("actionResult.l1: {}", actionResult.l1);
24 |
25 | if (actionResult.l1 == null) {
26 | logger.debug("actionResult.l1 is null; return");
27 | return;
28 | }
29 |
30 | if (actionResult.l1 instanceof Map) {
31 | logger.info("Reset trigger to \'none\'");
32 | Map map = (Map) actionResult.l1;
33 | if (map.containsKey(SECTION_TRIGGER))
34 | map.put(SECTION_TRIGGER, "none");
35 | }
36 | }
37 |
38 | // This action can only be executed if the section type and section identification are found in the YAML file
39 | public boolean needsSectionIdentifier() {
40 | return false;
41 | }
42 |
43 | // This action is not a custom action
44 | public boolean isCustomAction () { return true; }
45 | }
46 |
--------------------------------------------------------------------------------
/pipeline/powershell-mock.yml:
--------------------------------------------------------------------------------
1 | # Build numbering format
2 | name: $(Date:yyyyMMdd)$(Rev:.r)
3 |
4 | trigger: none
5 |
6 | stages:
7 | - stage: PowerShellMockStage
8 | jobs:
9 | - job: PowerShellMockJob
10 | pool:
11 | vmImage: 'windows-latest'
12 | steps:
13 | # Multiple Invoke-RestMethod commands to test that mockPowerShellCommandSearchStepByDisplayName is able to mock multiple
14 | # instances of the Invoke-RestMethod in one step
15 | - pwsh: |
16 | $Url = "https://server.contoso.com:8089/services/search/jobs/export"
17 | $Body = @{
18 | search = "search index=_internal | reverse | table index,host,source,sourcetype,_raw"
19 | output_mode = "csv"
20 | earliest_time = "-2d@d"
21 | latest_time = "-1d@d"
22 | }
23 | $result = Invoke-RestMethod -Method 'Post' -Uri $url -Body $body -OutFile output.csv
24 | Write-Output "Result: $($result.element)"
25 |
26 | $result = Invoke-RestMethod -Method 'Post' -Uri $url -Body $body -OutFile output.csv
27 | Write-Output "Result: $($result.element)"
28 | displayName: 'Invoke-RestMethod step 1 of 2'
29 |
30 | # An extra step with a Invoke-RestMethod to validate that mockPowershellCommandSearchStepByDisplayName resets for each new step
31 | - pwsh: |
32 | $Url = "https://server.contoso.com:8089/services/search/people/export"
33 | $result = Invoke-RestMethod -Method 'Post' -Uri $url -OutFile output.csv
34 | Write-Output "Result: $($result.element)"
35 | displayName: 'Invoke-RestMethod step 2 of 2'
36 |
37 | # Validate that the PowerShell@2 task is supported by mockPowershellCommandSearchStepByDisplayName
38 | - task: PowerShell@2
39 | inputs:
40 | targetType: 'inline'
41 | script: |
42 | $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
43 | $pipeline = Invoke-RestMethod -Uri $url -Headers @{
44 | Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
45 | }
46 | Write-Output "Result: $($pipeline.element)"
47 | displayName: 'PowerShell@2 task'
48 |
49 |
--------------------------------------------------------------------------------
/pipeline/bash-mock.yml:
--------------------------------------------------------------------------------
1 | # Build numbering format
2 | name: $(Date:yyyyMMdd)$(Rev:.r)
3 |
4 | trigger: none
5 |
6 | stages:
7 | - stage: bashMockStage
8 | jobs:
9 | - job: bashMockJob
10 | pool:
11 | vmImage: 'ubuntu-latest'
12 | steps:
13 | # Multiple curl commands to test that mockBashCommandSearchStepByDisplayName is able to mock multiple
14 | # instances of the same command in one step
15 | - script: |
16 | var=$(curl --silent --head https://www.example.com | awk '/^HTTP/{print $2}')
17 | echo "$var"
18 | var=$(curl --silent --head https://www.example.com | awk '/^HTTP/{print $2}')
19 | echo "$var"
20 | var=$(curl --silent --head https://www.example.com | awk '/^HTTP/{print $2}')
21 | echo "$var"
22 | displayName: 'Curl step 1 of 2'
23 |
24 | # An extra step with a curl command to validate that mockBashCommandSearchStepByDisplayName resets for each new step
25 | - script: |
26 | # Return the HTTP status code. This should be 200 (if not mocked).
27 | var=$(curl --silent --head https://www.example.com | awk '/^HTTP/{print $2}')
28 | echo "$var"
29 | displayName: 'Curl step 2 of 2'
30 |
31 | # Validate that the "bash" step works for mockBashCommandSearchStepByDisplayName
32 | # Validate that the wget command is supported by mockBashCommandSearchStepByDisplayName
33 | - bash: |
34 | # The wget command downloads a .jar file
35 | wget "https://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-jre8-standalone/2.35.0/wiremock-jre8-standalone-2.35.0.jar"
36 | displayName: 'Wget step'
37 |
38 | # Validate that the ftp command is supported by mockBashCommandSearchStepByDisplayName
39 | - script: |
40 | # This ftp command fails
41 | ftp -u ftp://user:secret@ftp.example.com/my-local-file.txt my-local-file.txt
42 | displayName: 'Ftp step'
43 |
44 | # Validate that the Bash@3 task is supported by mockBashCommandSearchStepByDisplayName
45 | - task: Bash@3
46 | inputs:
47 | targetType: 'inline'
48 | script: |
49 | var=$(curl --silent --head https://www.example.com | awk '/^HTTP/{print $2}')
50 | echo "$var"
51 | displayName: 'Bash@3 task'
52 |
--------------------------------------------------------------------------------
/src/main/java/azdo/action/ActionReturnPropertyValue.java:
--------------------------------------------------------------------------------
1 | package azdo.action;
2 |
3 | import azdo.yaml.ActionResult;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Map;
7 |
8 | /******************************************************************************************
9 | This class is used to return the value of a property in a section.
10 | This section is searched using 'sectionType' and 'property'.
11 | If the property is found, it's value is returned.
12 | ******************************************************************************************/
13 | public class ActionReturnPropertyValue extends ActionOnSectionByProperty {
14 |
15 | private ArrayList propertyValues = new ArrayList<>();
16 | public ActionReturnPropertyValue(String sectionType,
17 | String property) {
18 | super(ACTION.GET_PROPERTY,
19 | sectionType,
20 | property,
21 | null,
22 | null,
23 | false);
24 | }
25 |
26 | // Perform a custom execute
27 | public void execute(ActionResult actionResult) {
28 | if (actionResult.l1 == null) {
29 | logger.debug("l1 is null");
30 | return;
31 | }
32 |
33 | if (actionResult.l1 instanceof ArrayList) {
34 | logger.debug("l1 is instance of ArrayList");
35 |
36 | // Run through the elements of the list and update the section
37 | ArrayList