🍁

Azure DevOpsの別のProjectやOrganizationにいるソースコードの同期をPipelineで自動化する

2023/10/04に公開

Azure DevOpsで複数のチームで開発する場合、Forkで別のProjectに共有したりPAT(Personal Access Token)で別のOrganization配下のProject間でソースコードを共有したりすることができます。

※PATを使ってOrganization間でソースコードを共有する方法は過去のこちらの記事をご覧ください(Forkで別のProjectに共有する方法の記事は現在準備中!)
https://zenn.dev/yuriemori/articles/7a6097654f2afc

複数のProject間でRepositoryのソースコードをやり取りする場合、効率的なコードの同期と管理が運用の上でキーになります。
今回の記事では複数Project間でソースコードを同期するステップをPipelineで自動化する方法について紹介します。

上流(Upstream)と下流(Downstream)のRepository

ソースを複数のProject間で共有する場合、そのProjectのRepositoryは「上流(Upstream)」と「下流(DownStream)」という関係で表されます。
今回は、Project AlphaをオリジナルのRepository(上流)、Project BravoをAlphaからソースを受け取る下流のRepositoryとして、同期の仕方を説明していきます。

Project AlphaとProject Bravoの関係は以下のようになっています。

  • 上流のProject Alphaのmainブランチが更新されたら、下流のProject Bravoのalpha-baseブランチに更新内容を同期する
  • 下流のProject Bravoのブランチ戦略は以下のようになっており、mainブランチから派生したalpha-baseをAlphaのソースの同期専用のブランチとしている
main(Bravoでプロダクト開発を行うためのbranch) ←alpha-baseをmerge : これをdefaultとする
 └── alpha-base: ここにReomote Reposとして登録したAlphaからプロダクトコードをpullする 

※alpha-baseは上流のProject Alphaからのソースコードを取得するのみ。これによりBravoで開発中のプロダクトコードへの汚されと同期の際のconflictを回避する。integrationはmainにmergeする際に行う。

上流Reposと下流Reposの同期のステップ

同期のフローは下記のようになります。

  1. 上流のProject Alphaのmainブランチが更新される(コードがpushされる)
  2. 下流のProject Bravoで上流のProject Alphaをupstreamとしてremote repositoryに登録する(※これをするためにProjetc AlphaのソースのRead権限があるPATが必要)
  3. Project Bravoのalpha-baseブランチで2で登録したremote repositoryから変更を取得する
  4. alpha-baseのリモートブランチにpushする

2, 3, 4のステップをまじめにGitコマンドで一通り書くとこんな感じになります。

■作業環境:Project Bravo

// 下流のProject Bravoで上流のProject Alphaをupstreamとしてremote repositoryに登録
$ git remote add upstream https://{YOUR_PAT}@dev.azure.com/{YOUR_ORGANIZATION_NAME}/{YOUR_PROJECT_NAME}/_git/{YOUR_REPOS_NAME} {BRANCH_NAME}

// upstream(上流)の更新情報を取得
$ git fetch upstream

// upstreamの変更を取得する専用のalpha-baseブランチに切替
$ git checkout alpha-base

// upstreamtのmainブランチから変更を取得
$ git pull origin upstream main

// alpha-baseのリモートブランチに変更をpush
$ git push origin alpha-base

再掲ですが、この辺のステップの詳細は以下の過去の記事をご覧ください。
https://zenn.dev/yuriemori/articles/7a6097654f2afc

手動でまじめにやる場合はこんな感じになりますが、一回やったらめんどくさかったのでPipelineでこれを自動化します。

Project AlphaにBuild Pipelineを作成

前提として、上流のProject Alphaのmainブランチに更新が入った場合にProject Bravoにソースを同期したいので、このイベントを自動化の際のトリガーとしてProject AlphaにPipelineを構成していきます。

1. Project BravoのCodeのRead&WriteができるPATを作成

■作業環境:Project Bravo
Project AlphaのPipelieでProject Bravoのソースを同期したいので、Project AlphaからBravoのRepositoryに対してアクセスできるように、BravoでPATを作成します。
Azure DevOpsで別のProjectやOrganizationに対して何かしたい場合、ターゲットの環境のPATさえあれば大抵のことはなんとかなります。

Project Bravoの右上のUser Settings(人に⚙のアイコンのやつ)を選択 > Personal Aaccess Tokenを選択します。

New Tokenを選択

