anchor.diff:  We did mention earlier that our application was cross-platform. So, let's assume that the functional tests need to be run on three different operating systems - Mac OS X, Windows and Linux. We could start to approach this by adding jobs in Stage 4 and use GoCD's [*resource*](https://docs.gocd.io/current/introduction/concepts_in_go.html#resources) concept to make sure that the jobs are picked up by [*agents*](https://docs.gocd.io/current/introduction/concepts_in_go.html#agent) with the right operating system. This will involve running agents on the different operating systems and tagging them with resources "mac", "windows" and "linux". Once that's done, we could setup our pipeline to look like this:
   
   <div class='imagezoom'>
  -  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-05.jpg', :alt => 'Pipeline', :title => 'Pipeline'%>
  +  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-05.jpg', :alt => 'Pipeline with duplicate jobs', :title => 'Pipeline with duplicate jobs'%>
     <span class='info_txt'>Click image to zoom in</span>
   </div>
   However, this approach isn't the most optimal.
  
positive.code: 
  A typical approach to automate this process would be to have a build script (using Rake, Make, Ant, etc. or even a batch file or a shell script) which has all the individual steps of the process automated so that they can be run locally (<%= link_to 'Principle 5', '/posts/2017-03-01-importance-and-principles-of-cd-pipelines.html#principle-run-locally' %>). Having this, you can now create a GoCD [*pipeline*](https://docs.gocd.io/current/introduction/concepts_in_go.html#pipeline) with a single [*stage*](https://docs.gocd.io/current/introduction/concepts_in_go.html#stage) which has a single [*job*](https://docs.gocd.io/current/introduction/concepts_in_go.html#job) which has a single [*task*](https://docs.gocd.io/current/introduction/concepts_in_go.html#task) which calls "make all" (for instance). It'll look like this:
  
  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-01.jpg', :alt => 'Pipeline', :title => 'Simple Pipeline' %>
  
  While this approach works, it's not very flexible. It doesn't make it easy to run different parts of the process on different agents, makes it hard to track progress and hard to parallelize. Even though it's inside a pipeline, it doesn't use any advantages of the *pipeline* concept and its modeling capabilities. This is no different from using a standard CI tool and making it run commands.
  
  A slightly better approach is to break apart the individual pieces into separate GoCD *tasks*, like so:
  
  <%= image_tag 'blog/beginnings-real-pipeline/pipeline-02.jpg', :alt => 'Pipeline', :title => 'Pipeline' %>
  
  This approach makes the individual tasks and the order in which they are run, more explicit. It can be argued that this comes at the expense of tying the order of the processes to the CD tool. However, we think that this orchestration is the job of the CD tool and entrusting it to the CD tool allows better flexibility in modeling the processes.
  
  
negative.code: To get around this, we can use GoCD's powerful [pipeline chaining mechanism](https://docs.gocd.io/current/introduction/concepts_in_go.html#pipeline_dependency), where a stage of a pipeline can be setup as a dependency for another pipeline. We can create one pipeline per operating system's functional test. Let's see how that looks:
  
  <div class='imagezoom'>
    <%= image_tag 'blog/beginnings-real-pipeline/pipeline-06.jpg', :alt => 'Setting up Pipeline Dependencies', :title => 'Setting up Pipeline Dependencies'%>
    <span class='info_txt'>Click image to zoom in</span>
  </div>
  
  