can't use extends and stages together azure pipelines

755 Views Asked by At

I am trying to use a template in azure devops, because it is a template to make the build of a proyect with gradle and weblogic, but before doing that i need to create the build in the front and move it to the back, the problem with that is when i add the stages it throws an error Unexpected property extends And it is not because of the version because without the steps it works normally

There is a correct option to do that, without changing the template?, i already tried many things but doesnt work, this is my code

trigger:
  - none

parameters:
  - name: deliveryTrain
    type: object
    default:
      continuousIntegration:
        build:
          - with: gradle
            configure:
              javaVersion: '1.8'
              gradleExtraOptionsLabo: 'clean build'
              workingDirectory: 'Gerencia_Tecnologia/salud-mensajeria_dinamica-back'
        artifact:
          with: 'artifactory'
          configure:
            artifactName: 'dinamica.md.ear'
      continuousDelivery:
        deployment:
          - environment: 'labo'
            platform:
              with: 'weblogic'
              configure:
                serviceConnection: 'lab-Salud-wl-12.2.1.4'
      continuousTesting:
        - environment: 'labo'
          cases:
            - type: performance
              with: 'jmeter'
              configure:
                repo:
                  name: 'Gerencia_Tecnologia/salud-mensajeria_dinamica-back-ml'
                  branch: 'feature/hu_comun_1707'
                performanceTestFiles: 'jmeter/test/test.jmx'
                performanceTestPercentilTest: '99'
                performanceTestResultFiles: 'jmeter/test/result.jtl'

