<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><id>https://blog.tusooa.xyz</id><title>infra - 何事西风不待人</title><link href="https://blog.tusooa.xyz"/><subtitle>迷糊萝莉</subtitle><updated>2024-06-26T12:00:00.000Z</updated><entry><id>https://blog.tusooa.xyz/2024/06/26/Use-phorge-for-code-review/</id><title>Use phorge for code review</title><link rel="alternate" href="https://blog.tusooa.xyz/2024/06/26/Use-phorge-for-code-review/"/><published>2024-06-26T12:00:00.000Z</published><content type="html">&lt;div&gt; &lt;p&gt;I have always wanted to self-host a &lt;a href=&quot;https://phabricator.com/&quot;&gt;Phabricator&lt;/a&gt; for task management, as
I found KDE&apos;s Phabricator pretty useful for this. But one day
&lt;a href=&quot;https://tofuball.moe/&quot;&gt;Tofu&lt;/a&gt; told me that she likes Phabricator for
a different reason: stacked diffs. After some research, I found out that
Phabricator has been discontinued while there is an active fork called
&lt;a href=&quot;https://phorge.it/&quot;&gt;Phorge&lt;/a&gt;. And I began to use it.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-is-Phorge-intriguing-为什么-Phorge-吸引人呢？&quot;&gt;&lt;span&gt; &lt;span&gt; Why is Phorge intriguing? &lt;/span&gt;&lt;span&gt; 为什么 Phorge 吸引人呢？ &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;The main reason I wanted Phorge was indeed the task management system.
GitLab issues has almost nonexistent task management features, at least
in the free version. (Paid versions may have more, like mutually-exclusive
tags, but I frown upon the idea of using non-libre software for hosting
my code, or why wouldn&apos;t I use GitHub.)&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;Stacked diffs, while taking quite some time for me to understand at first,
do solve an important problem for my workflow when I write code for the
Kazv Project. In the original workflow, I needed to branch out from trunk&lt;sup&gt;&lt;a href=&quot;#user-content-fn-trunk&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;,
write code, add a changelog entry in the &lt;code&gt;changelogs&lt;/code&gt; folder, commit, then
open a merge request and wait for our other developer to review it.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;In the mean time, if I wanted to work on other things, I needed to branch
out from trunk again, and follow the same procedure, all while waiting for
reviews from the other developer. If the two branches touched the same file,
conflicts will arise, and the problems are:&lt;/p&gt; &lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span&gt; &lt;span&gt; I usually want to use the new features by myself immediately. This means I need to maintain two states of the same set of changes (one on my local branch, one rebased upon trunk). &lt;/span&gt;&lt;span&gt;  &lt;/span&gt; &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt; &lt;span&gt; The two states may well have conflicts against each other. &lt;/span&gt;&lt;span&gt;  &lt;/span&gt; &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt; &lt;span&gt; I need to do this for &lt;em&gt;each&lt;/em&gt; of my merge requests. &lt;/span&gt;&lt;span&gt;  &lt;/span&gt; &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt; &lt;p&gt;Stacked diffs solves this problem, because the unit of code reviews is not
restricted to the difference between &lt;em&gt;trunk and&lt;/em&gt; one of the other branches.
Instead, it can be any diff. So, if I write feature A upon trunk and then
go on to write feature B, I can start with A, and then submit the diff
&lt;em&gt;between A and B&lt;/em&gt; for review. The state only needs to be maintained once.
And then I can &lt;code&gt;git format-patch&lt;/code&gt; and copy them into my &lt;code&gt;/etc/portage/patches&lt;/code&gt;
to have my package manager install the patched version onto my system
so that I can use every new feature I just wrote.&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#Setting-up-Phorge-to-mirror-a-repository-from-GitLab让-Phorge-从-GitLab-镜像一个仓库&quot;&gt;&lt;span&gt; &lt;span&gt; Setting up Phorge to mirror a repository from GitLab &lt;/span&gt;&lt;span&gt; 让 Phorge 从 GitLab 镜像一个仓库 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;Installing &lt;strong&gt;Phorge&lt;/strong&gt; and &lt;strong&gt;Arcanist&lt;/strong&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-arcanist&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; is covered by their
&lt;a href=&quot;https://we.phorge.it/book/phorge/article/installation_guide/&quot;&gt;official docs&lt;/a&gt;.
I will omit the steps here (my set up is using Docker, so there are some
slight differences, maybe one day I will write another post about this).
One thing to note is that if you are also
on Gentoo, you will need the &lt;code&gt;curl&lt;/code&gt; USE flag on &lt;code&gt;php&lt;/code&gt; to use Arcanist:&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;] euse -E curl -p dev-lang/php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;To use Phorge for code reviews, we first need to host the repository on
Phorge. Phorge can be set up to pull from another git repository, or to
push to another one, or both. But first, we need to create a repository
in &lt;strong&gt;Diffusion&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;First, we go to the main page of Diffusion, and click on &lt;strong&gt;Create Repository&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;It will prompt us to choose a version control system. We choose Git, of course.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;It will then give us a form. Give the repository a name you like. The
&lt;strong&gt;callsign&lt;/strong&gt; is a string composed of only the ASCII capital letters A-Z,
and must be unique across the Phorge installation. It is recommended
to give the repository a callsign as we might need this for Arcanist
to find it properly.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;After submitting the form, we will be directed to the overview page of
the repository. Click on &lt;strong&gt;URIs&lt;/strong&gt; on the left sidebar.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;We can see that there already are default URIs in the list, but we cannot
use them yet (because the repository has not yet been &lt;strong&gt;activated&lt;/strong&gt;).
As we want to mirror them from GitLab, we will add another URI pointing
to GitLab. Click on &lt;strong&gt;Add New URI&lt;/strong&gt; on the right sidebar.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Copy the clone link from your GitLab repository and paste it into
the &lt;strong&gt;URI&lt;/strong&gt; entry. In &lt;strong&gt;I/O Type&lt;/strong&gt;, select &lt;strong&gt;Observe: Copy from a remote&lt;/strong&gt;.
If the GitLab repository is public, using the &lt;strong&gt;https&lt;/strong&gt; clone link would
suffice. If not, use the &lt;strong&gt;ssh&lt;/strong&gt; clone link, and add a credential by
generating a new ssh key, pasting the private key into Phorge, and
the public key into your GitLab account.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Finally, we can go back to the &lt;strong&gt;Basics&lt;/strong&gt; page and click &lt;strong&gt;Activate Repository&lt;/strong&gt;
on the right sidebar. You will soon see your repository being imported.&lt;/p&gt; &lt;/div&gt;
&lt;h3&gt;&lt;a href=&quot;#arcconfig&quot;&gt;&lt;code&gt;.arcconfig&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;We need to make a &lt;code&gt;.arcconfig&lt;/code&gt; file in the repository root so that &lt;strong&gt;Arcanist&lt;/strong&gt;
will know where to find the repository on our Phorge server. Replace the URI
and callsign to the one you have.&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;phabricator.uri&quot; : &quot;https://iron.lily-is.land/&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;repository.callsign&quot;: &quot;TESTTWO&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;It is recommended to commit &lt;code&gt;.arcconfig&lt;/code&gt; into the repository. Why not create
a diff out of it to test that it works?&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;] git add .arcconfig&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;] git commit&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;] arc diff HEAD^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;If you have not used Arcanist before, it will ask you to log in. Otherwise,
your favourite editor (hopefully) will open a file asking you to fill out
a &lt;strong&gt;Summary&lt;/strong&gt; and a &lt;strong&gt;Test Plan&lt;/strong&gt;. After you save and close the file, it will
give you the corresponding Revision URI. You can open it to review it.
&lt;a href=&quot;https://iron.lily-is.land/D74&quot;&gt;Here&lt;/a&gt; is a sample Revision page.&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#But-what-about-CI-CD-那-CI-CD-呢？&quot;&gt;&lt;span&gt; &lt;span&gt; But what about CI/CD? &lt;/span&gt;&lt;span&gt; 那 CI/CD 呢？ &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;GitLab has great CI/CD tooling. How to make use of it when submitting diffs
through Differential Revisions? There is one good news and one bad news.
The bright side is that it has a built-in tool called Harbormaster, which
can be set up to do certain things when you submit or change a Revision.
The dark side? Well... the only thing it can do right now is making an HTTP
request.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The first key is to use a Phorge feature called &lt;strong&gt;Staging Area&lt;/strong&gt;. A staging
area is an url that Arcanist will push your changes to. There is no need that
the Phorge server has write access to that url. Only the user who is using
Arcanist need to have access. To use GitLab CI, we want the staging area to
be on GitLab. For this, we create another GitLab repository. Then, from the
Phorge repository, click &lt;strong&gt;Staging Area&lt;/strong&gt; on the left sidebar. Click on
&lt;strong&gt;Edit Staging&lt;/strong&gt; on the right, and paste the URI of the newly created
GitLab repository into it. This URI will be used to push when you submit
diffs using &lt;code&gt;arc diff&lt;/code&gt;, so use a protocol (https or ssh+git) that you will
be comfortable with.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;&lt;code&gt;arc diff&lt;/code&gt; will push two tags to the staging area: &lt;code&gt;phabricator/diff/X&lt;/code&gt;
and &lt;code&gt;phabricator/base/X&lt;/code&gt;. The former corresponds to the state &lt;em&gt;after&lt;/em&gt;
the diff, and the latter &lt;em&gt;before&lt;/em&gt; it. Of course, we want to run our
pipelines on the &lt;code&gt;phabricator/diff/X&lt;/code&gt; tags. The first thing you
might think of is to have the pipelines run when the tag being pushed
starts with &lt;code&gt;phabricator/diff/&lt;/code&gt;. That is a good idea, but then you
do not have a way to report the status of the build directly to Phorge,
and you will need to find the corresponding pipeline manually.
Instead, we will have Phorge &lt;strong&gt;trigger&lt;/strong&gt; a build on GitLab. Add the
following to your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; in your &lt;strong&gt;main repository&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;workflow:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: &apos;$CI_PIPELINE_SOURCE == &quot;trigger&quot;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: &apos;$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      when: never&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: $CI_COMMIT_BRANCH&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: &apos;$CI_COMMIT_TAG !~ /^phabricator\//&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;a href=&quot;#Triggering-the-build-from-Phorge从-Phorge-触发构建&quot;&gt;&lt;span&gt; &lt;span&gt; Triggering the build from Phorge &lt;/span&gt;&lt;span&gt; 从 Phorge 触发构建 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;we will need to create a &lt;strong&gt;trigger token&lt;/strong&gt; for the staging area repository.
Go to &lt;strong&gt;Settings -&amp;gt; CI/CD&lt;/strong&gt;, then in &lt;strong&gt;Pipeline trigger tokens&lt;/strong&gt;,
click on &lt;strong&gt;Add new token&lt;/strong&gt;. Follow the instructions there.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Go to &lt;strong&gt;Harbormaster&lt;/strong&gt; on Phorge, click on &lt;strong&gt;Manage Build Plans&lt;/strong&gt; on the
left sidebar, and then &lt;strong&gt;Create Build Plan&lt;/strong&gt; on the top-right (by default,
you will need to be an administrator of the Phorge instance to do this).
After you created the build plan, click &lt;strong&gt;Add Build Step&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Choose &lt;strong&gt;Make HTTP Request&lt;/strong&gt; from the list.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;This is where the limitations of Harbormaster comes in our way, as
you can see on this page. First, it
does not support a request body, even though it can send POST requests.
Second, it can only send Basic Auth credentials. Even though GitLab supports
trigger tokens provided by a query parameter, this is not a recommended way
because your token will then be exposed to everyone who can see the diff
you submitted.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;#Proxying-GitLab-requests代理-GitLab-的请求&quot;&gt;&lt;span&gt; &lt;span&gt; Proxying GitLab requests &lt;/span&gt;&lt;span&gt; 代理 GitLab 的请求 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;We will use nginx to reverse-proxy our requests and rewrite a Basic
Auth header into a query parameter. This will take in the user part
of a Basic Auth header and add it to the query parameter called &lt;code&gt;token&lt;/code&gt;.
Replace &lt;code&gt;&amp;lt;gitlab&amp;gt;&lt;/code&gt; in the following
file with the address and port your GitLab is listening to. For example,
you might write &lt;code&gt;proxy_pass http://localhost:8964;&lt;/code&gt;. Remember &lt;strong&gt;not&lt;/strong&gt; to
have a trailing slash after it.&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;server {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; listen 0.0.0.0:443 ssl;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; listen [::]:443 ssl;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; server_name gt.lily-is.land;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; server_tokens off;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/gt.lily-is.land/fullchain.pem;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/gt.lily-is.land/privkey.pem;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; location /api {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rewrite ^(.+)$ $1?token=$remote_user break;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_pass http://&amp;lt;gitlab&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_redirect off;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header Host $http_host;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header X-Real-IP $remote_addr;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header X-Forwarded-Proto $scheme;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header X-Forwarded-Protocol $scheme;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  proxy_set_header X-Url-Scheme $scheme;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; access_log /var/log/nginx/gitlab_access.log;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; error_log /var/log/nginx/gitlab_error.log;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;a href=&quot;#Two-step-trigger-for-GitLabGitLab-的两步触发器&quot;&gt;&lt;span&gt; &lt;span&gt; Two-step trigger for GitLab &lt;/span&gt;&lt;span&gt; GitLab 的两步触发器 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;Although GitLab offers a way to trigger a pipeline without using the request
body, it does not work in our case, because our tag name &lt;code&gt;phabricator/diff/X&lt;/code&gt;
has slashes in it. (GitLab docs say it works if you urlencode the slash, but
I tried, and it does not, at least when called from Phorge.) Instead, we use
a simple branch name, &lt;code&gt;servant&lt;/code&gt;. Add the following to the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;
file in the &lt;code&gt;servant&lt;/code&gt; branch of your &lt;strong&gt;staging repository&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;workflow:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: &apos;$CI_PIPELINE_SOURCE == &quot;trigger&quot;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;stages:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  - trigger&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;trigger-build:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: trigger&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  image: curlimages/curl&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - &apos;curl --request POST --form token=&quot;$TRIGGER_TOKEN&quot; --form ref=phabricator/diff/&quot;$DIFFID&quot; --form &quot;variables[TARGET_PHID]=$TARGET_PHID&quot; &quot;https://lily-is.land/api/v4/projects/$CI_PROJECT_ID/trigger/pipeline&quot;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;And in your &lt;strong&gt;staging repository&lt;/strong&gt;,
add a CI variable &lt;code&gt;TRIGGER_TOKEN&lt;/code&gt;, masked and protected, with the
value set to the trigger token you just generated.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;Now go back to Harbormaster&apos;s Add Build Step page, we have collected everything
we need to trigger a pipeline.
Put &lt;code&gt;https://&amp;lt;gitlab&amp;gt;/api/v4/projects/&amp;lt;project-id&amp;gt;/ref/servant/trigger/pipeline?variables[TARGET_PHID]=${target.phid}&amp;amp;variables[DIFFID]=${buildable.diff}&lt;/code&gt;
in the &lt;strong&gt;URI&lt;/strong&gt; field. Replace &lt;code&gt;&amp;lt;gitlab&amp;gt;&lt;/code&gt; with the publicly accessible URI
of your GitLab instance, and &lt;code&gt;&amp;lt;project-id&amp;gt;&lt;/code&gt; with the project id of your
&lt;strong&gt;staging repository&lt;/strong&gt;. Choose &lt;strong&gt;POST&lt;/strong&gt; as the &lt;strong&gt;HTTP Method&lt;/strong&gt;.
In &lt;strong&gt;Credentials&lt;/strong&gt;, &lt;strong&gt;Add New Credential&lt;/strong&gt;, and put the trigger token into
&lt;strong&gt;Login/Username&lt;/strong&gt; field, leaving &lt;strong&gt;Password&lt;/strong&gt; empty. Choose &lt;strong&gt;Wait For Message&lt;/strong&gt;
for &lt;strong&gt;When Complete&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;#Trigger-a-build-automatically自动触发构建&quot;&gt;&lt;span&gt; &lt;span&gt; Trigger a build automatically &lt;/span&gt;&lt;span&gt; 自动触发构建 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;You will need to create a &lt;strong&gt;Herald rule&lt;/strong&gt; for this. As an administrator,
go to &lt;strong&gt;Herald&lt;/strong&gt; in Phorge, and click on &lt;strong&gt;Create Herald Rule&lt;/strong&gt;. Choose
&lt;strong&gt;Differential Revisions&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Then click on &lt;strong&gt;Global Rule&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;In &lt;strong&gt;Conditions&lt;/strong&gt;, put &lt;strong&gt;Repository&lt;/strong&gt; &lt;strong&gt;is any of&lt;/strong&gt;, then enter the
Phorge repository just created. In &lt;strong&gt;Action&lt;/strong&gt;, choose &lt;strong&gt;every time
this rule matches&lt;/strong&gt;, and select &lt;strong&gt;Run build plans&lt;/strong&gt;, then choose
the build plan we just created.&lt;/p&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt; &lt;p&gt;Now change something else, use &lt;code&gt;arc diff HEAD^&lt;/code&gt; to create another diff.
It should push to the staging area (maybe it will prompt you for
credentials), and run the build plan automatically.&lt;/p&gt; &lt;/div&gt;
&lt;h3&gt;&lt;a href=&quot;#Reporting-the-results-back-to-Phorge把结果报回给-Phorge&quot;&gt;&lt;span&gt; &lt;span&gt; Reporting the results back to Phorge &lt;/span&gt;&lt;span&gt; 把结果报回给 Phorge &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt; &lt;p&gt;We need to first generate a &lt;strong&gt;Conduit API Token&lt;/strong&gt; for this. To do so,
it is advised to use a separate Phorge account for it. Make sure
that the Phorge account has access to the build plan and the diff.
In your user settings page, go to &lt;strong&gt;Conduit API Tokens&lt;/strong&gt; and click on
&lt;strong&gt;Generate Token&lt;/strong&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;In the &lt;strong&gt;staging repository&lt;/strong&gt;&apos;s CI/CD settings, add a variable, masked,
called &lt;code&gt;CONDUIT_TOKEN&lt;/code&gt;, and paste the generated into it.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;Add the following to your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; of your &lt;strong&gt;main repository&lt;/strong&gt;.
&lt;strong&gt;Also, add a stage &lt;code&gt;prepare&lt;/code&gt; to the very beginning of the &lt;code&gt;stages&lt;/code&gt;
and &lt;code&gt;report&lt;/code&gt; to the end.&lt;/strong&gt;&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;.report:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  image:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    name: &apos;reg.lily.kazv.moe/infra/phorge-ci-tools:servant&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: $TARGET_PHID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      when: always&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - when: never&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  before_script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - pipelineUrl=&quot;$CI_PROJECT_URL&quot;/-/pipelines/&quot;$CI_PIPELINE_ID&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;report-start:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  extends: .report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: prepare&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - &apos;echo &quot;{\&quot;receiver\&quot;: \&quot;$TARGET_PHID\&quot;, \&quot;type\&quot;: \&quot;work\&quot;, \&quot;unit\&quot;: [{\&quot;name\&quot;: \&quot;GitLab CI (information only)\&quot;, \&quot;result\&quot;: \&quot;skip\&quot;, \&quot;details\&quot;: \&quot;$pipelineUrl\&quot;, \&quot;format\&quot;: \&quot;remarkup\&quot;}]}&quot; | /tools/arcanist/bin/arc call-conduit --conduit-uri https://iron.lily-is.land/ --conduit-token &quot;$CONDUIT_TOKEN&quot; -- harbormaster.sendmessage&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;report-success:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  extends: .report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: $TARGET_PHID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      when: on_success&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - when: never&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - &apos;echo &quot;{\&quot;receiver\&quot;: \&quot;$TARGET_PHID\&quot;, \&quot;type\&quot;: \&quot;pass\&quot;}&quot; | /tools/arcanist/bin/arc call-conduit --conduit-uri https://iron.lily-is.land/ --conduit-token &quot;$CONDUIT_TOKEN&quot; -- harbormaster.sendmessage&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;report-failure:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  extends: .report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: $TARGET_PHID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      when: on_failure&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - when: never&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - &apos;echo &quot;{\&quot;receiver\&quot;: \&quot;$TARGET_PHID\&quot;, \&quot;type\&quot;: \&quot;fail\&quot;}&quot; | /tools/arcanist/bin/arc call-conduit --conduit-uri https://iron.lily-is.land/ --conduit-token &quot;$CONDUIT_TOKEN&quot; -- harbormaster.sendmessage&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;Update the diff to include the changes. Then you will be able to see the
pipeline run, and the link to the pipeline can be found on the &lt;strong&gt;Buildable&lt;/strong&gt;
page. Here is &lt;a href=&quot;https://iron.lily-is.land/B100&quot;&gt;an example&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;] git add .gitlab-ci.yml&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;] git commit --amend&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;] arc diff HEAD^&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;a href=&quot;#And-code-coverage-还有代码覆盖呢？&quot;&gt;&lt;span&gt; &lt;span&gt; And code coverage? &lt;/span&gt;&lt;span&gt; 还有代码覆盖呢？ &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;Another good thing from GitLab is code coverage visualization. On
the merge request page, you can see which lines are covered and which
are not. GitLab takes an XML file in cobertura format. Phorge, on the
other hand, uses a different format, which is a mapping from file names
to a &lt;a href=&quot;https://we.phorge.it/book/phorge/article/arcanist_coverage/#building-coverage-support&quot;&gt;string indicating the lines covered&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;Luckily, there is a tool called [pycobertura][pycob] that can help us
do the conversion. I created a &lt;a href=&quot;https://lily-is.land/infra/phorge-ci-tools/-/blob/eaae8d89c1332defa650d69bbd82ff57de62e6c7/cobertura-to-phorge&quot;&gt;script&lt;/a&gt; to convert cobertura XML files to
a JSON in Phorge&apos;s coverage format.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;We can add the following to the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; in the &lt;strong&gt;main repository&lt;/strong&gt;.
Assuming your previous jobs give you a cobertura XML in &lt;code&gt;build/coverage.xml&lt;/code&gt;
and you collect it as an artifact, the &lt;code&gt;coverage-report&lt;/code&gt; job generates a
HTML file visualizing the code coverage in addition to the JSON.
The &lt;code&gt;upload-coverage&lt;/code&gt; job sends the coverage information to Harbormaster,
so you can view it in the Differential Revision. Here is an &lt;a href=&quot;https://iron.lily-is.land/D74&quot;&gt;example&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The &lt;code&gt;coverage-vis&lt;/code&gt; stage should be after the stage where your coverage job
is run, and the &lt;code&gt;coverage-upload&lt;/code&gt; stage should be after &lt;code&gt;coverage-vis&lt;/code&gt;, but
before &lt;code&gt;report&lt;/code&gt; (this is important, because the &lt;code&gt;report&lt;/code&gt; stage marks the
build as final, and you cannot change the status any more).&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&apos;coverage-report&apos;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules: *build-rules&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: coverage-vis&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  image: &apos;reg.lily.kazv.moe/infra/phorge-ci-tools/pycobertura:servant&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - pycobertura show ./build/coverage.xml --format html --output ./build/coverage.html --source .&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - /tools/cobertura-to-phorge ./build/coverage.xml . &amp;gt; ./build/coverage.json&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  artifacts:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    paths:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      - build/coverage.html&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      - build/coverage.json&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;upload-coverage:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  extends: .report&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  stage: coverage-upload&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rules:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - if: $TARGET_PHID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      changes: *src-chg&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      when: always&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - when: never&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - &apos;{ echo &quot;{\&quot;receiver\&quot;: \&quot;$TARGET_PHID\&quot;, \&quot;type\&quot;: \&quot;work\&quot;, \&quot;unit\&quot;: [{\&quot;name\&quot;: \&quot;Test coverage\&quot;, \&quot;result\&quot;: \&quot;pass\&quot;, \&quot;details\&quot;: \&quot;$pipelineUrl\&quot;, \&quot;format\&quot;: \&quot;remarkup\&quot;, \&quot;coverage\&quot;:&quot;; cat build/coverage.json; echo &quot;}]}&quot;; } | /tools/arcanist/bin/arc call-conduit --conduit-uri https://iron.lily-is.land/ --conduit-token &quot;$CONDUIT_TOKEN&quot; -- harbormaster.sendmessage&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;section&gt;&lt;h2&gt;&lt;a href=&quot;#footnote-label&quot;&gt;Footnotes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It&apos;s called &lt;code&gt;servant&lt;/code&gt; in the repositories of the Kazv Project.
This name comes from Fate/Zero. &lt;a href=&quot;#user-content-fnref-trunk&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Arcanist is the command line tool to interact with Phorge. &lt;a href=&quot;#user-content-fnref-arcanist&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content></entry></feed>