Configure a pipeline and push updates

In this article, you'll learn how to use the Azure Developer CLI (azd) to push template changes through a CI/CD pipeline such as GitHub Actions or Azure DevOps. For this example you'll use the React Web App with Node.js API and MongoDB on Azure template, but you can apply the principles you learn in this article to any of the Azure Developer CLI templates.

Note

The azd pipeline config command is still in beta. Read more about alpha and beta feature support on the feature versioning and release strategy page.

Prerequisites

azd templates may or may not include a default GitHub Actions and/or Azure DevOps pipeline configuration file called azure-dev.yml, which is required to setup CI/CD. This configuration file provisions your Azure resources and deploy your code to the main branch. You can find azure-dev.yml:

  • For GitHub Actions: in the .github/workflow directory.
  • For Azure DevOps: in the .azdo/pipelines directory.

You can use the configuration file as-is or modify it to suit your needs.

Note

Make sure your template has a pipeline definition (azure-dev.yaml) before calling azd pipeline config. azd will not automatically create this file. See Create a pipeline definition for azd below.

To configure a CI/CD pipeline you'll use the azd pipeline config command, which handles the following tasks:

  • Creates and configures a service principal for the app on the Azure subscription. Your user must have either Owner role or Contributor + User Access Administrator roles within the Azure subscription because to allow azd to create and assign roles to the service principal.
  • Steps you through a workflow to create and configure a GitHub or Azure DevOps repository and commit your project code to it. You can also choose to use an existing repository.
  • Creates a secure connection between Azure and your repository.
  • Runs the GitHub action when you check in the workflow file.

For more granular control over this process, or if you user does not have the required roles, you can manually configure a pipeline.

Select your preferred pipeline provider to continue:

Authorize GitHub to deploy to Azure

To configure the workflow, you need to authorize a service principal to deploy to Azure on your behalf, from a GitHub action. azd creates the service principal and a federated credential for it.

  1. Run the following command to create the Azure service principal and configure the pipeline:

    azd pipeline config
    

    This command, optionally creates a GitHub repository and pushes code to the new repo.

    Note

    By default, azd pipeline config uses OpenID Connect (OIDC), called federated credentials. If you'd rather not use OIDC, run azd pipeline config --auth-type client-credentials.

    OIDC/federated credentials are not supported for Terraform.

    Learn more about OIDC support in azd.

  2. Supply the requested GitHub information.

  3. When prompted about committing and pushing your local changes to start a new GitHub Actions run, specify y.

  4. In the terminal window, view the results of the azd pipeline config command. The azd pipeline config command will output the GitHub repository name for your project.

  5. Using your browser, open the GitHub repository for your project.

  6. Select Actions to see the workflow running.

    Screenshot of GitHub workflow running.

Make and push a code change

  1. In the project's /src/web/src/layout directory, open header.tsx.

  2. Locate the line <Text variant="xLarge">ToDo</Text>.

  3. Change the literal ToDo to myTodo.

  4. Save the file.

  5. Commit your change. Committing the change starts the GitHub Action pipeline to deploy the update.

    Screenshot of steps required to make and commit change to test file.

  6. Using your browser, open your project's GitHub repository to see both:

    • Your commit
    • The commit from GitHub Actions being set up.

    Screenshot of your committed change in GitHub.

  7. Select Actions to see the test update reflected in the workflow.

    Screenshot of GitHub workflow running after test update.

  8. Visit the web frontend URL to inspect the update.

azd as a GitHub action

Add azd as a GitHub action. This action will install azd. To use it, you can add the following to .github\workflows\azure-dev.yml:

on: [push]

jobs:
   build:
      runs-on: ubuntu-latest
      steps:
         - name: Install azd
         uses: Azure/setup-azd@v0.1.0

Clean up resources

When you no longer need the Azure resources created in this article, run the following command:

azd down

Advanced features

You can extend the azd pipeline config command for specific template scenarios or requirements, as described in the following sections.

Additional secrets or variables

By default, azd sets variables and secrets for the pipeline. For example, the azd pipeline config command creates the subscription id, environment name and the region as pipeline variables whenever it executes. The pipeline definition then references those variables:

env:
   AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
   AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
   AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
   AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
   AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}

When the pipeline runs, azd gets the values from the environment, which is mapped to the variables and secrets. Depending on the template, there might be settings which you can control using environment variables. For example, an environment variable named KEY_VAULT_NAME could be set to define the name of a Key Vault resource within the template infrastructure. For such cases, the list of variables and secrets can be defined by the template, using the azure.yaml. For example, consider the following azure.yaml configuration:

pipeline:
  variables:
    - KEY_VAULT_NAME
    - STORAGE_NAME
  secrets:
    - CONNECTION_STRING

With this configuration, azd checks if any of the variables or secrets have a non-empty value in the environment. azd then creates either a variable or a secret for the pipeline using the name of the key in the configuration as the name of the variable or secret, and the non-string value from the environment for the value.

The azure-dev.yaml pipeline definition can then reference the variables or secrets:

- name: Provision Infrastructure
   run: azd provision --no-prompt
   env:
      KEY_VAULT_NAME: ${{ variables.KEY_VAULT_NAME }}
      STORAGE_NAME: ${{ variables.STORAGE_NAME }}
      CONNECTION_STRING: ${{ secrets.CONNECTION_STRING }}

