お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。

GitHub Actionsで前のジョブの結果を後続で利用したい時に使えるやつ

サンプルコード

  • 適当な文字列を変数にセットして、各ジョブで出力する例
name: outputs sharing example
on:
  pull_request:
jobs:
  first:
    runs-on: ubuntu-latest
    outputs:
      # <out-job-name>: ${{ steps.<step-id>.outputs.<in-job-name> }}
      baz: ${{ steps.foo.outputs.bar }}
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - id: foo
        # この場合、FOO-BARという値がセットされる
        run: echo "::set-output name=bar::$(echo FOO-BAR)"
      - id: test
        # steps.<step-id>.outputs.<in-job-name>
        run: echo "${{ steps.foo.outputs.bar }}"
  second:
    needs: [first]
    runs-on: ubuntu-latest
    steps:
      - id: test
        # needs.<job-id>.outputs.<out-job-name>
        run: echo "${{ needs.first.outputs.baz }}"

参考

投稿日:
ジャンル::サイト運営言語::Markdown

Markdownを使って快適にブログを書きたくない?書きたいですよね?そう、書きたい!
ではどうすればいいか?というのをこれから書いていきます。
JAMStackを使ってGitHub PagesとNext.js SSGでMarkdownブログを作ろう!みたいな人はブラウザバックをオススメします。

技術選定

  • JAMStack
  • はてなブログ
  • WordPress

JAMStack

まずJAMStackは真っ先に除外します。ブログを書きたいのであってブログを作りたいわけではないからです。

またSSGだとクライアントサイドのレンダリングコストが重く、リッチなブログにしようとすると負荷がしんどい気がしています。恐らくSEO対策的にもCSRを妥協して極限までSSGしていないと厳しいのではないでしょうか?

はてなブログ

カスタマイズがすんごくだるい上に、真面目にやろうとするとクライアントサイドでHTMLをゴリゴリ書き換えたり、orderなどのハックに近いCSSを多用して擬似的に要素を移動させたりする必要があり、レイアウトを組むのが非常に面倒です。

エディタもしょぼいしカテゴリはないし(はてブロのカテゴリは実質的にタグなので)年会費が高い割に出来ることの制限が強い…。あんまSEOも強くなかったし、試しに使ってみたものの流入が激減…正直個人的にこれはですね。

WordPress

多分こいつが一番現実的な選択肢です。WP Githuber MDを使うことで不自由なくMarkdownを扱うことが出来ると思います。但し内蔵のPrism.jsはなんかいい感じに動いてくれないケースがあり、その場合はカスタマイズが必要です。

カスタマイズについてもプラグインやテーマが豊富にあり、改造も容易なのでローコストでリッチなものが実現しやすいと思います。またセルフホストなのでデータの取り回しの自由が効きやすいのも大きなポイントですね。

CMSは色々使ってきましたが、なんだかんだブログはWordPressが一番だなって思います。SEO対策もGoogle謹製のやつがあるし、特に何もしなくてもある程度なんとかなるのは強みだと思います。

カスタマイズ法

CSS

使っているテーマと整合性が取れるようにいい感じにします。私は Dracula for Prism.js を改造して使いました。

JS

私の場合は次のコードをヘッダタグの中に足して対処しました。特に内容の説明はしませんが、行番号とコピーボタンが出るようにしています。

<script src="https://unpkg.com/prismjs@1.28.0/components/prism-core.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script src="https://unpkg.com/prismjs@1.28.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
<script>
  document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('pre > code').forEach((codeEl) => {
      codeEl.className = codeEl.className === '' ? 'language-none' : codeEl.className;
      codeEl.className = codeEl.className.replace(/^sh$/, 'shell');
      codeEl.parentNode.className = 'line-numbers';
    });

    window.Prism.highlightAll();
  });
