Exercise - Protect your main branch

Completed

Your team is working on a Bicep template that already contains a website and a database. You've deployed the components to your production environment. Now, you need to update your Bicep template to add your order processing queue.

In this exercise, you'll create a feature branch for your change. You'll also protect your main branch and only allow changes to be merged to the main branch after they've been reviewed. Before that, though, you need to make sure that your environment is set up to complete the rest of this module.

During the process, you'll:

  • Set up a GitHub repository for this module.
  • Clone the repository to your computer.
  • Add branch protection to your repository's main branch.
  • Create a local feature branch for your change.
  • Try to merge your feature branch into main.
  • Set up an Azure DevOps project for this module.
  • Clone the project's repository to your computer.
  • Add branch policies to your repository's main branch.
  • Create a local feature branch for your change.
  • Try to merge your feature branch into main.

Get the GitHub repository

Here, you make sure that your GitHub repository is set up to complete the rest of this module. You set it up by creating a new repository based on a template repository. The template repository contains the files that you need to get started for this module.

Start from the template repository

Run a template that sets up your GitHub repository.

On the GitHub site, follow these steps to create a repository from the template:

  1. Select Use this template > Create a new repository.

    Screenshot of the GitHub interface that shows the template repo, with the button for using the current template highlighted.

  2. Enter a name for your new project, such as toy-website-review.

  3. Select the Public option.

    When you create your own repositories, you might want to make them private. In this module, you'll work with features of GitHub that work only with public repositories and with GitHub Enterprise accounts.

  4. Select Create repository from template.

    Screenshot of the GitHub interface that shows the repo creation page.

Get the Azure DevOps project

Here, you make sure that your Azure DevOps organization is set up to complete the rest of this module. You set it up by running a template that creates a project in Azure DevOps.

On the Azure DevOps Demo Generator site, follow these steps:

  1. Select Sign In and accept the usage terms.

  2. On the Create New Project page, select your Azure DevOps organization. Then enter a project name, such as toy-website-review.

    Screenshot that shows creating a project through the Azure DevOps Demo Generator.

  3. Select Create Project.

    The template takes a few moments to run. It automatically creates a pipeline and Bicep file that you'll use in later exercises.

  4. Select Navigate to project to go to your project in Azure DevOps.

Clone the repository

You now have a copy of the template repository in your own account. Clone this repository locally so you can start working in it.

  1. Select Code, and then select the Copy icon.

    Screenshot of the GitHub interface that shows the new repository, with the repository U R L copy button highlighted.

  2. Open Visual Studio Code.

  3. Open a Visual Studio Code terminal window by selecting Terminal > New Terminal. The window usually opens at the bottom of the screen.

  4. In the terminal, go to the directory where you want to clone the GitHub repository on your local computer. For example, to clone the repository to the toy-website-review folder, run the following command:

    cd toy-website-review
    
  5. Type git clone and paste the URL that you copied earlier, and then run the command. The command looks like this:

    git clone https://github.com/mygithubuser/toy-website-review.git
    
  6. Reopen Visual Studio Code in the repository folder by running the following command in the Visual Studio Code terminal:

    code -r toy-website-review
    

You now have a project in your own account. Clone this repository locally so you can start working in it.

  1. Select Repos > Files.

    Screenshot of Azure DevOps that shows the Repos menu, with Files highlighted.

  2. Select Clone.

    Screenshot of Azure DevOps that shows the repository, with the Clone button highlighted.

  3. If you're using macOS, you need a special password to clone the Git repository. Select Generate Git credentials and copy the displayed username and password to somewhere safe.

  4. Select Clone in VS Code. If you're prompted to allow Visual Studio Code to open, select Open.

    Screenshot of Azure DevOps that shows the repository settings, with the button for cloning in Visual Studio Code highlighted.

  5. Create a folder to use for the repository, and then choose Select Repository Location.

  6. You're using this repository for the first time, so you're prompted to sign in.

    • If you're using Windows, enter the same credentials that you used to sign in to Azure DevOps earlier in this exercise.

    • If you're using macOS, enter the Git username and password that you generated a few moments ago.

  7. Visual Studio Code prompts you to open the repository. Select Open.

    Screenshot of Visual Studio Code that shows a prompt to open the cloned repository, with the Open button highlighted.

Add branch protections

Configure your Git repository to prevent direct pushes to the main branch.

  1. In your browser, select Settings.

  2. Select Branches.

  3. Select Add branch protection rule.

    Screenshot of GitHub that shows the page for adding branch protection rules, with the button for adding a rule highlighted.

  4. In the Branch name pattern text box, enter main.

  5. Select Require a pull request before merging.

    Clear Require approvals. Normally, you'd select this option. But in this example, you're going to merge your own pull request, and the Require approvals option prevents you from doing so.

  6. Select Do not allow bypassing the above settings.

    You select this setting as an example to show how git push to main fails later in this exercise. In a production environment, you might not want to restrict direct merges to main for administrators or repository owners.

  7. Near the bottom of the page, select Create.

    Screenshot of GitHub that shows the Create button.

    GitHub might ask you to sign in again to confirm your identity.

Add branch policies

Configure your Git repository to prevent direct pushes to the main branch.

  1. In your browser, go to Repos > Branches.

  2. Hover over the main branch, and select the three dots.

  3. Select Branch policies.

    Screenshot of Azure DevOps that shows the list of branches, with the context menu displayed and the menu item for branch policies highlighted.

  4. In the Branch policies window, change the Require a minimum number of reviewers setting to On.

  5. Change the minimum number of reviewers to 1, and select the Allow requestors to approve their own changes option.

    Screenshot of Azure DevOps that shows the branch policies page for the main branch.

    Note

    Here, you enable the Allow requestors to approve their own changes option. In these exercises, you're working on your own, so you need to both create and approve your changes. But in a real team environment, you might not want to enable this option.

