GitHub Actions Quickstart
This guide shows you how to use PPDS ALM reusable workflows and composite actions in your GitHub Actions pipelines.
Prerequisites
- A GitHub repository with your Power Platform solution
- An Azure AD app registration for authentication
- GitHub repository secrets configured (see Authentication)
Quick Setup
1. Configure GitHub Environment
- Go to Settings > Environments > New environment
- Create environments for each target (e.g.,
Dev,QA,Prod) - Add variables and secrets to each environment:
Variables:
| Variable | Example |
|---|---|
POWERPLATFORM_ENVIRONMENT_URL | https://myorg-qa.crm.dynamics.com/ |
POWERPLATFORM_TENANT_ID | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
POWERPLATFORM_CLIENT_ID | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
Secrets:
| Secret | Description |
|---|---|
POWERPLATFORM_CLIENT_SECRET | Service principal client secret |
2. Create Your First Workflow
Create .github/workflows/deploy-qa.yml:
name: Deploy to QA
on:
push:
branches: [develop]
workflow_dispatch:
jobs:
deploy:
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-deploy.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
build-plugins: true
package-type: Managed
secrets: # Reusable workflow input - accepts both vars and secrets
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }} # Only this needs to be a secret
Available Workflows
Solution Workflows
| Workflow | Purpose | When to Use |
|---|---|---|
solution-export.yml | Export from environment | Nightly exports, on-demand sync |
solution-import.yml | Import to environment | Direct import without build |
solution-build.yml | Build and pack | CI builds, artifact creation |
solution-validate.yml | PR validation | Pull request checks |
solution-deploy.yml | Full deployment | CD to QA/Prod |
Plugin Workflows
| Workflow | Purpose | When to Use |
|---|---|---|
plugin-deploy.yml | Deploy plugins | Plugin-only deployments |
plugin-extract.yml | Extract registrations | Generate registration file |
Example Workflows
Nightly Export from Dev
name: Nightly Export
on:
schedule:
- cron: '0 2 * * *' # 2 AM UTC daily
workflow_dispatch:
jobs:
export:
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-export.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
filter-noise: true
commit-changes: true
secrets:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
PR Validation
name: PR Validation
on:
pull_request:
branches: [develop, main]
jobs:
validate:
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-validate.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
build-code: true
run-tests: true
run-solution-checker: true
checker-fail-level: High
secrets:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
Deploy to Production with Approval
name: Deploy to Production
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
environment: Prod # Requires approval if configured
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-deploy.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
build-plugins: true
package-type: Managed
skip-if-same-version: true
secrets:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
Multi-Environment Pipeline
name: Release Pipeline
on:
push:
branches: [main]
jobs:
build:
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-build.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
build-plugins: true
package-type: Managed
deploy-qa:
needs: build
environment: QA
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-deploy.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
package-type: Managed
secrets:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
deploy-prod:
needs: deploy-qa
environment: Prod
uses: joshsmithxrm/ppds-alm/.github/workflows/solution-deploy.yml@v1
with:
solution-name: MySolution
solution-folder: solutions/MySolution/src
package-type: Managed
secrets:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
Using Composite Actions Directly
For more control, use composite actions directly in your workflows:
name: Custom Workflow
on:
workflow_dispatch:
jobs:
custom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PAC CLI
uses: joshsmithxrm/ppds-alm/.github/actions/setup-pac-cli@v1
- name: Authenticate
uses: joshsmithxrm/ppds-alm/.github/actions/pac-auth@v1
with:
environment-url: ${{ vars.POWERPLATFORM_ENVIRONMENT_URL }}
tenant-id: ${{ vars.POWERPLATFORM_TENANT_ID }}
client-id: ${{ vars.POWERPLATFORM_CLIENT_ID }}
client-secret: ${{ secrets.POWERPLATFORM_CLIENT_SECRET }}
- name: Export solution
uses: joshsmithxrm/ppds-alm/.github/actions/export-solution@v1
with:
solution-name: MySolution
output-folder: solutions/MySolution/src
- name: Analyze changes
id: analyze
uses: joshsmithxrm/ppds-alm/.github/actions/analyze-changes@v1
with:
solution-folder: solutions/MySolution/src
- name: Commit if real changes
if: steps.analyze.outputs.has-real-changes == 'true'
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add -A
git commit -m "chore: sync solution from Dev"
git push
Troubleshooting
"Cannot find reusable workflow"
- Verify the repository path:
joshsmithxrm/ppds-alm - Check the workflow path matches exactly
- Ensure you're using a valid ref (
@v1,@main, etc.)
Authentication Failed
- Verify secrets are correctly configured
- Ensure the app registration has proper permissions
- Check the environment URL is correct and accessible
Import Skipped (Version Match)
This is expected behavior when skip-if-same-version: true (default). The target environment already has the same or newer version.
See Troubleshooting for more help.