Familiarization with the Workshop Project The workshop project is composed of two repositories.
Between both repositories, there are two categories of workflows we will leverage.
Application developer workflows Platform engineering workflows As we explore the project we will give special focus to the highlighted sections of the sources.
continuous-deployments-the-github-way This repository models an the code base for application development.
tree -a --gitignore -I .git continuous-deployments-the-github-way
.
├── .devcontainer
│ └── devcontainer.json #(1)!
├── .github
│ ├── dependabot.yml #(2)!
│ ├── dependency-review-config.yml #(3)!
│ ├── release.yml #(4)!
│ └── workflows #(5)!
│ ├── 1 -check-pull-requests.yaml
│ ├── 2 -version-changes-to-main-branch.yaml
│ ├── 3 -release-new-version.yaml
│ └── 4 -build-and-deploy.yaml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app #(6)!
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── index.html
│ ├── main.mjs
│ ├── package-lock.json
│ ├── package.json
│ └── rollup.config.mjs
├── bicepconfig.json #(7)!
└── infrastructure #(8)!
├── day-0
│ ├── 1 -resource-group.bicep
│ ├── 2 -app-service.bicep
│ ├── 3 -application-identity-registration.bicep
│ ├── 4 -container-registry.bicep
│ ├── main.bicep
│ ├── parameters.json
│ └── provision.azcli
└── day-1
└── oidc-config.json
When you work in a codespace, the environment you are working in is created using a development container, or dev container, hosted on a virtual machine. The configuration files for a dev container are contained in a .devcontainer directory in your repository. See "Introduction to dev containers ."
Dependabot takes the effort out of maintaining your dependencies. You can use it to ensure that your repository automatically keeps up with the latest releases of the packages and applications it depends on. For information on the supported repositories and ecosystems, see "Dependabot supported ecosystems and repositories ." You enable Dependabot version updates by checking a dependabot.yml configuration file into your repository.
Dependency review helps you understand dependency changes and the security impact of these changes at every pull request. It provides an easily understandable visualization of dependency changes with a rich diff on the "Files Changed" tab of a pull request. Dependency review informs you of:
Which dependencies were added, removed, or updated, along with the release dates. How many projects use these components. Vulnerability data for these dependencies. For more information, see "About dependency review " and "Reviewing dependency changes in a pull request ."
See "Automatically generated release notes ."
GitHub Actions workflows can automate tasks throughout the software development lifecycle. The application source code. Bicep supports an optional configuration file named bicepconfig.json. Within this file, you can add values that customize your Bicep development experience. See "Configure your Bicep environment ." The infrastructure resources template. The Application Development Workflows Check pull requests .github/workflows/1-check-pull-requests.yaml name : Check Pull Requests [Workshop]
# on:
# pull_request:
# branches:
# - main
permissions :
id-token : write
contents : read
checks : write
pull-requests : write
jobs :
check-pull-request :
runs-on : ubuntu-latest
steps :
- name : Checkout code
uses : actions/checkout@v4
- name : Dependency review
uses : actions/dependency-review-action@v4
with :
config-file : >-
./.github/dependency-review-config.yml
- name : Build
working-directory : app
run : |
docker build -t app .
- name : Run
run : |
docker run -d -p 8080:80 app
- name : Health check
run : |
curl \
--head \
--request GET \
--retry 10 \
--retry-delay 1 \
--retry-max-time 10 \
--retry-all-errors \
http://localhost:8080
- name : Run tests
run : |
curl -Ls http://localhost:8080?name=hello
Version changes to the main branch .github/workflows/2-version-changes-to-main-branch.yaml name : Version changes to the main branch
# on:
# push:
# branches:
# - main
# workflow_dispatch: {}
jobs :
version-main-branch-changes :
permissions :
contents : read
runs-on : ubuntu-latest
steps :
- uses : actions/create-github-app-token@v1
id : generate-ci-app-token
with :
app-id : ${{ vars.CI_APP_ID }}
private-key : ${{ secrets.CI_APP_KEY }}
- uses : actions/checkout@v4
with :
fetch-depth : 0
token : ${{ steps.generate-ci-app-token.outputs.token }}
- name : Compute latest version
id : get_latest_version
run : |
# Retrieve the latest git tag, as we will only be processing one delivery line.
latest_version=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "Latest version is $latest_version"
echo "latest_version=$latest_version" >> "$GITHUB_OUTPUT"
- name : Compute next version
id : get_next_version
run : |
major=$(echo $latest_version | cut --delimiter=. --fields=1)
minor=$(echo $latest_version | cut --delimiter=. --fields=2)
patch=$(echo $latest_version | cut --delimiter=. --fields=3)
change_type=$(git log -1 --pretty=%B | grep -oP '(?<=change-type:\s).+' | xargs)
echo "Change type is: $change_type"
if [ "$change_type" == "backward-incompatible" ]; then
major_number=$(echo "$major" | cut --delimiter=v --fields=2)
major="v$((major_number+1))"
minor="0"
patch="0"
elif [ "$change_type" == "backward-compatible features" ]; then
minor=$((minor+1))
patch="0"
else
patch=$((patch+1))
fi
next_version="$major.$minor.$patch"
echo "Next version is $next_version"
echo "next_version_major=$major" >> "$GITHUB_OUTPUT"
echo "next_version_minor=$minor" >> "$GITHUB_OUTPUT"
echo "next_version_patch=$patch" >> "$GITHUB_OUTPUT"
echo "next_version=$next_version" >> "$GITHUB_OUTPUT"
env :
latest_version : ${{ steps.get_latest_version.outputs.latest_version }}
- name : Configure git user
run : |
git config user.name "ci-app[bot]"
git config user.email "ci-app[bot]@users.noreply.github.com"
- name : Create reproducible tag
run : |
if git tag -a "$next_version" -m "$next_version"; then
git push --follow-tags origin "$next_version"
else
echo "Failed to create tag $next_version, does it already exist?"
fi
env :
next_version : "${{ steps.get_next_version.outputs.next_version }}"
Release new version .github/workflows/3-release-new-version.yaml name : Release new version
# on:
# push:
# tags:
# - "v*.*.*"
permissions :
contents : write
jobs :
package-delivery :
permissions :
contents : read
runs-on : ubuntu-latest
steps :
- uses : actions/create-github-app-token@v1
id : generate-ci-app-token
with :
app-id : ${{ vars.CI_APP_ID }}
private-key : ${{ secrets.CI_APP_KEY }}
- uses : actions/github-script@v7
id : publish-release
with :
github-token : ${{ steps.generate-ci-app-token.outputs.token }}
script : |
const response = await github.request(
'POST /repos/{owner}/{repo}/releases',
{
owner: context.repo.owner,
repo: context.repo.repo,
draft: false,
tag_name: '${{ github.ref }}',
generate_release_notes: true,
make_latest: 'true',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
}
);
console.dir(response);
return response.data.id;
Build Docker image of application and deploy .github/workflows/4-build-and-deploy.yaml name : Build Docker image of application and deploy
# on:
# release:
# types:
# - released
permissions :
attestations : write
checks : write
contents : read
id-token : write
jobs :
build :
uses : demos-by-igwejk/platform-library-workflows/.github/workflows/reusable-build.yaml@main
with :
image-name : app
tag-name : ${{ github.event.release.tag_name }}
environment : staging
build-directory : app
deploy :
uses : demos-by-igwejk/platform-library-workflows/.github/workflows/reusable-deployment.yaml@main
needs : build
with :
image-name : app
image-tag : ${{ github.event.release.tag_name }}
environment : staging
This repository models the code base for platform engineering. In addition to providing standardization over the build and deploymnet processes in the organization, it also ensures governance of the process.
tree -a --gitignore -I .git platform-library-workflows
.
├── .devcontainer
│ └── devcontainer.json
├── .github
│ └── workflows
│ ├── reusable-build.yaml
│ └── reusable-deployment.yaml
├── LICENSE
└── README.md
Build and push image to GitHub Container Registry .github/workflows/reusable-build.yaml name : Build and push image to container registry
on :
workflow_call :
inputs :
image-name :
required : true
type : string
tag-name :
required : true
type : string
environment :
required : true
type : string
build-directory :
required : true
type : string
jobs :
build-and-push :
permissions :
attestations : write
checks : write
contents : read
id-token : write
runs-on : ubuntu-latest
environment :
name : ${{ inputs.environment }}
steps :
- uses : actions/checkout@v4
with :
ref : ${{ inputs.tag-name }}
- name : Login to Azure
uses : azure/login@v2
with :
client-id : ${{ vars.AZURE_CLIENT_ID }}
tenant-id : ${{ vars.AZURE_TENANT_ID }}
subscription-id : ${{ vars.AZURE_SUBSCRIPTION_ID }}
- name : Login to Azure Container Registry
run : az acr login --name ${{ vars.CONTAINER_REGISTRY }}
- name : Build and push docker image
id : container-image-build-and-push
uses : docker/build-push-action@v6
with :
context : ${{ inputs.build-directory }}
push : true
tags : ${{ vars.CONTAINER_REGISTRY }}/${{ inputs.image-name }}:${{ inputs.tag-name }}
- name : Generate artifact attestation
uses : actions/attest-build-provenance@v1
with :
subject-name : ${{ vars.CONTAINER_REGISTRY }}/${{ inputs.image-name }}
subject-digest : ${{ steps.container-image-build-and-push.outputs.digest }}
push-to-registry : true
Deploy image to App Service .github/workflows/reusable-deployment.yaml name : Deploy image to App Service
on :
workflow_call :
inputs :
environment :
required : true
type : string
image-name :
required : true
type : string
image-tag :
required : true
type : string
jobs :
deploy :
permissions :
attestations : read
id-token : write
contents : read
checks : write
runs-on : ubuntu-latest
environment :
name : ${{ inputs.environment }}
url : ${{ steps.deploy-azure-webapp.outputs.webapp-url }}
steps :
- name : Login to Azure
uses : azure/login@v2
with :
client-id : ${{ vars.AZURE_CLIENT_ID }}
tenant-id : ${{ vars.AZURE_TENANT_ID }}
subscription-id : ${{ vars.AZURE_SUBSCRIPTION_ID }}
- name : Login to Azure Container Registry
run : az acr login --name ${{ vars.CONTAINER_REGISTRY }}
- name : Verify attestation
env :
GH_TOKEN : ${{ github.token }}
run : |
gh attestation verify \
oci://${{ vars.CONTAINER_REGISTRY }}/${{ inputs.image-name }}:${{ inputs.image-tag }} \
-R ${{ github.repository}} \
--signer-workflow ${{ vars.PLATFORM_LIBRARY_WORKFLOWS }}/.github/workflows/reusable-build.yaml
- uses : azure/webapps-deploy@v3
id : deploy-azure-webapp
with :
app-name : ${{ vars.APP_SERVICE_NAME }}
images : ${{ vars.CONTAINER_REGISTRY }}/${{ inputs.image-name }}:${{ inputs.image-tag }}
slot-name : production