</script>
投稿日:
ソフトウェア::VSCode
{
  "terminal.integrated.defaultProfile.windows": "MSYS2",
  "terminal.integrated.profiles.windows": {
    "MSYS2": {
      "overrideName": true,
      "path": ["C:\\env\\msys64\\msys2_shell.cmd"],
      "args": [
        "-defterm",
        "-here",
        "-use-full-path",
        "-no-start",
        "-mingw64",
        "-shell",
        "zsh"
      ]
    },
    "PowerShell": {
      "source": "PowerShell",
      "icon": "terminal-powershell"
    },
    "Command Prompt": {
      "path": [
        "${env:windir}\\Sysnative\\cmd.exe",
        "${env:windir}\\System32\\cmd.exe"
      ],
      "args": [],
      "icon": "terminal-cmd"
    }
  },
  "terminal.integrated.defaultProfile.linux": "zsh",
  "terminal.integrated.profiles.linux": {
    "zsh": {
      "path": "zsh"
    },
    "bash": {
      "path": "bash"
    }
  },
  "terminal.integrated.automationProfile.windows": {
    "path": "${env:windir}\\System32\\cmd.exe",
    "args": [],
    "icon": "terminal-cmd"
  },
  "terminal.integrated.allowChords": false,
  "terminal.integrated.commandsToSkipShell": [
    "-workbench.action.quickOpenView",
    "-workbench.action.terminal.focusFind"
  ],
  "workbench.startupEditor": "newUntitledFile",
  "workbench.iconTheme": "vscode-icons",
  "workbench.editor.decorations.badges": false,
  "workbench.editor.decorations.colors": false,
  "workbench.tree.enableStickyScroll": false,
  "workbench.layoutControl.enabled": false,
  "workbench.editor.empty.hint": "hidden",
  "files.eol": "\n",
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "scm.showIncomingChanges": "never",
  "scm.showOutgoingChanges": "never",
  "git.autorefresh": true,
  "git.autoStash": true,
  "git.suggestSmartCommit": false,
  "git.mergeEditor": false,
  "git.openRepositoryInParentFolders": "never",
  "remote.autoForwardPortsSource": "hybrid",
  "diffEditor.ignoreTrimWhitespace": true,
  "diffEditor.renderGutterMenu": false,
  "explorer.confirmDragAndDrop": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "editor.stickyScroll.enabled": false,
  "[markdown]": {
    "editor.tabSize": 4,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "php.validate.run": "onSave",
  "vsicons.dontShowNewVersionMessage": true,
  "pasteImage.path": "${currentFileDir}/${currentFileNameWithoutExt}.assets",
  "todo-tree.filtering.excludeGlobs": ["**/node_modules/**/*"],
  "todo-tree.highlights.customHighlight": {
    "TODO": {
      "foreground": "#f8ff96",
      "type": "text-and-comment"
    },
    "FIXME": {
      "foreground": "#ff9696",
      "type": "text-and-comment"
    }
  },
  "todo-tree.general.tags": ["TODO", "FIXME"],
  "todo-tree.regex.regex": "(//|#|<!--|/\\*|^\\s*\\*)\\s*($TAGS)",
  "gitlens.currentLine.format": "${author, }${date}${' via 'pullRequest}${ • message|50?}",
  "gitlens.statusBar.format": "${author}, ${date}${' via 'pullRequest}",
  "gitlens.statusBar.tooltipFormat": "${avatar} &nbsp;__${author}__, ${date}${' via 'pullRequest}\n\n${message}${\n\n---\n\nfootnotes}\n\n${commands}",
  "gitlens.hovers.detailsMarkdownFormat": "${avatar} &nbsp;__${author}__, ${date}${' via 'pullRequest}\n\n${message}${\n\n---\n\nfootnotes}\n\n${commands}",
  "gitlens.views.formats.stashes.description": "${date}",
  "gitlens.views.formats.commits.description": "${author, }${date}",
  "gitlens.defaultDateFormat": "YYYY-MM-DD",
  "terminal.integrated.shellIntegration.decorationsEnabled": "never",
  "security.workspace.trust.untrustedFiles": "open",
  "explorer.copyRelativePathSeparator": "/",
  "typescript.tsserver.log": "off",
  "gitlens.ai.experimental.generateCommitMessage.enabled": false,
  "redhat.telemetry.enabled": true
}
投稿日:
ソフトウェア::Git開発::設計開発::自動化

これは、かつて参画したGitHubを利用したプロジェクトでブランチフローが悪く事故が多発したので考案し、運用した内容です。
基本的には後々の運用を考えた時に情報源になり、かつGit操作に極力手間を取られることがなく、CI/CDを回しながら品質を維持できる内容で考えています。

フローの要件として考えたこと

取り回しが単純明快であること

開発以外の要素に振り回されないように単純なフローにしていて、世に言われる履歴の綺麗さとか言うのは個人的には関心が薄いので重視していません。その代わりコミットが壊れないことや、インデックスとして見やすくなるような部分を重視しています。

GitHubとの相性が良いこと

まず個々の開発タスクをIssueベースで管理し、Pull Requestベースで取り込む運用としました。
Pull Requestの取り込み方式はSquash Mergeとし、メインブランチのコミット履歴がPull Requestのマージコミットになるようにしました。
これはメインブランチのコミット履歴はPull Requestのマージコミットだけあれば後から追えるというのと、メインブランチのコミットログを単純にする意味でこの方式にしています。

CI/CDを活用しやすいこと

これは割とどこでもやっていると思いますが、ブランチ名にdevelopとかstaging, productionとか付けて管理することで、自動的に環境を識別できるようにしました。

実際に運用したフロー

フロー図

運用したブランチフロー

フローの運用内容

  • develop/mainブランチを最新ブランチとする運用
    • develop/mainブランチ相当のものが複数ある状態というのが世の中にあると思いますが、管理が非常に大変なのでそれはしない方向にしました
  • 機能ブランチをdevelop/mainブランチに取り込むのはSquash Merge
    • 基本的に変更履歴を見る時はGitLensやblameで変更行からPull Requestを当てて、そこを見に行くという運用にしていました
  • 機能ブランチにdevelop/mainブランチを取り込むのはmerge
    • 一般的にはrebaseが多いと思いますが、次の観点から採用しませんでした
      • どのポイントで取り込んだのかわからない
      • mergeと比較した場合にコンフリクト対応に手を取られる
        • 経験上ここで事故が頻発する
      • 素直にpush出来ない
    • mergeであれば以下のように単純な流れに出来ますし、push前に差分確認して事故を防ぐことも容易です
      • git switch develop/main
      • git pull
      • git switch -
      • git merge -
      • コンフリクトがあれば解消
      • git push
  • デプロイ方式によるルートブランチ分割
    • ルートブランチ名によってデプロイ先を変更できるようにしました
    • GitHub Actionsでブランチ名を拾って環境変数を差し替えることでデプロイするワークフローを組んでいます
    • staging/production/ブランチはdevelop/mainからcheckoutする運用です
      • これらはデプロイするためだけの使い捨てブランチなので毎回生えます

あとがき

このフローの利点としてはマージでコンフリクトが起きても基本的にCurrentとIncomingを一回比較するだけで済むのでコンフリクトの解消が簡単で、コンフリクト時はIncomingが壊れないようにCurrentを直すのが基本になり、Currentを優先する場合は適宜上書きするといった内容です。

ブランチの合流はmergeだとマージコミット分一回の解消だけでいいので事故の発生要因が低いのがrebaseと比較した時の利点です。rebaseだとコミット回数分再帰的に合流させる必要があるのでブランチの寿命が長かったりすると苦行になってきます。

このフローができた経緯としては元々はGitHub Flowをベースにしていたのですが、色々やっていくうちにこうしたらもっと良くなるのではないか?というのを試行錯誤していてこの形に落ち着いたのですが、後から調べたらGitLab Flowに近い形式に見えたので、似た内容は既に誰かが考えているものだなと感じました。

上で挙げた内容の他にもGitHubのリポジトリ設定でブランチ保護のルールを設定したり、Pull Requestのマージ設定でSquash mergingだけ許可したり、ヘッドブランチの自動削除をするなど、基本的に面倒なことを考えたり、しなくて良い様にするなど、開発に注力しやすいように環境を整えると心理的な抵抗が少なく運用できて便利だなと感じています。