Azure PipelineからAzure DevOps Wikiを更新する
まったくもって誰得なのかわからないような記事ですが、Zennに書いて見るネタが欲しかったので書いてみることにしました。
動機
社内のとある活動で経費精算を取りまとめたかったのですが、エンジニアなのにExcelシートってなんか嫌じゃないですか? なので申請時にYAMLを書いてもらってプルリク投げてもらう運用にしたかったのです。
YAMLからMarkdownテーブルへ
こっちはTypescriptでサクッと(TS2.x以降久しぶりに触ったので興味津々で調べていたのでちっともサクッとではなかったのですが)作ったので割愛します。npm start
するとYAMLを食ってMarkdownを吐き出してくれるごくごく簡単なものです。
なぜGithubではない?
社内向けなので社内で使っているAzure DevOpsなのです。Azure DevOpsはその名の通りAzureの親戚でMicrosoftが提供しているGithubのようなものです。これがまた意外とスルメのようなサービスで最初はとっつきにくいのですが、MS内で実プロジェクト利用で揉まれまくっていて実に細部までうまくまとめられた仕様で、使いこなせるとGithubよりもかゆいところに手が届く完成度の高いサービスです。
しかし、Githubがマイクロソフトに買収された今、2つがそのうち統合されることは想像に難くない訳でおそらくはGithub側にAzure DevOpsのテイストが入り込んでくるんじゃないかと思われます。(その片鱗はGithub flowにすでに現れていて、Github flowのyaml構文はAzure Pipelinesの構文と非常によく似ています)
で本文
前置きが長くなりました。やりたいことは
- PipelineでMarkdownをビルド
- そのMarkdownをWikiに反映
なのですが、Azure DevOpsのWikiは実はGitで管理されたMarkdownファイルの集合体です。なので、
- PipelineでMarkdownをビルド
- WikiのGitをFetchしてくる
- そこに1で作ったMarkdownを上書き
- git commit
- git push
こんな流れになります。
どうやったのよ?
pipeline用のYAML全文をさらします。
trigger:
- main
pool:
vmImage: "ubuntu-20.04"
stages:
- stage: build
jobs:
- job: build
steps:
- script: docker-compose run markdown
displayName: create markdown
- script: >
mkdir $(Build.ArtifactStagingDirectory)/Markdown &&
cp ./processor/output/ExpenseReport.md $(Build.ArtifactStagingDirectory)/Markdown &&
git log --pretty=format:"%s" -n 1 > $(Build.ArtifactStagingDirectory)/Markdown/commit.txt
displayName: pack artifacts
- publish: $(Build.ArtifactStagingDirectory)/Markdown
artifact: Markdown
- job: publish
dependsOn: build
steps:
- checkout: git://MyPrj/MyPrj.wiki@wikiMaster
persistCredentials: true
- script: >
git config --global user.email "dummy@example.com" &&
git config --global user.name "dummy" &&
git checkout wikiMaster
displayName: initialize git
- download: current
artifact: Markdown
- script: cp $(Pipeline.Workspace)/Markdown/ExpenseReport.md ./経費精算/精算シート.md
displayName: apply change
- script: git branch -a
- script: >
git add * &&
git commit -m "`cat $(Pipeline.Workspace)/Markdown/commit.txt`"
displayName: commit change
- script: git push origin wikiMaster
displayName: push to publish
buildジョブは単にdocker-compose経由でnpmを実行しているだけなので解説は割愛します。
ちょっとコツが必要だったのはpublishジョブの方でした。
1. 別のリポジトリからpullしてくる
- checkout: git://MyPrj/MyPrj.wiki@wikiMaster
persistCredentials: true
これはcheckoutタスクを利用します。通常はJOBの初期工程で自動的にトリガーされたリポジトリからチェックアウトされるのですが、本件では別のリポジトリ(Wiki用のリポジトリ)を扱いたいので明示的に指定します。
ポイントは
- チェックアウトするリポジトリの指定
- 別のプロジェクトやGithubからのチェックアウトだともう少し複雑な書き方になるのですが、同じOrganization内のリポジトリであれば
git://プロジェクト名/リポジトリ名
で良いです。 - デフォルトのWikiは
プロジェクト名.wiki
というリポジトリ名です - デフォだとmasterかmainブランチになってしまうので明示的にブランチ名を@で指定します。Wikiのデフォルトブランチは
wikiMaster
です。
- 別のプロジェクトやGithubからのチェックアウトだともう少し複雑な書き方になるのですが、同じOrganization内のリポジトリであれば
- 初めてパイプラインを実行するときに「こいつリポジトリをいじろうとしているぞ」みたいなINFOが出るのでGUI上からOKする必要があります(キャプチャは撮ってません)
-
persistCredentials
はあとからpushするときに必要になるのでtrueに指定します。
詳細は下記を参照すると良いです。
2. Gitの設定
- script: >
git config --global user.email "dummy@example.com" &&
git config --global user.name "dummy" &&
git checkout wikiMaster
2.1 email, name
こちらを見るとあらかた書いてあるのですが、email, nameを設定しておく必要があります。
2.2 ブランチの設定
ここはcheckoutタスクの出力結果と小一時間にらめっこする羽目にあったのですが、checkoutタスクは素直にpullはしておらずfetchしかしていません。そのためそのまま変更をcommitしてpushをしようとすると下記のように怒られます。
error: src refspec wikiMaster does not match any
error: failed to push some refs to 'https://newgyu.visualstudio.com/MyPrj/_git/MyPrj.wiki'
明示的にcheckoutしてwikiMasterブランチ上で変更をcommitした後にpushすることにしました。
Pushに必要なpermission
- script: git push origin wikiMaster
displayName: push to publish
最後にpushするためにはそのパイプラインが一定の権限を持っている必要があります。権限不足の場合にはこんなエラーが出ると思います。
! [remote rejected] wikiMaster -> wikiMaster (TF401027: You need the Git 'GenericContribute' permission to perform this action. Details: identity 'Build\12014033-3fcb-4980-b04e-98b51384fd49', scope 'repository'.)
error: failed to push some refs to 'https://newgyu.visualstudio.com/MyPrj/_git/MyPrj.wiki'
GenericContribute
ってなんじゃいってかんじでしたが、
という設定でうまくいきました。
下記のStackOverFlowを参考にしました。
ということで
申請yamlの入ったPullRequestがmainブランチにマージされると自動的にWiki上にmarkdownの申請ページが反映されるようになりました。
Discussion
分かりやすい記事ありがとうございます。
この方法の場合、コンフリクトがあるような場合だと面倒な気もしますが、何か良い解決策などあるのでしょうか?
私は、 Publish Markdown Reports を作り、パイプラインのビルド結果の画面で表示してみましたが、これはこれで Wiki のようには簡単にたどれず、一長一短な気がしています。。
いわゆるgitでいうconflict状態にはならないと思います。というのも毎回最新をgit fetchした上でファイルまるごと上書きしているので。だれかが手動で変更しても問答無用でパイプラインに上書きされる仕様にしています。
自分のユースケースだとそもそもWikiにしたかったのでパイプラインごとの実行レポートみたいな形式は考えていなかったですね。