Note

You must run azd pipeline config after updating the list of secrets or variables in azure.yaml for azd to reset the pipeline values.

Infrastructure parameters

Consider the following bicep example:

@secure()
param BlobStorageConnection string

The parameter BlobStorageConnection has no default value set, so azd prompts the user to enter a value. However, there is no interactive prompt during CI/CD. azd must request the value for the parameter when you run azd pipeline config, save the value in the pipeline, and then fetch the value again when the pipeline runs.

azd uses a pipeline secret called AZD_INITIAL_ENVIRONMENT_CONFIG to automatically save and set the value of all the required parameters in the pipeline. You only need to reference this secret in your pipeline:

- name: Provision Infrastructure
   run: azd provision --no-prompt
   env:
      AZD_INITIAL_ENVIRONMENT_CONFIG: ${{ secrets.AZD_INITIAL_ENVIRONMENT_CONFIG }}

When the pipeline runs, azd takes the values for the parameters from the secret, removing the need for an interactive prompt.

Note

You must re-run azd pipeline config if you add a new parameter.

Create a pipeline definition

If your azd template doesn't already have a CI/CD pipeline definition file, you can create one yourself. A CI/CD pipeline definition has typically 4 main sections:

  • trigger
  • permissions
  • operating system or pool
  • steps to be run

The following examples demonstrate how to create a definition file and related configurations for GitHub Actions and Azure Pipelines.

Running azd in GitHub Actions requires the following configurations:

  • Grant id-token: write and contents: read access scopes.
  • Install the azd action, unless you are using a docker image where azd is already installed.

You can use the following template as a starting point for your own pipeline definition:

on:
  workflow_dispatch:
  push:
    # Run when commits are pushed to mainline branch (main or master)
    # Set this to the mainline branch you are using
    branches:
      - main
      - master

# Set this permission if you are using a Federated Credential.
permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    # azd build-in variables.
    # This variables are always set by `azd pipeline config`
    # You can set them as global env (apply to all steps) or you can add them to individual steps' environment
    env:
      AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
      AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
      AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
      AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
      ## Define the additional variables or secrets that are required globally (provision and deploy)
      # ADDITIONAL_VARIABLE_PLACEHOLDER: ${{ variables.ADDITIONAL_VARIABLE_PLACEHOLDER }}
      # ADDITIONAL_SECRET_PLACEHOLDER: ${{ secrets.ADDITIONAL_SECRET_PLACEHOLDER }}      
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      # using the install-azd action
      - name: Install azd
        uses: Azure/setup-azd@v1.0.0

      # # If you want to use azd-daily build, or install it from a PR, you can remove previous step and
      # # use the next one:
      # - name: Install azd - daily or from PR
      #  # Update this scrip based on the OS - pool of your pipeline. This example is for a linux pipeline installing daily build
      #  run: curl -fsSL https://aka.ms/install-azd.sh | bash -s -- --version daily
      #  shell: pwsh

      # azd set up Federated Credential by default. You can remove this step if you are using Client Credentials
      - name: Log in with Azure (Federated Credentials)
        if: ${{ env.AZURE_CLIENT_ID != '' }}
        run: |
          azd auth login `
            --client-id "$Env:AZURE_CLIENT_ID" `
            --federated-credential-provider "github" `
            --tenant-id "$Env:AZURE_TENANT_ID"
        shell: pwsh

      ## If you set up your pipeline with Client Credentials, remove previous step and uncomment this one
      # - name: Log in with Azure (Client Credentials)
      #   if: ${{ env.AZURE_CREDENTIALS != '' }}
      #   run: |
      #     $info = $Env:AZURE_CREDENTIALS | ConvertFrom-Json -AsHashtable;
      #     Write-Host "::add-mask::$($info.clientSecret)"

      #     azd auth login `
      #       --client-id "$($info.clientId)" `
      #       --client-secret "$($info.clientSecret)" `
      #       --tenant-id "$($info.tenantId)"
      #   shell: pwsh
      #   env:
      #     AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Provision Infrastructure
        run: azd provision --no-prompt
        env:
         #  # uncomment this if you are using infrastructure parameters
         #  AZD_INITIAL_ENVIRONMENT_CONFIG: ${{ secrets.AZD_INITIAL_ENVIRONMENT_CONFIG }}
         ## Define the additional variables or secrets that are required only for provision 
         #  ADDITIONAL_VARIABLE_PLACEHOLDER: ${{ variables.ADDITIONAL_VARIABLE_PLACEHOLDER }}
         #  ADDITIONAL_SECRET_PLACEHOLDER: ${{ secrets.ADDITIONAL_SECRET_PLACEHOLDER }}

      - name: Deploy Application
        run: azd deploy --no-prompt
        env:
         ## Define the additional variables or secrets that are required only for deploy
         #  ADDITIONAL_VARIABLE_PLACEHOLDER: ${{ variables.ADDITIONAL_VARIABLE_PLACEHOLDER }}
         #  ADDITIONAL_SECRET_PLACEHOLDER: ${{ secrets.ADDITIONAL_SECRET_PLACEHOLDER }}