What is Markdown?

Markdown exists to shield content creators from the overhead of HTML. While HTML is great for rendering content exactly how it was intended, it takes up a lot of space and can be unwieldy to work with, even in small doses. The invention of Markdown offered a great compromise between the power of HTML for content description and the ease of plain text for editing.

Emphasizing text

The most important part of any communication on GitHub is usually the text itself. But what do you do when some parts of the text are more important than others?

Using italics in text is as easy as surrounding the target text with an asterisk (*) or underscore (_). Just be sure to close an emphasis with the same character it opened with (do not mix asterisks and underscores).

markdown
This is *italic* text.

This is italic text.

Bold text uses two asterisks (**) or underscores (__).

markdown
This is **bold** text.

This is bold text.

You can also mix different emphases.

markdown
_This is **bold and italic** text_.

This is bold and italic text.

To use a literal asterisk, escape it with a backslash (\).

markdown
\_This is all \*\*plain\*\* text\_.

_This is all **plain** text_.

Declaring headings

HTML provides content headings, such as the <h1> tag. In Markdown, this is supported via the # symbol. Just use one # for each heading level from 1-6.

markdown
###### This is H6 text
This is H6 text

Linking to images and sites

Image and site links use a very similar syntax.

markdown
![Link an image](https://cloudspoint.xyz/media/mara.png)

marad

markdown
[Link to Microsoft Learn](https://docs.microsoft.com/learn)

Link to Microsoft Learn

Making lists

You can define ordered or unordered lists. Ordered lists start with numbers and unordered lists can use asterisks or dashes (-).

markdown
1. First
1. Second
1. Third
  1. First
  2. Second
  3. Third

You can also define nested items through indentation.

markdown
- First
  - Nested
- Second
- Third
  • First
  • Nested
  • Second
  • Third

Building tables

Tables can be constructed using a combination of pipes (|) and dashes (-).

First|Second
-|-
1|2
3|4
TABLE 1
First Second
1 2
3 4

Quoting text

Blockquotes can be created using the greater than (>) character.

> This is quoted text.

This is quoted text.

Filling the gaps with inline HTML

If you come across an HTML scenario not supported by Markdown, you can simply use that HTML inline.

markdown
Here is a<br />line break

Here is a
line break

Working with code

Markdown provides default behavior for working with inline code blocks delimited by the backtick (`) character. When decorating text with this character, it is rendered as code.

This is `code`.

This is code.

If you have a code segment spanning multiple lines, you can use three backticks (“`) before and after to create a fenced code block.

```
var first = 1;
var second = 2;
var sum = first + second;
```
var first = 1;
var second = 2;
var sum = first + second;

GFM extends this support with syntax highlighting for popular languages. Just specify the language as part of the first tick sequence.

```javascript
var first = 1;
var second = 2;
var sum = first + second;
```
JavaScript
var first = 1;
var second = 2;
var sum = first + second;

Cross-linking issues and pull requests

GFM supports a variety of shortcode formats to make it easy to link to issues and pull requests. The easiest way to do this is to use the format #ID, such as #3602. GitHub will automatically adjust longer links to this format if you paste them in. There are also additional conventions you can follow, such as if you are working with other tools or want to specify other projects/branches.

CROSS-LINKING ISSUES AND PULL REQUESTS
Reference type Raw reference Short link
Issue or pull request URL https://github.com/desktop/desktop/pull/3602 #3602
# and issue or pull request number #3602 #3602
GH- and issue or pull request number GH-3602 GH-3602
Username/Repository# and issue or pull request number desktop/desktop#3602 desktop/desktop#3602

For more information, see Autolinked references and URLs.

Linking specific commits

You can link to a commit by pasting in its ID.

LINKING SPECIFIC COMMITS
Reference type Raw reference Short link
Commit URL https://github.com/desktop/desktop/commit/8304e9c271a5e5ab4fda797304cd7bcca7158c87 8304e9c
SHA 8304e9c271a5e5ab4fda797304cd7bcca7158c87 8304e9c
User@SHA desktop@8304e9c271a5e5ab4fda797304cd7bcca7158c87 desktop@8304e9c
Username/Repository@SHA desktop/desktop@8304e9c271a5e5ab4fda797304cd7bcca7158c87 desktop/desktop@8304e9c

Mentioning users and teams

Typing an @ symbol, followed by a GitHub username, will send a notification to that person about the comment. This is called an “@mention”, because you’re mentioning the individual. You can also @mention teams within an organization.

@githubteacher

@githubteacher

For more information, see Receiving notifications about activity on GitHub.

Tracking task lists

You can create task lists within issues or pull requests using the syntax illustrated below. These can be helpful to track progress when used in the body of an issue or pull request.

trak list

- [x] First task
- [x] Second task
- [ ] Third task

 

How to Create a GitHub Action to build a container image

In this article, you’ll complete the following tasks: Create a GitHub Action to implement a build pipeline Modify the coupon service code to trigger the build workflow Monitor the build workflow’s progress in real time, Update a failing unit test to fix the build.

Create the build action

Create a GitHub Action for the build with the following steps:

  1. Select the Actions tab in your repository and select the set up a workflow yourself link: custom-github-workflow
  2. Replace the YAML in the editor with the following YAML:
    name: eShop build
    
    on:
      push:
        paths:
        - 'src/Services/Coupon/**'
        - 'tests/Services/Coupon/**'
        branches: [ main ]
    
    jobs:
      build-and-push-docker-image:
        runs-on: ubuntu-latest
        steps:
        - name: Get code from the repository
          uses: actions/checkout@v1
          with:
            ref: main
    
        - name: Run unit tests
          run: dotnet test tests/Services/Coupon/*.Tests/*.csproj
          env:
            DOTNET_CLI_TELEMETRY_OPTOUT: true
            DOTNET_NOLOGO: true
    
        - name: Build and push Docker image
          uses: docker/build-push-action@v1.1.0
          with:
            username: ${{ secrets.REGISTRY_USERNAME }}
            password: ${{ secrets.REGISTRY_PASSWORD }}
            registry: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            path: .
            dockerfile: './src/Services/Coupon/Coupon.API/Dockerfile.acr'
            repository: 'coupon.api'
            tags: 'linux-latest'
            push: true
    

    The preceding YAML defines a GitHub Action that:

    • Is triggered when a commit is pushed to the coupon service’s source code or unit tests in the main branch.
    • Defines step-specific environment variables. For example, the Run unit tests step defines DOTNET_CLI_TELEMETRY_OPTOUT and DOTNET_NOLOGO. With regards to the .NET Core CLI, those environment variables opt out of usage data collection and suppress the first-run telemetry message, respectively.
    • Has one job—a set of steps that execute on the same workflow runner—named build-and-push-docker-image. The job:
      • Executes the xUnit tests for the coupon service.
      • Builds the Docker image and pushes it to an ACR instance. ACR is a private container registry used for the modified coupon container image. You don’t have permission to modify the Microsoft-owned container registry from which the original image was retrieved.
      • Runs in an ubuntu-latest runner and has three steps, two of which use actions available from the GitHub Actions marketplace:
        • Get code from the repository uses the actions/checkout@v1 action to check out the main branch.
        • Build and push Docker image uses the docker/build-push-action@v1.1.0 action to build the container image and push it to ACR.

     Important

    Trigger conditions and other artifacts of GitHub Actions or workflows depend on the apps and environments. For ease of understanding, details are kept simple here. Both the build and the deploy workflows are scoped to coupon service changes because all the microservices are kept under a single repository. In an actual production scenario, each microservice is kept in a separate repository.

  3. Replace the default workflow file name of main.yml with build.yml:
  4. Select the Start commit button, select the Commit directly to the `main` branch radio button, and select Commit new file to save the workflow file.

Trigger a build

You’ve finished creating the build workflow for your CI/CD pipeline on Cloud Hosting. The Marketing department wants to start a campaign to better track discount code usage. With this feature, Marketing can better understand which discount codes are most effective in boosting sales. To support this feature, make the following changes in the main branch:

  1. Select the Code tab in your fork of the repository.
  2. Select the edit icon to open the src/Services/Coupon/Coupon.API/Controllers/CouponController.cs file in the editor:
  3. Replace the comment // Add LogInformation call with the following code:
    _logger.LogInformation("Applying coupon {CouponCode}", code);
    

    The preceding code logs the discount code being applied.

  4. Select the Commit directly to the `main` branch radio button and select the Commit changes button.The build workflow is triggered automatically.

 

Monitor the build

View the real-time progress of the build by completing the following steps:

  1. Select the Actions tab.
  2. Select the most recent workflow run listed for the eShop build workflow. The commit message used in the previous step becomes the run’s name.
  3. Select the build-and-push-docker-image task.
  4. Wait a few minutes. Notice that:
    • The build fails on the Run unit tests step.
    • The Build and push Docker image step doesn’t run because the previous step failed.

     

Fix the build

  1. From the Code tab, edit the tests/Services/Coupon/Coupon.API.Tests/Controllers/CouponControllerTests.cs file. In the CouponControllerTests.cs file, notice that Assert.True(false); causes the unit test to fail. Replace that line with the following code:
    Assert.True(true);
    

    The preceding code causes the test to always pass. This test is for illustrative purposes only. Real tests should test actual functionality.

  2. Commit and push this change to the main branch.The build workflow is triggered automatically.

When the build completes successfully, all steps are prefixed with a green check mark. Expand any task for the output generated during its execution. For example:

 

 Notes:

It’s possible to move the dotnet test command to the Dockerfile. In this example, you’re running dotnet test in the GitHub Action to:

  • Understand how to execute .NET Core CLI commands in GitHub Actions.
  • Understand how the failure of a step can prevent execution of the remaining build steps.

In this unit, you created a GitHub Action to build the coupon service. You added logging to the coupon service and saw how committing that code triggered the build workflow. Next, you fixed a failing unit test and triggered the build again. Finally, you learned how to monitor the build’s progress in real time.

ASP.NET Core Microservice – How to Configure GitHub Action permissions and secrets

In this unit, you’ll complete the following tasks:

  • Verify the app is deployed correctly
  • Set up permissions to deploy to ACR and AKS from GitHub
  • Create secrets to store sensitive data used by the GitHub Actions

Verify the deployment to AKS

After the app has deployed to AKS, you’ll see a variation of the following message in the command shell:

The eShop-Learn application has been deployed to "http://203.0.113.55" (IP: 203.0.113.55).

You can begin exploring these services (when ready):
- Centralized logging       : http://203.0.113.55/seq/#/events?autorefresh (See transient failures during startup)
- General application status: http://203.0.113.55/webstatus/ (See overall service status)
- Web SPA application       : http://203.0.113.55/

 Tip

To display these URLs again, run the following command:

cat ~/clouddrive/aspnet-learn-temp/deployment-urls.txt

Even though the app has been deployed, it might take a few minutes to come online. Verify that the app is deployed and online with the following steps:

  1. Select the General application status link in the command shell to view the WebStatus health checks dashboard. The resulting page displays the status of each microservice in the deployment. The page refreshes automatically, every 10 seconds.

     Note: While the app is starting up, you might initially receive an HTTP 503 or 502 response from the server. Retry after about one minute. The Seq logs, which are viewable at the Centralized logging URL, are available before the other endpoints.

  2. After all the services are healthy, select the Web SPA application link in the command shell to test the eShopOnContainers web app. The following page appears:
  3. Complete a purchase as follows:
    1. Select the LOGIN link in the upper right to sign into the app. The credentials are provided on the page.
    2. Add the .NET BLUE HOODIE to the shopping bag by selecting the image.
    3. Select the shopping bag icon in the upper right.
    4. Select the CHECKOUT button.
    5. Enter the code DISC-10 in the HAVE A DISCOUNT CODE? text box for a 10 USD discount, and select APPLY.
    6. Select PLACE ORDER to complete the purchase.

You’ve successfully verified that the app was deployed to AKS and is working properly. The discount code feature is supported by the coupon service. In this module, you’ll build a CI/CD pipeline to automate the build and deployment of the coupon service.

Set up permissions to deploy from GitHub

GitHub Actions will be used to publish the container image to ACR. To configure permissions so the GitHub Actions runner can connect to Azure, complete the following steps:

  1. Run the following command to create an Azure Active Directory service principal to allow access from GitHub:
    Azure CLI: 
    az ad sp create-for-rbac --sdk-auth --name http://eshop-learn-sp
    

    A variation of the following output appears:

    Creating a role assignment under the scope of "/subscriptions/<SUBSCRIPTION-ID>"
    {
      "clientId": "<CLIENT-ID>",
      "clientSecret": "<CLIENT-SECRET>",
      "subscriptionId": "<SUBSCRIPTION-ID>",
      "tenantId": "<TENANT-ID>",
      "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
      "resourceManagerEndpointUrl": "https://management.azure.com/",
      "activeDirectoryGraphResourceId": "https://graph.windows.net/",
      "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
      "galleryEndpointUrl": "https://gallery.azure.com/",
      "managementEndpointUrl": "https://management.core.windows.net/"
    }
    
  2. Copy the JSON output from the command shell. Don’t include the text output above the JSON. You’ll need the JSON and the credentials for the GitHub Action in next step.

Create the secrets

The service principal and the credentials for the container registry are sensitive information. The GitHub Actions runner will need the credentials to interact with ACR and AKS. As a best practice, sensitive information should be stored as encrypted secrets in a secure location. The secrets should be managed by repository administrators and accessed by the GitHub Actions runner. Complete the following steps to securely store the sensitive information as environment variables in your repository:

  1. In the GitHub repository you forked, go to Settings > Secrets.
  2. Select the New secret button.
  3. Enter AZURE_CREDENTIALS and the JSON output you copied in the Name and Value text boxes, respectively.At this point, you should have something like this: 
  4. Select the Add secret button.
  5. Create four additional secrets. Run the following command to get the values for the new secrets:
    Bash:
    cat ~/clouddrive/aspnet-learn-temp/config.txt
    

    Name the secrets as follows and use the values provided in the text output:

    • IP_ADDRESS
    • REGISTRY_LOGIN_SERVER
    • REGISTRY_PASSWORD
    • REGISTRY_USERNAME

With all five secrets configured, you’ll see the following page:

 

In this unit, you verified the app was deployed correctly. You then created an Azure Active Directory service principal and stored related sensitive information as GitHub secrets.