In the post, we are going to take our sample Workflow that builds two ASP.NET Core web applications and split it so each web application is built individually. This post is using the repo and Workflow built in the following posts if you need to catch up.
GitHub: Import an Azure DevOps Repo
GitHub: Use Actions to build ASP.NET Core Application
GitHub: Use Actions to Publish Artifacts
Starting Point and the Plan
Our Workflow currently contains a single job that just happens to build two ASP.NET Core web application based on the fact that the .NET CLI picks up and builds both applications. The following is the YAML for our current Workflow.
name: .NET Core on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: 3.1.101 - name: Install dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --no-restore --verbosity normal - name: Publish run: dotnet publish - name: Upload WebApp1 Build Artifact uses: actions/upload-artifact@v2 with: name: WebApp1 path: /home/runner/work/Playground/Playground/src/WebApp1/bin/Debug/netcoreapp3.1/publish/ - name: Upload WebApp2 Build Artifact uses: actions/upload-artifact@v2 with: name: WebApp2 path: /home/runner/work/Playground/Playground/src/WebApp2/bin/Debug/netcoreapp3.1/publish/
This post is going to take this Workflow and split the build and publish of the two web applications into two jobs. By splitting the Workflow into multiple jobs we open the possibility that the jobs can run in parallel. One reason to do this would be to speed up the total Workflow run time if you have parts of your build that are independent. Another example of why you would need multiple jobs is if the different jobs need different needed to run on different operating systems such as one needing to run Windows and another a Linux.
Creating the Jobs
The following is the Workflow set up along with the job to build the first web application. The first change was of the ID from build to build_web_app1 since each job has to have a unique ID. Most of the rest of the highlighted changes are related to the .NET CLI commands that are now directed at a specific project. Do also note that we changed from a hardcoded path to using expression to get the workspace path which is the ${{ github.workspace }} bit instead of /home/runner/work/Playground/Playground/. See the expression syntax docs for more info.
name: .NET Core on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build_web_app1: name: Build WebApp1 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: 3.1.101 - name: Install dependencies run: dotnet restore ${{ github.workspace }}/src/WebApp1/WebApp1.csproj - name: Build run: dotnet build ${{ github.workspace }}/src/WebApp1/WebApp1.csproj --configuration Release --no-restore - name: Test run: dotnet test ${{ github.workspace }}/src/WebApp1/WebApp1.csproj --no-restore --verbosity normal - name: Publish run: dotnet publish ${{ github.workspace }}/src/WebApp1/WebApp1.csproj - name: Upload Build Artifact uses: actions/upload-artifact@v2 with: name: WebApp1 path: ${{ github.workspace }}/src/WebApp1/bin/Debug/netcoreapp3.1/publish/
Here is the full file with both jobs defined. As you can see the second job is basically the same thing as the first one with a different ID, name, and project.
name: .NET Core on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build_web_app1: name: Build WebApp1 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: 3.1.101 - name: Install dependencies run: dotnet restore ${{ github.workspace }}/src/WebApp1/WebApp1.csproj - name: Build run: dotnet build ${{ github.workspace }}/src/WebApp1/WebApp1.csproj --configuration Release --no-restore - name: Test run: dotnet test ${{ github.workspace }}/src/WebApp1/WebApp1.csproj --no-restore --verbosity normal - name: Publish run: dotnet publish ${{ github.workspace }}/src/WebApp1/WebApp1.csproj - name: Upload Build Artifact uses: actions/upload-artifact@v2 with: name: WebApp1 path: ${{ github.workspace }}/src/WebApp1/bin/Debug/netcoreapp3.1/publish/ build_web_app2: name: Build WebApp2 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: 3.1.101 - name: Install dependencies run: dotnet restore ${{ github.workspace }}/src/WebApp2/WebApp2.csproj - name: Build run: dotnet build ${{ github.workspace }}/src/WebApp2/WebApp2.csproj --configuration Release --no-restore - name: Test run: dotnet test ${{ github.workspace }}/src/WebApp2/WebApp2.csproj --no-restore --verbosity normal - name: Publish run: dotnet publish ${{ github.workspace }}/src/WebApp2/WebApp2.csproj - name: Upload Build Artifact uses: actions/upload-artifact@v2 with: name: WebApp2 path: ${{ github.workspace }}/src/WebApp2/bin/Debug/netcoreapp3.1/publish/
After all the edits are done commit the changes to the repo to run the Workflow. From the results of the Workflow run, you will see that it now has two jobs and we still got the artifacts for both applications as we had before.
Wrapping Up
If your applications need it breaking them up into different jobs can be helpful not only with Workflow runtimes but it can also help your ability to reason about what each part of your build process is doing.
Also published on Medium.
Hi, the step called “Setup .NET Core” is used in both jobs. Is it possible to extract it into a separate job/reusable component to avoid code duplication?