tag:crieit.net,2005:https://crieit.net/tags/Forem/feed 「Forem」の記事 - Crieit Crieitでタグ「Forem」に投稿された最近の記事 2021-03-22T13:21:27+09:00 https://crieit.net/tags/Forem/feed tag:crieit.net,2005:PublicArticle/16763 2021-03-22T13:21:27+09:00 2021-03-22T13:21:27+09:00 https://crieit.net/posts/sync-zenn-with-dev-action Zenn の記事を DEV に自動的に同期させる GitHub Action 作ってみた <h1 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h1> <p>去年 <a target="_blank" rel="nofollow noopener" href="https://dev.to/">DEV</a> のアカウントを作成したものの、今まで全く有効活用出来ていませんでした。</p> <p>DEV には <a target="_blank" rel="nofollow noopener" href="https://dev.to/michaelburrows/comment/125j0">カノニカル URL</a> を設定出来るので、常々 Zenn の記事を投稿する際にクロスポストしたいなと考えておりました。そこで、<strong>Zenn に記事を投稿したら、自動的に DEV にも記事を投稿 & 同期する GitHub Action を作ってみました。</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/sync-zenn-with-dev-action">sync-zenn-with-dev-action</a></p> <p>今回初めて GitHub Action を自作したのですが、その中で得た知見を残す形で記事を書くことにしました。また、GitHub Action は TypeScript で作成しました。</p> <h1 id="開発した GitHub Action の概要"><a href="#%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F+GitHub+Action+%E3%81%AE%E6%A6%82%E8%A6%81">開発した GitHub Action の概要</a></h1> <p>まずはザッとどのような GitHub Action を作成したのか、概要について説明いたします。</p> <p><strong>GitHub リポジトリで管理している Zenn の記事を DEV に同期して投稿する GitHub Action を作成しました。</strong> その際に DEV へ投稿する記事には Zenn の該当記事へのカノニカル URL も自動で設定できます。これにより DEV と Zenn へ記事をシームレスにクロスポストすることが可能となります。</p> <p>今回作成した GitHub Action を利用するワークフローファイルの一例は下記となります。</p> <pre><code class="yml">name: "Sync all Zenn articles to DEV" on: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - name: checkout my project uses: actions/checkout@v2 - name: dev.to action step uses: nikaera/sync-zenn-with-dev-action@v1 # id を設定することで、後のジョブで Output で指定した値が参照可能になる id: dev-to with: # DEV の API キーを指定する api_key: $<span>{</span><span>{</span> secrets.api_key <span>}</span><span>}</span> # (オプション) DEV に記事を投稿した際に Zenn のカノニカル URL を設定したい場合に指定する # username: nikaera # (オプション) 改行区切りで指定した articles フォルダ内のファイルパスを記載した txt ファイルを指定することで、記載された記事のみを同期するようになる。 # 他プラグインと組み合わせることで差分のみを txt ファイルに載せることが可能。詳細については後述の Outputs の項目に記載。 # added_modified_filepath: ./added_modified.txt # (オプション) Zenn の articles 以下全ての記事を常に DEV に同期するか指定する # update_all が true のときは added_modified_filepath は無視される。 # update_all: false # 上記アクション実行時に DEV に新規で同期する記事に関しては Zenn のマークダウンヘッダに # 該当する DEV の記事の ID が dev_article_id として記載されるようになる。 # 今後はその ID を元に同期するようになるため、該当する Zenn の記事をコミットする。 # 新規で同期する記事が無ければ、このジョブは実行しない。 - name: write article id of DEV to articles of Zenn. run: | git config user.name github-actions git config user.email [email protected] git add $<span>{</span><span>{</span> steps.dev-to.outputs.newly-sync-articles <span>}</span><span>}</span> git commit -m "sync: Zenn with DEV [skip ci]" git push if: steps.dev-to.outputs.newly-sync-articles # Outputs には DEV の記事情報 (title, url) が含まれるようになるため、 # 最後に出力して実行結果の内容を確認することもできる - name: Get the output articles. # dev-to という id が紐付いたジョブの Outputs を取得して echo で内容を出力する run: echo "$<span>{</span><span>{</span> steps.dev-to.outputs.articles <span>}</span><span>}</span>" </code></pre> <p>簡単に <code>nikaera/sync-zenn-with-dev-action@v1</code> というジョブの内部処理について説明いたします。</p> <ol> <li>Inputs の <code>update_all</code> 及び <code>added_modified_filepath</code> で受け取った情報を元に、<br /> どの記事を DEV に同期させるか判定する</li> <li>DEV に同期する記事のファイルパス一覧を取得して、<br /> それぞれの記事のヘッダに <code>dev_article_id</code> の記載があるか判定する</li> <li>Inputs の <code>api_key</code> を利用して、Zenn の記事に <code>dev_article_id</code> が含まれていれば、<br /> 該当する DEV の記事を更新する。含まれていなければ DEV に新規で記事を作成する</li> <li>Inputs の <code>username</code> を利用して、<br /> DEV の記事に該当する Zenn 記事のカノニカル URL を設定する</li> <li>DEV に新規で記事を作成した場合は、<br /> Zenn の該当記事のヘッダに <code>dev_article_id</code> を書き込む</li> <li>DEV に記事を投稿する際、Zenn は対応しているが、<br /> DEV では対応していない記述は削除する (<code>:::</code> 記法や一部のコード記法)</li> <li>記事の公開ステータス及びタグなどについても DEV の記事に反映する<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li> <li>新規で DEV に記事を同期した Zenn 記事のファイルパスを、<br /> Outputs の <code>newly-sync-articles</code> に設定する<br /> (後のジョブで <code>dev_article_id</code> の含まれた記事をコミットしたいため)</li> <li>ワークフローで同期された記事情報は Outouts の <code>articles</code> に設定する</li> </ol> <p>Inputs と Outputs の内容一覧については下記になります。</p> <p><strong>Inputs</strong></p> <div class="table-responsive"><table> <thead> <tr> <th align="left">キー</th> <th align="left">説明</th> <th align="center">必須</th> </tr> </thead> <tbody> <tr> <td align="left">api_key</td> <td align="left">DEV の <a target="_blank" rel="nofollow noopener" href="https://docs.forem.com/api/#section/Authentication">API Key</a> を設定する</td> <td align="center">o</td> </tr> <tr> <td align="left">username</td> <td align="left">Zenn の <strong>自分のアカウント名</strong> を設定する (DEV に同期する記事に Zenn のカノニカル URL を設定したい場合のみ)</td> <td align="center">x</td> </tr> <tr> <td align="left">added_modified_filepath</td> <td align="left">改行区切りで指定した articles フォルダ内のファイルパスを記載した txt ファイルを指定することで、記載された記事のみを同期するようになる。<strong>PR やコミット差分のファイルのみを取得するための GitHub Action <a target="_blank" rel="nofollow noopener" href="https://github.com/jitterbit/get-changed-files">jitterbit/get-changed-files@v1</a> と組み合わせることで、更新差分のあった記事のみを随時同期することも可能。<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></strong> 更新差分のあった記事のみを随時同期するための<a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/zenn.dev/blob/main/.github/workflows/sync-zenn-with-dev.yml">実際のワークフローファイルはこちら</a></td> <td align="center">x</td> </tr> <tr> <td align="left">update_all</td> <td align="left">Zenn の全ての記事をどうきするかどうかを設定する。GitHub Action 初回実行時のみ true にする使い方を想定している。デフォルトは true。<strong><code>added_modified_filepath</code> よりも <code>update_all</code> が優先されるため <code>added_modified_filepath</code> を設定する場合は false を設定する必要あり`</strong></td> <td align="center">x</td> </tr> </tbody> </table></div> <p><strong>Outputs</strong></p> <div class="table-responsive"><table> <thead> <tr> <th align="left">キー</th> <th align="left">説明</th> </tr> </thead> <tbody> <tr> <td align="left">articles</td> <td align="left">同期された DEV の記事のタイトル及び URL が格納された配列</td> </tr> <tr> <td align="left">newly-sync-articles</td> <td align="left">DEV で新たに新規作成された Zenn 記事のファイルパスが格納された配列。<strong><a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/sync-zenn-with-dev-action/blob/main/.github/workflows/test.yml#L31-L38">実際のワークフローファイルの該当する記述</a>のように、必ずコミットに含めるようにする必要がある (理由は後述)</strong></td> </tr> </tbody> </table></div> <p>Inputs 及び Outputs については<a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/metadata-syntax-for-github-actions#">公式サイトの説明</a>をご参照ください。</p> <h2 id="Zenn の記事を DEV に同期するための仕組み"><a href="#Zenn+%E3%81%AE%E8%A8%98%E4%BA%8B%E3%82%92+DEV+%E3%81%AB%E5%90%8C%E6%9C%9F%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF">Zenn の記事を DEV に同期するための仕組み</a></h2> <p>Zenn の記事を新規で DEV に同期する際は、DEV に記事を新規作成する必要があります。<strong>その際に Zenn の記事と DEV の記事を紐付けるための何らかの仕組みが必要となります。そうしないと、今後 Zenn の記事内容を更新した際に、DEV のどの記事に内容を同期させればよいかが不明なためです。</strong></p> <p>そこで、記事を同期するための仕組みとして、<strong><code>dev_article_id</code> というフィールドを Zenn のマークダウンヘッダに追記することで DEV の同期すべき記事との紐付けを行うことにしました。</strong><code>dev_article_id</code> には <a target="_blank" rel="nofollow noopener" href="https://docs.forem.com/api/#operation/createArticle">DEV の記事作成 API</a> 実行時の返り値である <code>id</code> を設定します。</p> <p>一度 <code>id</code> を <code>dev_article_id</code> として Zenn の記事に紐付けてしまえば、次回以降に記事の同期を行う際は <a target="_blank" rel="nofollow noopener" href="https://docs.forem.com/api/#operation/updateArticle">DEV の記事更新 API</a> を利用できます。</p> <p>また、<strong>Outputs の <code>newly-sync-articles</code> には新規で作成された DEV 記事の <code>id</code> である <code>dev_article_id</code> が追記された Zenn 記事のファイルパスが格納されています。そのため、<code>nikaera/sync-zenn-with-dev-action@v1</code> 実行後は、下記のように <code>steps.dev-to.outputs.newly-sync-articles</code> 内に格納されたファイル群をコミットに反映させる必要があります。</strong></p> <pre><code class="yml"># `nikaera/sync-zenn-with-dev-action@v1` 実行後に必ず定義すべきジョブ # DEV に新規に作成した記事がなければ実行しない (if: steps.dev-to.outputs.newly-sync-articles) - name: write article id of DEV to articles of Zenn. run: | git config user.name github-actions git config user.email [email protected] git add $<span>{</span><span>{</span> steps.dev-to.outputs.newly-sync-articles <span>}</span><span>}</span> git commit -m "sync: Zenn with DEV [skip ci]" git push if: steps.dev-to.outputs.newly-sync-articles </code></pre> <p>上記のジョブで <code>newly-sync-articles</code> に格納された <code>dev_article_id</code> が追記された Zenn 記事は随時コミットに反映しないと、<strong>Zenn の全ての記事が同期毎 DEV に新規作成され続けるという不具合を引き起こしてしまうので、ご注意ください</strong></p> <h1 id="GitHub Action を開発する手順"><a href="#GitHub+Action+%E3%82%92%E9%96%8B%E7%99%BA%E3%81%99%E3%82%8B%E6%89%8B%E9%A0%86">GitHub Action を開発する手順</a></h1> <p>サクッと開発に取り組みたかったため、<a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action">Docker コンテナを利用する方法</a> ではなく、<a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/creating-a-javascript-action">JavaScript を利用する方法</a> で開発を進めていくことにしました。</p> <h2 id="TypeScript で GitHub Action を作る"><a href="#TypeScript+%E3%81%A7+GitHub+Action+%E3%82%92%E4%BD%9C%E3%82%8B">TypeScript で GitHub Action を作る</a></h2> <p>GitHub 公式が TypeScript で GitHub Action を作るための <a target="_blank" rel="nofollow noopener" href="https://github.com/actions/typescript-action">テンプレートプロジェクト</a> を用意してくれています。今回はこのテンプレートプロジェクトを利用する形でプロジェクトを作成しました。</p> <p><em>(余談) GitHub Action では <a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action">Docker コンテナ</a> を用いてワークフローを実行可能です。<strong>そのため、実行環境は自由に設定出来ます。(Go, Python, Ruby, etc.)</strong></em></p> <p>早速 TypeScript のテンプレートプロジェクトを元に自分の GitHub Action プロジェクトを作成します。</p> <p><img src="https://i.gyazo.com/359f6f795bab9807c9f480c0f922973a.png" alt="スクリーンショット 2021-03-21 13.25.54.png" /><br /> <strong>1. テンプレートプロジェクトを元に GitHub Action の TypeScript プロジェクトを作成する</strong></p> <p><img src="https://i.gyazo.com/76aecd3d63db95d34c086774ded122d4.png" alt="スクリーンショット 2021-03-21 13.29.43.png" /><br /> <strong>2. プロジェクトの作成後 <code>git clone</code> してきて開発する準備を整える</strong></p> <h2 id="GitHub Action プロジェクトの開発を進めるための準備を行う"><a href="#GitHub+Action+%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E9%96%8B%E7%99%BA%E3%82%92%E9%80%B2%E3%82%81%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E6%BA%96%E5%82%99%E3%82%92%E8%A1%8C%E3%81%86">GitHub Action プロジェクトの開発を進めるための準備を行う</a></h2> <p>テンプレートプロジェクトを <code>git clone</code> したら、まずは <code>action.yml</code> の内容を変更します。<br /> 今回作成した GitHub Action の <code>action.yml</code> は下記となっております。</p> <pre><code class="yml"># action.yml # GitHub Action のプロジェクト名 name: 'Sync Zenn articles to DEV' # GitHub Action のプロジェクト説明文 description: 'Just sync Zenn articles to DEV.' # GitHub Action の作者 author: 'nikaera' # GitHub Action に渡せる引数の値定義 inputs: api_key: # フィールドの指定が必須であれば true、必須でなければ false を設定する # DEV の API キーは同期を行う際に必須なため、true を設定している required: true # フィールドの説明文 description: 'The api_key required to use the DEV API (https://docs.forem.com/api/#section/Authentication)' username: required: false description: "Zenn user's account name. (Fields to be filled in if canonical url is set.)" articles: required: false description: "The directory where Zenn articles are stored." # フィールドにはデフォルト値を指定することも可能 # Zenn の記事がデフォで格納されているフォルダ名を指定している default: articles update_all: require: false description: "Whether to synchronize all articles." default: true added_modified_filepath: required: false description: | Synchronize only the articles in the file path divided by line breaks. You can use jitterbit/get-changed-files@v1 to get only the file paths of articles that have changed in the correct format. (https://github.com/jitterbit/get-changed-files) # GitHub Action 実行後に参照可能になる値定義 outputs: articles: description: 'A list of URLs of dev.to articles that have been created or updated' newly-sync-articles: description: 'File path list of newly synchronized articles.' # GitHub Action の実行環境 runs: using: 'node12' # テンプレートプロジェクトでは コンパイル先が dist になるため `dist/index.js` を指定している main: 'dist/index.js' </code></pre> <p>TypeScript のテンプレートプロジェクトでは、バンドルツールとして <a target="_blank" rel="nofollow noopener" href="https://github.com/vercel/ncc"><code>ncc</code></a> が採用されています。<strong>GitHub Action 実行時に使用されるのは ncc によりコンパイルされた単一の JavaScript ファイル (<code>dist/index.js</code>) になります。</strong></p> <p>あとは <code>src</code> フォルダ内でプログラムを書いて、<code>npm run all && node dist/index.js</code> のようにコマンド実行しながら開発を進めていくだけです。</p> <p><em>(余談) GitHub Action の開発ツールとして Docker を利用した <a target="_blank" rel="nofollow noopener" href="https://github.com/nektos/act"><code>act</code></a> というものが存在するようです。ローカル環境で検証する際は <a target="_blank" rel="nofollow noopener" href="https://github.com/nektos/act#known-issues">既知の問題</a> に対応する必要がありそうですが、GitHub Action の開発で非常に有効活用できそうで気になっております。</em></p> <p>今回の開発では利用しなかったのですが、今後開発を進めていく中で利用する機会も出てきそうなので、その際は本記事内容を更新する形で知見を追記したいと考えております。</p> <p>:::</p> <h2 id="GitHub Action を実装する際に利用した機能"><a href="#GitHub+Action+%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AB%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9F%E6%A9%9F%E8%83%BD">GitHub Action を実装する際に利用した機能</a></h2> <p>GitHub Action を実装する際に利用した機能を、実際のコード内容を抜粋して簡単に説明していきます。下記で紹介する内容は <a target="_blank" rel="nofollow noopener" href="https://github.com/actions/toolkit">GitHub Actions Toolkit</a> の機能です。</p> <pre><code class="typescript">/** 下記の yml の with で指定した値は core.getInput で受け取ることが可能。 - name: dev.to action step uses: nikaera/sync-zenn-with-dev-action@v1 id: dev-to with: # DEV の API キーを指定する api_key: $<span>{</span><span>{</span> secrets.api_key <span>}</span><span>}</span> */ core.getInput("api_key", { required: true }); core.getInput("update_all", { required: false }); /** 下記の yml の steps.<ジョブで指定した id>.outputs で参照可能な値をセットすることが可能。 セットする内容は文字列である必要がある。 - name: dev.to action step uses: nikaera/sync-zenn-with-dev-action@v1 id: dev-to - name: Get the output articles. run: echo "$<span>{</span><span>{</span> steps.dev-to.outputs.articles <span>}</span><span>}</span>" */ core.setOutput("articles", JSON.stringify(devtoArticles, undefined, 2)); core.setOutput("newly-sync-articles", newlySyncedArticles.join(" ")); /** GitHub Action 実行時に出力されるログをレベルごとに出力することが可能 core.debug はローカル実行時のみに出力内容を確認することができる */ core.debug("debug"); core.info(`update_all: ${updateAll}`); core.error(JSON.stringify(error)); </code></pre> <p>上記だけ把握してれば GitHub Action の開発は問題なく行うことができました。</p> <h1 id="作成した GitHub Action を実際に GitHub 上で実行可能にする"><a href="#%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F+GitHub+Action+%E3%82%92%E5%AE%9F%E9%9A%9B%E3%81%AB+GitHub+%E4%B8%8A%E3%81%A7%E5%AE%9F%E8%A1%8C%E5%8F%AF%E8%83%BD%E3%81%AB%E3%81%99%E3%82%8B">作成した GitHub Action を実際に GitHub 上で実行可能にする</a></h1> <p>ローカル環境で一通り開発が完了したら、GitHub リポジトリに push した後タグ付けを行います。<strong>GitHub Action はタグを設定しないと実行できないため必要な作業となります。</strong> 今回タグ付けは GitHub 上で行いました。</p> <p><img src="https://i.gyazo.com/252514cca20470154475db75b133e9b3.png" alt="スクリーンショット 2021-03-22 8.11.58.png" /><br /> <strong>1. タグの項目をクリックする</strong></p> <p><img src="https://i.gyazo.com/a8c145f8d6ae7b1f6253eb4866bcbb51.png" alt="スクリーンショット 2021-03-22 8.14.47.png" /><br /> <strong>2. <code>Create a new release</code> ボタンをクリックしてタグ作成画面に遷移する</strong></p> <p><img src="https://i.gyazo.com/25e019e42227ad7e0b0b634e68bb1873.png" alt="スクリーンショット 2021-03-22 8.20.00.png" /><br /> <strong>3. <code>Publish release</code> ボタンをクリックしてタグの作成を完了する</strong></p> <p><strong>上記の例では <code>v1</code> というタグを作成したので <code>nikaera/sync-zenn-with-dev-action@v1</code> のような記述で GitHub Action を利用可能になりました。</strong> 私は Zenn の記事を <a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/zenn.dev/"><code>zenn.dev</code></a> というリポジトリで管理しているため、早速このリポジトリに GitHub Action を導入してみます。</p> <h2 id="Zenn の全ての記事を DEV に同期するためのワークフロー"><a href="#Zenn+%E3%81%AE%E5%85%A8%E3%81%A6%E3%81%AE%E8%A8%98%E4%BA%8B%E3%82%92+DEV+%E3%81%AB%E5%90%8C%E6%9C%9F%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC">Zenn の全ての記事を DEV に同期するためのワークフロー</a></h2> <p>本記事の GitHub Action では DEV の API キーを使用するため、<strong>事前にシークレットへ <code>API_KEY</code> という名称で値を登録しておきます。</strong><a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository">公式サイトの手順</a> に従い シークレットの登録が完了したら、該当リポジトリに <code>.github/workflows/sync-zenn-with-dev-all.yml</code> というワークフローファイルを作成します。</p> <pre><code class="yml"># .github/workflows/sync-zenn-with-dev-all.yml name: "Sync-All Zenn with DEV" on: workflow_dispatch: jobs: build: runs-on: ubuntu-latest if: contains(github.event.head_commit.message, '[skip ci]') == false steps: - name: setup node project uses: actions/checkout@v2 - name: dev.to action step uses: nikaera/sync-zenn-with-dev-action@v1 id: dev-to with: api_key: $<span>{</span><span>{</span> secrets.api_key <span>}</span><span>}</span> # Zenn の自分のアカウント名を指定すると # DEV 記事のカノニカル URL に Zenn 記事の URL を指定できる # username: nikaera update_all: true - name: write article id of DEV to articles of Zenn. run: | git config user.name github-actions git config user.email [email protected] git add $<span>{</span><span>{</span> steps.dev-to.outputs.newly-sync-articles <span>}</span><span>}</span> git commit -m "sync: Zenn with DEV [skip ci]" git push if: steps.dev-to.outputs.newly-sync-articles - name: Get the output articles. run: echo "$<span>{</span><span>{</span> steps.dev-to.outputs.articles <span>}</span><span>}</span>" </code></pre> <p>上記は手動実行が可能な Zenn の記事を全て DEV に同期するためのワークフローファイルになります。作成が完了したらワークフローファイルを実行して、記事が正常に同期できているか確認してみます。</p> <p><img src="https://i.gyazo.com/e0740fe369752db67514e0ab50e88772.png" alt="スクリーンショット 2021-03-22 8.35.38.png" /><br /> <strong>1. <code>Actions</code> タブをクリックする</strong></p> <p><img src="https://i.gyazo.com/2aeadddccf08c0dddc54dddab464edee.png" alt="スクリーンショット 2021-03-22 8.37.24.png" /><br /> <strong>2. 作成した <code>Sync-All Zenn with DEV</code> ワークフローファイルを選択する</strong></p> <p><img src="https://i.gyazo.com/d9e138de1f6e0baac8b0c3bc6742f4f2.png" alt="スクリーンショット 2021-03-22 8.40.11.png" /><br /> <strong>3. <code>Run workflow</code> ボタンを実行して、ワークフローを実行する</strong></p> <p><img src="https://i.gyazo.com/e67df0f6e33d1f57a46000d20ef2c824.png" alt="スクリーンショット 2021-03-22 8.45.23.png" /><br /> <strong>4. ワークフローの実行が正常に完了していれば、ログに DEV の記事情報が出力される</strong></p> <p><img src="https://i.gyazo.com/4acc0b0de3acd6731918a9347e7baea8.png" alt="スクリーンショット 2021-03-22 8.50.37.png" /><br /> <strong>5. <code>dev.to</code> にアクセスして Zenn の記事情報が正常に同期されていることを確認する</strong></p> <p>正常に Zenn の全ての記事が DEV に同期されていることが確認できたら、次は Zenn の記事が新規作成されたり、更新されたときのみに DEV に同期するためのワークフローファイルを作成します。</p> <h2 id="更新差分のあった Zenn 記事のみを DEV に同期するためのワークフロー"><a href="#%E6%9B%B4%E6%96%B0%E5%B7%AE%E5%88%86%E3%81%AE%E3%81%82%E3%81%A3%E3%81%9F+Zenn+%E8%A8%98%E4%BA%8B%E3%81%AE%E3%81%BF%E3%82%92+DEV+%E3%81%AB%E5%90%8C%E6%9C%9F%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC">更新差分のあった Zenn 記事のみを DEV に同期するためのワークフロー</a></h2> <p><code>main</code> ブランチが更新されたときのみ更新された記事のみを DEV に同期するためのワークフローファイルを作成します。該当リポジトリに <code>.github/workflows/sync-zenn-with-dev.yml</code> というワークフローファイルを作成します。</p> <pre><code class="yml"># .github/workflows/sync-zenn-with-dev.yml name: "Sync Zenn with DEV" on: push: branches: - main jobs: build: runs-on: ubuntu-latest if: contains(github.event.head_commit.message, '[skip ci]') == false steps: - name: setup node project uses: actions/checkout@v2 - name: get modified files id: files uses: jitterbit/get-changed-files@v1 - name: output modified files to text run: | for changed_file in $<span>{</span><span>{</span> steps.files.outputs.added_modified <span>}</span><span>}</span>; do echo "${changed_file}" >> added_modified.txt done - name: dev.to action step uses: nikaera/sync-zenn-with-dev-action@v1 id: dev-to with: api_key: $<span>{</span><span>{</span> secrets.api_key <span>}</span><span>}</span> # Zenn の自分のアカウント名を指定すると # DEV 記事のカノニカル URL に Zenn 記事の URL を指定できる # username: nikaera added_modified_filepath: ./added_modified.txt update_all: false - name: write article id of DEV to articles of Zenn. run: | git config user.name github-actions git config user.email [email protected] git add $<span>{</span><span>{</span> steps.dev-to.outputs.newly-sync-articles <span>}</span><span>}</span> git commit -m "sync: Zenn with DEV [skip ci]" git push if: steps.dev-to.outputs.newly-sync-articles - name: Get the output articles. run: echo "$<span>{</span><span>{</span> steps.dev-to.outputs.articles <span>}</span><span>}</span>" </code></pre> <p>上記ワークフローファイルの作成が完了したら、早速動作確認のために、<strong>まさに今執筆中の本記事内容をリポジトリに push してみます。</strong></p> <p><img src="https://i.gyazo.com/36512e7874b49edc1e48f0ef88af5d89.png" alt="スクリーンショット 2021-03-22 9.07.55.png" /><br /> <strong>1. <code>git push</code> 後に該当するワークフローの実行結果を確認する</strong></p> <p><img src="https://i.gyazo.com/cbb0a1cf7b94605680e39630dded0096.png" alt="Image from Gyazo" /><br /> <strong>2. <code>dev.to</code> に執筆途中の内容で記事が同期されていることを確認する</strong></p> <p>これまで説明してきた 2 つのワークフローを利用することで、大抵のユースケースはカバーできるはずです。</p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>GitHub Action の勉強のために取り組んだプロジェクトですが、思いの外楽しくて他にも色々な機能のアイデアがあるので随時実装していきたいと考えています。(英訳, タイトルフォーマット変更, etc.)</p> <p>DEV に Zenn の記事をクロスポストする GitHub Action を公開することで、いつもお世話になっている Zenn というプラットフォームを海外の方に認知していただける機会を創出できたのかもと考えたらテンションが上がってきました。</p> <p>それはさておき、Zenn の記事を他でも有効活用するための GitHub Action を開発する際には、恐らく本記事で紹介した GitHub Action のコードが参考になるはずです。</p> <p>また、<a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/publishing-actions-in-github-marketplace">GitHub Action の Marketplace</a> というものが用意されているようなので、開発がある程度完了次第、こちらに申請するのも試してみたいと考えております。</p> <p>ところで、<em>Crieit さんにも記事投稿 API ができたらクロスポストできるようにしたいな...という個人的願望がありますw</em></p> <h1 id="参考リンク"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF">参考リンク</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://dev.to/">DEV Community 👩‍💻👨‍💻</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://dev.to/michaelburrows/comment/125j0">dev.to supports canonical URLs so you can share content without impacting SEO... - DEV Community</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/sync-zenn-with-dev-action">nikaera/sync-zenn-with-dev-action: Just sync Zenn articles to DEV.</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.forem.com/api/#section/Authentication">DEV API (beta)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/jitterbit/get-changed-files">jitterbit/get-changed-files: Get all of the files changed/modified in a pull request or push's commits.</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action">Docker コンテナのアクションを作成する - GitHub Docs</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/creating-actions/creating-a-javascript-action">JavaScript アクションを作成する - GitHub Docs</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/actions/typescript-action">actions/typescript-action: Create a TypeScript Action with tests, linting, workflow, publishing, and versioning</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/vercel/ncc">vercel/ncc: Compile a Node.js project into a single file. Supports TypeScript, binary addons, dynamic requires.</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/nektos/act">nektos/act: Run your GitHub Actions locally 🚀</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/actions/toolkit">actions/toolkit: The GitHub ToolKit for developing GitHub Actions.</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository">暗号化されたシークレット - GitHub Docs</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.deepl.com/ja/pro#developer">DeepL Pro:テキストの他、Word などの文書をセキュアに翻訳</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/">Qiita</a></li> <li><a href="https://crieit.net/advent-calendars/2020/crieit">Crieit - プログラマー、クリエイターが何でも気軽に書けるコミュニティ</a></li> </ul> <div class="footnotes" role="doc-endnotes"> <hr /> <ol> <li id="fn:1" role="doc-endnote"> <p>DEV (Forem) の仕様上、<a target="_blank" rel="nofollow noopener" href="https://dev.to/p/editor_guide#front-matter">タグは最大でも 4 つまで</a>しか設定できないため、Zenn で設定したタグの先頭 4 つまで DEV の記事には設定しています <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p> </li> <li id="fn:2" role="doc-endnote"> <p>当然といえば当然ですが <a target="_blank" rel="nofollow noopener" href="https://github.com/jitterbit/get-changed-files">jitterbit/get-changed-files@v1</a> は <code>workflow_dispatch</code> でワークフローを手動実行した際や、<code>force push</code> 等でファイル差分を正確に特定できない操作には対応しておりませんので、その場合はエラーが発生します <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p> </li> </ol> </div> nikaera