{"id":20376688,"url":"https://github.com/andrebriggs/bedrock-templates","last_synced_at":"2026-06-06T17:33:13.022Z","repository":{"id":148713818,"uuid":"262688448","full_name":"andrebriggs/bedrock-templates","owner":"andrebriggs","description":null,"archived":false,"fork":false,"pushed_at":"2020-05-20T23:18:33.000Z","size":64,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-15T07:12:21.413Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrebriggs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-10T01:10:43.000Z","updated_at":"2020-05-19T23:51:01.000Z","dependencies_parsed_at":"2023-05-28T18:15:11.185Z","dependency_job_id":null,"html_url":"https://github.com/andrebriggs/bedrock-templates","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebriggs%2Fbedrock-templates","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebriggs%2Fbedrock-templates/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebriggs%2Fbedrock-templates/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebriggs%2Fbedrock-templates/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrebriggs","download_url":"https://codeload.github.com/andrebriggs/bedrock-templates/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241928529,"owners_count":20043820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T01:39:09.707Z","updated_at":"2026-06-06T17:33:12.965Z","avatar_url":"https://github.com/andrebriggs.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Templating the `bedrock-cli`\n\nThis repository contains a proposal around pipeline generation for the [bedrock-cli](https://github.com/microsoft/bedrock-cli). Inspired by my post [here](https://github.com/microsoft/bedrock/issues/1006#issuecomment-592771163).\n\n## Problem\n\nCustomers are on their own between AKS (infra creation) and Azure Devops (orchestration). The Bedrock CLI is a tool that provides solutions for automating deployments on to AKS.\n\nSome customers don't want to use Bedrock CLI because:\n\n* They don't want or need to use Fabrikate with their current scenario.\n  * Fabrikate might be too advanced for their current needs\n* They have to make several changes to `bedrock` generated pipelines\n  * Want something more templated that allows customization\n* `bedrock` can not anticpate all needs in GitOps scenarios upfront\n\n## Proposal\n\nThis repo contains a proof of concept of what `bedrock` could be doing instead. Simplify what `bedrock` cli generates. Push logic into Azure DevOps Templates to allow customization of business logic in templates and scripts\n\nThe reason for this is to make `bedrock` pipeline generation less rigid. Instead we can focus on composition and encapsulation. This unlocks several benefits:\n\n* Business logic specific data and functions are packaged\n* More definition of what components need (via parameters)\n* More logic reuse\n* Separation of concerns\n  \n## Scenarios\n\n__GitOps pipeline using High Level Definition repo and Fabrikate__: The default scenario `bedrock` provides has the user calling `bedrock service create` and `bedrock service install-build-pipeline` to install the pipeline to AzDO and build a Docker image, push to ACR, and update a HLD repo using Fabrikate.\n\n__GitOps pipeline _without_ Fabrikate__:Consider a user who doesn't want to use Fabrikate for any variety of reasons. The user specifies a pre-canned template such as `helm-gitops`. This template generates a pipeline for Docker build/push but instead of having Fabrikate being called on a HLD repo it will modify a Helm chart then call `helm template` to generate yaml manifests. These yaml manifest can be saved in a \"manifest\" repository. A user has a GitOps pipeline using only Helm.\n\n__Not using ACR__: Another scenario builds on top of the previous two examples but instead of pushing to an Azure Container Registry we can push the built Docker image to DockerHub or any other Docker registry.\n\n__Bedrock in private networks__: Customers who don't want to download external packages outside of their private network but want to take advantage of Bedrock style deployment. We've thought about these story of scenarios from the [build agent](https://github.com/andrebriggs/bedrock-agents) side but a complete solution requires generated pipelines from `bedrock` to be aware. Such a solution would require confuguration that can be easily manipulated with minimal changes to the the Bedrock CLI. If we provide switches to turn on and off certain pieces of logic (i.e. don't download Fabrikate) we can make these sort of scenario easier to acheive to for customers. These switches are just conditionals in the in the templated AzDO yaml.\n\n## How it would work\n\nThe use of templates is applicable to any AzDO pipeline that `bedrock` generates. In this repository example we simulate calling `bedrock service create` which creates a `build-update-hld.yaml` file.\n\nConsider the `azure-pipelines.yml` files in thie repository has a new version of the `build-update-hld.yaml` file. The `azure-pipelines.yml` references templates yaml files that in turn reference bash scripts:\n\n`azure-pipelines.yml` --\u003e `templates/*` --\u003e `scripts/*`\n\nThe *templates* and *scripts* directories can be copied locally to the [project](https://microsoft.github.io/bedrock-cli/commands/#master@project_init) level of bedrock scaffolded service. Alternatively Azure DevOps Yaml templates __can be referenced from other repositories__. This is very powerful because it allows the Bedrock repo to store these default templates or users can choose to copy the templates to their own repository.\n\nThe vision here is that users can __extend__ the logic `bedrock` sets up for them. We are enabling a library of GitOps AZDO templates and scripts that the community can extend.\n\n## Breaking apart `build.sh`\n\nThe Bedrock repo has a `build.sh` file which has become a monolith where several functions are defined. Currently `bedrock` downloads this file during pipeline execution to do things suchs as \n- Find the latest version of Fabrikate\n- Initialize Helm2 in client only mode\n- Determine if a build is for a pull request or a merge for master   \n\nThe proposed approach would break out pieces of logic from that file into smaller scripts that can be re-used in the templated model approach.\n\n## Testing\n\n* With so much logic pushed down into bash scripts that are based on ENV VARs, it becomes easier to test building blocks of logic.\n* We will rely more on integration tests since the solution space has exploded compared to the hardcoded paths of the current CLI\n* The templatizing makes it easier for someone to take what we are doing and massage it to their needs. The current model doesn't invite people to change what has been scaffolding\n\n## Appendix\n\n### Current `bedrock service create` yaml\n\n```yaml\n# GENERATED WITH BEDROCK VERSION 0.6.5\ntrigger:\n  branches:\n    include:\n      - master\nvariables:\n  - group: quick-start-vg\nstages:\n  - stage: build\n    jobs:\n      - job: run_build_push_acr\n        pool:\n          vmImage: ubuntu-latest\n        steps:\n          - task: HelmInstaller@1\n            inputs:\n              helmVersionToInstall: 2.16.3\n          - script: |-\n              set -e\n              echo \"az login --service-principal --username $(SP_APP_ID) --password $(SP_PASS) --tenant $(SP_TENANT)\"\n              az login --service-principal --username \"$(SP_APP_ID)\" --password \"$(SP_PASS)\" --tenant \"$(SP_TENANT)\"\n            displayName: Azure Login\n          - script: |-\n              set -e\n              # Download build.sh\n              curl $BEDROCK_BUILD_SCRIPT \u003e build.sh\n              chmod +x ./build.sh\n            displayName: Download bedrock bash scripts\n            env:\n              BEDROCK_BUILD_SCRIPT: $(BUILD_SCRIPT_URL)\n          - script: |-\n              set -e\n              . ./build.sh --source-only\n              get_bedrock_version\n              download_bedrock\n              export BUILD_REPO_NAME=$(echo $(Build.Repository.Name)-quick-start-app | tr '[:upper:]' '[:lower:]')\n              tag_name=\"$BUILD_REPO_NAME:$(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber)\"\n              commitId=$(Build.SourceVersion)\n              commitId=$(echo \"${commitId:0:7}\")\n              service=$(./bedrock/bedrock service get-display-name -p ./)\n              url=$(git remote --verbose | grep origin | grep fetch | cut -f2 | cut -d' ' -f1)\n              repourl=${url##*@}\n              ./bedrock/bedrock deployment create -n $(INTROSPECTION_ACCOUNT_NAME) -k $(INTROSPECTION_ACCOUNT_KEY) -t $(INTROSPECTION_TABLE_NAME) -p $(INTROSPECTION_PARTITION_KEY) --p1 $(Build.BuildId) --image-tag $tag_name --commit-id $commitId --service $service --repository $repourl\n            displayName: 'If configured, update Spektate storage with build pipeline'\n            condition: 'and(ne(variables[''INTROSPECTION_ACCOUNT_NAME''], ''''), ne(variables[''INTROSPECTION_ACCOUNT_KEY''], ''''),ne(variables[''INTROSPECTION_TABLE_NAME''], ''''),ne(variables[''INTROSPECTION_PARTITION_KEY''], ''''))'\n          - script: |-\n              set -e\n              export BUILD_REPO_NAME=$(echo $(Build.Repository.Name)-quick-start-app | tr '[:upper:]' '[:lower:]')\n              export IMAGE_TAG=$(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber)\n              export IMAGE_NAME=$BUILD_REPO_NAME:$IMAGE_TAG\n              echo \"Image Name: $IMAGE_NAME\"\n              ACR_BUILD_COMMAND=\"az acr build -r $(ACR_NAME) --image $IMAGE_NAME .\"\n\n              echo \"Exporting build variables from variable groups, if available: \"\n              echo \"Build Variables: \"\n\n              cd ./\n              echo \"ACR BUILD COMMAND: $ACR_BUILD_COMMAND\"\n              $ACR_BUILD_COMMAND\n            displayName: ACR Build and Publish\n  - stage: hld_update\n    dependsOn: build\n    condition: succeeded('build')\n    jobs:\n      - job: update_image_tag\n        pool:\n          vmImage: ubuntu-latest\n        steps:\n          - task: HelmInstaller@1\n            inputs:\n              helmVersionToInstall: 2.16.3\n          - script: |-\n              set -e\n              # Download build.sh\n              curl $BEDROCK_BUILD_SCRIPT \u003e build.sh\n              chmod +x ./build.sh\n            displayName: Download bedrock bash scripts\n            env:\n              BEDROCK_BUILD_SCRIPT: $(BUILD_SCRIPT_URL)\n          - script: |-\n              set -e\n              export SERVICE_NAME_LOWER=$(echo quick-start-app | tr '[:upper:]' '[:lower:]')\n              export BUILD_REPO_NAME=$(echo $(Build.Repository.Name)-quick-start-app | tr '[:upper:]' '[:lower:]')\n              export BRANCH_NAME=DEPLOY/$BUILD_REPO_NAME-$(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber)\n              export FAB_SAFE_SERVICE_NAME=$(echo $SERVICE_NAME_LOWER | tr . - | tr / -)\n              # --- From https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/release.sh\n              . build.sh --source-only\n\n              # Initialization\n              verify_access_token\n              init\n              helm_init\n\n              # Fabrikate\n              get_fab_version\n              download_fab\n\n              # Clone HLD repo\n              git_connect\n              # --- End Script\n\n              # Update HLD\n              git checkout -b \"$BRANCH_NAME\"\n              export BUILD_REPO_NAME=$(echo $(Build.Repository.Name)-quick-start-app | tr '[:upper:]' '[:lower:]')\n              export IMAGE_TAG=$(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber)\n              export IMAGE_NAME=$BUILD_REPO_NAME:$IMAGE_TAG\n              echo \"Image Name: $IMAGE_NAME\"\n              export IMAGE_REPO=$(echo $(ACR_NAME).azurecr.io | tr '[:upper:]' '[:lower:]')\n              echo \"Image Repository: $IMAGE_REPO\"\n              cd $(Build.Repository.Name)/$FAB_SAFE_SERVICE_NAME/$(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )\n              echo \"FAB SET\"\n              fab set --subcomponent chart image.tag=$IMAGE_TAG image.repository=$IMAGE_REPO/$BUILD_REPO_NAME\n\n              # Set git identity\n              git config user.email \"admin@azuredevops.com\"\n              git config user.name \"Automated Account\"\n\n              # Commit changes\n              echo \"GIT ADD and COMMIT -- Will throw error if there is nothing to commit.\"\n              git_commit_if_changes \"Updating $SERVICE_NAME_LOWER image tag to $(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber).\" 1 unusedVar\n\n              # Git Push\n              git_push\n\n              # Open PR via az repo cli\n              echo 'az extension add --name azure-devops'\n              az extension add --name azure-devops\n\n              echo 'az repos pr create --description \"Updating $SERVICE_NAME_LOWER to $(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber).\" \"PR created by: $(Build.DefinitionName) with buildId: $(Build.BuildId) and buildNumber: $(Build.BuildNumber)\"'\n              response=$(az repos pr create --description \"Updating $SERVICE_NAME_LOWER to $(echo $(Build.SourceBranchName) | tr / - | tr . - | tr _ - )-$(Build.BuildNumber).\" \"PR created by: $(Build.DefinitionName) with buildId: $(Build.BuildId) and buildNumber: $(Build.BuildNumber)\")\n              pr_id=$(echo $response | jq -r '.pullRequestId')\n\n              # Update introspection storage with this information, if applicable\n              if [ -z \"$(INTROSPECTION_ACCOUNT_NAME)\" -o -z \"$(INTROSPECTION_ACCOUNT_KEY)\" -o -z \"$(INTROSPECTION_TABLE_NAME)\" -o -z \"$(INTROSPECTION_PARTITION_KEY)\" ]; then\n              echo \"Introspection variables are not defined. Skipping...\"\n              else\n              latest_commit=$(git rev-parse --short HEAD)\n              tag_name=\"$BUILD_REPO_NAME:$(Build.SourceBranchName)-$(Build.BuildNumber)\"\n              url=$(git remote --verbose | grep origin | grep fetch | cut -f2 | cut -d' ' -f1)\n              repourl=${url##*@}\n              get_bedrock_version\n              download_bedrock\n              ./bedrock/bedrock deployment create  -n $(INTROSPECTION_ACCOUNT_NAME) -k $(INTROSPECTION_ACCOUNT_KEY) -t $(INTROSPECTION_TABLE_NAME) -p $(INTROSPECTION_PARTITION_KEY) --p2 $(Build.BuildId) --hld-commit-id $latest_commit --env $(Build.SourceBranchName) --image-tag $tag_name --pr $pr_id --repository $repourl\n              fi\n            displayName: 'Download Fabrikate, Update HLD, Push changes, Open PR, and if configured, push to Spektate storage'\n            env:\n              ACCESS_TOKEN_SECRET: $(PAT)\n              AZURE_DEVOPS_EXT_PAT: $(PAT)\n              REPO: $(HLD_REPO)\n```\n\n### Proposed yaml style\n\n```yaml\n# File: azure-pipelines.yml\ntrigger:\n- master\n\nvariables:\n  - group: quick-start-vg\n  - name: APP_NAME\n    value: quick-start-app\n\nstages:\n  - stage: build\n    jobs:\n      - job: run_build_push_acr\n        pool:\n          vmImage: ubuntu-latest\n        steps:\n        - template: templates/azure-login.yml  # Template reference\n          parameters:\n            appId: $(SP_APP_ID)\n            password: $(SP_PASS)\n            tenantId: $(SP_TENANT)\n        - template: templates/container-build-strategy.yml  # Template reference\n          parameters:\n            downloadTools: false\n            imageRepoType: ACR\n            imageName: \"$(APP_NAME)-$(Build.SourceBranchName)\"\n            imageTag: $(Build.BuildNumber)\n            buildArgs:\n            - AZP_POOL\n            - ACR_NAME\n  - stage: hld_update\n    dependsOn: build\n    condition: succeeded('build')\n    jobs:\n      - job: update_image_tag\n        pool:\n          vmImage: ubuntu-latest\n        steps:\n        - template: templates/git-update-strategy.yml  # Template reference\n          parameters:\n            downloadFab: true\n            downloadTools: true\n            azureContainerRegistry: $(ACR_NAME)\n            gitUpdateType: HLD\n            gitRepoURL: $(HLD_REPO)\n            gitAccessToken: $(PAT)\n            imageName: \"$(APP_NAME)-$(Build.SourceBranchName)\"\n            imageTag: $(Build.BuildNumber)\n```\n\n\u003c!--\n\u003cpre\u003e\n.\n├── README.md\n├── azure-pipelines.yml\n├── \u003cb\u003escripts\u003c/b\u003e\n│   ├── AzureContainerRegistryBuild.sh\n│   ├── Test.AzureContainerRegistryBuild.sh\n│   ├── download-fabrikate.sh\n│   ├── fab-image-tag-update.sh\n│   ├── git-clone.sh\n│   └── git-pull-request-azdo.sh\n└── \u003cb\u003etemplates\u003c/b\u003e\n    ├── app-variables.yml\n    ├── azure-login.yml\n    ├── container-build-strategy.yml\n    └── git-update-strategy.yml\n\u003c/pre\u003e\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrebriggs%2Fbedrock-templates","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrebriggs%2Fbedrock-templates","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrebriggs%2Fbedrock-templates/lists"}