This article is Publishing Power Apps to clients production environments securely using GitHub with Power Platform (part 3) (2) . You'll need to have completed part 1, part 2 and part 3 before continuing. This article deals with the GitHub workflow required to deploy a Power Platform app into a production environment via GitHub thus providing a recognisable governance and software assurance methodology for your Power Platform apps.
Contents
Create a managed solution and publish it in a GitHub repo
- Navigate to "Actions" and select "New workflow"
- Click "Actions" and choose "Simple workflow"
- Delete the content and paste the content of release-solution-to-prod-with-inputs from the Microsoft Power Platform GitHub Actions Lab repository.
- Rename the file from "blank.yml" to "release-solution-to-prod-with-inputs.yml".
- Edit the solution_name default from ALMLab to whatever your solution is named!
- Now commit the changes and your workflow is created

Release workflow
This workflow runs automatically when you create a release in GitHub.
- Navigate to "Actions" and select "New workflow"
- Click "Actions" and choose "Simple workflow"
- Delete the content and paste the content of release-action-call from the Microsoft Power Platform GitHub Actions Lab repository.
- Rename the file from "blank.yml" to "release.yml".
- Update
<BUILD_ENVIRONMENT_URL>with the URL for the build environment you are going to use to generate the managed solution e.g. "c0ffeebuild.crm.dynamics.com". - Update
<PRODUCTION_ENVIRONMENT_URL>with the URL for the build environment you are going to use to generate the managed solution e.g. "c0ffeeprod.crm.dynamics.com". - Update
<BUILD_CLIENT_ID>with the ID you saved from Azure Active Directory. - Update
<PRODUCTION_CLIENT_ID>with the ID you saved from Azure Active Directory. - Update
<APPID>and<TENANT ID>with the values you saved away somewhere safe back in part one of this series of articles - Add the secrets variables to reflect your environments. I added buildSecret and prodSecret and set required to true.
- Edit the code to ensure that buildSecret is used for the build environment (your trial environment) and prodSecret is used for the production environment (your default environment).
- Now commit the changes and your workflow is created
My release.yml
name: Release action
# Call the reusable workflow release-solution-with-inputs.yml
# Release your solution to prod when you create a new release.
on:
release:
types: [created]
permissions:
contents: write
jobs:
Release-solution-utopia:
uses: ./.github/workflows/release-solution-to-prod-with-inputs.yml
with:
# The solution name.
solution_name: utopia
# Tenant and environment variables.
TENANT_ID: 4fb7a570-09cb-4565-9518-0005ef2f0ef8
BUILD_ENVIRONMENT_URL: 'https://orge29f1013.crm11.dynamics.com'
BUILD_CLIENT_ID: 397a288b-a275-454f-bc53-1885d29e2fb9
PRODUCTION_ENVIRONMENT_URL: 'https://org9481e946.crm11.dynamics.com'
PRODUCTION_CLIENT_ID: f0b791a0-cb9f-4b89-b9b0-8a858b7b7c7b
# Azure Active Directory App registration for each environment lets you specify client secrets which identify and authorise GitHub Actions
secrets:
buildSecret: ${{ secrets.POWER_ANGUSF_TRIAL }}
prodSecret: ${{ secrets.POWER_MULTIZONE_DEFAULT }}
Release to Production workflow details
- Navigate to "Actions" and select "New workflow"
- Click "Actions" and choose "Simple workflow"
- Delete the content and paste the content of release-solution-to-prod-with-inputs.yml from the Microsoft Power Platform GitHub Actions Lab repository.
- Rename the file from "blank.yml" to "release-solution-to-prod-with-inputs.yml".
- Update "solution_name" default to the name of your Power App solution
- Update
<BUILD_ENVIRONMENT_URL>with the URL for the build environment you are going to use to generate the managed solution e.g. "c0ffeebuild.crm.dynamics.com". - Update
<PRODUCTION_ENVIRONMENT_URL>with the URL for the build environment you are going to use to generate the managed solution e.g. "c0ffeeprod.crm.dynamics.com". - Update
<BUILD_CLIENT_ID>with the ID you saved from Azure Active Directory. - Update
<PRODUCTION_CLIENT_ID>with the ID you saved from Azure Active Directory. - Add the secrets variables to reflect your environments. I added buildSecret and prodSecret and set required to true.
- Edit the code to ensure that buildSecret is used for the build environment (your trial environment) and prodSecret is used for the production environment (your default environment).
- Now commit the changes and your workflow is created
My release-solution-to-prod-with-inputs.yml
name: release-solution-to-prod-reusable
# Reusable workflow
# convert solution to managed (using a build PowerPlatform environment for the conversion)
# upload the solution to the GitHub artifacts and deploy to the PROD environment
on:
workflow_call:
inputs:
#Do Not change these values
#Values are set by the caller
#caller sample: release-action-call.ymnl
solution_name:
description: 'The solution name.'
type: string
default: utopia
solution_shipping_folder:
description: 'folder name for staging the exported solution *do not change*'
type: string
default: out/ship/
solution_outbound_folder:
description: 'staging the unpacked solution folder before check-in *do not change*'
type: string
default: out/solutions/
solution_source_folder:
description: 'folder name to be created and checked in *do not change*'
type: string
default: solutions/
solution_release_folder:
description: 'folder where the released binaries are going to be hosted *do not change*'
type: string
default: out/release
BUILD_ENVIRONMENT_URL:
description: 'Build environment url.'
type: string
required: true
PRODUCTION_ENVIRONMENT_URL:
description: 'Production environment url.'
type: string
required: true
BUILD_CLIENT_ID:
description: 'The client id'
type: string
required: true
PRODUCTION_CLIENT_ID:
description: 'The client id'
type: string
required: true
TENANT_ID:
description: 'The tenant id'
type: string
required: true
secrets:
buildSecret:
description: 'The secret value for authentication to build env via SPN'
required: true
prodSecret:
description: 'The secret value for authentication to prod env via SPN'
required: true
jobs:
convert-to-managed:
runs-on: windows-latest
# or you can say runs-on: ubuntu-latest
env:
RUNNER_DEBUG: 1
steps:
- uses: actions/checkout@v2
with:
lfs: true
- name: Pack solution
uses: microsoft/powerplatform-actions/pack-solution@v0
with:
solution-folder: ${{ inputs.solution_source_folder}}/${{ inputs.solution_name }}
solution-file: ${{ inputs.solution_outbound_folder}}/${{ inputs.solution_name }}.zip
solution-type: Unmanaged
- name: Import solution as unmanaged to build env
uses: microsoft/powerplatform-actions/import-solution@v0
with:
environment-url: ${{inputs.BUILD_ENVIRONMENT_URL}}
app-id: ${{inputs.BUILD_CLIENT_ID}}
client-secret: ${{ secrets.buildSecret }}
tenant-id: ${{inputs.TENANT_ID}}
solution-file: ${{ inputs.solution_outbound_folder}}/${{ inputs.solution_name }}.zip
force-overwrite: true
publish-changes: true
- name: Export solution as managed
uses: microsoft/powerplatform-actions/export-solution@v0
with:
environment-url: ${{inputs.BUILD_ENVIRONMENT_URL}}
app-id: ${{inputs.BUILD_CLIENT_ID}}
client-secret: ${{ secrets.buildSecret }}
tenant-id: ${{inputs.TENANT_ID}}
solution-name: ${{ inputs.solution_name }}
managed: true
solution-output-file: ${{ inputs.solution_shipping_folder}}/${{ inputs.solution_name }}_managed.zip
- name: Upload the ready to ship solution to GH artifact store
uses: actions/upload-artifact@v2
with:
name: managedSolutions
path: ${{ inputs.solution_shipping_folder}}/
release-to-staging:
needs: [ convert-to-managed ]
runs-on: windows-latest
env:
RUNNER_DEBUG: 1
steps:
- uses: actions/checkout@v2
with:
lfs: true
- name: Fetch the ready to ship solution from GH artifact store
uses: actions/download-artifact@v2
with:
name: managedSolutions
path: ${{ inputs.solution_release_folder}}
- name: Import solution to prod env
uses: microsoft/powerplatform-actions/import-solution@v0
with:
environment-url: ${{inputs.PRODUCTION_ENVIRONMENT_URL}}
app-id: ${{inputs.PRODUCTION_CLIENT_ID}}
client-secret: ${{ secrets.prodSecret }}
tenant-id: ${{inputs.TENANT_ID}}
solution-file: ${{ inputs.solution_release_folder}}/${{ inputs.solution_name }}_managed.zip
force-overwrite: true
publish-changes: true
Results
If you made it this far, and didn't make any mistakes, then you should be able to run the workflow successfully. It takes your tagged release, builds it in your trial environment, and then deploys it in your production environment. This means that you built this Power Platform app with the benefit of application lifecycle management and a clear separation from development, testing, and production software. thats got to be worth the setup. I hope Microsoft make it easier. Its still too many moving parts and too difficult to manage and I suspect it will be beyond citizen developers until it is too late.
