DEV Community

Cover image for Building a workflow for your ASP.NET Core app with Github Actions
Ignacio laborde for Cloud(x);

Posted on • Edited on

Building a workflow for your ASP.NET Core app with Github Actions

For this example, I merged two workflows provided by GitHub: .NET and Deploy to Amazon ECS. The idea is build a simple workflow like this:
api-deployment

Why Github Actions?

Github Actions offers workflows that can build the code in your repository and run your tests. Workflows can run on GitHub-hosted virtual machines, or on machines that you host yourself.

To start with Actions, create a new file in the .github/workflows directory named api-deployment.yml and copy the following YAML:

name: API workflow

on:
  push:
    branches: [ main ]
    paths:
      - 'src/**'    
  pull_request:
    branches: [ main ]
    paths:
      - 'src/**'

jobs:
  build:
    name: Build API
    runs-on: ubuntu-latest
    env:
      working-directory: './src'
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-dotnet@v1
      with:
        dotnet-version: '3.1.x'
    - name: Restore dependencies
      run: dotnet restore API.sln
      working-directory: ${{env.working-directory}}
    - run: dotnet build --no-restore
      working-directory: ${{env.working-directory}}    
    - run: dotnet test --no-build --verbosity normal
      working-directory: ${{env.working-directory}}

  deploy-dev:
    name: Deploy to Dev
    if: github.event.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    needs: [build]

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-2

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: your-ecr-name
        IMAGE_TAG: ${{ github.sha }}
      run: |
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build -f src/api/Dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG src/api
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: .github/task-definitions/your-api-task-definition.json
        container-name: your-container-name
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: your-service-name
        cluster: your-cluster-name
        wait-for-service-stability: true

Enter fullscreen mode Exit fullscreen mode

That is quite a long file, so let's start to dissect the most important lines.

Events

An event is an activity that triggers a workflow. To define the event (or events) we use the on keyword. Also, you can add constraints over those triggers.
Here we are setting that our action is going to be triggered on every push or pull request to main, and at least one modified file matches the configured paths.
Note: push and pull_request events support paths and paths-ignore filter, for more info read here

on:
  push:
    branches: [ main ]
    paths:
      - 'src/**'    
  pull_request:
    branches: [ main ]
    paths:
      - 'src/**' 
Enter fullscreen mode Exit fullscreen mode

Jobs

A job is a set of steps that execute on the same runner. By default, a workflow with multiple jobs will run those jobs in parallel.

Build

Build is just a name for this job, you can set whatever you want. Here I'm using mostly the example from the .NET workflow. Will restore dependencies, build the code and run the unit tests.

  build:
    name: Build API
    runs-on: ubuntu-latest
    env:
      working-directory: './src'
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-dotnet@v1
      with:
        dotnet-version: '3.1.x'
    - name: Restore dependencies
      run: dotnet restore API.sln
      working-directory: ${{env.working-directory}}
    - run: dotnet build --no-restore
      working-directory: ${{env.working-directory}}    
    - run: dotnet test --no-build --verbosity normal
      working-directory: ${{env.working-directory}}
Enter fullscreen mode Exit fullscreen mode

Deploy-dev

Deploy-dev job is using the Github workflows templates,
an upcoming post will cover how to create this infrastructure in detail to complete a full deployment.
But I want to highlight the following block:

  deploy-dev:
    name: Deploy to Dev
    if: github.event.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    needs: [build]
Enter fullscreen mode Exit fullscreen mode

Using the needs keyword we define a dependency to the previous job build, only if the build was successfully completed this job is going to be executed. In that form, we change the default behavior of running the jobs in parallel to run sequentially.

On the other way, the if conditional allows avoiding the execution of a job unless a condition is met.
Here we use the github context to get the branch that is triggering the workflow, if the branch is "main" means that the PR was merged, so we can complete our deployment to our dev environment.

So that's it!

You can find a public repo with the example here

Top comments (0)