stages:
  - stage: MensajeriaDinamicaFrontBuild
    displayName: 'MensajeriaDinamica-Front-build'
    jobs:
      - job: BuildFrontEnd
        displayName: 'Build Front Artifact'
        pool:
          name: 'linux-generic'
        steps:
          - checkout: front
          - task: NodeTool@0
            inputs:
              versionSpec: '12.16.1'
            displayName: 'Install Node.js'
          - script: npm install -g @angular/[email protected]
            displayName: 'Install Angular CLI'
          - script: |
              npm install &&
              ng build --aot --output-hashing=all --prod
            displayName: 'Built Front Artifact'
          - task: PublishPipelineArtifact@1
            displayName: 'Publish Front Artifact to dist carpet'
            inputs:
              targetPath: '$(System.DefaultWorkingDirectory)/dist'
              artifact: 'front-artifact'
          - task: CopyFiles@2
            displayName: 'Copy files to ArtifactStagingDirectory'
            inputs:
              SourceFolder: '$(System.DefaultWorkingDirectory)/dist'
              Contents: '**'  
              TargetFolder: '$(Build.ArtifactStagingDirectory)'
          - task: PublishBuildArtifacts@1
            displayName: 'Publish front Artifact to ArtifactStagingDirectory'
            inputs:
              pathToPublish: '$(Build.ArtifactStagingDirectory)'
              artifactName: 'MensajeriaDinamicaFrontArtifact'  

      - job: CopyArtifactsToBack
        condition: succeeded('BuildFrontEnd')
        dependsOn: BuildFrontEnd
        displayName: 'Move Front Artifact to Back-End Repository'
        pool:
          name: 'linux-generic'
        steps:
            - checkout: back
            - script: |
                rm -r $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp/* &&
                echo "Listing the deleted folders file:"
                ls -R $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp
              displayName: 'cleaned back webcontent'
            - task: DownloadPipelineArtifact@2
              inputs:
                artifactName: 'MensajeriaDinamicaFrontArtifact' 
                targetPath: '$(System.DefaultWorkingDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp/'
            - script: |
                echo "Listing the downloaded artifact:"
                ls -R $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp
            - template: templates/gradle-weblogic.yaml@templates
                
      - job: UsingTemplate
        displayName: 'Usar plantilla de gradle weblogic'
        steps:
          - checkout: templates
          - script: |
              ls -R $(Build.SourcesDirectory)/templates
            displayName: 'List Files in Cloned Repositories'


resources:
  repositories:
    - repository: back
      type: git
      name: Gerencia_Tecnologia/salud-mensajeria_dinamica-back-ml
      ref: feature/hu_comun_1707
    - repository: front
      type: git
      name: Gerencia_Tecnologia/salud-mensajeria_dinamica-fr
      ref: feature/hu-comun-tablas
    - repository: templates
      type: git
      name: Gerencia_Tecnologia/ti-templates_pipelines-conf
      ref: master

extends:
  template: 'templates/gradle-weblogic.yaml@templates'
  parameters:
    deliveryTrain: ${{ parameters.deliveryTrain }}

And this is the template used

variables:
- template: ../transversal/vars/vars-global.yaml

parameters:
- name: deliveryTrain
  type: object
- name: changeOrderHistoriasId
  type: string
  default: ''
- name: changeOrderApprover
  type: string
  default: ''
- name: changeOrderItemApproverBusiness
  type: string
  default: ''
- name: changeOrderRequester
  type: string
  default: ''

stages:
  - template: ../transversal/stages/continuous-integration.yaml
    parameters:
      continuousIntegration: ${{ parameters.deliveryTrain.continuousIntegration }}
  
  - ${{ if ne(variables['Build.Reason'],'PullRequest') }}:
    - ${{ if parameters.deliveryTrain.continuousDelivery }}:
      - template: ../transversal/stages/approvals.yaml
        parameters:
          deployment: ${{ parameters.deliveryTrain.continuousDelivery.deployment }}
              
      - template: ../transversal/stages/continuous-delivery.yaml
        parameters:
          continuousDelivery: ${{ parameters.deliveryTrain.continuousDelivery }}
          artifact: ${{ parameters.deliveryTrain.continuousIntegration.artifact }}
          changeOrderHistoriasId: ${{ parameters.changeOrderHistoriasId }}
          changeOrderApprover: ${{ parameters.changeOrderApprover }}
          changeOrderItemApproverBusiness: ${{ parameters.changeOrderItemApproverBusiness }}
          changeOrderRequester: ${{ parameters.changeOrderRequester }}
    
    - template: ../transversal/stages/continuous-testing.yaml
      ${{ each environment in parameters.deliveryTrain.continuousTesting }}:
        ${{ if or( and(contains(variables['Build.SourceBranch'], 'refs/pull/' ), eq( environment.environment, 'none') ), and( eq(variables['Build.SourceBranch'], 'refs/heads/develop' ), eq( environment.environment, 'dllo') ), and( contains(variables['Build.SourceBranch'], 'refs/heads/release' ), eq( environment.environment, 'labo') ), and( eq(variables['Build.SourceBranch'], 'refs/heads/master' ), eq( environment.environment, 'pdn') ), and( contains(variables['Build.SourceBranch'], 'refs/heads/feature/' ), eq( environment.environment, 'dllo') )) }}:
          parameters:
            continuousTesting: ${{ environment.cases }}
  
    - ${{ if or(parameters.deliveryTrain.continuousDelivery, parameters.deliveryTrain.continuousTesting ) }}:
      - template: ../transversal/stages/post-delivery.yaml
        parameters:
          deliveryTrain: ${{ parameters.deliveryTrain }}
2

There are 2 best solutions below

6
Kevin Lu-MSFT On BEST ANSWER

Based on your YAML sample, I can reproduce the same issue.

enter image description here

I am afraid that the extends and the stages fields are not able to be defined at the same time in YAML Pipeline.

To meet your requirement, you can change to use - template field to use the YAML template and define the stages at the same time.

Update1:

Based on your YAML sample, you can use the following YAML Pipeline YAML code:

Main YAML:

trigger:
  - none

variables:
- template: ../transversal/vars/vars-global.yaml  

resources:
  repositories:
    - repository: back
      type: git
      name: Gerencia_Tecnologia/salud-mensajeria_dinamica-back-ml
      ref: feature/hu_comun_1707
    - repository: front
      type: git
      name: Gerencia_Tecnologia/salud-mensajeria_dinamica-fr
      ref: feature/hu-comun-tablas
    - repository: templates
      type: git
      name: Gerencia_Tecnologia/ti-templates_pipelines-conf
      ref: master

parameters:
  - name: deliveryTrain
    type: object
    default:
      continuousIntegration:
        build:
          - with: gradle
            configure:
              javaVersion: '1.8'
              gradleExtraOptionsLabo: 'clean build'
              workingDirectory: 'Gerencia_Tecnologia/salud-mensajeria_dinamica-back'
        artifact:
          with: 'artifactory'
          configure:
            artifactName: 'dinamica.md.ear'
      continuousDelivery:
        deployment:
          - environment: 'labo'
            platform:
              with: 'weblogic'
              configure:
                serviceConnection: 'lab-Salud-wl-12.2.1.4'
      continuousTesting:
        - environment: 'labo'
          cases:
            - type: performance
              with: 'jmeter'
              configure:
                repo:
                  name: 'Gerencia_Tecnologia/salud-mensajeria_dinamica-back-ml'
                  branch: 'feature/hu_comun_1707'
                performanceTestFiles: 'jmeter/test/test.jmx'
                performanceTestPercentilTest: '99'
                performanceTestResultFiles: 'jmeter/test/result.jtl'

stages:
  - stage: MensajeriaDinamicaFrontBuild
    displayName: 'MensajeriaDinamica-Front-build'
    jobs:
      - job: BuildFrontEnd
        displayName: 'Build Front Artifact'
        pool:
          name: 'linux-generic'
        steps:
          - checkout: front
          - task: NodeTool@0
            inputs:
              versionSpec: '12.16.1'
            displayName: 'Install Node.js'
          - script: npm install -g @angular/[email protected]
            displayName: 'Install Angular CLI'
          - script: |
              npm install &&
              ng build --aot --output-hashing=all --prod
            displayName: 'Built Front Artifact'
          - task: PublishPipelineArtifact@1
            displayName: 'Publish Front Artifact to dist carpet'
            inputs:
              targetPath: '$(System.DefaultWorkingDirectory)/dist'
              artifact: 'front-artifact'
          - task: CopyFiles@2
            displayName: 'Copy files to ArtifactStagingDirectory'
            inputs:
              SourceFolder: '$(System.DefaultWorkingDirectory)/dist'
              Contents: '**'  
              TargetFolder: '$(Build.ArtifactStagingDirectory)'
          - task: PublishBuildArtifacts@1
            displayName: 'Publish front Artifact to ArtifactStagingDirectory'
            inputs:
              pathToPublish: '$(Build.ArtifactStagingDirectory)'
              artifactName: 'MensajeriaDinamicaFrontArtifact'  

      - job: CopyArtifactsToBack
        condition: succeeded('BuildFrontEnd')
        dependsOn: BuildFrontEnd
        displayName: 'Move Front Artifact to Back-End Repository'
        pool:
          name: 'linux-generic'
        steps:
            - checkout: back
            - script: |
                rm -r $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp/* &&
                echo "Listing the deleted folders file:"
                ls -R $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp
              displayName: 'cleaned back webcontent'
            - task: DownloadPipelineArtifact@2
              inputs:
                artifactName: 'MensajeriaDinamicaFrontArtifact' 
                targetPath: '$(System.DefaultWorkingDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp/'
            - script: |
                echo "Listing the downloaded artifact:"
                ls -R $(Build.SourcesDirectory)/WAR_MensajeriaDinamica/WebContent/resultadosapp
            - template: templates/gradle-weblogic.yaml@templates
                
      - job: UsingTemplate
        displayName: 'Usar plantilla de gradle weblogic'
        steps:
          - checkout: templates
          - script: |
              ls -R $(Build.SourcesDirectory)/templates
            displayName: 'List Files in Cloned Repositories'




  - template: 'templates/gradle-weblogic.yaml@templates'
    parameters:
      deliveryTrain: ${{ parameters.deliveryTrain }}

Template YAML:

parameters:
- name: deliveryTrain
  type: object
- name: changeOrderHistoriasId
  type: string
  default: ''
- name: changeOrderApprover
  type: string
  default: ''
- name: changeOrderItemApproverBusiness
  type: string
  default: ''
- name: changeOrderRequester
  type: string
  default: ''

stages:
  - template: ../transversal/stages/continuous-integration.yaml
    parameters:
      continuousIntegration: ${{ parameters.deliveryTrain.continuousIntegration }}
  
  - ${{ if ne(variables['Build.Reason'],'PullRequest') }}:
    - ${{ if parameters.deliveryTrain.continuousDelivery }}:
      - template: ../transversal/stages/approvals.yaml
        parameters:
          deployment: ${{ parameters.deliveryTrain.continuousDelivery.deployment }}
              
      - template: ../transversal/stages/continuous-delivery.yaml
        parameters:
          continuousDelivery: ${{ parameters.deliveryTrain.continuousDelivery }}
          artifact: ${{ parameters.deliveryTrain.continuousIntegration.artifact }}
          changeOrderHistoriasId: ${{ parameters.changeOrderHistoriasId }}
          changeOrderApprover: ${{ parameters.changeOrderApprover }}
          changeOrderItemApproverBusiness: ${{ parameters.changeOrderItemApproverBusiness }}
          changeOrderRequester: ${{ parameters.changeOrderRequester }}
    
    - template: ../transversal/stages/continuous-testing.yaml
      ${{ each environment in parameters.deliveryTrain.continuousTesting }}:
        ${{ if or( and(contains(variables['Build.SourceBranch'], 'refs/pull/' ), eq( environment.environment, 'none') ), and( eq(variables['Build.SourceBranch'], 'refs/heads/develop' ), eq( environment.environment, 'dllo') ), and( contains(variables['Build.SourceBranch'], 'refs/heads/release' ), eq( environment.environment, 'labo') ), and( eq(variables['Build.SourceBranch'], 'refs/heads/master' ), eq( environment.environment, 'pdn') ), and( contains(variables['Build.SourceBranch'], 'refs/heads/feature/' ), eq( environment.environment, 'dllo') )) }}:
          parameters:
            continuousTesting: ${{ environment.cases }}
  
    - ${{ if or(parameters.deliveryTrain.continuousDelivery, parameters.deliveryTrain.continuousTesting ) }}:
      - template: ../transversal/stages/post-delivery.yaml
        parameters:
          deliveryTrain: ${{ parameters.deliveryTrain }}

For more detailed info, you can refer to the doc: Template usage reference

4
bryanbcook On

Templates can only be used to define stages, jobs, steps or variables. The extends feature is intended to build off an existing pipeline that already defines stages. You unfortunately can't define stages and extends at the same time.

It would appear that the author of your templates library has provided a template that accepts a deliveryTrain parameter. This parameter is custom to your organization and is a loosely defined YAML object that is interpreted by their template. Hard to say what the template is doing without access to it, but I'd assume that it's defining the stages based on the continuous integration, continuous delivery keywords. Based on what you've provided, it looks like this template generates a maven artifact and pushes it to a storage mechanism (artifactory).

My suggestion would be to view the expanded template to understand what it's doing:

  1. In the Pipeline Editor, provide the YAML that uses their template

  2. Choose 'Download Full YAML' from the ellipsis:

    enter image description here

  3. Review the steps provided by the template and determine where your custom tasks should go.

  4. Reach out to your template authors to determine if their template allows you to specify your additional steps.

For example,

extends:
  template: /pipeline.yml@templates
  parameters:
    deliveryTrain:
       continuousIntegration:
         build:
         - with: gradle
           ...
         - with: customSteps
             steps: # custom defined steps
             - checkout: 'salud-mensajeria_dinamica-fr'
             - task: UseNode@1
                inputs:
                  version: '12.16.1'
             - script: |
                 npm install @angular/[email protected] &&
                 npm install &&
                 ng build --aot --output-hashing=all --prod &&
                 cp -r dist/. $(Build.ArtifactStagingDirectory)
               displayName: 'Built and Copied Front Artifact'
         artifact:
          with: 'artifactory'
          configure:
            artifactName: 'dinamica.md.ear'
       continuousDelivery:
         ...
       continuousTesting:
         ...

An example of a template that would support this, based on the above:

jobs:
- job: continuousIntegration
  steps:

  - ${{ each item in parameters.deliveryTrain.continuousIntegration.build }}:
    - ${{ if eq(item.with, 'customSteps') }}:
      - ${{ insert }}: ${{ with.steps }}