Skip to content

Commit 7c7bfea

Browse files
Merge pull request #97 from Factory-AI/dev
Merge Dev into main to add gitlab functionality
2 parents 6dd4ac3 + 150e8c2 commit 7c7bfea

46 files changed

Lines changed: 4052 additions & 343 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,39 @@ The guided flow will:
3838

3939
For GitHub-only setups you can also run `/install-github-app`. See the [Automated Code Review guide](https://docs.factory.ai/guides/droid-exec/code-review) and the [GitHub App installation guide](https://docs.factory.ai/cli/features/install-github-app) for full details.
4040

41+
### GitLab
42+
43+
GitLab support ships as a **GitLab CI/CD Component** that delivers automated code review — inline MR comments on every merge request, with optional security review.
44+
45+
Two files in your project:
46+
47+
`factory/droid-review.yml`:
48+
49+
```yaml
50+
include:
51+
- project: "factory-components/droid-action"
52+
ref: main
53+
file: "/templates/droid-review.yml"
54+
inputs:
55+
automatic_review: "true"
56+
automatic_security_review: "false"
57+
review_depth: "deep"
58+
59+
droid-review:
60+
variables:
61+
FACTORY_API_KEY: $FACTORY_API_KEY
62+
GITLAB_TOKEN: $GITLAB_TOKEN
63+
```
64+
65+
`.gitlab-ci.yml` (one include line, append to existing if present):
66+
67+
```yaml
68+
include:
69+
- local: "factory/droid-review.yml"
70+
```
71+
72+
Full setup, available inputs, and troubleshooting live in [`docs/gitlab-setup.md`](docs/gitlab-setup.md).
73+
4174
### Manual Setup
4275

4376
If you prefer to wire things up by hand:

docs/gitlab-setup.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# GitLab Setup
2+
3+
This action ships a **GitLab CI/CD Component** that delivers the same
4+
automated code-review experience as the GitHub action on GitLab merge
5+
requests (MRs). The component runs on every `merge_request_event` pipeline,
6+
posts inline comments on the diff, maintains a sticky tracking note, and
7+
optionally runs a security-focused subagent in parallel.
8+
9+
## Quick start with `/install-code-review`
10+
11+
The fastest path is the guided installer built into the Droid CLI:
12+
13+
```bash
14+
droid
15+
> /install-code-review
16+
```
17+
18+
It detects GitLab, asks which account should be the poster of review
19+
comments (you supply its PAT as `GITLAB_TOKEN`), asks the configuration
20+
questions below, drops `factory/droid-review.yml` in your project, wires
21+
it into `.gitlab-ci.yml`, and opens an MR / direct-commits to the target
22+
project(s).
23+
24+
## Manual installation
25+
26+
### 1. Prerequisites
27+
28+
| Requirement | How to get it |
29+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30+
| GitLab Maintainer role on the project | Repo admin grants you Maintainer (40) |
31+
| `FACTORY_API_KEY` CI/CD variable | Generate at <https://app.factory.ai/settings/api-keys>; add as **masked**, **unprotected** variable at the project, subgroup, or top-level group level |
32+
| `GITLAB_TOKEN` CI/CD variable | A personal access token with the `api` scope, owned by whichever account should post review comments. The token owner is the poster — there is no API impersonation. Add as **masked**, **unprotected**. |
33+
34+
### 2. Add the CI/CD Component
35+
36+
Drop-in samples live in [`gitlab/examples/`](../gitlab/examples/). The
37+
layout is two files:
38+
39+
- [`factory/droid-review.yml`](../gitlab/examples/factory/droid-review.yml) — self-contained config (include + inputs + variables). Drop verbatim.
40+
- [`.gitlab-ci.yml`](../gitlab/examples/.gitlab-ci.yml) — project-root entry point. If you already have one, append the include line below to its `include:` block.
41+
42+
**`factory/droid-review.yml`** (drop into your project):
43+
44+
```yaml
45+
include:
46+
- project: "factory-components/droid-action"
47+
ref: main
48+
file: "/templates/droid-review.yml"
49+
inputs:
50+
automatic_review: "true"
51+
automatic_security_review: "false"
52+
review_depth: "deep"
53+
include_suggestions: "true"
54+
security_block_on_critical: "true"
55+
security_block_on_high: "false"
56+
57+
droid-review:
58+
variables:
59+
FACTORY_API_KEY: $FACTORY_API_KEY
60+
GITLAB_TOKEN: $GITLAB_TOKEN
61+
```
62+
63+
**`.gitlab-ci.yml`** (project root, just needs the one include line):
64+
65+
```yaml
66+
include:
67+
- local: "factory/droid-review.yml"
68+
```
69+
70+
> The remote `include:` URL is pinned to `@main`, which tracks the
71+
> latest stable cut of droid-action.
72+
73+
### 3. Push an MR
74+
75+
Open or push to an MR. The next `merge_request_event` pipeline will run
76+
the `droid-review` job. Expect ~5-10 minutes for a typical change.
77+
78+
## Inputs
79+
80+
| Input | Default | Description |
81+
| ---------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
82+
| `automatic_review` | `"true"` | Run code review automatically on every MR pipeline. |
83+
| `automatic_security_review` | `"false"` | Run a parallel security-focused subagent on every MR pipeline. Findings are prefixed `[security]` and posted alongside code-review comments. |
84+
| `review_depth` | `"deep"` | `"deep"` (thorough) or `"shallow"` (fast). |
85+
| `review_model` | `""` | Override the model. Empty = use depth preset. |
86+
| `reasoning_effort` | `""` | Override reasoning effort. Empty = use depth preset. |
87+
| `include_suggestions` | `"true"` | Include code suggestion blocks in review comments when the fix is high-confidence. |
88+
| `security_block_on_critical` | `"true"` | Block merge on CRITICAL security findings. (Mirrors GitHub action; surface-level parity.) |
89+
| `security_block_on_high` | `"false"` | Block merge on HIGH security findings. (Mirrors GitHub action; surface-level parity.) |
90+
| `settings` | `""` | Droid Exec settings as a JSON string or a path to a JSON file. Merged into `~/.factory/droid/settings.json` before each `droid exec` call. |
91+
92+
## What you get
93+
94+
Each MR pipeline produces:
95+
96+
- **Inline review comments** anchored to the relevant diff lines, posted in a
97+
single batched `submit_review` call. Findings are prefixed with priority
98+
tags (`P0`, `P1`, `P2`, `P3`) and `[security]` for security findings.
99+
- **A sticky tracking note** on the MR with pipeline + job links, telemetry
100+
(`N turns • Xm Ys`), session IDs, and a security badge when
101+
`automatic_security_review` is enabled.
102+
- **Debug artifacts** at `.droid-debug/` (prompts, candidate JSON, raw
103+
stream-json logs) retained for 1 week.
104+
- **A custom droid library** copied from
105+
`$DROID_ACTION_DIR/.factory/droids` into `~/.factory/droids` on the
106+
runner, so subagents like `security-reviewer` are reachable.

gitlab/examples/.gitlab-ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Example project-root .gitlab-ci.yml.
2+
#
3+
# If the project doesn't have a .gitlab-ci.yml yet, create one with at
4+
# minimum the include line below. If it already has one, just append the
5+
# `- local: "factory/droid-review.yml"` entry to its existing `include:`
6+
# block (or add a new `include:` block if there isn't one).
7+
8+
include:
9+
- local: "factory/droid-review.yml"

gitlab/examples/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# GitLab examples
2+
3+
Two-file layout for consuming the droid-action GitLab CI/CD Component:
4+
5+
```
6+
your-project/
7+
├── .gitlab-ci.yml # gains one `include:` line
8+
└── factory/
9+
└── droid-review.yml # self-contained droid-review config
10+
```
11+
12+
| File | Where it lives in your project | Purpose |
13+
| ----------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------- |
14+
| `factory/droid-review.yml` | drop verbatim | Self-contained config: includes the remote Component, sets inputs, wires CI/CD variables. |
15+
| `.gitlab-ci.yml` | append one `include:` line if the file exists | Project-root entry point. Just needs to include `factory/droid-review.yml`. |
16+
17+
The two required CI/CD variables (`FACTORY_API_KEY`, `GITLAB_TOKEN`) are set
18+
in the GitLab UI under **Project → Settings → CI/CD → Variables** (or at
19+
the group level for org-wide rollout), masked and unprotected.
20+
21+
For the full input reference see the docs at [`docs/gitlab-setup.md`](../../docs/gitlab-setup.md).
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# factory/droid-review.yml
2+
#
3+
# Drop this file at `factory/droid-review.yml` in your project, then
4+
# add a single `include: - local: "factory/droid-review.yml"` line to
5+
# your `.gitlab-ci.yml` (see ../.gitlab-ci.yml for the entry-point
6+
# example).
7+
#
8+
# Prerequisites (one-time, set in Project / Group → Settings → CI/CD):
9+
#
10+
# * FACTORY_API_KEY — masked variable. Get one at
11+
# https://app.factory.ai/settings/api-keys
12+
# * GITLAB_TOKEN — masked variable. A personal access token with
13+
# `api` scope, owned by whichever GitLab account should post review
14+
# comments. The token owner IS the poster.
15+
16+
include:
17+
- project: "factory-components/droid-action"
18+
ref: main
19+
file: "/templates/droid-review.yml"
20+
inputs:
21+
automatic_review: "true" # run on every MR event; "false" disables
22+
review_depth: "deep" # "deep" (thorough) or "shallow" (fast)
23+
include_suggestions: "true" # post code-suggestion blocks for high-confidence fixes
24+
automatic_security_review: "false" # enable to flag vulns alongside the regular review
25+
security_block_on_critical: "true" # block merge on CRITICAL findings (when security review is on)
26+
security_block_on_high: "false" # block merge on HIGH findings
27+
28+
droid-review:
29+
variables:
30+
FACTORY_API_KEY: $FACTORY_API_KEY
31+
GITLAB_TOKEN: $GITLAB_TOKEN

src/core/review/artifacts/types.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Shared shape for the three on-disk review artifacts. Both GitHub and
3+
* GitLab pipelines pre-compute the same trio (diff, existing comments,
4+
* description) and write them under `${tempDir}/droid-prompts/`, then
5+
* pass the resulting paths into the Pass 1 / Pass 2 prompts.
6+
*
7+
* The fetch mechanics differ substantially per platform (git+gh CLI vs
8+
* REST API), so we don't try to share the fetchers — only the path
9+
* shape and the disk-write helper.
10+
*/
11+
export type ReviewArtifactPaths = {
12+
diffPath: string;
13+
commentsPath: string;
14+
descriptionPath: string;
15+
};
16+
17+
/**
18+
* Raw content for each of the three artifacts, before they're written
19+
* to disk by `writeReviewArtifacts`.
20+
*/
21+
export type ReviewArtifactContents = {
22+
diff: string;
23+
comments: unknown; // JSON-serializable
24+
description: string;
25+
};

src/core/review/artifacts/write.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as fs from "fs/promises";
2+
import * as path from "path";
3+
import type { ReviewArtifactContents, ReviewArtifactPaths } from "./types";
4+
5+
/**
6+
* Naming convention for review-artifact files on disk. Each platform
7+
* gets its own basename for the diff and description (pr.diff /
8+
* mr.diff, pr_description.txt / mr_description.txt) but the existing
9+
* comments file is platform-neutral.
10+
*/
11+
export type ReviewArtifactNames = {
12+
diff: string;
13+
comments: string;
14+
description: string;
15+
};
16+
17+
/**
18+
* Write the three review-artifact files into `outDir` in parallel,
19+
* creating `outDir` if it doesn't yet exist. Returns the resolved
20+
* on-disk paths so the caller can hand them straight to the prompt
21+
* builder.
22+
*/
23+
export async function writeReviewArtifacts(
24+
outDir: string,
25+
contents: ReviewArtifactContents,
26+
names: ReviewArtifactNames,
27+
): Promise<ReviewArtifactPaths> {
28+
await fs.mkdir(outDir, { recursive: true });
29+
30+
const diffPath = path.join(outDir, names.diff);
31+
const commentsPath = path.join(outDir, names.comments);
32+
const descriptionPath = path.join(outDir, names.description);
33+
34+
await Promise.all([
35+
fs.writeFile(diffPath, contents.diff),
36+
fs.writeFile(commentsPath, JSON.stringify(contents.comments, null, 2)),
37+
fs.writeFile(descriptionPath, contents.description),
38+
]);
39+
40+
return { diffPath, commentsPath, descriptionPath };
41+
}

0 commit comments

Comments
 (0)