Microsoft Power Platform の ALM を Github Actions で実現する

# 概要

　業務でMicrosoft Power Platformを使用する機会があり、DevOpsのような開発フローを実現するために、[アプリケーションライフサイクル管理(ALM)](https://learn.microsoft.com/ja-jp/power-platform/alm/)というドキュメントがあります。本記事では、ALMのデプロイ操作をGithub Actionsで実現します。

# Power Platform

https://www.microsoft.com/ja-jp/power-platform

　Power Platformは、Microsoftが提供するローコード開発プラットフォームです。ローコードの製品として以下が存在します。
- Power Apps
- Power Automate
- Power BI
- Power Pages
- Copilot Studio

これらの製品を使用することで、Web画面や自動化のパイプライン、可視化をプログラミング知識が乏しくても作成することができます。アプリケーションライフサイクルに関係があるのは、Power Apps、Power Automate、Microsoft Copilot Studioの3つです。

# ALM

https://learn.microsoft.com/ja-jp/power-platform/alm/

　ALMを実現するために、ソリューションという機能があります。ソリューションには１つのシステムを構成する Power Apps や Power Automate 、接続情報等の要素を含めてパッケージ化することができます。ALMでは環境を作成することができ、開発/テスト/運用の3種類の環境を作成することが推奨されています。ALMでは、ソリューションを各種環境にデプロイすることでDevOpsのような開発フローを実現しています。
　デプロイ操作は[Power Platform側で提供される組み込みの機能](https://learn.microsoft.com/ja-jp/power-platform/alm/pipelines)や外部CI/CDサービスのGithub Actions, Azure DevOpsで実行することができます。今回業務では、ライセンスの問題で組み込みの機能が使用できなかったため、Github Actionsで実現することにしました。

# Github Actions

https://learn.microsoft.com/ja-jp/power-platform/alm/devops-github-actions

https://github.com/microsoft/powerplatform-actions

作成したGithub Actionsのyamlを以下に提示します。

- yaml
    ```yaml deploy.yml
    name: Deploy Power Platform Solution
    
    on:
      workflow_dispatch:
        inputs:
          export_environment: 
            description: 'export environment'
            required: true
            type: environment
          import_environment: 
            description: 'import environment'
            required: true
            type: environment
      workflow_call:
        inputs:
          export_environment: 
            description: 'export environment'
            required: true
            type: string
          import_environment: 
            description: 'import environment'
            required: true
            type: string
    
    permissions:
      id-token: write
    
    jobs:
      export-solution:
        runs-on: ubuntu-latest
        environment: ${{ inputs.export_environment }}
    
        steps:
        - name: Install Power Platform Tools
          uses: microsoft/powerplatform-actions/actions-install@v1
    
        - name: who-am-i action
          uses: microsoft/powerplatform-actions/who-am-i@v1
          with:
            environment-url: ${{ vars.POWER_PLATFORM_ENVIRONMENT_URL }}
            app-id: ${{ vars.POWER_PLATFORM_AZURE_SERVICE_CLIENT_ID }}
            tenant-id: ${{ vars.POWER_PLATFORM_AZURE_TENANT_ID }}
    
        - name: Export Solution
          uses: microsoft/powerplatform-actions/export-solution@v1
          with:
            environment-url: ${{ vars.POWER_PLATFORM_ENVIRONMENT_URL }}
            app-id: ${{ vars.POWER_PLATFORM_AZURE_SERVICE_CLIENT_ID }}
            tenant-id: ${{ vars.POWER_PLATFORM_AZURE_TENANT_ID }}
            solution-name: ${{ vars.SOLUTION_NAME }}
            solution-output-file: ${{ vars.POWER_PLATFORM_SOLUTION_NAME }}.zip
        
        - name: Upload Github Artifact
          uses: actions/upload-artifact@v4
          with:
            name: ${{ vars.POWER_PLATFORM_SOLUTION_NAME }}_${{ github.run_id }}
            path: ${{ vars.POWER_PLATFORM_SOLUTION_NAME }}.zip
            overwrite: true
    
      import-solution:
        runs-on: ubuntu-latest
        needs: export-solution
        environment: ${{ inputs.import_environment }}
    
        steps:
        - name: Download Artifact
          uses: actions/download-artifact@v4
          with:
            name: ${{ vars.POWER_PLATFORM_SOLUTION_NAME }}_${{ github.run_id }}
    
        - name: Install Power Platform Tools
          uses: microsoft/powerplatform-actions/actions-install@v1
    
        - name: who-am-i action
          uses: microsoft/powerplatform-actions/who-am-i@v1
          with:
            environment-url: ${{ vars.POWER_PLATFORM_ENVIRONMENT_URL }}
            app-id: ${{ vars.POWER_PLATFORM_AZURE_SERVICE_CLIENT_ID }}
            tenant-id: ${{ vars.POWER_PLATFORM_AZURE_TENANT_ID }}
        
        - name: Import Solution
          uses: microsoft/powerplatform-actions/import-solution@v1
          with:
            environment-url: ${{ vars.POWER_PLATFORM_ENVIRONMENT_URL }}
            app-id: ${{ vars.POWER_PLATFORM_AZURE_SERVICE_CLIENT_ID }}
            tenant-id: ${{ vars.POWER_PLATFORM_AZURE_TENANT_ID }}
            solution-file: ${{ vars.POWER_PLATFORM_SOLUTION_NAME }}.zip
            publish-changes: true
    ```

- Github Variables
    | 名称 | 用途 |
    |-|-|
    | `POWER_PLATFORM_AZURE_SERVICE_CLIENT_ID` | サービスプリンシパルのクライアントID  |
    | `POWER_PLATFORM_AZURE_TENANT_ID` | サービスプリンシパルのテナントID |
    | `POWER_PLATFORM_ENVIRONMENT_URL` | 環境URL |
    | `POWER_PLATFORM_SOLUTION_NAME` | ソリューションの名称 |

yamlの特徴
- [Github Environment](https://docs.github.com/ja/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment)の機能を使用し、ソリューションのエクスポート先/インポート先の環境を変数で分けています
  - Github Artifactを使用して、ジョブ間でエクスポートされたzipファイルの受け渡しをしています
- Github ActionsのOIDC
  - https://github.com/microsoft/powerplatform-actions/discussions/576
  - リポジトリのREADMEには整備されておらず、Discussionsの箇所に実現方法が記載されています
      - リポジトリが熱心に更新されているわけではないので、少々使用することに抵抗がある
- 筆者はこれを`workflow_call`で呼び出し、ステージング環境/本番環境用のActionsを別途作成して、運用しています

# まとめ

　本記事では、Microsoft Power PlatformのALMを実現するGithub Actionsのコードを提示しました。本コードは必要最低限なデプロイ機能しか持っていないので、ユースケースに合わせてアレンジしてください。 一方で、Power Platform の[Github Actionsのリポジトリ](https://github.com/microsoft/powerplatform-actions
)はあまり整備されていないようなので、使用するのに不安があります。もし、必要最低限なデプロイ機能で十分であれば[Power Platformの組み込みの機能](https://learn.microsoft.com/ja-jp/power-platform/alm/pipelines)を採用した方がお手軽です。