各項目を設定

  • NameでPATの名前を
  • OrganizationでこのPATでアクセスできるOrganizationを
  • ExpirationでPATのアクセス期限を(最長で1年ぐらい設定可能)
  • ScopesでCustom difinedを(Full Accessにするとなんでもできてしまうので、セキュリティ的にリスク高いのでおすすめしません)
  • (ここが大事 CodeでRead&Writeを選択(今回はBravoのRepositoryへの同期が必要なので)

設定が完了後、Createを押下するとPATが作成される。

2. Project AlphaのReposのルートに.ymlファイルを作成

BravoのReposへのRead&writeができるPATができたので、これを使ってProject AlphaでPipelineを作っていきます。

■作業環境:Project Alphaのmainブランチ
Azure DevOpsのPipelineはymlファイルをベースに実行されます。
Azure DevOpsでソースを同期したいRepositoryに移動します。
また、今回のトリガーは 「Alphaのmainブランチにコードがpushされること」 なので、トリガーが発火されるmainブランチでPipelineを作成するので、mainブランチに移動して下さい。

  • New > Fileでymlファイルを作成します。

今回はsync-asset-pipeline.ymlという名称にしてます。
ファイル名を入力したらCreatを押下して下さい。

ファイル作成後、Commitを押下

ここでコミットメッセージを設定してcommitを押下し、mainに直にcommitします。

これでPipelineのベースとなるymlファイルが作成されました。

3. ymlファイルをベースにPipelineを作成

Azure DevOpsの左メニューでPipelineを選択

右上のNew pipelineを選択

Pipelineで同期したいコードはAzDOのReposにいるので、Where is your code?ではAzure Repos Gitを選択

Repsositoryの選択。同じく、同期したいコードがいるのはProject AlphaのRepositoryを選択。

何をベースにPipelineを構成するか選択。
今回はすでにProject AlphaのReposのmainブランチにベースになるsync-asset-pipeline.ymlを作成したので、Exsiting Azure Pipelines YAML fileを選択。

Branchがmainであることを確認し(今回はイベントの発火:CodeへのPushを拾うのがmainブランチなのでmainを選択しますが、別のブランチへのpushを拾いたい場合は別のブランチを選択する必要があります)、Pathで先程Pipelineのベースとして作ったsync-asset-pipeline.ymlをドロップダウンから選択(ymlファイルがドロップダウンで選択できるようになっている)。

選択が完了したら、Continueを押下。

ymlファイルの編集画面になるので、以下のように設定。

//コメントはあくまで説明なので実際動かすときは除外して下さい

// mainブランチにpushされたのをトリガーとする
trigger:
  branches:
    include:
      - main

pool:
  vmImage: 'windows-latest'

// jobの名前をSnynAlphaと定義している
// 最初のstepでcheckout: selfで自分自身(main)をcheckout
jobs:
- job: SyncAlpha
  steps:
  - checkout: self

// ここで実行したいbashスクリプトを設定
  - script: |
      git config user.email "{YOUR_EMAIL}"
      git config user.name "{YOUR_USER_NAME}"
      
      // ローカルではremote reposの追加は一度でよいが、Pipelineで動かす場合は毎回の実行ごとに環境が初期化されるのでremote addのstepも必要。
      // BravoのPATを使用してProject Bravoをbravo-remoteという名前でremote reposに追加。すでにある場合は"bravo-remote already added"のメッセージを返す。
      git remote add bravo-remote https://$(PAT_BRAVO)@dev.azure.com/{YOUR_ORGANIZATION}/Project_Bravo/_git/{Bravoの同期したいReposの名前} || echo "bravo-remote already added"
      git fetch bravo-remote alpha-base
      
      // ローカルでalpha-baseというブランチを新規作成して切替
      git checkout -b alpha-base
      
      // origin main(Project Alpha)のmainブランチを取得してBravoのalpha-baseブランチにpush
      git pull --rebase origin main
      git push -f bravo-remote alpha-base
    displayName: 'Sync Project Alpha changes to Bravo'

右上のVariablesを押下し、

+(New variables)を選択

  • Nameで変数名を設定
  • Valueで値(今回の場合は1で作成したBravoのPAT)を設定
    ※Keep this value secretにするとこの作成するタイミング以降は値がマスクされ、PATの漏洩リスクが低くなりセキュリティが高まります

To reference a variable in YAML, prefix it with a dollar sign and enclose it in parentheses. For example: $(PAT_BRAVO)

と書いてある通り、ymlファイル内でこの変数を使用する際は$(value)の形式で使用してください。
作成したら、Variablesで使用したい変数名の右の赤枠箇所を押下すると、クリップボードに$(value)の形式でコピーされるので、ymlファイル内で使用したい箇所で使用してください。

以上でPipelineの設定が完了です。

Runを押下すれば、Pipelineを実行できます。

試しにProject AlphaのReadMeをこんな感じで更新すると

Pipelineが動いてProject BravoのReadMeも更新されました。

※Pipelineの実行状況と結果はPipelinesのメニューから確認できます。

References

https://learn.microsoft.com/ja-jp/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/get-started/pipelines-get-started?view=azure-devops

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch

Discussion