Create a local feature branch

  1. In the Visual Studio Code terminal, run the following statement:

    git checkout -b add-orders-queue
    

    This command creates a new feature branch for you to work from.

  2. Open the main.bicep file in the deploy folder.

    Screenshot of Visual Studio Code that shows the main dot bicep file in the deploy folder.

  3. Below the parameters, add a new variable for the name of the queue:

    var storageAccountSkuName = (environmentType == 'prod') ? 'Standard_GRS' : 'Standard_LRS'
    var processOrderQueueName = 'processorder'
    
  4. Within the storage account resource, add the queue as a nested child resource:

    resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
      name: storageAccountName
      location: location
      sku: {
        name: storageAccountSkuName
      }
      kind: 'StorageV2'
      properties: {
        accessTier: 'Hot'
      }
    
      resource queueServices 'queueServices' existing = {
        name: 'default'
    
        resource processOrderQueue 'queues' = {
          name: processOrderQueueName
        }
      }
    }
    
  5. In the appService module definition, add the storage account and queue names as parameters:

    module appService 'modules/appService.bicep' = {
      name: 'appService'
      params: {
        location: location
        appServiceAppName: appServiceAppName
        storageAccountName: storageAccount.name
        processOrderQueueName: storageAccount::queueServices::processOrderQueue.name
        environmentType: environmentType
      }
    }
    

    This code enables the application to find the queue where it will send messages.

  6. Save the main.bicep file.

  7. Open the appService.bicep file in the deploy/modules folder.

  8. Near the top of the appService.bicep file, add new parameters for the storage account and queue names:

    @description('The Azure region into which the resources should be deployed.')
    param location string
    
    @description('The name of the App Service app to deploy. This name must be globally unique.')
    param appServiceAppName string
    
    @description('The name of the storage account to deploy. This name must be globally unique.')
    param storageAccountName string
    
    @description('The name of the queue to deploy for processing orders.')
    param processOrderQueueName string
    
    @description('The type of the environment. This must be nonprod or prod.')
    @allowed([
      'nonprod'
      'prod'
    ])
    param environmentType string
    
  9. Update the appServiceApp resource to propagate the storage account and queue names to the application's environment variables:

    resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
      name: appServiceAppName
      location: location
      properties: {
        serverFarmId: appServicePlan.id
        httpsOnly: true
        siteConfig: {
          appSettings: [
            {
              name: 'StorageAccountName'
              value: storageAccountName
            }
            {
              name: 'ProcessOrderQueueName'
              value: processOrderQueueName
            }
          ]
        }
      }
    }
    

Commit and push your feature branch

Commit your changes and push them to your GitHub repository by running the following commands in the Visual Studio Code terminal:

Commit your changes and push them to your Azure Repos repository by running the following commands in the Visual Studio Code terminal:

git add .
git commit -m "Add orders queue and associated configuration"
git push --set-upstream origin add-orders-queue

The feature branch is pushed to a new branch, also named add-orders-queue, in your remote repository.

Try to merge the feature branch to main

You've learned why it's not advisable to push directly to the main branch. Here, you try to break that guideline so you can see how your main branch's protection prevents you from accidentally pushing your changes to a protected branch.

  1. In the Visual Studio Code terminal, run the following statements to switch to the main branch and merge the add-orders-queue branch into it:

    git checkout main
    git merge add-orders-queue
    

    The command worked, but you merged the add-orders-queue branch into your main branch in only your local Git repository.

  2. Run the following statement to try to push your changes to GitHub:

    git push
    

    Notice that your push fails with an error message that looks like this one:

    Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
    remote: error: GH006: Protected branch update failed for refs/heads/main.
    remote: error: Changes must be made through a pull request.
    To https://github.com/mygithubuser/toy-website-review.git
     ! [remote rejected] main -> main (protected branch hook declined)
    error: failed to push some refs to 'https://github.com/mygithubuser/toy-website-review.git'
    

    The error message tells you that pushes to the main branch aren't permitted, and that you must use a pull request to update the branch.

  3. Undo the merge by running the following statement:

    git reset --hard HEAD~1
    

    This command tells your local Git repository to reset the state of the main branch to what it was before the last commit was merged in, and not to save your changes. The add-orders-queue branch isn't affected.

You've learned why it's not advisable to push directly to the main branch. Here, you try to break that guideline so you can see how the branch policies prevent you from accidentally pushing your changes to a protected branch.

  1. In the Visual Studio Code terminal, run the following statements to switch to the main branch and merge the add-orders-queue branch to it:

    git checkout main
    git merge add-orders-queue
    

    The command worked, but you merged the add-orders-queue branch into your main branch in only your local Git repository.

  2. Run the following statement to try to push your changes to Azure Repos:

    git push
    

    Notice that your push fails with an error message that looks like this one:

    Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
    To https://dev.azure.com/mytoycompany/toy-website-review/_git/toy-website-review
    ! [remote rejected] main -> main (TF402455: Pushes to this branch are not permitted; you must use a pull request to update this branch.)
    error: failed to push some refs to 'https://dev.azure.com/mytoycompany/toy-website-review/_git/toy-website-review'
    

    The error message tells you that pushes to the main branch aren't permitted, and that you must use a pull request to update the branch.

  3. Undo the merge by running the following statement:

    git reset --hard HEAD~1
    

    This command tells your local Git repository to reset the state of the main branch to what it was before the last commit was merged in, and not to save your changes. The add-orders-queue branch isn't affected.