<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><author><name>CC康纳百川</name></author><generator uri="https://hexo.io/">Hexo</generator><icon>https://cdn.jsdmirror.com/gh/ccknbc-backup/cdn/logo/CC.png</icon><id>https://blog.ccknbc.cc/</id><link href="https://blog.ccknbc.cc/" rel="alternate"/><link href="https://blog.ccknbc.cc/atom.xml" rel="self"/><rights>All rights reserved 2026, CC康纳百川</rights><subtitle>CC康纳百川</subtitle><title>CC的部落格</title><updated>2026-08-29T09:30:44.282Z</updated><entry><author><name>CC康纳百川</name></author><category term="工具" scheme="https://blog.ccknbc.cc/categories/%E5%B7%A5%E5%85%B7/"/><category term="工具" scheme="https://blog.ccknbc.cc/tags/%E5%B7%A5%E5%85%B7/"/><content><![CDATA[<p>本文首发在<a href="https://www.yuque.com/ccknbc/blog/21/"><strong>语雀</strong></a></p><p>自动同步更新至<a href="https://blog.ccknbc.cc/posts/github-automatically-merges-pull-requests-notes/"><strong>CC的部落格</strong></a></p><hr><h1>automerge-action</h1><p>GitHub action to automatically merge pull requests when they are ready.</p><p><img src="https://cdn.nlark.com/yuque/0/2021/svg/8391407/1610874798961-ae345ffc-d1e6-425f-900a-8f69e4ee5a53.svg" alt="" loading="lazy"></p><p>When added, this action will run the following tasks on pull requests with the</p><p><code>automerge</code> label:</p><ul><li>Changes from the base branch will automatically be merged into the pull<br>request (only when “Require branches to be up to date before merging”<br>is enabled in the branch protection rules)</li><li>When the pull request is ready, it will automatically be merged. The action<br>will only wait for status checks that are marked as required in the branch<br>protection rules</li><li>Pull requests without any configured labels will be ignored</li></ul><p>Labels, merge and update strategies are configurable, see <a href="#configuration">Configuration</a>.</p><p>A pull request is considered ready when:</p><ol><li>the required number of review approvals has been given (if enabled in the<br>branch protection rules) and</li><li>the required checks have passed (if enabled in the branch protection rules)<br>and</li><li>the pull request is up to date (if enabled in the branch protection rules)</li></ol><p>After the pull request has been merged successfully, the branch will <em>not</em> be</p><p>deleted. To delete branches after they are merged,</p><p>see <a href="https://help.github.com/en/articles/managing-the-automatic-deletion-of-branches">automatic deletion of branches</a>.</p><h2 id="Usage">Usage<a class="fa-solid fa-hashtag" href="#Usage"></a></h2><p>Create a new <code>.github/workflows/automerge.yml</code> file:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">automerge</span></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">pull_request:</span></span><br><span class="line">    <span class="attr">types:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">labeled</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">unlabeled</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">synchronize</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">opened</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">edited</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ready_for_review</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">reopened</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">unlocked</span></span><br><span class="line">  <span class="attr">pull_request_review:</span></span><br><span class="line">    <span class="attr">types:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">submitted</span></span><br><span class="line">  <span class="attr">check_suite:</span></span><br><span class="line">    <span class="attr">types:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">completed</span></span><br><span class="line">  <span class="attr">status:</span> &#123;&#125;</span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">automerge:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">automerge</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">&quot;pascalgn/automerge-action@v0.13.0&quot;</span></span><br><span class="line">        <span class="attr">env:</span></span><br><span class="line">          <span class="attr">GITHUB_TOKEN:</span> <span class="string">&quot;$<span class="template-variable">&#123;&#123; secrets.GITHUB_TOKEN &#125;&#125;</span>&quot;</span></span><br></pre></td></tr></table></figure><p>For the latest version, see the <a href="https://github.com/pascalgn/automerge-action/releases">list of releases</a>.</p><h2 id="Configuration">Configuration<a class="fa-solid fa-hashtag" href="#Configuration"></a></h2><p>The following merge options are supported:</p><ul><li><code>MERGE_LABELS</code>: The labels that need to be present for a pull request to be<br>merged (using <code>MERGE_METHOD</code>). The default value is <code>automerge</code>.<br>This option can be a comma-separated list of labels that will be checked. All<br>labels in the list need to be present, otherwise the pull request will be<br>skipped (until all labels are present). Labels prefixed with an exclamation<br>mark (<code>!</code>) will block a pull request from being merged, when present.<br>For example, when <code>automerge,!wip,!work in progress</code> is given,<br>any pull requests with the labels <code>wip</code> or <code>work in progress</code> and any pull<br>requests <em>without</em> the label <code>automerge</code> will not be merged.<br>Blocking labels take precedence, so if a pull request has both labels<br><code>wip</code> and <code>automerge</code>, it will not be merged.<br>When an empty string (<code>&quot;&quot;</code>) is given, all pull requests will be merged.</li><li><code>MERGE_REMOVE_LABELS</code>: The labels to automatically remove from a pull request<br>once it has been merged by the action. The default value is <code>&quot;&quot;</code>.<br>This option can be a comma-separated list of labels that will be removed.<br>When an empty string (<code>&quot;&quot;</code>) is given, no labels will be removed.</li><li><code>MERGE_METHOD</code>: Which method to use when merging the pull request into<br>the base branch. Possible values are<br><code>[merge](https://help.github.com/en/articles/about-pull-request-merges)</code> (create a merge commit),<br><code>[rebase](https://help.github.com/en/articles/about-pull-request-merges#rebase-and-merge-your-pull-request-commits)</code><br>(rebase all commits of the branch onto the base branch)<br>or <code>[squash](https://help.github.com/en/articles/about-pull-request-merges#squash-and-merge-your-pull-request-commits)</code><br>(squash all commits into a single commit). The default option is <code>merge</code>.</li><li><code>MERGE_METHOD_LABELS</code>: Set to allow labels to determine the merge method<br>(see <code>MERGE_METHOD</code> for possible values).<br>For example, <code>automerge=merge,autosquash=squash</code>. If no such label is present,<br>the method set by <code>MERGE_METHOD</code> will be used. The default value is <code>&quot;&quot;</code>.</li><li><code>MERGE_METHOD_LABEL_REQUIRED</code>: Set to <code>true</code> to require one of the<br><code>MERGE_METHOD_LABELS</code> to be set. The default value is <code>false</code>.</li><li><code>MERGE_COMMIT_MESSAGE</code>: The commit message to use when merging the pull<br>request into the base branch. Possible values are <code>automatic</code> (use GitHub’s<br>default message), <code>pull-request-title</code> (use the pull request’s title),<br><code>pull-request-description</code> (use the pull request’s description),<br><code>pull-request-title-and-description</code> or a literal<br>value with optional placeholders (for example <code>Auto merge &#123;pullRequest.number&#125;</code>).<br>The default value is <code>automatic</code>.</li><li><code>MERGE_COMMIT_MESSAGE_REGEX</code>: When using a commit message containing the<br>PR’s body, use the first capturing subgroup from this regex as the commit<br>message. Can be used to separate content that should go with the commit into<br>the code base’s history from boilerplate associated with the PR (licensing<br>notices, check lists, etc). For example, <code>(.*)^---</code> would keep everything up<br>until the first 3-dash line (horizontal rule in MarkDown) from the commit<br>message. The default value is empty, which disables this feature.</li><li><code>MERGE_FILTER_AUTHOR</code>: When set, only pull requests raised by this author<br>will be merged automatically.</li><li><code>MERGE_FORKS</code>: Whether merging from external repositories is enabled<br>or not. By default, pull requests with branches from forked repositories will<br>be merged the same way as pull requests with branches from the main<br>repository. Set this option to <code>false</code> to disable merging of pull requests<br>from forked repositories. The default value is <code>true</code>.</li><li><code>MERGE_RETRIES</code> and <code>MERGE_RETRY_SLEEP</code>: Sometimes, the pull request check<br>runs haven’t finished yet, so the action will retry the merge after some time.<br>The number of retries can be set with <code>MERGE_RETRIES</code>.<br>The default number of retries is <code>6</code> and setting it to <code>0</code> disables the retry logic.<br><code>MERGE_RETRY_SLEEP</code> sets the time to sleep between retries, in milliseconds.<br>The default is <code>5000</code> (5 seconds) and setting it to <code>0</code> disables sleeping<br>between retries.</li><li><code>MERGE_DELETE_BRANCH</code>: Automatic deletion of branches does not work for all<br>repositories. Set this option to <code>true</code> to automatically delete branches<br>after they have been merged. The default value is <code>false</code>.</li></ul><p>The following update options are supported:</p><ul><li><code>UPDATE_LABELS</code>: The labels that need to be present for a pull request to be<br>updated (using <code>UPDATE_METHOD</code>). The default value is <code>automerge</code>.<br>Note that updating will only happen when the option “Require branches to be<br>up to date before merging” is enabled in the branch protection rules.<br>This option can be a comma-separated list of labels, see the <code>MERGE_LABELS</code><br>option for more information.</li><li><code>UPDATE_METHOD</code>: Which method to use when updating the pull request<br>to the base branch. Possible values are <code>merge</code> (create a merge commit) or<br><code>rebase</code> (rebase the branch onto the head of the base branch). The default<br>option is <code>merge</code>.<br>When the option is <code>rebase</code> and the <a href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing">rebasing</a><br>failed, the action will exit with error code 1. This will also be visible<br>in the pull request page, with a message like “this branch has conflicts<br>that must be resolved” and a list of conflicting files.</li><li><code>UPDATE_RETRIES</code> and <code>UPDATE_RETRY_SLEEP</code>: Sometimes, the pull request check<br>runs haven’t finished yet and the action doesn’t know if an update is<br>necessary. To query the pull request state multiple times, the number of<br>retries can be set with <code>UPDATE_RETRIES</code>. The default number of retries is <code>1</code><br>and setting it to <code>0</code> disables the retry logic.<br><code>UPDATE_RETRY_SLEEP</code> sets the time to sleep between retries, in milliseconds.<br>The default is <code>5000</code> (5 seconds) and setting it to <code>0</code> disables sleeping<br>between retries.</li></ul><p>Also, the following general options are supported:</p><ul><li><code>GITHUB_TOKEN</code>: This should always be <code>&quot;$&#123;&#123; secrets.GITHUB_TOKEN &#125;&#125;&quot;</code>.<br>However, in some cases it can be useful to run this action as a certain user<br>(by default, it will run as <code>github-actions</code>). This can be useful if you want<br>to use the “Restrict who can push to matching branches” option in the branch<br>protection rules, for example.<br>To use this setting for manually providing a token, you need to create a<br><a href="https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line">personal access token</a><br>for the user (make sure to check <code>public_repo</code> when it’s a public repository<br>or <code>repo</code> when it’s a private repository). All API requests (merge/rebase)<br>will then be executed as the specified user. The token should be kept secret,<br>so make sure to add it as secret, not as environment variable, in the GitHub<br>workflow file!</li></ul><p>You can configure the environment variables in the workflow file like this:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">env:</span></span><br><span class="line">  <span class="attr">GITHUB_TOKEN:</span> <span class="string">&quot;$<span class="template-variable">&#123;&#123; secrets.GITHUB_TOKEN &#125;&#125;</span>&quot;</span></span><br><span class="line">  <span class="attr">MERGE_LABELS:</span> <span class="string">&quot;automerge,!work in progress&quot;</span></span><br><span class="line">  <span class="attr">MERGE_REMOVE_LABELS:</span> <span class="string">&quot;automerge&quot;</span></span><br><span class="line">  <span class="attr">MERGE_METHOD:</span> <span class="string">&quot;squash&quot;</span></span><br><span class="line">  <span class="attr">MERGE_COMMIT_MESSAGE:</span> <span class="string">&quot;pull-request-description&quot;</span></span><br><span class="line">  <span class="attr">MERGE_FORKS:</span> <span class="string">&quot;false&quot;</span></span><br><span class="line">  <span class="attr">MERGE_RETRIES:</span> <span class="string">&quot;6&quot;</span></span><br><span class="line">  <span class="attr">MERGE_RETRY_SLEEP:</span> <span class="string">&quot;10000&quot;</span></span><br><span class="line">  <span class="attr">UPDATE_LABELS:</span> <span class="string">&quot;&quot;</span></span><br><span class="line">  <span class="attr">UPDATE_METHOD:</span> <span class="string">&quot;rebase&quot;</span></span><br></pre></td></tr></table></figure><h2 id="Supported-Events">Supported Events<a class="fa-solid fa-hashtag" href="#Supported-Events"></a></h2><p>Automerge can be configured to run for these events:</p><ul><li><code>check_run</code></li><li><code>check_suite</code></li><li><code>issue_comment</code></li><li><code>pull_request_review</code></li><li><code>pull_request_target</code></li><li><code>pull_request</code></li><li><code>push</code></li><li><code>repository_dispatch</code></li><li><code>schedule</code></li><li><code>status</code></li><li><code>workflow_dispatch</code></li></ul><p>For more information on when these occur, see the Github documentation on <a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows">events that trigger workflows</a> and <a href="https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads">their payloads</a>.</p><h2 id="Limitations">Limitations<a class="fa-solid fa-hashtag" href="#Limitations"></a></h2><ul><li>When a pull request is merged by this action, the merge will not trigger other GitHub workflows.<br>Similarly, when another GitHub workflow creates a pull request, this action will not be triggered.<br>This is because <a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows">an action in a workflow run can’t trigger a new workflow run</a>. However, the <code>[workflow_run](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#workflow_run)</code> event is triggered as expected.</li><li>When <a href="https://help.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token">using a personal access token (PAT) to work around the above limitation</a>, note that when the user issuing the PAT is an administrator and <a href="https://help.github.com/en/github/administering-a-repository/enabling-branch-restrictions">branch restrictions do not include administrators</a>, pull requests may be merged even if they are not mergeable for non-administrators (see <a href="https://github.com/pascalgn/automerge-action/issues/65">#65</a>).</li><li>Currently, there is no way to trigger workflows when the pull request branch<br>becomes out of date with the base branch. There is a request in the<br><a href="https://github.community/t5/GitHub-Actions/New-Trigger-is-mergable-state/m-p/36908">GitHub community forum</a>.</li></ul><h2 id="Debugging">Debugging<a class="fa-solid fa-hashtag" href="#Debugging"></a></h2><p>To run the action with full debug logging, update your workflow file as follows:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">- name: automerge</span><br><span class="line">  uses: pascalgn/automerge-action@...</span><br><span class="line">  with:</span><br><span class="line">    args: &quot;--trace&quot;</span><br></pre></td></tr></table></figure><p>If you need to further debug the action, you can run it locally.</p><p>You will need a <a href="https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line">personal access token</a>.</p><p>Then clone this repository, create a file <code>.env</code> in the repository, such as:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GITHUB_TOKEN=&quot;123abc...&quot;</span><br><span class="line">URL=&quot;https://github.com/pascalgn/repository-name/pull/123&quot;</span><br></pre></td></tr></table></figure><p>Install dependencies with <code>yarn</code>, and finally run <code>yarn it</code> (or <code>npm run it</code>).</p><h2 id="License">License<a class="fa-solid fa-hashtag" href="#License"></a></h2><p><a href="LICENSE">MIT</a></p><h1>bulldozer</h1><p><img src="https://cdn.nlark.com/yuque/0/2021/svg/8391407/1610874951039-f74d3099-f28f-4856-ade7-6c677ce4869d.svg" alt="" loading="lazy"> <img src="https://img.shields.io/docker/pulls/palantirtechnologies/bulldozer.svg" alt="" loading="lazy"></p><p><code>bulldozer</code> is a <a href="https://developer.github.com/apps/">GitHub App</a> that</p><p>automatically merges pull requests (PRs) when (and only when) all required</p><p>status checks are successful and required reviews are provided.</p><p>Additionally, <code>bulldozer</code> can:</p><ul><li>Only merge pull requests that match certain conditions, like having a<br>specific label or comment</li><li>Ignore pull requests that match certain conditions, like having a specific<br>label or comment</li><li>Automatically keep pull request branches up-to-date by merging in the target<br>branch</li><li>Wait for additional status checks that are not required by GitHub</li></ul><p>Bulldozer might be useful if you:</p><ul><li>Have CI builds that take longer than the normal review process. It will merge<br>reviewed PRs as soon as the tests pass so you don’t have to watch the pull<br>request or remember to merge it later.</li><li>Combine it with <a href="https://github.com/palantir/policy-bot">policy-bot</a> to<br>automatically merge certain types of pre-approved or automated changes.</li><li>Want to give contributors more control over when they can merge PRs without<br>granting them write access to the repository.</li><li>Have a lot of active development that makes it difficult to merge a pull<br>request while it is up-to-date with the target branch.</li></ul><h2 id="Contents">Contents<a class="fa-solid fa-hashtag" href="#Contents"></a></h2><ul><li><a href="#behavior">Behavior</a></li><li><a href="#configuration">Configuration</a><ul><li><a href="#bulldozeryml-specification">bulldozer.yml Specification</a></li></ul></li><li><a href="#faq">FAQ</a></li><li><a href="#deployment">Deployment</a></li><li><a href="#development">Development</a></li><li><a href="#contributing">Contributing</a></li><li><a href="#license">License</a></li></ul><h2 id="Behavior">Behavior<a class="fa-solid fa-hashtag" href="#Behavior"></a></h2><p><code>bulldozer</code> will only merge pull requests that GitHub allows non-admin</p><p>collaborators to merge. This means that all branch protection settings,</p><p>including required status checks and required reviews, are respected. It also</p><p>means that you <em>must</em> enable branch protection to prevent <code>bulldozer</code> from</p><p>immediately merging every pull request.</p><p>Only pull requests matching the trigger conditions (or <em>not</em> matching</p><p>ignore conditions) are considered for merging. <code>bulldozer</code> is event-driven,</p><p>which means it will usually merge a pull request within a few seconds of the</p><p>pull request satisfying all preconditions.</p><h2 id="Configuration-2">Configuration<a class="fa-solid fa-hashtag" href="#Configuration-2"></a></h2><p>The behavior of the bot is configured by a <code>.bulldozer.yml</code> file at the root of</p><p>the repository. The file name and location are configurable when running your</p><p>own instance of the server.</p><p>The <code>.bulldozer.yml</code> file is read from the most recent commit on the target</p><p>branch of each pull request. If <code>bulldozer</code> cannot find a configuration file,</p><p>it will take no action. This means it is safe to enable the <code>bulldozer</code> on all</p><p>repositories in an organization.</p><h3 id="bulldozer-yml-Specification">bulldozer.yml Specification<a class="fa-solid fa-hashtag" href="#bulldozer-yml-Specification"></a></h3><p>The <code>.bulldozer.yml</code> file supports the following keys.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># &quot;version&quot; is the configuration version, currently &quot;1&quot;.</span></span><br><span class="line"><span class="attr">version:</span> <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># &quot;merge&quot; defines how and when pull requests are merged. If the section is</span></span><br><span class="line"><span class="comment"># missing, bulldozer will consider all pull requests and use default settings.</span></span><br><span class="line"><span class="attr">merge:</span></span><br><span class="line">  <span class="comment"># &quot;trigger&quot; defines the set of pull requests considered by bulldozer. If</span></span><br><span class="line">  <span class="comment"># the section is missing, bulldozer considers all pull requests not excluded</span></span><br><span class="line">  <span class="comment"># by the ignore conditions.</span></span><br><span class="line">  <span class="attr">trigger:</span></span><br><span class="line">    <span class="comment"># Pull requests with any of these labels (case-insensitive) are added to</span></span><br><span class="line">    <span class="comment"># the trigger.</span></span><br><span class="line">    <span class="attr">labels:</span> [<span class="string">&quot;merge when ready&quot;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Pull requests where the body or any comment contains any of these</span></span><br><span class="line">    <span class="comment"># substrings are added to the trigger.</span></span><br><span class="line">    <span class="attr">comment_substrings:</span> [<span class="string">&quot;==MERGE_WHEN_READY==&quot;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Pull requests where any comment matches one of these exact strings are</span></span><br><span class="line">    <span class="comment"># added to the trigger.</span></span><br><span class="line">    <span class="attr">comments:</span> [<span class="string">&quot;Please merge this pull request!&quot;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Pull requests where the body contains any of these substrings are added</span></span><br><span class="line">    <span class="comment"># to the trigger.</span></span><br><span class="line">    <span class="attr">pr_body_substrings:</span> [<span class="string">&quot;==MERGE_WHEN_READY==&quot;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Pull requests targeting any of these branches are added to the trigger.</span></span><br><span class="line">    <span class="attr">branches:</span> [<span class="string">&quot;develop&quot;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Pull requests targeting branches matching any of these regular expressions are added to the trigger.</span></span><br><span class="line">    <span class="attr">branch_patterns:</span> [<span class="string">&quot;feature/.*&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="comment"># &quot;ignore&quot; defines the set of pull request ignored by bulldozer. If the</span></span><br><span class="line">  <span class="comment"># section is missing, bulldozer considers all pull requests. It takes the</span></span><br><span class="line">  <span class="comment"># same keys as the &quot;trigger&quot; section.</span></span><br><span class="line">  <span class="attr">ignore:</span></span><br><span class="line">    <span class="attr">labels:</span> [<span class="string">&quot;do not merge&quot;</span>]</span><br><span class="line">    <span class="attr">comment_substrings:</span> [<span class="string">&quot;==DO_NOT_MERGE==&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="comment"># &quot;method&quot; defines the merge method. The available options are &quot;merge&quot;,</span></span><br><span class="line">  <span class="comment"># &quot;rebase&quot;, &quot;squash&quot;, and &quot;ff-only&quot;.</span></span><br><span class="line">  <span class="attr">method:</span> <span class="string">squash</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># Allows the merge method that is used when auto-merging a PR to be different based on the</span></span><br><span class="line">  <span class="comment"># target branch. The keys of the hash are the target branch name, and the values are the merge method that</span></span><br><span class="line">  <span class="comment"># will be used for PRs targeting that branch. The valid values are the same as for the &quot;method&quot; key.</span></span><br><span class="line">  <span class="comment"># <span class="doctag">Note:</span> If the target branch does not match any of the specified keys, the &quot;method&quot; key is used instead.</span></span><br><span class="line">  <span class="attr">branch_method:</span></span><br><span class="line">    <span class="attr">develop:</span> <span class="string">squash</span></span><br><span class="line">    <span class="attr">master:</span> <span class="string">merge</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># &quot;options&quot; defines additional options for the individual merge methods.</span></span><br><span class="line">  <span class="attr">options:</span></span><br><span class="line">    <span class="comment"># &quot;squash&quot; options are only used when the merge method is &quot;squash&quot;</span></span><br><span class="line">    <span class="attr">squash:</span></span><br><span class="line">      <span class="comment"># &quot;title&quot; defines how the title of the commit message is created when</span></span><br><span class="line">      <span class="comment"># generating a squash commit. The options are &quot;pull_request_title&quot;,</span></span><br><span class="line">      <span class="comment"># &quot;first_commit_title&quot;, and &quot;github_default_title&quot;. The default is</span></span><br><span class="line">      <span class="comment"># &quot;pull_request_title&quot;.</span></span><br><span class="line">      <span class="attr">title:</span> <span class="string">&quot;pull_request_title&quot;</span></span><br><span class="line"></span><br><span class="line">      <span class="comment"># &quot;body&quot; defines how the body of the commit message is created when</span></span><br><span class="line">      <span class="comment"># generating a squash commit. The options are &quot;pull_request_body&quot;,</span></span><br><span class="line">      <span class="comment"># &quot;summarize_commits&quot;, and &quot;empty_body&quot;. The default is &quot;empty_body&quot;.</span></span><br><span class="line">      <span class="attr">body:</span> <span class="string">&quot;empty_body&quot;</span></span><br><span class="line"></span><br><span class="line">      <span class="comment"># If &quot;body&quot; is &quot;pull_request_body&quot;, then the commit message will be the</span></span><br><span class="line">      <span class="comment"># part of the pull request body surrounded by &quot;message_delimiter&quot;</span></span><br><span class="line">      <span class="comment"># strings. This is disabled (empty string) by default.</span></span><br><span class="line">      <span class="attr">message_delimiter:</span> <span class="string">==COMMIT_MSG==</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># &quot;required_statuses&quot; is a list of additional status contexts that must pass</span></span><br><span class="line">  <span class="comment"># before bulldozer can merge a pull request. This is useful if you want to</span></span><br><span class="line">  <span class="comment"># require extra testing for automated merges, but not for manual merges.</span></span><br><span class="line">  <span class="attr">required_statuses:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&quot;ci/circleci: ete-tests&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># If true, bulldozer will delete branches after their pull requests merge.</span></span><br><span class="line">  <span class="attr">delete_after_merge:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># &quot;update&quot; defines how and when to update pull request branches. Unlike with</span></span><br><span class="line"><span class="comment"># merges, if this section is missing, bulldozer will not update any pull requests.</span></span><br><span class="line"><span class="attr">update:</span></span><br><span class="line">  <span class="comment"># &quot;trigger&quot; defines the set of pull requests that should be updated by</span></span><br><span class="line">  <span class="comment"># bulldozer. It accepts the same keys as the trigger in the &quot;merge&quot; block.</span></span><br><span class="line">  <span class="attr">trigger:</span></span><br><span class="line">    <span class="attr">labels:</span> [<span class="string">&quot;WIP&quot;</span>, <span class="string">&quot;Update Me&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="comment"># &quot;ignore&quot; defines the set of pull requests that should not be updated by</span></span><br><span class="line">  <span class="comment"># bulldozer. It accepts the same keys as the ignore in the &quot;merge&quot; block.</span></span><br><span class="line">  <span class="attr">ignore:</span></span><br><span class="line">    <span class="attr">labels:</span> [<span class="string">&quot;Do Not Update&quot;</span>]</span><br></pre></td></tr></table></figure><h2 id="FAQ">FAQ<a class="fa-solid fa-hashtag" href="#FAQ"></a></h2><h4 id="Can-I-specify-both-ignore-and-trigger">Can I specify both <code>ignore</code> and <code>trigger</code>?<a class="fa-solid fa-hashtag" href="#Can-I-specify-both-ignore-and-trigger"></a></h4><p>Yes. If both <code>ignore</code> and <code>trigger</code> are specified, bulldozer will attempt to match</p><p>on both. In cases where both match, <code>ignore</code> will take precedence.</p><h4 id="Can-I-specify-the-body-of-the-commit-when-using-the-squash-strategy">Can I specify the body of the commit when using the <code>squash</code> strategy?<a class="fa-solid fa-hashtag" href="#Can-I-specify-the-body-of-the-commit-when-using-the-squash-strategy"></a></h4><p>Yes. When the merge strategy is <code>squash</code>, you can set additional options under the</p><p><code>options.squash</code> property, including how to render the commit body.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">merge:</span></span><br><span class="line">  <span class="attr">method:</span> <span class="string">squash</span></span><br><span class="line">  <span class="attr">options:</span></span><br><span class="line">    <span class="attr">squash:</span></span><br><span class="line">      <span class="attr">body:</span> <span class="string">summarize_commits</span> <span class="comment"># or `pull_request_body`, `empty_body`</span></span><br></pre></td></tr></table></figure><p>You can also define part of pull request body to pick as a commit message when</p><p><code>body</code> is <code>pull_request_body</code>.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">merge:</span></span><br><span class="line">  <span class="attr">method:</span> <span class="string">squash</span></span><br><span class="line">  <span class="attr">options:</span></span><br><span class="line">    <span class="attr">squash:</span></span><br><span class="line">      <span class="attr">body:</span> <span class="string">pull_request_body</span></span><br><span class="line">      <span class="attr">message_delimiter:</span> <span class="string">==COMMIT_MSG==</span></span><br></pre></td></tr></table></figure><p>Anything that’s contained between two <code>==COMMIT_MSG==</code> strings will become the</p><p>commit message instead of whole pull request body.</p><h4 id="What-if-I-don’t-want-to-put-config-files-into-each-repo">What if I don’t want to put config files into each repo?<a class="fa-solid fa-hashtag" href="#What-if-I-don’t-want-to-put-config-files-into-each-repo"></a></h4><p>You can add default repository configuration in your bulldozer config file.</p><p>It will be used only when your repo config file does not exist.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">options:</span></span><br><span class="line">  <span class="attr">default_repository_config:</span></span><br><span class="line">    <span class="attr">ignore:</span></span><br><span class="line">      <span class="attr">labels:</span> [<span class="string">&quot;do not merge&quot;</span>] <span class="comment"># or any other available config.</span></span><br></pre></td></tr></table></figure><h4 id="Bulldozer-isn’t-merging-my-commit-when-it-should-what-could-be-happening">Bulldozer isn’t merging my commit when it should, what could be happening?<a class="fa-solid fa-hashtag" href="#Bulldozer-isn’t-merging-my-commit-when-it-should-what-could-be-happening"></a></h4><p>Bulldozer will attempt to merge a branch whenever it passes the trigger/ignore</p><p>criteria. GitHub may prevent it from merging a branch in certain conditions, some of</p><p>which are to be expected, and others that may be caused by mis-configuring Bulldozer.</p><ul><li>Required status checks have not passed</li><li>Review requirements are not satisfied</li><li>The merge strategy configured in <code>.bulldozer.yml</code> is not allowed by your<br>repository settings</li><li>Branch protection rules are preventing <code>bulldozer[bot]</code> from <a href="https://help.github.com/articles/about-branch-restrictions/">pushing to the<br>branch</a>. Github apps can be added to the list of restricted<br>push users, so you can allow Bulldozer specifically for your repo.</li></ul><h4 id="Bulldozer-isn’t-updating-my-branch-when-it-should-what-could-be-happening">Bulldozer isn’t updating my branch when it should, what could be happening?<a class="fa-solid fa-hashtag" href="#Bulldozer-isn’t-updating-my-branch-when-it-should-what-could-be-happening"></a></h4><p>When using the branch update functionality, Bulldozer only acts when the target</p><p>branch is updated <em>after</em> updates are enabled for the pull request. For</p><p>example:</p><ol><li>User A opens a pull request targetting <code>develop</code></li><li>User B pushes a commit to <code>develop</code></li><li>User A adds the <code>update me</code> label to the first pull request</li><li>User C pushes a commit to <code>develop</code></li><li>Bulldozer updates the pull request with the commits from Users B and C</li></ol><p>Note that the update does <em>not</em> happen when the <code>update me</code> label is added,</p><p>even though there is a new commit on <code>develop</code> that is not part of the pull</p><p>request.</p><h4 id="Can-Bulldozer-work-with-push-restrictions-on-branches">Can Bulldozer work with push restrictions on branches?<a class="fa-solid fa-hashtag" href="#Can-Bulldozer-work-with-push-restrictions-on-branches"></a></h4><p>As mentioned above, as of Github ~2.19.x, GitHub Apps <em>can</em> be added to the list of users associated</p><p>with <a href="https://help.github.com/articles/about-branch-restrictions/">push restrictions</a>. If you don’t want to do this, or if you’re running</p><p>an older version of Github that doesn’t support this behaviour, you may work</p><p>around this:</p><ol><li>Use another app like <a href="https://github.com/palantir/policy-bot">policy-bot</a> to<br>implement <em>approval</em> restrictions as required status checks instead of using<br>push restrictions. This effectively limits who can push to a branch by<br>requiring changes to go through the pull request process and be approved.</li><li>Configure Bulldozer to use a personal access token for a regular user to<br>perform merges in this case. The token must have the <code>repo</code> scope and the<br>user must be allowed to push to the branch. In the server configuration<br>file, set:</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">options:</span></span><br><span class="line">  <span class="attr">push_restriction_user_token:</span> <span class="string">&lt;token-value&gt;</span></span><br></pre></td></tr></table></figure><ol start="2"><li>The token is <em>only</em> used if the target branch has push restrictions enabled.<br>All other merges are performed as the normal GitHub App user.</li></ol><h2 id="Deployment">Deployment<a class="fa-solid fa-hashtag" href="#Deployment"></a></h2><p>bulldozer is easy to deploy in your own environment as it has no dependencies</p><p>other than GitHub. It is also safe to run multiple instances of the server,</p><p>making it a good fit for container schedulers like Nomad or Kubernetes.</p><p>We provide both a Docker container and a binary distribution of the server:</p><ul><li>Binaries: <a href="https://bintray.com/palantir/releases/bulldozer">https://bintray.com/palantir/releases/bulldozer</a></li><li>Docker Images: <a href="https://hub.docker.com/r/palantirtechnologies/bulldozer/">https://hub.docker.com/r/palantirtechnologies/bulldozer/</a></li></ul><p>A sample configuration file is provided at <code>config/bulldozer.example.yml</code>.</p><p>Certain values may also be set by environment variables; these are noted in the</p><p>comments in the sample configuration file.</p><h3 id="GitHub-App-Configuration">GitHub App Configuration<a class="fa-solid fa-hashtag" href="#GitHub-App-Configuration"></a></h3><p>To configure Bulldozer as a GitHub App, these general options are required:</p><ul><li><strong>Webhook URL</strong>: <code>http(s)://&lt;your-bulldozer-domain&gt;/api/github/hook</code></li><li><strong>Webhook secret</strong>: A random string that matches the value of the<br><code>github.app.webhook_secret</code> property in the server configuration</li></ul><p>The app requires these permissions:</p><table><thead><tr><th>Permission</th><th>Access</th><th>Reason</th></tr></thead><tbody><tr><td>Repository administration</td><td>Read-only</td><td>Determine required status checks</td></tr><tr><td>Checks</td><td>Read-only</td><td>Read checks for ref</td></tr><tr><td>Repository contents</td><td>Read &amp; write</td><td>Read configuration, perform merges</td></tr><tr><td>Issues</td><td>Read &amp; write</td><td>Read comments, close linked issues</td></tr><tr><td>Repository metadata</td><td>Read-only</td><td>Basic repository data</td></tr><tr><td>Pull requests</td><td>Read &amp; write</td><td>Merge and close pull requests</td></tr><tr><td>Commit status</td><td>Read-only</td><td>Evaluate pull request status</td></tr></tbody></table><p>The app should be subscribed to these events:</p><ul><li>Check run</li><li>Commit comment</li><li>Pull request</li><li>Status</li><li>Push</li><li>Issue comment</li><li>Pull request review</li><li>Pull request review comment</li></ul><h3 id="Operations">Operations<a class="fa-solid fa-hashtag" href="#Operations"></a></h3><p>bulldozer uses <a href="https://github.com/palantir/go-baseapp">go-baseapp</a> and</p><p><a href="https://github.com/palantir/go-githubapp">go-githubapp</a>, both of which emit</p><p>standard metrics and structured log keys. Please see those projects for</p><p>details.</p><h3 id="Example-Files">Example Files<a class="fa-solid fa-hashtag" href="#Example-Files"></a></h3><p>Example <code>.bulldozer.yml</code> files can be found in <code>[config/examples](https://github.com/palantir/bulldozer/tree/develop/config/examples)</code></p><h3 id="Migrating-Version-0-4-X-to-1-X">Migrating: Version 0.4.X to 1.X<a class="fa-solid fa-hashtag" href="#Migrating-Version-0-4-X-to-1-X"></a></h3><p>The server configuration for bulldozer allows you to specify <code>configuration_v0_path</code>, which is a list of paths</p><p>to check for <code>0.4.X</code> style bulldozer configuration. When a <code>1.X</code> style configuration file does not appear</p><p>at the configured path, bulldozer will attempt to read from the paths configured by <code>configuration_v0_path</code>,</p><p>converting the legacy configuration into an equivalent <code>v1</code> configuration internally.</p><p>The upgrade process is therefore to deploy the latest version of bulldozer with both <code>configuration_path</code> and</p><p><code>configuration_v0_path</code> configured, and to enable the bulldozer GitHub App on all organizations where it was</p><p>previously installed.</p><h2 id="Development">Development<a class="fa-solid fa-hashtag" href="#Development"></a></h2><p>To develop <code>bulldozer</code>, you will need a <a href="https://golang.org/doc/install">Go installation</a>.</p><p><strong>Run style checks and tests</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./godelw verify</span><br></pre></td></tr></table></figure><p><strong>Running the server locally</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># copy and edit the server config</span><br><span class="line">cp config/bulldozer.example.yml config/bulldozer.yml</span><br><span class="line"></span><br><span class="line">./godelw run bulldozer server</span><br></pre></td></tr></table></figure><ul><li><code>config/bulldozer.yml</code> is used as the default configuration file</li><li>The server is available at <code>http://localhost:8080/</code></li></ul><p><strong>Running the server via Docker</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># copy and edit the server config</span><br><span class="line">cp config/bulldozer.example.yml config/bulldozer.yml</span><br><span class="line"></span><br><span class="line"># build the docker image</span><br><span class="line">./godelw docker build --verbose</span><br><span class="line"></span><br><span class="line">docker run --rm -v &quot;$(pwd)/config:/secrets/&quot; -p 8080:8080 palantirtechnologies/bulldozer:latest</span><br></pre></td></tr></table></figure><ul><li>This mounts the <code>config</code> directory (which should contain the <code>bulldozer.yml</code> configuration file) at the expected location</li><li>The server is available at <code>http://localhost:8080/</code></li></ul><h2 id="Contributing">Contributing<a class="fa-solid fa-hashtag" href="#Contributing"></a></h2><p>Contributions and issues are welcome. For new features or large contributions,</p><p>we prefer discussing the proposed change on a GitHub issue prior to a PR.</p><h2 id="License-2">License<a class="fa-solid fa-hashtag" href="#License-2"></a></h2><p>This application is made available under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>.</p><h1>probot-auto-merge</h1><p><img src="https://travis-ci.org/bobvanderlinden/probot-auto-merge.svg?branch=master" alt="" loading="lazy"></p><p><img src="https://img.shields.io/coveralls/github/bobvanderlinden/probot-auto-merge.svg" alt="" loading="lazy"></p><p>A GitHub App built with <a href="https://github.com/probot/probot">Probot</a> that automatically merges PRs</p><blockquote><p><img src="/" alt="" loading="lazy"></p></blockquote><h2 id="Usage-2">Usage<a class="fa-solid fa-hashtag" href="#Usage-2"></a></h2><ol><li><a href="https://github.com/apps/probot-auto-merge">Configure the GitHub App</a></li><li>Create <code>.github/auto-merge.yml</code> in your repository.</li><li>Customize configuration to your needs. See below.</li></ol><h2 id="Configuration-3">Configuration<a class="fa-solid fa-hashtag" href="#Configuration-3"></a></h2><p>Configuration of <code>probot-auto-merge</code> is done through <code>.github/auto-merge.yml</code> in</p><p>your repository. An example of this file can be found <a href="auto-merge.example.yml">here</a>.</p><p>You can also see the configuration for this repository <a href=".github/auto-merge.yml">here</a>.</p><p>The configuration has values that serve as conditions on whether or not a pull request</p><p>should be automatically merged and also configuration about the merge itself. Values</p><p>that serve as conditions are annotated as such below.</p><p>All conditions must be met before a PR will be automatically merged. You can get more</p><p>flexibility by defining multiple rules. Rules can have multiple conditions and if any</p><p>of the conditions inside a rule are met, the PR is also merged. See <a href="#rules-default-none">rules</a>.</p><p>If the target branch is a protected branch, you must add <code>probot-auto-merge</code> bot to</p><p>the list of <code>People, teams or apps with push access</code> in your branch protection rules.</p><p>Note that the default configuration options are to do nothing. This is to prevent</p><p>implicit and possibly unintended behavior.</p><p>The configuration fields are as follows:</p><h3 id="minApprovals-required-condition"><code>minApprovals</code> (required, condition)<a class="fa-solid fa-hashtag" href="#minApprovals-required-condition"></a></h3><p>The minimum number of reviews from each association that approve the pull request before</p><p>doing an automatic merge. For more information about associations see:</p><p><a href="https://developer.github.com/v4/enum/commentauthorassociation/">https://developer.github.com/v4/enum/commentauthorassociation/</a></p><p>Possible associations: <code>OWNER</code>, <code>MEMBER</code>, <code>COLLABORATOR</code>, <code>CONTRIBUTOR</code>, <code>FIRST_TIMER</code>, <code>FIRST_TIME_CONTRIBUTOR</code>, <code>NONE</code></p><p>In the example below when a pull request gets 2 approvals from owners, members or collaborators,</p><p>the automatic merge will continue.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">minApprovals:</span></span><br><span class="line">  <span class="attr">COLLABORATOR:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure><p>In the example below when a pull request gets 1 approval from an owner OR 2 approvals from members, the automatic merge will continue.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">minApprovals:</span></span><br><span class="line">  <span class="attr">OWNER:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">MEMBER:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure><h3 id="requiredReviewers-condition-default-none"><code>requiredReviewers</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#requiredReviewers-condition-default-none"></a></h3><p>Whenever required reviewers are configured, pull requests will only be automatically</p><p>merged whenever all of these reviewers have approved the pull request.</p><p>In the example below, pull requests need to have been approved by the user ‘rogerluan’</p><p>before they will be automatically merged.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredReviewers:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">rogerluan</span></span><br></pre></td></tr></table></figure><h3 id="maxRequestedChanges-condition-default-none"><code>maxRequestedChanges</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#maxRequestedChanges-condition-default-none"></a></h3><p>Similar to <code>minApprovals</code>, maxRequestedChanges determines the maximum number of</p><p>requested changes before a pull request will be blocked from being automatically</p><p>merged.</p><p>It yet again allows you to configure this per association.</p><p>Note that <code>maxRequestedChanges</code> takes precedence over <code>minApprovals</code>.</p><p>In the example below, automatic merges will be blocked when one of the owners, members</p><p>or collaborators has requested changes.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">maxRequestedChanges:</span></span><br><span class="line">  <span class="attr">COLLABORATOR:</span> <span class="number">0</span></span><br></pre></td></tr></table></figure><p>In the example below, automatic merges will be blocked when the owner has</p><p>requested changes or two members, collaborators or other users have requested</p><p>changes.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">maxRequestedChanges:</span></span><br><span class="line">  <span class="attr">OWNER:</span> <span class="number">0</span></span><br><span class="line">  <span class="attr">NONE:</span> <span class="number">1</span></span><br></pre></td></tr></table></figure><p>The default for this value is:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">maxRequestedChanges:</span></span><br><span class="line">  <span class="attr">NONE:</span> <span class="number">0</span></span><br></pre></td></tr></table></figure><h3 id="blockingBaseBranches-condition-default-none"><code>blockingBaseBranches</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#blockingBaseBranches-condition-default-none"></a></h3><p>Whenever blocking base branches are configured, pull requests will only be automatically</p><p>merged whenever their base branch (into which the PR would be merged) is not matching</p><p>the patterns listed.</p><p>In the example below, pull requests that have the base branch <code>develop</code> or one that starts</p><p>with <code>feature-</code> will not be merged automatically.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingBaseBranches:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">develop</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">regex:</span> <span class="string">^feature-</span></span><br></pre></td></tr></table></figure><p>Note: remove the whole section when you’re not using blocking base branches.</p><h3 id="requiredBaseBranches-condition-default-none"><code>requiredBaseBranches</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#requiredBaseBranches-condition-default-none"></a></h3><p>Whenever required base branches are configured, pull requests will only be automatically</p><p>merged whenever their base branch (into which the PR would be merged) is matching</p><p>any of the patterns listed.</p><p>In the example below, pull requests need to have the base branch <code>master</code> or one that</p><p>starts with <code>v&#123;number&#125;</code> before they will be automatically merged.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredBaseBranches:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">master</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">regex:</span> <span class="string">^v\d</span></span><br></pre></td></tr></table></figure><h3 id="blockingLabels-condition-default-none"><code>blockingLabels</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#blockingLabels-condition-default-none"></a></h3><p>Blocking labels are the labels that can be attached to a pull request to make</p><p>sure the pull request is not being merged automatically.</p><p>In the example below, pull requests that have the <code>blocked</code> label will not be</p><p>merged automatically.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingLabels:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">blocked</span></span><br></pre></td></tr></table></figure><p>The above example denotes literal label names. Regular expressions can be used to</p><p>partially match labels. This can be specified by the <code>regex:</code> property in the</p><p>configuration. The following example will block merging when a label is added that</p><p>starts with the text <code>blocked</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingLabels:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">regex:</span> <span class="string">^blocked</span></span><br></pre></td></tr></table></figure><p>Note: remove the whole section when you’re not using blocking labels.</p><h3 id="requiredLabels-condition-default-none"><code>requiredLabels</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#requiredLabels-condition-default-none"></a></h3><p>Whenever required labels are configured, pull requests will only be automatically</p><p>merged whenever all of these labels are attached to a pull request.</p><p>In the example below, pull requests need to have the label <code>merge</code> before they</p><p>will be automatically merged.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredLabels:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">merge</span></span><br></pre></td></tr></table></figure><p>The above example denotes literal label names. Regular expressions can be used to</p><p>partially match labels. This requires <code>regex:</code> property in the configuration. The</p><p>following example will requires at least one label that starts with <code>merge</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredLabels:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">regex:</span> <span class="string">^merge</span></span><br></pre></td></tr></table></figure><p>Note: remove the whole section when you’re not using required labels.</p><h3 id="blockingTitleRegex-condition-default-none"><code>blockingTitleRegex</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#blockingTitleRegex-condition-default-none"></a></h3><p>Whenever a blocking title regular expression is configured, pull requests that have a title</p><p>matching the configured expression will not be automatically merged.</p><p>This is useful whenever pull requests with <code>WIP</code> in their title need to be skipped.</p><p>In the example below, pull requests with the word <code>wip</code> in the title will not be</p><p>automatically merged. This also includes <code>[wip]</code>, <code>WIP</code> or <code>[WIP]</code>, but not <code>swiping</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingTitleRegex:</span> <span class="string">&#x27;\bWIP\b&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="requiredTitleRegex-condition-default-none"><code>requiredTitleRegex</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#requiredTitleRegex-condition-default-none"></a></h3><p>Whenever a required title regular expression is configured, only pull requests that have a title</p><p>matching the configured expression will automatically be merged.</p><p>This is useful for forks, that can only create pull request text, no labels.</p><p>In the example below, pull requests with the title containing <code>MERGE</code> will be</p><p>automatically merged. This also includes This also includes <code>[merge]</code>, <code>MERGE</code> or <code>[MERGE]</code>, but not <code>submerge</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredTitleRegex:</span> <span class="string">&#x27;\bMERGE\b&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="blockingBodyRegex-condition-default-none"><code>blockingBodyRegex</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#blockingBodyRegex-condition-default-none"></a></h3><p>Whenever a blocking body regular expression is configured, pull requests that have a body</p><p>matching the configured expression will not be automatically merged.</p><p>This is useful whenever pull requests with a certain string in their body need to be skipped.</p><p>In the example below, pull requests with the body containing <code>do-not-merge</code> will not be</p><p>automatically merged. This also includes <code>labels: do-not-merge</code>, <code>LABELS: DO-NOT-MERGE</code> or <code>some more text, but do-not-merge</code>,</p><p>but not <code>do-not-merge-just-kidding</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingBodyRegex:</span> <span class="string">&#x27;(^|\\s)do-not-merge($|\\s)&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="requiredBodyRegex-condition-default-none"><code>requiredBodyRegex</code> (condition, default: none)<a class="fa-solid fa-hashtag" href="#requiredBodyRegex-condition-default-none"></a></h3><p>Whenever a required body regular expression is configured, only pull requests that have a body</p><p>matching the configured expression will automatically be merged.</p><p>This is useful for forks, that can only create pull request text, no labels.</p><p>In the example below, pull requests with the body containing <code>ok-to-merge</code> will be</p><p>automatically merged. This also includes <code>labels: ok-to-merge</code>, <code>LABELS: OK-TO-MERGE</code> or <code>some more text, but ok-to-merge</code>, but not <code>not-ok-to-merge</code>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">requiredBodyRegex:</span> <span class="string">&#x27;(^|\\s)ok-to-merge($|\\s)&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="reportStatus-default-false"><code>reportStatus</code> (default: <code>false</code>)<a class="fa-solid fa-hashtag" href="#reportStatus-default-false"></a></h3><p>The status of the auto-merge process will be shown in each PR as a <a href="https://help.github.com/articles/about-status-checks/">check</a>. This can be especially useful to find out why a PR is not being merged automatically.</p><p>To enable status reporting, add the following to your configuration:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">reportStatus:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="updateBranch-default-false"><code>updateBranch</code> (default: <code>false</code>)<a class="fa-solid fa-hashtag" href="#updateBranch-default-false"></a></h3><p>Whether an out-of-date pull request is automatically updated.</p><p>It does so by merging its base on top of the head of the pull request.</p><p>This is similar to the behavior of the ‘Update branch’ button.</p><p><code>updateBranch</code> is useful for repositories where protected branches are used</p><p>and the option <em>Require branches to be up to date before merging</em> is enabled.</p><p>Note that this only works when the branch of the pull request resides in the same</p><p>repository as the pull request itself.</p><p>In the example below automatic updating of branches is enabled:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">updateBranch:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="deleteBranchAfterMerge-default-false"><code>deleteBranchAfterMerge</code> (default: <code>false</code>)<a class="fa-solid fa-hashtag" href="#deleteBranchAfterMerge-default-false"></a></h3><p>Whether the pull request branch is automatically deleted.</p><p>This is the equivalent of clicking the ‘Delete branch’ button shown on merged</p><p>pull requests.</p><p>Note that this only works when the branch of the pull request resides in the same</p><p>repository as the pull request itself.</p><p>In the example below automatic deletion of pull request branches is enabled:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deleteBranchAfterMerge:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="mergeMethod-default-merge"><code>mergeMethod</code> (default: <code>merge</code>)<a class="fa-solid fa-hashtag" href="#mergeMethod-default-merge"></a></h3><p>In what way a pull request is merged. This can be:</p><ul><li><code>merge</code>: creates a merge commit, combining the commits from the pull request on top of<br>the base of the pull request (default)</li><li><code>rebase</code>: places the commits from the pull request individually on top of the base of the pull request</li><li><code>squash</code>: combines all changes from the pull request into a single commit and places the commit on top<br>of the base of the pull request</li></ul><p>For more information see <a href="https://help.github.com/articles/about-pull-request-merges/">https://help.github.com/articles/about-pull-request-merges/</a></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mergeMethod:</span> <span class="string">merge</span></span><br></pre></td></tr></table></figure><h3 id="mergeCommitMessage-default-none"><code>mergeCommitMessage</code> (default: none)<a class="fa-solid fa-hashtag" href="#mergeCommitMessage-default-none"></a></h3><p>Optionally specify the merge commit message format. The following template tags</p><p>are supported:</p><ul><li><code>&#123;title&#125;</code>: The pull request title at the moment it is merged</li><li><code>&#123;body&#125;</code>: The pull request body at the moment it is merged</li><li><code>&#123;number&#125;</code>: The pull request number</li><li><code>&#123;branch&#125;</code>: The name of the source branch</li><li><code>&#123;commits&#125;</code>: A list of merged commits</li></ul><p>When this option is not set, the merge commit message is controlled by</p><p>GitHub and uses a combination of the title of the pull request when it was</p><p>opened (note that later changes to the title are ignored) and a list of</p><p>commits.</p><p>This settings is ignored when <code>mergeMethod</code> is set to <code>rebase</code>.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mergeCommitMessage:</span> <span class="string">|</span></span><br><span class="line"><span class="string">  &#123;title&#125; (#&#123;number&#125;)</span></span><br><span class="line"><span class="string">  &#123;body&#125;</span></span><br></pre></td></tr></table></figure><h3 id="rules-default-none"><code>rules</code> (default: none)<a class="fa-solid fa-hashtag" href="#rules-default-none"></a></h3><p>Rules allow more flexibility configuring conditions for automatically merging. Each rule is defined by</p><p>multiple conditions. All conditions inside a rule must be met before a rule triggers a merge. Any of the</p><p>defined rules can trigger a merge individually.</p><p>An example of a configuration with 2 rules that will trigger a merge upon 1 approval from an owner <em>or</em> a <code>merge</code> label:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">rules:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">minApprovals:</span></span><br><span class="line">    <span class="attr">OWNER:</span> <span class="number">1</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">requiredLabels:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">merge</span></span><br></pre></td></tr></table></figure><p>This can be combined with conditions on global level, as the global conditions will take precedence. The following example will not trigger a merge when a PR has the <code>blocking</code> label, regardless what the rules say:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blockingLabels:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">blocking</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">minApprovals:</span></span><br><span class="line">    <span class="attr">OWNER:</span> <span class="number">1</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">requiredLabels:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">merge</span></span><br></pre></td></tr></table></figure><p>Note: remove the whole rules section when you’re not using any rules.</p><h3 id="requiredAuthorRole-default-none"><code>requiredAuthorRole</code> (default: none)<a class="fa-solid fa-hashtag" href="#requiredAuthorRole-default-none"></a></h3><p>Using the <code>requiredAuthorRole</code> condition you can specify conditions based on the role of the pull request author.</p><p>For instance, using <code>rules</code>, one can be more loose when the author is an owner, and more restrictive otherwise.</p><p>Here’s an example of a configuration that requires acceptance of 2 owners or 1 owner if the other owner made the PR:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">rules:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">requiredAuthorRole:</span> <span class="string">OWNER</span></span><br><span class="line">  <span class="attr">minApprovals:</span></span><br><span class="line">    <span class="attr">OWNER:</span> <span class="number">1</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">minApprovals:</span></span><br><span class="line">    <span class="attr">OWNER:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure><h2 id="Development-2">Development<a class="fa-solid fa-hashtag" href="#Development-2"></a></h2><h3 id="Setup">Setup<a class="fa-solid fa-hashtag" href="#Setup"></a></h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Install dependencies</span></span><br><span class="line">npm install</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Run typescript</span></span><br><span class="line">npm run build</span><br></pre></td></tr></table></figure><h3 id="Testing">Testing<a class="fa-solid fa-hashtag" href="#Testing"></a></h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run test</span><br></pre></td></tr></table></figure><p>or during development:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run test:watch</span><br></pre></td></tr></table></figure><h3 id="Running">Running<a class="fa-solid fa-hashtag" href="#Running"></a></h3><p>See <a href="https://probot.github.io/docs/development/#configuring-a-github-app">https://probot.github.io/docs/development/#configuring-a-github-app</a></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run build &amp;&amp; npm run dev</span><br></pre></td></tr></table></figure><h3 id="Running-on-Docker">Running on Docker<a class="fa-solid fa-hashtag" href="#Running-on-Docker"></a></h3><p>This will build and run the app on a container called <code>probot-auto-merge</code>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run docker</span><br></pre></td></tr></table></figure><p>To just build the container image:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run docker:build</span><br></pre></td></tr></table></figure><p>To run the built image:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run docker:run</span><br></pre></td></tr></table></figure><h3 id="Running-the-linter">Running the linter<a class="fa-solid fa-hashtag" href="#Running-the-linter"></a></h3><p>This will run the linter, pointing out the infractions, but it won’t fix them automatically.</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run lint</span><br></pre></td></tr></table></figure><h2 id="Deployment-2">Deployment<a class="fa-solid fa-hashtag" href="#Deployment-2"></a></h2><p>To deploy <code>probot-auto-merge</code> yourself, please follow <a href="https://probot.github.io/docs/deployment/">the guidelines defined by Probot on deploying GitHub applications</a>.</p><p>The permissions and events needed for the app to function can be found below.</p><h3 id="Permissions">Permissions<a class="fa-solid fa-hashtag" href="#Permissions"></a></h3><ul><li>Administration: Read-only</li><li>Checks: Read &amp; write</li><li>Contents: Read &amp; write</li><li>Issues: Read &amp; write</li><li>Metadata: Read-only</li><li>Pull requests: Read &amp; write</li><li>Commit statuses: Read-only</li><li>Members: Read-only</li></ul><h3 id="Events">Events<a class="fa-solid fa-hashtag" href="#Events"></a></h3><ul><li>Check run</li><li>Check suite</li><li>Label</li><li>Pull request</li><li>Pull request review</li><li>Pull request review comment</li><li>Status</li></ul><h2 id="Contributing-2">Contributing<a class="fa-solid fa-hashtag" href="#Contributing-2"></a></h2><p>If you have suggestions for how <code>probot-auto-merge</code> could be improved, or want to report a bug, open an issue! We’d love all and any contributions.</p><p>For more, check out the <a href="CONTRIBUTING.md">Contributing Guide</a>.</p><h2 id="License-3">License<a class="fa-solid fa-hashtag" href="#License-3"></a></h2><p><a href="LICENSE">ISC</a> © 2018 Bob van der Linden <a href="mailto:bobvanderlinden@gmail.com">bobvanderlinden@gmail.com</a> (<a href="https://github.com/bobvanderlinden/probot-auto-merge">https://github.com/bobvanderlinden/probot-auto-merge</a>)</p><h1>auto-label-merge-conflicts</h1><blockquote><p>A Github action to auto-label PRs with merge conflicts</p></blockquote><h2 id="Purpose">Purpose<a class="fa-solid fa-hashtag" href="#Purpose"></a></h2><p>This action checks all open Pull Requests for merge conflicts and marks them with a Github label.</p><p><img src="/./demo.png" alt="" loading="lazy"></p><p>Once a conflict is resolved the label is automatically removed.</p><p>The typical use case is to run this action post merge (e.g. push to <code>master</code>) to quickly see which other PRs are now in conflict.</p><p>We use this setup e.g. on our monorepo at <a href="https://github.com/comtravo">Comtravo</a>. Instead of a grumpy CTO pinging developers to fix their merge conflicts there’s now a shiny bot.</p><h2 id="Set-up">Set up<a class="fa-solid fa-hashtag" href="#Set-up"></a></h2><p>To configure the action on your repo you have to do 2 things:</p><ol><li>pick a Github label that should be used to mark PRs with conflicts</li></ol><p>This label will then be managed by this action. It will be added to PRs with merge conflicts and removed from PRs without conflicts.</p><ol start="2"><li>configure the new workflow by creating a YML config file in your <code>.github/workflows</code> folder:</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">master</span></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">triage:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">mschilde/auto-label-merge-conflicts@master</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">CONFLICT_LABEL_NAME:</span> <span class="string">&quot;has conflicts&quot;</span></span><br><span class="line">          <span class="attr">GITHUB_TOKEN:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">MAX_RETRIES:</span> <span class="number">5</span></span><br><span class="line">          <span class="attr">WAIT_MS:</span> <span class="number">5000</span></span><br></pre></td></tr></table></figure><p>The label from step 1 should be referenced in the parameter <code>CONFLICT_LABEL_NAME</code></p><p>Take a look at <a href="https://github.com/mschilde/auto-label-merge-conflicts/blob/master/%2Egithub/workflows/label_merge_conflicts.yml">this repo</a> for an example setup.</p><h3 id="Arguments">Arguments:<a class="fa-solid fa-hashtag" href="#Arguments"></a></h3><ul><li>MAX_RETRIES: optional (default 5)</li><li>WAIT_MS: optional (default 5000)</li></ul><h2 id="Limitations-2">Limitations<a class="fa-solid fa-hashtag" href="#Limitations-2"></a></h2><p>Github does not reliably compute the <code>mergeable</code> status which is used by this action to detect merge conflicts.</p><p>If <code>master</code> changes the mergeable status is unknown until someone (most likely this action) requests it. <a href="https://stackoverflow.com/a/30620973">Github then tries to compute the status with an async job.</a></p><p>This is usually quick and simple, but there are no guarantees and Github might have issues.</p><p>You can tweak <code>MAX_RETRIES</code> and <code>WAIT_MS</code> to increase the timeout before giving up on a Pull Request.</p><h2 id="Local-dev-setup">Local dev setup<a class="fa-solid fa-hashtag" href="#Local-dev-setup"></a></h2><p>To play around with the code base, you need <code>Docker</code> and <code>make</code> set up locally.</p><p>Run <code>make build</code>, <code>make develop</code>, then <code>yarn install</code>.</p><h1>How to use PR Valet</h1><p>Step 1: Install <a href="https://github.com/marketplace/pr-valet">PR Valet</a>.</p><p>Step 2: Add the <code>valet:merge</code> label to your pull request.</p><p>Step 3: Work on your other tasks while PR Valet takes care of merging your pull request.</p><h1><a href="https://docs.mergify.io/">https://docs.mergify.io/</a></h1><h1><a href="https://snyk.io/">https://snyk.io/</a></h1>]]></content><id>https://blog.ccknbc.cc/posts/github-automatically-merges-pull-requests-notes/</id><link href="https://blog.ccknbc.cc/posts/github-automatically-merges-pull-requests-notes/"/><published>2026-08-29T09:30:44.271Z</published><summary>GitHub 自动合并 PR 笔记</summary><title>GitHub 自动合并 PR 笔记</title><updated>2026-08-29T09:30:44.282Z</updated></entry><entry><author><name>CC康纳百川</name></author><content><![CDATA[<p>本文首发在<a href="https://www.yuque.com/ccknbc/blog/23/"><strong>语雀</strong></a></p><p>自动同步更新至<a href="https://blog.ccknbc.cc/posts/awesome-status-pages/"><strong>CC的部落格</strong></a></p><h2 id="Awesome-status-pages">Awesome status pages<a class="fa-solid fa-hashtag" href="#Awesome-status-pages"></a></h2><p>Awesome list of status pages open source software, online services and public status pages of major internet companies</p><h2 id="Opensource">Opensource<a class="fa-solid fa-hashtag" href="#Opensource"></a></h2><ul><li><a href="https://cachethq.io/">Cachet</a> - Laravel based status page system for everyone.</li><li><a href="https://github.com/weeblrpress/clearstatus/">ClearStatus</a> - Hugo-based status page, supports Netlify. Supports events from Github, Gitlab or any git repo with markdown.</li><li><a href="https://github.com/jayfk/statuspage">Corestats</a> - turn GitHub issues into a status page</li><li><a href="https://github.com/cstate/cstate">cState</a> - Simple, dev friendly, and free to host (Netlify &amp; GitHub Pages)</li><li><a href="https://github.com/TwinProduction/gatus">Gatus</a> - Automated service health dashboard</li><li><a href="https://github.com/tadhglewis/issue-status">Issue Status</a> - Simple, modern and flexible status page</li><li><a href="https://github.com/tmobile/kardio">Kardio</a> - Simple Health Status Tool with Rich UI for Services deployed on Kubernetes and other platforms.</li><li><a href="https://lambstatus.github.io">LambStatus</a> (<em>Deprecated</em>)</li><li><a href="https://monitoror.com/">Monitoror</a> - monitoring wallboard</li><li><a href="https://github.com/Pryx/server-status">Server-Status</a></li><li><a href="http://www.stashboard.org/">StashBoard</a> - Python, for Google App Engine (<em>Deprecated</em>)</li><li><a href="https://github.com/Cyclenerd/static_status">Static status</a> - Bash script to generate a static status page</li><li><a href="https://github.com/hunterlong/statping">Statping</a></li><li><a href="https://marquez.co/statusfy">Statusfy</a></li><li><a href="https://github.com/sanathp/statusok">StatusOK</a></li><li><a href="https://github.com/darkpixel/statuspage">statuspage</a> - Simple self-hosted open source status page site written in Django (inspired by <a href="https://cachethq.io/">Cachet</a>)</li><li><a href="https://staytus.co/">Staytus</a>  (<em>Deprecated</em>)</li><li><a href="https://github.com/ianheggie/health_check">health_check</a> - Simple health check of Rails app for use with uptime checking sites like newrelic and pingdom</li><li><a href="https://github.com/rails-engine/status-page">status-page</a> - Mountable status page for your Rails application, to check Cache, Redis, Sidekiq</li><li><a href="https://github.com/lbeder/health-monitor-rails">health-monitor-rails</a> - A Rails plugin which provides a health checking and monitoring API of various services and application aspects</li><li><a href="https://github.com/valeriansaliou/vigil">Vigil</a> - Microservices Status Page. Monitors a distributed infrastructure and sends alerts (Slack, SMS, etc.).</li><li><a href="https://github.com/EvotecIT/Statusimo">Statusimo</a> - A PowerShell module that is able to generate a status page entirely from PowerShell.</li><li><a href="https://github.com/eidam/cf-workers-status-page">Workers Status Page</a> - Cloudflare Workers (completely on the edge) powered monitoring &amp; status page.</li><li><a href="https://github.com/upptime/upptime">Upptime</a> - monitor and status page powered by GitHub</li><li><a href="https://github.com/RatherLogical/Uptimon">Uptimon</a> - A PHP powered status page/monitoring solution.</li><li><a href="https://github.com/bderenzo/tinystatus">Tinystatus</a> - A tiny static status page generator (written in pure shell)</li></ul><h2 id="Services">Services<a class="fa-solid fa-hashtag" href="#Services"></a></h2><ul><li><a href="https://www.adminlabs.com/status-page/">AdminLabs Statuspage</a></li><li><a href="https://www.appbeat.io/">AppBeat Monitoring</a> - uptime monitoring with integrated status page</li><li><a href="https://asserted.io"><s>Asserted.io</s></a>~~ - uptime tests written in Mocha ~~<s><em>(Discontinued)</em></s></li><li><a href="https://www.freshworks.com/statuspage/">FreshStatus</a></li><li><a href="https://hetrixtools.com">HetrixTools</a> - uptime monitoring for ips and websites with an integrated status page</li><li><a href="https://tryhexadecimal.com">Hexadecimal</a> - uptime &amp; certificate monitoring and hosted status pages</li><li><a href="https://hund.io/">Hund</a></li><li><a href="https://instatus.com">Instatus</a> - Free online service with a static &amp; customizable page.</li><li><a href="https://lambstatus.github.io/">LambStatus</a></li><li><a href="https://nixstats.com/">NixStats</a> - service for servers, web, log and blacklists monitoring</li><li><a href="https://pagefate.com">PageFate.com</a> - free online service with customisable design</li><li><a href="https://www.ping2me.io/">ping2me</a> - monitor endpoints to make sure that they are online.</li><li><a href="https://pingpong.one">PingPong</a> - incident management, uptime &amp; certificate monitoring and hosted status pages</li><li><a href="https://www.sorryapp.com">Sorry™</a></li><li><a href="https://www.squadcast.com">Squadcast</a> - On-Call &amp; SRE platform with StatusPages built-in</li><li><a href="https://status.io">Status.io</a></li><li><a href="https://statuskeeper.com/">StatusKeeper</a></li><li><a href="https://statuskit.com/">StatusKit</a></li><li><a href="https://www.statuspage.io">Statuspage.io</a> - online service from Atlassian</li><li><a href="https://statuspal.io">Statuspal</a> - Hosted status pages &amp; monitoring.</li><li><a href="https://statusy.co"><s>Statusy</s></a>~~ ~~<s><em>(Discontinued)</em></s></li><li><a href="https://updown.io/">UpDown.io</a> - uptime monitoring with flexible status with rest api</li><li><a href="https://uptimerobot.com/">Uptime Robot</a></li><li><a href="https://www.uptimetoolbox.com/">UptimeToolbox</a> - Website/Server monitors with status pages.</li></ul><h2 id="Public-status-pages">Public status pages<a class="fa-solid fa-hashtag" href="#Public-status-pages"></a></h2><ul><li><a href="https://status.adobe.com/">Adobe System Status</a> - Adobe services status</li><li><a href="https://cloudharmony.com/status-for-akamai">Akamai Status</a> - Akamai Service Status</li><li><a href="https://status.aws.amazon.com/">Amazon AWS Service health dashboard</a></li><li><a href="https://www.apple.com/support/systemstatus/">Apple Support System Status</a> - Apple support status</li><li><a href="https://status.box.com/">Box Status</a> - <a href="http://Box.net">Box.net</a> status</li><li><a href="https://www.cloudflarestatus.com/">Cloudflare Status</a> - Cloudflare System Status</li><li><a href="https://cloudharmony.com/status-of-cdn-for-aws">CloudFront Status</a> - Amazon CloudFront Service Status</li><li><a href="https://status.datadoghq.com/">Datadog Status</a> - the status of Datadog.</li><li><a href="https://status.digitalocean.com/">DigitalOcean Status</a> - DigitalOcean Status page</li><li><a href="https://status.discordapp.com/">Discord App Status</a> - Discord App (videoconferencing, audioconferencing) status page</li><li><a href="https://developers.facebook.com/status/dashboard/">Facebook Platform Status</a> - Facebook platform status page</li><li><a href="https://status.fastly.com/">Fastly Status Page</a> - Fastly Status</li><li><a href="https://status.github.com/api">GitHub Status API</a> - GitHub status using REST API</li><li><a href="https://status.github.com/">GitHub Status</a> - GitHub status page</li><li><a href="https://status.gitlab.com">GitLab System Status</a> - GitLab status page</li><li><a href="https://status.cloud.google.com/">Google Cloud Status</a> - Status of Google Cloud</li><li><a href="https://www.google.com/appsstatus">Google GSuite Appstatus</a> - Google Applications (G Suite) online status page</li><li><a href="https://status.heroku.com/">Heroku Status</a> - Heroku status page</li><li><a href="https://status.ads.microsoft.com/">Microsoft Advertizement Status</a> - Microsoft Advertizement status page</li><li><a href="https://status.azure.com/ru-ru/status">Microsoft Azure Status</a> - Microsoft Azure status page</li><li><a href="https://status.office365.com/">Microsoft Office365 Status</a> - Microsoft Office365 status page</li><li><a href="https://www.paypal-status.com/product/production">Paypal Status Page</a></li><li><a href="https://www.pintereststatus.com/">Pinterest Status Page</a></li><li><a href="https://status.rackspace.com/">Rackspace System Status</a> - Rackspace hosting and services status page</li><li><a href="https://www.redditstatus.com/">reddit Status</a> - reddit Social Media status page</li><li><a href="https://support.skype.com/en/status/">Skype Status</a> - Microsoft Skype Status page</li><li><a href="https://status.slack.com/">Slack Status</a> - Slack, chat platform, status page</li><li><a href="https://api.twitterstat.us/">Twitter API Status</a> - Twitter API status page</li><li><a href="https://grafana.wikimedia.org/d/000000479/frontend-traffic?orgId=1">Wikipedia Frontend Monitoring</a> - Graphana based status page replacement for Wikipedia</li><li><a href="https://status.zoom.us/">Zoom Cloud Status</a> - Zoom (videoconferencing) status page</li></ul><h2 id="目前使用">目前使用<a class="fa-solid fa-hashtag" href="#目前使用"></a></h2><p><a href="https://cc.instatus.com/"><strong>Instatus</strong></a>（中文）| <a href="https://ccknbc.statuspage.io/"><strong>Statuspage</strong></a>（English)</p><p>因为 Instatus 我贡献了翻译，而且相较于其他免费产品，可自定义的地方实在太多了（好评，白嫖党的胜利）</p><p>而 Statuspage 主要是他可链接的第三方实在太多了，免费帐户的话能添加 25 个组件，反正也没有外国人看我，就当自用吧</p><p>配合 Freshping, Uptimerobot 等监控联动，这两个均可自动化向推特发送通知，当然 Uptimerobot 自身推送的方式也很多，RSS, Telegram, Webhook 等满足日常需要了。此外良心的他们对于订阅更新支持也很完善，虽然根本没人会去订阅，但还是要有这些功能对吧，高大上点（不是）</p><p>不过对于使用中文为主的我们来说，Instatus 是您的不二选择，时区，时间格式，语言什么的自定义太友好了，免费账号是完全够个人站长使用的，但是他的 embed 目前来说我希望能自适应大小，深色模式等，反正还很期待啦。而说到 embed， Statuspage 的 embed 个人觉得好看点吧，可以选择弹窗模式，悬浮模式，基础模式，徽标模式，自适应也不错，不过因为不支持中文（就是懒得自己在再整，官方那个代码都两年没动了）。此外 <a href="https://instatus.com/out"><strong>Instatus OUT</strong></a> 提供了网页端或者客户端（状态栏）快捷监控第三方的服务，而未来 Instatus 还会带来哪些服务呢，让我们共同期待吧！</p><hr><p>但自从 <a href="https://www.vercel-status.com/incidents/r758bhbklgfd"><strong>Vercel 事件</strong></a> 后，我们自己的状态页不受影响，IP换到了中国专用IP，但是 Instatus 官方还是原来的 A记录 IP，导致中国大陆用户无法访问其状态页和官网，这对用户体验来说是没什么，但对于站长就麻烦点了，得使用代理才能更新事件。不过 API, 邮件， WebHook 等方式应该可以解决，但官网控制面板更加方便，然后和开发者沟通更换了 IP， 目前一切正常，并且提前拥有了多语言和深色模式的支持，未来也会有其他功能，静态网页访问就是快！！！</p>]]></content><id>https://blog.ccknbc.cc/posts/undefined/</id><link href="https://blog.ccknbc.cc/posts/undefined/"/><published>2026-08-29T09:30:44.273Z</published><summary><![CDATA[<p>本文首发在<a href="https://www.yuque.com/ccknbc/blog/23/"><strong>语雀</strong></a></p>
<p>自动同步更新至<a]]></summary><title>很棒的状态页面</title><updated>2026-08-29T09:30:44.281Z</updated></entry><entry><author><name>CC康纳百川</name></author><category term="音乐" scheme="https://blog.ccknbc.cc/categories/%E9%9F%B3%E4%B9%90/"/><category term="台湾" scheme="https://blog.ccknbc.cc/tags/%E5%8F%B0%E6%B9%BE/"/><category term="音乐" scheme="https://blog.ccknbc.cc/tags/%E9%9F%B3%E4%B9%90/"/><content><![CDATA[<blockquote><p>版权归属 台湾 相信音乐</p></blockquote><p>刘若英X苏慧伦X丁当X白安</p><p>2023《好好》线上演唱会</p><p>Song About You live in the sky 2023</p><h2 id="歌单一览">歌单一览<a class="fa-solid fa-hashtag" href="#歌单一览"></a></h2><blockquote><p><strong>已在视频中标出</strong></p></blockquote><hr><p>苏慧伦part</p><p>0:30 鸭子</p><p>4:27 被动</p><p>8:18说话</p><p>9:09 严重</p><p>13:12说话</p><p>13:24 恋恋真言</p><p>17:17 在我生命中的每一天 feat.丁当</p><hr><p>丁当part</p><p>21:58 开头</p><p>22:39 夜猫</p><p>26:13 花火</p><p>30:18说话</p><p>31:07 猜不透</p><p>35:12说话</p><p>37:25 女字旁</p><p>41:56 我爱他</p><hr><p>白安 part</p><p>46:54 不够特别的我不要</p><p>51:41 刚好</p><p>56:01说话</p><p>56:39 是什么让我遇见这样的你</p><p>1:00:39 没有人写歌给你过吧</p><p>1:05:39 让我逃离平庸的生活</p><hr><p>刘若英 part</p><p>1:10:25 所有相爱的人啊</p><p>1:14:28 成全</p><p>1:18:57说话</p><p>1:20:55 固执</p><p>1:25:47 缩影</p><p>1:29:30 talking feat.白安</p><p>1:31:20 妈妈 feat.白安</p><p>1:35:51 后来</p><p>1:40:52 快乐天堂 feat.苏慧伦、丁当、白安</p><hr><p>女加上子 每个女子生而为好</p><p>该对自己好 该好好疼爱自己</p><p>女子女子 就是好好</p><p>好歌相伴 好上加好</p><p>《好好》线上演唱会</p><p>一场女子们的闺密音乐聚会</p><p>宜尽兴 宜微醺 宜舒心 宜走心</p><p>妳有多久没有好好跟自己说说话了？</p><p>妳有多久没有好好聆听心底声音了？</p><p>妳有多久没有好好跟好友聊聊天了？</p><p>妳有多久没有好好欣赏美好事物了？</p><p>女子，要好好去爱，更要好好爱自己。</p><p>「3月8日」是一年一度的「国际妇女节」 （International Women’s Day），提醒每个女子要爱自己，更能去爱别人、去爱这个世界。 在这个这个专属于女子的节日，刘若英X苏慧伦X丁当X白安，四个女子的美好相遇，要在38妇女节的周三夜，以音乐用心地打造出一场属于每个你的 “Lady’s Night”，你可以与你自己，也可以与好闺密们，一起好好享受、好好尽欢、好好聆听一首首动人的女子心声。</p><p>如水 如石 如光 如树</p><p>一场音乐与自然的飨宴</p><p>将美好谱写 如歌而行</p><p>当音乐遇见自然 当内心遇见自己</p><p>美的时节 好的相遇</p><p>女子女子 好好与你以歌相聚</p><p>「女」加上「子」等于「好」，「女子」加上「女子」就是「好好」，好上加好！ 「好好女声」刘若英、苏慧伦、丁当、白安，春暖花开时节献唱，，以歌相聚在《好好》线上演唱会，不仅渲染多首个人经典好歌，彼此间更有精彩的合唱新火花！ 《好好》演唱会以「女野」概念，结合「水、石、光、树」为主题，女子在自然旷野里吟唱，呈现出如水之柔美、如石之坚强、如光之魔幻、如树之实在的演唱氛围。</p><p>新的一年一切都在慢慢变好，刘若英、苏慧伦、丁当、白安，四美女子以美好歌声陪伴每个认真生活、认真爱的女子，一起告别因疫情闷久的坏坏情绪，迎接温暖美丽的好好心情</p><h2 id="流媒体平台">流媒体平台<a class="fa-solid fa-hashtag" href="#流媒体平台"></a></h2><p><a href="https://t.cn/A6CNy1Rx">QQ音乐</a> | <a href="https://t.cn/A6CodoGG">网易云音乐</a> | <a href="https://t.cn/A6CNylOl">酷狗音乐</a> | <a href="https://t.cn/A6CNylOW">酷我音乐</a> | <a href="https://t.cn/A6CKz5LV">咪咕音乐</a> | <a href="https://t.cn/A6CKz5Lq">汽水音乐</a></p>]]></content><id>https://blog.ccknbc.cc/posts/%3Cfont%20style=%22color:rgb(38,%2038,%2038);%22%3Esong-about-you-live-in-the-sky-2023%3C/font%3E/</id><link href="https://blog.ccknbc.cc/posts/%3Cfont%20style=%22color:rgb(38,%2038,%2038);%22%3Esong-about-you-live-in-the-sky-2023%3C/font%3E/"/><published>2026-08-29T09:30:44.280Z</published><summary><![CDATA[<font style="color:rgb(38, 38, 38);">刘若英X苏慧伦X丁当X白安 2023《好好》线上演唱会 Song About You live in the sky 2023</font>]]></summary><title><![CDATA[<font style=color:rgb(38, 38, 38);>2023《好好》线上演唱会</font>]]></title><updated>2026-08-29T09:30:44.281Z</updated></entry><entry><author><name>CC康纳百川</name></author><category term="工具" scheme="https://blog.ccknbc.cc/categories/%E5%B7%A5%E5%85%B7/"/><category term="工具" scheme="https://blog.ccknbc.cc/tags/%E5%B7%A5%E5%85%B7/"/><content><![CDATA[<div class="note danger simple"><p>本文大部分内容已作废，请直接查看<a href="https://waline.js.org/"><strong>官方文档</strong></a></p></div><p>本文首发在<a href="https://www.yuque.com/ccknbc/blog/20/"><strong>语雀</strong></a></p><p>自动同步更新至<a href="https://blog.ccknbc.cc/posts/waline-commens-system-deployment-logs/"><strong>CC的部落格</strong></a></p><p><strong>本文仅作为官方文档的补充，若有错误，还望指正</strong></p><p><a href="https://ccknbc.now.sh/posts/waline-commens-system-deployment-logs/#Todo">Waline 评论系统部署日志</a></p><hr><p>Waline - 一款从 <a href="https://valine.js.org">Valine</a> 衍生的带后端评论系统。可以将 Waline 等价成 With backend Valine.</p><h2 id="特性">特性<a class="fa-solid fa-hashtag" href="#特性"></a></h2><ul><li>快速</li><li>真·安全</li><li>Markdown 语法支持</li><li>轻量易用</li><li>免费部署</li><li>多种部署部署方式和存储服务支持，每列选择一项多达 84 种（可以更多）部署方式任君选择</li></ul><table><thead><tr><th></th><th>Waline</th><th></th></tr></thead><tbody><tr><td><strong>客户端脚本</strong></td><td><strong>服务端部署</strong></td><td><strong>数据存储</strong></td></tr><tr><td><a href="https://waline.js.org/"><strong>@waline/client</strong></a></td><td>Vercel</td><td>LeanCloud</td></tr><tr><td><a href="https://minivaline.js.org/"><strong>MiniValine</strong></a></td><td>CloudBase</td><td>CloudBase</td></tr><tr><td><a href="https://github.com/innc11/AprilComment"><strong>AprilComment</strong></a></td><td>Docker</td><td>MongoDB</td></tr><tr><td></td><td>独立部署</td><td>MySQL</td></tr><tr><td></td><td></td><td>SQLite</td></tr><tr><td></td><td></td><td>PostgreSQL</td></tr><tr><td></td><td></td><td>GitHub</td></tr></tbody></table><p>对于想免费使用的用户， <code>Vercel</code>  + <code>LeanCloud（国际版）</code>  是不错的选择，不过<code>Deta</code>一个服务就能解决所有问题而且还快点，如果你主要面向对象为大陆用户，使用 <code>CloudBase</code>  部署也是个不错的选择，它在海外表现也没那么差，或者您仅使用 <code>CloudBase</code>  来做数据存储</p><p><font style="color:#333333;"><div class="note warning simple"><p>如果您使用 </font> <code>Vercel</code> + <code>LeanCloud</code> ，并且使用 <code>Vercel</code>  发送评论通知，您不必担心 LeanCloud 流控问题，并且之前使用过 Valine 或者部署过 <code>Valine-Admin</code>  项目的可以直接拿来用；对于评论转移，官方提供了<a href="https://waline.js.org/migration/tool.html">迁移助手</a>供您使用，不用担心之前评论丢失的问题<font style="color:#333333;"></p></div></font></p><h2 id="Todo">Todo<a class="fa-solid fa-hashtag" href="#Todo"></a></h2><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;> 微信通知</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>QQ 通知</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>Telegram 通知</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>Akismet</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>文章统计</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>多语言同步</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>自定义语言支持</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;> 登录支持</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>评论管理</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>评论删除</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p>其它数据库支持 </font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>基于 IP 的发布评论频率限制</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>基于关键词的评论过滤限制</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>IP 黑名单</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>重复内容检测</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>CloudBase 腾讯云开发部署支持</font><font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox green checked'><input type="checkbox" checked="checked"/>            <p></font><font style=color:#333333;>社交登录</p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox red'><input type="checkbox" />            <p></font>AWS</p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox red'><input type="checkbox" />            <p></font>置顶评论<font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox red'><input type="checkbox" />            <p></font>评论赞踩<font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class='checkbox blue'><input type="checkbox" />            <p></font>其它…<font style=color:#333333;></p>            </div></font></p><p><font style="color:#333333;"><div class="note warning simple"><p>目前社交登录仅支持 </font><code>&lt;font style=&quot;color:#333333;&quot;&gt;GitHub&lt;/font&gt;</code> <font style="color:#333333;">， 未来会支持更多平台</p></div></font></p><hr><h2 id="Vercel-LeanCloud-部署">Vercel + LeanCloud 部署<a class="fa-solid fa-hashtag" href="#Vercel-LeanCloud-部署"></a></h2><p>这部分请前往<a href="https://waline.js.org/quick-start.html">官方文档</a>查看，不过需要注意的是如果你的 <code>GitHub</code>  账号主邮箱是 <code>QQ</code> 邮箱的话建议更改为其他邮箱（毕竟他们认为QQ邮箱是垃圾邮箱）再去注册   Vercel（或者你可以选择给客服发一封邮件让他们帮忙解锁你的账号），环境变量配置部分官方文档也写了，这里不再赘述</p><p>如果您之前用过 Valine，那么关于 LeanCloud 部分你就不用做什么了，数据兼容，拿到那几个 <code>key</code> 即可</p><h3 id="配置项">配置项<a class="fa-solid fa-hashtag" href="#配置项"></a></h3><p>这个可直接参考官方文档按需进行配置即可，因为目前云开发因众所周知的原因不支持连接 <code>Telegram</code> 服务器，所以如果您要配置电报新评论通知，请使用 Vercel 进行配置，不过因为目前没有异步通知，加上反垃圾检测等功能，发布评论可能需要很长时间，这个我使用了 LeanCloud 来继续帮我发送通知（反正我也没什么评论，流控问题第二天补发评论也不是不可）</p><p><font style="color:#333333;"><div class="note warning simple"><p>对于邮件通知部分，目前的设定是，对于新评论，如果博主配置了 QQ/微信/Telegram 通知中任意一种或多种，则邮件通知将会取消，而对于回复（子评论），博主和被回复者（如果填了邮箱的话）均可收到邮件通知</p></div></font></p><p><font style="color:#333333;">我目前使用的 Hexo Butterfly 主题已经从 3.5.0 beta3 版本起内置了 Waline 评论系统，如果您使用老版本主题请升级，或者根据您所用版本的 Valine 模板 pug 来照葫芦画瓢，根据官方配置进行对应修改，主题中 option 为可选配置，万一将来增加了某些配置，主题不必为此升级, bg 为主题配置项</font></p><p>这里注意一下 serverURL 以及环境变量里的 SITE_URL 网址最后的斜杠因为作者没做兼容，所以不要带上 / ，导致跳转不到对应评论界面</p><p>客户端脚本里可以通过 <code>langMode.admin</code>  这个配置自定义角标的文案,例如：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">waline</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="title class_">Waline</span> = <span class="built_in">require</span>(<span class="string">&#x27;@waline/client&#x27;</span>);</span><br><span class="line">  <span class="keyword">new</span> <span class="title class_">Waline</span>(&#123;</span><br><span class="line">    <span class="attr">el</span>: <span class="string">&#x27;#waline-comment&#x27;</span>,</span><br><span class="line">    <span class="attr">serverURL</span>: <span class="string">&#x27;https://waline.vercel.app&#x27;</span>,</span><br><span class="line">    <span class="attr">path</span>: <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">pathname</span>,</span><br><span class="line">    <span class="attr">visitor</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">lang</span>: location.<span class="property">pathname</span>.<span class="title function_">startsWith</span>(<span class="string">&#x27;/en/&#x27;</span>) ? <span class="string">&#x27;en&#x27;</span> : <span class="string">&#x27;zh-CN&#x27;</span>,</span><br><span class="line">    <span class="attr">langMode</span>: &#123;</span><br><span class="line">      <span class="attr">admin</span>: location.<span class="property">pathname</span>.<span class="title function_">startsWith</span>(<span class="string">&#x27;/en/&#x27;</span>) ? <span class="string">&#x27;Administrator&#x27;</span> : <span class="string">&#x27;可爱的管理员&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>对于同主题在主题配置里找到 <code>waline</code>  配置项相关内容</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># waline - A simple comment system with backend support fork from Valine</span></span><br><span class="line"><span class="comment"># https://waline.js.org/</span></span><br><span class="line"><span class="attr">waline:</span></span><br><span class="line">  <span class="attr">serverURL:</span> <span class="string">https://waline.ccknbc.ml</span> <span class="comment"># Waline server address url</span></span><br><span class="line">  <span class="attr">avatar:</span> <span class="string">monsterid</span> <span class="comment"># gravatar style https://zh-tw.gravatar.com/site/implement/images/#default-image</span></span><br><span class="line">  <span class="attr">bg:</span> <span class="comment"># waline background</span></span><br><span class="line">  <span class="attr">emojiCDN:</span> <span class="string">https://cdn.jsdelivr.net/gh/GamerNoTitle/ValineCDN@master/</span></span><br><span class="line">  <span class="attr">visitor:</span> <span class="literal">false</span></span><br><span class="line">  <span class="attr">option:</span> </span><br><span class="line">    <span class="attr">pageSize:</span> <span class="number">10</span></span><br><span class="line">    <span class="attr">requiredFields:</span> <span class="string">mail</span></span><br><span class="line">    <span class="comment"># anonymous: false </span></span><br><span class="line">    <span class="attr">placeholder:</span>                                                                                      </span><br><span class="line">    <span class="attr">avatarCDN:</span> <span class="string">https://sdn.geekzu.org/avatar/</span></span><br><span class="line">    <span class="comment">#https://valinecdn.bili33.top/</span></span><br><span class="line">    <span class="attr">langMode:</span></span><br><span class="line">      <span class="attr">admin:</span> <span class="string">博主兼管理员</span></span><br><span class="line">      <span class="attr">nick:</span> <span class="string">昵称(选填)</span></span><br><span class="line">      <span class="attr">mail:</span> <span class="string">邮箱(必填)</span></span><br><span class="line">      <span class="attr">link:</span> <span class="string">网址(选填)</span></span><br><span class="line">      <span class="attr">sofa:</span> <span class="string">这里冷冷清清的，快来留下脚印吧！</span></span><br><span class="line"> <span class="comment"># 如果你查看了源码，会发现还有这个可以配置 copyRight: false，但不建议大家设为 false 啦，保留也没什么的（没错，我不要脸）</span></span><br></pre></td></tr></table></figure><p><s>还有就是可能有人会觉得默认邮件通知模板太单调，想和 Valine-Admin 一样切换模板，其实有这个配置的，只是目前的方法是写在环境变量中，而环境变量限制长度（大小），或者说是不适合这种方式配置，如果要改的话可以先查看</s><a href="https://github.com/lizheming/waline/issues/106"><s>issues/106</s></a><s>相关内容，或者等以后优化再说；当然如果你的评论不是很多，并且之前配置过 Valine-Admin，那么你仍然可以使用 LeanCloud 来做异步发送通知，关闭默认的通知配置，或者使用 js 推送</s></p><p>关于邮件模板大家可查看<a href="https://waline.js.org/server/notification.html#%E9%80%9A%E7%9F%A5%E6%A8%A1%E6%9D%BF">官方文档</a>相关章节，或者使用<a href="#%E9%82%AE%E4%BB%B6%E9%80%9A%E7%9F%A5%E6%A8%A1%E6%9D%BF">附录提供的邮件通知模板</a>，也提交了 PR</p><p><a href="https://waline.js.org/server/basic.html#%E8%AF%84%E8%AE%BA-hooks">评论 Hooks</a>，可以根据官方的例子自己做一些配置，相比于其他，违禁词，屏蔽IP等配置可以说是人性化了，但万一配置不好一些正常评论可能也会被判定为垃圾内容，所以我推荐使用人工审核功能，不过这边不得不说另一个评论系统 <a href="https://twikoo.js.org/">Twikoo</a>，支持查看自己审核中的评论，评论置顶，点赞等，不过我想 Waline 将来也能实现，毕竟 Flag 立那了</p><p>图片上传 uploadImage 部分配置 理论上是可以适配任何图床，配置例子可查看 <a href="https://github.com/lizheming/waline/issues/123">issues/123</a>，当然内置了一个默认图床，开箱即用</p><p>表情配置和之前 Valine 是一样的，同主题还可使用 <code>walien.json</code> 的配置方式，具体可查看<a href="https://butterfly.js.org/posts/ceeb73f/#%E8%A9%95%E8%AB%96">主题文档</a></p><h2 id="CloudBase-云开发部署">CloudBase 云开发部署<a class="fa-solid fa-hashtag" href="#CloudBase-云开发部署"></a></h2><h3 id="一键部署">一键部署<a class="fa-solid fa-hashtag" href="#一键部署"></a></h3><p>一键脚本部署可以查看<a href="https://waline.js.org/server/cloudbase.html">官方文档</a>，我删了之后就没成功过</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612362992018-14b2a225-27d6-4996-948b-e746d26bb2e0.png" alt="" loading="lazy"></p><p>截至文档最新更新日期，这个已被修复（不过tcb-starter那个链接还没改所以还是失败），不过我只能说作者非常不细心，毕竟能一天发十几个版本，详见 <a href="https://github.com/lizheming/waline/commit/d87d3092a34fd6b2b7f0b1c72bd95ad784a086e7">commit</a>，他还是把链接协议头多打了一个 h ,所以请<a href="https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&amp;appUrl=https%3A%2F%2Fgithub.com%2Fwalinejs%2Ftcb-starter&amp;branch=master&amp;appName=waline">点击这里</a>一键部署</p><p>嗯，后来修复了，期待接下来的开发</p><hr><p>警告内容来自 <a href="https://twikoo.js.org/quick-start.html">Twikoo 官方文档</a> 建议您直接查看 <a href="#%E6%89%8B%E5%8A%A8%E9%83%A8%E7%BD%B2">手动部署部分</a>！！！</p><p><font style="color:#333333;"><div class="note warning simple"><p></font></p></p><p>一键部署虽然方便，但是仅支持按量计费环境——也就是说，<strong>一键部署的环境，当免费资源用尽后，将会产生费用</strong>。且按量计费环境无法切换为包年包月环境。免费额度数据库读操作数只有 500 次 / 天，<strong>无法支撑 Twikoo 的运行需求</strong>。Twikoo 建议您<a href="#%E6%89%8B%E5%8A%A8%E9%83%A8%E7%BD%B2">手动部署</a>以节约成本。</p><p><font style="color:#333333;"></div></font></p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1610953378969-db93161e-24d3-4a48-8934-5566774b94d2.png" alt="" loading="lazy"></p><p>对于新用户或者说没有创建过按量计费环境的用户会显示如下内容，记得勾选开启免费资源</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1610873567827-825cde85-7c99-4c5a-95e0-44c0966784cb.png" alt="" loading="lazy"></p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612859364523-006d98ba-bd5c-4868-878f-9c9ac158d836.png" alt="" loading="lazy"></p><p>为了日后升级的方便，不管您是否使用了 Vercel 部署，您都可以 fork <a href="https://github.com/ccknbc-actions/waline">我的仓库</a> ，稍加配置即可完成自动部署更新</p><h3 id="手动部署">手动部署<a class="fa-solid fa-hashtag" href="#手动部署"></a></h3><p>首先前往<a href="https://cloud.tencent.com/act/pro/cloudbase01"><strong>腾讯云的活动区域</strong></a>，注册/登陆后往下滑，找到新用户专享云开发标准型（基础版1）资源套餐，0元购买一个免费包年包月环境</p><hr><p>没错，这个环境不错吧</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1610870670315-08e65148-3819-48fb-878e-03fdb0c9ab64.png" alt="" loading="lazy"></p><p>按照提示购买后稍等几分钟，<a href="https://console.cloud.tencent.com/tcb/env/index">在这个界面可查看您所购买的环境</a></p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1610870083481-8e4cad1a-c70a-4cad-9192-11be8003241c.png" alt="" loading="lazy"></p><p>有能力的其实可以看一下 Vercel <a href="#%E8%87%AA%E5%8A%A8%E5%8D%87%E7%BA%A7">自动升级</a>和TCB<a href="#%E8%87%AA%E5%8A%A8%E5%8D%87%E7%BA%A7-1">自动升级</a>部分，间接实现一键部署，自动更新</p><p><a href="https://console.cloud.tencent.com/tcb/scf/index">点击云函数</a>，新建云函数，函数内存选择 128M，名称随意，例如 Waline，其他默认,单击进入下一步</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612359288449-66b53150-2146-4ec9-aa08-910b99aebd1b.png" alt="" loading="lazy"></p><p>下图中的函数代码部分填入以下代码</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612359460424-4b8cf9b4-2ef4-4758-92f6-09ae040a91ea.png" alt="" loading="lazy"></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Tencent is pleased to support the open source community by making CloudBaseFramework - 云原生一体化部署工具 available.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Copyright (C) 2020 THL A29 Limited, a Tencent company.  All rights reserved.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Please refer to license text included with this package for license details.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>.<span class="property">main</span> = <span class="title function_">async</span> (event, context) =&gt; &#123;</span><br><span class="line">  context.<span class="property">callbackWaitsForEmptyEventLoop</span> = <span class="literal">false</span>;</span><br><span class="line">  <span class="keyword">const</span> entry = (<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> result = <span class="built_in">require</span>(<span class="string">&#x27;./app.js&#x27;</span>);</span><br><span class="line">    <span class="comment">// const app = require(&#x27;express&#x27;)();</span></span><br><span class="line">    <span class="comment">// result = app.use(result);</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125;)();</span><br><span class="line">  <span class="keyword">const</span> serverless = <span class="built_in">require</span>(<span class="string">&#x27;serverless-http&#x27;</span>);</span><br><span class="line">  <span class="keyword">let</span> app = entry;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// support for async load app</span></span><br><span class="line">  <span class="keyword">if</span> (entry &amp;&amp; entry.<span class="property">tcbGetApp</span> &amp;&amp; <span class="keyword">typeof</span> entry.<span class="property">tcbGetApp</span> === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">    app = <span class="keyword">await</span> entry.<span class="title function_">tcbGetApp</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="title function_">serverless</span>(app, &#123;</span><br><span class="line">    <span class="attr">binary</span>: [</span><br><span class="line">      <span class="string">&#x27;application/javascript&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;application/json&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;application/octet-stream&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;application/xml&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;font/eot&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;font/opentype&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;font/otf&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;image/*&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;video/*&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;audio/*&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/comma-separated-values&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/css&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/javascript&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/plain&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/text&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;text/xml&#x27;</span>,</span><br><span class="line">    ],</span><br><span class="line">  &#125;)(event, context);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>点击对应的云函数，进入在线编辑页面，按照<a href="https://github.com/walinejs/tcb-starter">模板仓库</a>里的文件，新建对应的文件，并复制粘贴对应的内容即可</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612360652232-9eb2ad2b-bebe-4964-bb5f-75e2f9946d25.png" alt="" loading="lazy"></p><p>注意点击<strong>保存并安装依赖</strong>，可能会没有反应一会儿，然后等待转圈圈部署完毕即可</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612360855940-241970ec-5c18-4bc8-9168-9fd945deb761.png" alt="" loading="lazy"><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612361085479-f39b6b2b-2293-4685-882e-9e20aa611dea.png" alt="" loading="lazy"></p><p>当然还没有结束，我们需要点击 <code>环境 --&gt; HTTP 访问服务</code> （<a href="https://console.cloud.tencent.com/tcb/env/access">点击直达</a>)，如果你想绑定自定义域名可以照图中绑定，记得先申请一下证书，如果你想要 HTTPS（这个可能花的时间有点长）</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612361294908-3ef584b5-5cbc-43e5-b744-cda357057ec0.png" alt="" loading="lazy"></p><p>点击新建，新建触发路径，点击保存即可，注意路径最后没有 / ，等待构建完成后你就可通过对应的链接访问 demo 页面了，这个链接就是上面提到的 <code>serverURL</code> ，例如我的 <a href="https://tcb.ccknbc.cc/waline">https://tcb.ccknbc.cc/waline</a></p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612361631129-fecd45a5-f694-4154-8707-9976eb10adb5.png" alt="" loading="lazy"></p><p>然后我们需要设置<a href="https://console.cloud.tencent.com/tcb/env/safety"> WEB 安全域名</a>，把你的域名放入白名单即可（本地测试的话端口也要对应上哦）</p><h2 id="如何升级">如何升级<a class="fa-solid fa-hashtag" href="#如何升级"></a></h2><h3 id="Vercel">Vercel<a class="fa-solid fa-hashtag" href="#Vercel"></a></h3><h4 id="手动升级">手动升级<a class="fa-solid fa-hashtag" href="#手动升级"></a></h4><p>找到 Vercel 帮你在创建的仓库，叫 <code>waline</code> 啦，编辑 <code>package.json</code> 中依赖版本号即可完成升级，版本号以 <code>npm</code> <img src="https://img.shields.io/npm/v/@waline/vercel?color=critical&amp;logo=npm&amp;style=flat-square" alt="" loading="lazy"><font style="color:#2C3E50;"> 为准，因为 GitHub 由于考虑到电报机器人自动推送消息过于频繁影响到群友，会延迟推送</font></p><h4 id="自动升级">自动升级<a class="fa-solid fa-hashtag" href="#自动升级"></a></h4><p>其实原理还是一样的，因为Vercel会监控仓库文件的变化来帮我们自动部署，那么我们要做的就是自动更改版本号，这里你可以用 <code>Github Actions</code> 实现，定时每隔半小时自动更新并push，但这样似乎有点浪费资源，所以不怎么推荐，而我们这个仓库通常都是公开的（私有也没关系）</p><p>首先你需要安装一个应用<a href="https://github.com/marketplace/renovate">Renovate</a>,选择免费版计划即可，他会帮我们监控所用依赖的版本更新变化，并为提交一个 <code>PR</code> ，我们要做的只是合并 PR 而已，但手动合并之前也讲过，多少有点不方便，自动合并我们知道有打标签自动合并，GitHub Actions 工具人自动合并，这些大家搜以下关键词就好，但这个应用它本身实际上支持自动合并，查看<a href="https://docs.renovatebot.com/configuration-options/#automerge">官方文档</a>发现在 <code>renovate.json</code> 中配置即可，示例代码如下，其中代理人是为了通知更新的作用，与PR同理，但也可删除此段配置，同样的PR也可关闭通知静默自动更新。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;extends&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;config:base&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;assignees&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;CCKNBC&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;separateMinorPatch&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;packageRules&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;updateTypes&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">          <span class="string">&quot;minor&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="string">&quot;patch&quot;</span></span><br><span class="line">      <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;automerge&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;automergeType&quot;</span><span class="punctuation">:</span> <span class="string">&quot;branch&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>我目前还是用的默认的提交PR自动合并的方式，如果你是公开仓库，还可以使用<a href="https://github.com/marketplace/mergify">Mergify</a>，安装完成后他能它免费帮我们自动合并公开仓库的PR，我们设定一个条件，比如 PR 提交作者为 renovate，就自动帮我们点击合并，并删除多余分支，当然这些都需要配置，这里具体会在另一篇文档中讲到</p><p><font style="color:#333333;"><div class="note info simple"><p></font>以上两个应用你可以选择安装到全部仓库，或者只安装到选择的仓库<font style="color:#333333;"></p></div></font></p><p>如果你想懒的话可以先删除你现有的名为 Waine 的仓库，再 fork <a href="https://github.com/ccknbc-actions/waline">我的仓库</a>，然后去你的 Vercel 解绑之前的仓库，再绑定你fork的仓库，最后点一下重新部署即可</p><p>但是如果你没用tcb 就把  <code>.github/workflows/Update Waline TCB.yml</code>  里的文件删掉，因为涉及到自动部署更新云开发，还有环境变量问题，如果没设定会导致报错</p><h3 id="CloudBase">CloudBase<a class="fa-solid fa-hashtag" href="#CloudBase"></a></h3><hr><h4 id="一键部署-2">一键部署<a class="fa-solid fa-hashtag" href="#一键部署-2"></a></h4><p>就是点击<a href="https://console.cloud.tencent.com/tcb/apps/index">我的应用</a>找到 Waline 点击部署即可</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/8391407/1612711217029-250d0b1a-75d1-4a7c-9f4c-8a9413ab51fa.png" alt="" loading="lazy"></p><h4 id="手动部署-2">手动部署<a class="fa-solid fa-hashtag" href="#手动部署-2"></a></h4><h5 id="手动升级-2">手动升级<a class="fa-solid fa-hashtag" href="#手动升级-2"></a></h5><p>就是去<a href="https://github.com/walinejs/tcb-starter">仓库</a>复制粘贴修改过的文件的事情了，如果没有文件改动就点击 <code>保存并安装依赖</code> 即可（知道在哪了吧）</p><h5 id="自动升级-2">自动升级<a class="fa-solid fa-hashtag" href="#自动升级-2"></a></h5><p>原理在上面讲了，结合 <a href="#%E8%87%AA%E5%8A%A8%E5%8D%87%E7%BA%A7">Vercel 自动升级</a>部分查看，这部分其实可以作为上面的手动部署，或者自动部署？</p><p>你可以 fork <a href="https://github.com/ccknbc-actions/waline">我的仓库</a> 进行更改，和上面提到的原理差不多，只是用到了 Actions（如果你之前没接触过这些，建议使用 Vercel 部署或者上面的一键部署，也比较方便），在合并PR后帮我们自动升级部署到云开发，解释一下几个密钥，您需要在 仓库的 <code>settings/secrets/actions</code> 中配置，组织的话可以把常用到的密钥添加为组织密钥</p><p>，比如 ID KEY 等</p><table><thead><tr><th>变量名</th><th>变量解释</th></tr></thead><tbody><tr><td><font style="color:#404040;background-color:#FFFFFF;">SECRETID</font></td><td>API 访问密钥 ID，可<a href="https://console.cloud.tencent.com/cam/capi">点击这里</a>新建/查看</td></tr><tr><td><font style="color:#404040;background-color:#FFFFFF;">SECRETKEY</font></td><td><font style="color:#404040;background-color:#FFFFFF;">API 访问密钥 KEY，可</font><a href="https://console.cloud.tencent.com/cam/capi">点击这里</a><font style="color:#404040;background-color:#FFFFFF;">新建/查看</font></td></tr><tr><td>TCBFUNNAME（没什么好加密的，就叫 waline 算了）</td><td>你想要新建/已有函数的名称，比如 <code>Waline</code></td></tr><tr><td>TCBENVID</td><td>环境ID，可<a href="https://console.cloud.tencent.com/tcb/env/overview">点击这里</a>或<a href="https://console.cloud.tencent.com/tcb/env/index">这里</a>查看，地址栏后也会显示，反正就是很多地方都在上面点一下就能看到</td></tr></tbody></table><h2 id="附录">附录<a class="fa-solid fa-hashtag" href="#附录"></a></h2><h3 id="邮件通知模板">邮件通知模板<a class="fa-solid fa-hashtag" href="#邮件通知模板"></a></h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mailSubject</span>: <span class="string">&#x27;&#123;&#123;parent.nick&#125;&#125;，您在 &#123;&#123;site.name&#125;&#125; 上发表的评论,收到了来自 &#123;&#123;self.nick&#125;&#125; 的回复&#x27;</span>,</span><br><span class="line"><span class="attr">mailSubjectAdmin</span>: <span class="string">&#x27;&#123;&#123;site.name&#125;&#125; 上收到了来自 &#123;&#123;self.nick&#125;&#125; 的留言&#x27;</span>,</span><br><span class="line"><span class="attr">mailTemplate</span>: <span class="string">&#x27;&lt;head&gt;&lt;base target=&quot;_blank&quot;/&gt;&lt;style id=&quot;scrollbar&quot;type=&quot;text/css&quot;&gt;::-webkit-scrollbar&#123;width:0!important&#125;pre&#123;white-space:pre-wrap!important;word-wrap:break-word!important;*white-space:normal!important&#125;pre&#123;white-space:pre-wrap!important;word-wrap:break-word!important;*white-space:normal!important&#125;#letter img&#123;max-width:300px&#125;&lt;/style&gt;&lt;style id=&quot;from-wrapstyle&quot;type=&quot;text/css&quot;&gt;#form-wrap&#123;overflow:hidden;height:447px;position:relative;top:0px;transition:all 1s ease-in-out.3s;z-index:0&#125;&lt;/style&gt;&lt;style id=&quot;from-wraphoverstyle&quot;type=&quot;text/css&quot;&gt;#form-wrap:hover&#123;height:1300px;top:-200px&#125;&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div style=&quot;width: 530px;margin: 20px auto 0;height: 1000px;&quot;&gt;&lt;div id=&quot;form-wrap&quot;&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/Akilarlxh/Valine-Admin@v1.0/source/img/before.png&quot;alt=&quot;before&quot;style=&quot;position: absolute;bottom: 126px;left: 0px;background-repeat: no-repeat;width: 530px;height: 317px;z-index:-100&quot;&gt;&lt;div style=&quot;position: relative;overflow: visible;height: 1500px;width: 500px;margin: 0px auto;transition: all 1s ease-in-out .3s;padding-top:200px;&quot;&lt;form&gt;&lt;div style=&quot;background: white;width: 95%;max-width: 800px;margin: auto auto;border-radius: 5px;border: 1px solid;overflow: hidden;-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);&quot;&gt;&lt;img style=&quot;width:100%;overflow: hidden;&quot;src=&quot;https://area.sinaapp.com/bingImg&quot;/&gt;&lt;div style=&quot;padding: 5px 20px;&quot;&gt;&lt;br&gt;&lt;div&gt;&lt;h3 style=&quot;text-decoration: none; color: #8fbc8f;&quot;&gt;&#123;&#123;parent.nick&#125;&#125;，见信安：&lt;/h3&gt;&lt;/div&gt;&lt;br&gt;&lt;div id=&quot;letter&quot;style=&quot;overflow:auto;height:300px;width:100%;display:block;word-break: break-all;word-wrap: break-word;&quot;&gt;&lt;p style=&quot;display: inline-block;&quot;&gt;您在&lt;a style=&quot;text-decoration: none;color: #8fbc8f&quot;target=&quot;_blank&quot;href=&quot;&#123;&#123;site.postUrl&#125;&#125; display: inline-block;&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;上发表的评论:&lt;/p&gt;&lt;div style=&quot;border-bottom: #ddd 1px solid;border-left: #ddd 1px solid;padding-bottom: 20px;background-color: #eee;margin: 15px 0px;padding-left: 20px;padding-right: 20px;border-top: #ddd 1px solid;border-right: #ddd 1px solid;padding-top: 20px;font-family: &quot;Arial&quot;, &quot;Microsoft YaHei&quot; , &quot;黑体&quot; , &quot;宋体&quot; , sans-serif;&quot;&gt;&#123;&#123;parent.comment | safe&#125;&#125;&lt;/div&gt;&lt;p&gt;收到了来自&#123;&#123;self.nick&#125;&#125;的回复：&lt;/p&gt;&lt;div style=&quot;border-bottom: #ddd 1px solid;border-left: #ddd 1px solid;padding-bottom: 20px;background-color: #eee;margin: 15px 0px;padding-left: 20px;padding-right: 20px;border-top: #ddd 1px solid;border-right: #ddd 1px solid;padding-top: 20px;font-family: &quot;Arial&quot;, &quot;Microsoft YaHei&quot; , &quot;黑体&quot; , &quot;宋体&quot; , sans-serif;&quot;&gt;&#123;&#123;self.comment | safe&#125;&#125;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;div style=&quot;text-align: center;margin-top: 40px;&quot;&gt;&lt;img src=&quot;https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png&quot;alt=&quot;hr&quot;style=&quot;width:100%; margin:5px auto 5px auto; display: block;&quot;/&gt;&lt;a style=&quot;text-transform: uppercase;text-decoration: none;font-size: 14px;border: 2px solid #ace0f9;color: #FFFFFF;padding: 10px;display: inline-block;margin: 10px auto 0;background-color: #8fbc8f;&quot;target=&quot;_blank&quot;href=&quot;&#123;&#123;site.postUrl&#125;&#125;&quot;&gt;&#123;&#123;site.name&#125;&#125;｜请您签收~&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-size: 12px;text-align: center;color: #999;&quot;&gt;自动书记人偶竭诚为您服务！&lt;br&gt;©2020 - 2021 &lt;a style=&quot;text-decoration:none; color:#8fbc8f&quot;href=&quot;&#123;&#123;site.url&#125;&#125;&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/form&gt;&lt;/div&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/Akilarlxh/Valine-Admin@v1.0/source/img/after.png&quot;alt=&quot;after&quot;style=&quot;      position: absolute;bottom: -2px;left: 0;background-repeat: no-repeat;width: 530px;height: 259px;z-index:100&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&#x27;</span>,</span><br><span class="line"><span class="attr">mailTemplateAdmin</span>: <span class="string">&#x27;&lt;head&gt;&lt;base target=&quot;_blank&quot;/&gt;&lt;style id=&quot;scrollbar&quot;type=&quot;text/css&quot;&gt;::-webkit-scrollbar&#123;width:0!important&#125;pre&#123;white-space:pre-wrap!important;word-wrap:break-word!important;*white-space:normal!important&#125;#letter img&#123;max-width:300px&#125;&lt;/style&gt;&lt;style id=&quot;from-wrapstyle&quot;type=&quot;text/css&quot;&gt;#form-wrap&#123;overflow:hidden;height:447px;position:relative;top:0px;transition:all 1s ease-in-out.3s;z-index:0&#125;&lt;/style&gt;&lt;style id=&quot;from-wraphoverstyle&quot;type=&quot;text/css&quot;&gt;#form-wrap:hover&#123;height:1300px;top:-200px&#125;&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div style=&quot;width: 530px;margin: 20px auto 0;height: 1000px;&quot;&gt;&lt;div id=&quot;form-wrap&quot;&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/Akilarlxh/Valine-Admin@v1.0/source/img/before.png&quot;alt=&quot;before&quot;style=&quot;position: absolute;bottom: 126px;left: 0px;background-repeat: no-repeat;width: 530px;height: 317px;z-index:-100&quot;&gt;&lt;div style=&quot;position: relative;overflow: visible;height: 1500px;width: 500px;margin: 0px auto;transition: all 1s ease-in-out .3s;padding-top:200px;&quot;&gt;&lt;form&gt;&lt;div style=&quot;background: white;width: 95%;max-width: 800px;margin: auto auto;border-radius: 5px;border: 1px solid;overflow: hidden;-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.12);box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.18);&quot;&gt;&lt;img style=&quot;width:100%;overflow: hidden;&quot;src=&quot;https://area.sinaapp.com/bingImg&quot;/&gt;&lt;div style=&quot;padding: 5px 20px;&quot;&gt;&lt;br&gt;&lt;div&gt;&lt;h3 style=&quot;text-decoration: none; color: #8fbc8f;&quot;&gt;来自&#123;&#123;self.nick&#125;&#125;的留言:&lt;/h3&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;&lt;div id=&quot;letter&quot;style=&quot;overflow:auto;height:300px;width:100%;display:block;word-break: break-all;word-wrap: break-word;&quot;&gt;&lt;div style=&quot;border-bottom: #ddd 1px solid;border-left: #ddd 1px solid;padding-bottom: 20px;background-color: #eee;margin: 15px 0px;padding-left: 20px;padding-right: 20px;border-top: #ddd 1px solid;border-right: #ddd 1px solid;padding-top: 20px;font-family: &quot;Arial&quot;, &quot;Microsoft YaHei&quot; , &quot;黑体&quot; , &quot;宋体&quot; , sans-serif;&quot;&gt;&#123;&#123;self.comment | safe&#125;&#125;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;margin-top: 40px;&quot;&gt;&lt;img src=&quot;https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png&quot;alt=&quot;hr&quot;style=&quot;width:100%; margin:5px auto 5px auto; display: block;&quot;/&gt;&lt;a style=&quot;text-transform: uppercase;text-decoration: none;font-size: 14px;border: 2px solid #ace0f9;color: #FFFFFF;padding: 10px;display: inline-block;margin: 10px auto 0;background-color: #8fbc8f;&quot;target=&quot;_blank&quot;href=&quot;&#123;&#123;site.postUrl&#125;&#125;&quot;&gt;&#123;&#123;site.name&#125;&#125;｜请您过目~&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-size: 12px;text-align: center;color: #999;&quot;&gt;©2020 - 2021 &lt;a style=&quot;text-decoration:none; color:#8fbc8f&quot;href=&quot;&#123;&#123;site.url&#125;&#125;&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/form&gt;&lt;/div&gt;&lt;img src=&quot;https://cdn.jsdelivr.net/gh/Akilarlxh/Valine-Admin@v1.0/source/img/after.png&quot;alt=&quot;after&quot;style=&quot;      position: absolute;bottom: -2px;left: 0;background-repeat: no-repeat;width: 530px;height: 259px;z-index:100&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="下载">下载<a class="fa-solid fa-hashtag" href="#下载"></a></h3><p><a href="https://file.nmb.show/down.php/4ca88b8fe0729c213cd3a425f87d2f51.rar">邮件通知模板下载</a>（包含 Waline/Valine/Twikoo），您可以下载后根据官方文档提及的变量自行修改<code>index.js</code>相关内容，以上代码仅作参考，对于本文未涉及到的其他内容，请自行查看官方文档，如有错误，欢迎指正，谢谢！</p>]]></content><id>https://blog.ccknbc.cc/posts/waline-comments-system-deployment-logs/</id><link href="https://blog.ccknbc.cc/posts/waline-comments-system-deployment-logs/"/><published>2026-08-29T09:30:44.272Z</published><summary>Waline 评论系统部署日志，希望你也能用上这款评论系统</summary><title>Waline 评论系统部署日志</title><updated>2026-08-29T09:30:44.280Z</updated></entry><entry><author><name>CC康纳百川</name></author><category term="工具" scheme="https://blog.ccknbc.cc/categories/%E5%B7%A5%E5%85%B7/"/><category term="工具" scheme="https://blog.ccknbc.cc/tags/%E5%B7%A5%E5%85%B7/"/><content><![CDATA[<p>本文首发在<a href="https://www.yuque.com/ccknbc/blog/19/"><strong>语雀</strong></a></p><p>自动同步更新至<a href="https://blog.ccknbc.cc/posts/a-simple-but-not-simple-m3u8-download-tool/"><strong>CC的部落格</strong></a></p><p><a href="https://github.com/nilaoda/N_m3u8DL-CLI">官方仓库</a></p><p><img src="https://cdn.nlark.com/yuque/0/2021/gif/8391407/1610273643341-942cd95d-6f1e-4356-afc9-d5961c7d078a.gif" alt="" loading="lazy"></p><p>批量下载优酷m3u8</p><p><img src="https://cdn.nlark.com/yuque/0/2021/gif/8391407/1610273775655-7e8c3956-6d5a-4760-a59b-d02e6c21126e.gif" alt="" loading="lazy"></p><p>LINETV（台湾站解析）<br><img src="https://cdn.nlark.com/yuque/0/2021/gif/8391407/1610273823214-764f768e-4b64-4073-8793-498c61a30285.gif" alt="" loading="lazy"></p><p>其实 SimpleG 提供了 CLI 更直观简单的调用方式，因此更加方便快捷，解密，录直播必备。</p>]]></content><id>https://blog.ccknbc.cc/posts/a-simple-but-not-simple-m3u8-download-tool/</id><link href="https://blog.ccknbc.cc/posts/a-simple-but-not-simple-m3u8-download-tool/"/><published>2026-08-29T09:30:44.272Z</published><summary>一款简洁却不简单的 m3u8 下载工具</summary><title>一款简洁却不简单的 m3u8 下载工具</title><updated>2026-08-29T09:30:44.280Z</updated></entry></feed>