Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3c2c612
feat(gitlab): implement component 1 read-only package skeleton
Kaap10 Sep 24, 2026
b35c5f4
test(gitlab): implement component 2 offline unit tests suite
Kaap10 Sep 24, 2026
3aa7784
fix(gitlab): correct string interpolation and pyproject config
Kaap10 Sep 24, 2026
73e88db
docs(gitlab): implement component 3 docs and contracts
Kaap10 Sep 24, 2026
962934d
docs(gitlab): implement component 4 registry and taxonomy sync
Kaap10 Sep 24, 2026
0194e33
fix(validator): resolve windows test suite encoding and pathing issues
Kaap10 Sep 24, 2026
67239a2
feat(gitlab): implement GitLab bridge tool adapter
Kaap10 Sep 24, 2026
95fa943
fix(validator): improve Windows path handling and symlink compatibility
Kaap10 Sep 24, 2026
e835a88
docs(release-management): tighten prepare SKILL.md frontmatter length
Kaap10 Sep 24, 2026
960725f
fix(ci): resolve codeql alerts, gitlab contract docs, and token counts
Kaap10 Sep 24, 2026
55820df
fix(gitlab): satisfy documentation contract, ruff lint, and mypy typing
Kaap10 Sep 24, 2026
476acf8
fix(gitlab): complete readme metadata, SIM102 ruff fix, and mypy typing
Kaap10 Sep 24, 2026
853b154
fix(gitlab): complete readme metadata, SIM102 ruff fix, and mypy typing
Kaap10 Sep 24, 2026
9339331
fix(validator): remove unneeded conftest to resolve ruff and mypy sta…
Kaap10 Sep 24, 2026
f3ea7f8
fix(gitlab): address code review findings for auth, redirects, pagina…
Kaap10 Sep 25, 2026
5a00631
fix(gitlab): address maintainer review feedback on coverage, auth, re…
Kaap10 Sep 25, 2026
1bf90f3
Merge remote-tracking branch 'upstream/main' into feat/tools-gitlab
Kaap10 Sep 25, 2026
70f7b76
fix(gitlab): address maintainer review on partial coverage, paginatio…
Kaap10 Sep 25, 2026
1efbfea
docs(vendor-neutrality): restore skill assessment counts in generated…
Kaap10 Sep 25, 2026
2a5d060
fix(gitlab): address maintainer review on auth scheme, limit paginati…
Kaap10 Sep 27, 2026
6d60842
Merge branch 'upstream/main' into feat/tools-gitlab
Kaap10 Sep 27, 2026
1c0ee2c
fix(dev): make test_identical_text_inside_generated_regions_is_invisi…
Kaap10 Sep 27, 2026
3bcfa26
style(dev): format test_check_duplication.py with ruff
Kaap10 Sep 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ contract:change-request:
- 'tools/bitbucket/**'
- 'tools/change-request/**'
- 'tools/github/**'
- 'tools/gitlab/**'
- 'tools/jira-patch/**'
- 'tools/mail-patch/**'

Expand Down Expand Up @@ -95,6 +96,7 @@ contract:source-control:
- 'tools/asf-svn/**'
- 'tools/fossil/**'
- 'tools/github/**'
- 'tools/gitlab/**'
- 'tools/sourcehut/**'
- 'tools/vcs/**'

Expand All @@ -107,6 +109,7 @@ contract:tracker:
- 'tools/github/**'
- 'tools/github-body-field/**'
- 'tools/github-rollup/**'
- 'tools/gitlab/**'
- 'tools/jira/**'
- 'tools/sourcehut/**'

Expand Down
2 changes: 1 addition & 1 deletion docs/adapters/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extension point = a documented, labelled slot with a tracking issue.
| [`tools/forwarder-relay`](../../tools/forwarder-relay/) | ASF-security ([`tools/gmail/asf-relay.md`](../../tools/gmail/asf-relay.md)) | huntr.com, HackerOne, GHSA relay |
| [`tools/scan-format`](../../tools/scan-format/) | ASVS | other scanner formats |
| [`tools/vcs`](../../tools/vcs/) | Git, Mercurial, Fossil | Subversion [\#602](https://github.com/apache/magpie/issues/602), Jujutsu [\#603](https://github.com/apache/magpie/issues/603), Perforce [\#605](https://github.com/apache/magpie/issues/605) |
| Forge / tracker | [`github`](../../tools/github/), [`jira`](../../tools/jira/), [`bitbucket`](../../tools/bitbucket/) `partial-read-only` foundation, [`sourcehut`](../../tools/sourcehut/), [`fossil`](../../tools/fossil/) | GitLab [\#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [\#310](https://github.com/apache/magpie/issues/310), Pagure [\#312](https://github.com/apache/magpie/issues/312), deeper Bitbucket/Jira coverage [\#606](https://github.com/apache/magpie/issues/606), Bugzilla [\#302](https://github.com/apache/magpie/issues/302) |
| Forge / tracker | [`github`](../../tools/github/), [`jira`](../../tools/jira/), [`bitbucket`](../../tools/bitbucket/) `partial-read-only` foundation, [`sourcehut`](../../tools/sourcehut/), [`fossil`](../../tools/fossil/), [`gitlab`](../../tools/gitlab/) `partial-read-only` foundation | Forgejo/Gitea [\#310](https://github.com/apache/magpie/issues/310), Pagure [\#312](https://github.com/apache/magpie/issues/312), deeper Bitbucket/Jira coverage [\#606](https://github.com/apache/magpie/issues/606), GitLab [\#305](https://github.com/apache/magpie/issues/305), Bugzilla [\#302](https://github.com/apache/magpie/issues/302) |
| Agent harness | Claude Code, [Codex](codex.md) `experimental` ([#313](https://github.com/apache/magpie/issues/313)), [Gemini CLI](gemini.md) `experimental` ([#314](https://github.com/apache/magpie/issues/314)), [Local LLM (Ollama / llama.cpp / vLLM)](local-llm.md) ([#315](https://github.com/apache/magpie/issues/315)), [Cursor](cursor.md) ([#316](https://github.com/apache/magpie/issues/316)), [Goose](goose.md) `guide only` ([#319](https://github.com/apache/magpie/issues/319)), [Aider](aider.md) `guide only` ([#317](https://github.com/apache/magpie/issues/317)), [GitHub Copilot](copilot.md) `guide only` ([#318](https://github.com/apache/magpie/issues/318)) | Amazon Q [#320](https://github.com/apache/magpie/issues/320)–OpenHands [#322](https://github.com/apache/magpie/issues/322) |
| Security cross-ref | [`tools/osv`](../../tools/osv/) | — |

Expand Down
1 change: 1 addition & 0 deletions docs/labels-and-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ or a contract-free mix of substrates (e.g. `tools/spec-inventory` is
| [`tools/bitbucket`](../tools/bitbucket/) | `contract:change-request` + `contract:tracker` | Coverage: `partial`. Bitbucket Cloud and Bitbucket Data Center bridge foundation for repository metadata context, branch restriction context for PR-management decisions, pull-request discovery/fetching, read-only commit fetching, read-only diff fetching, comments-only discussion fetching, read-only review-state fetching, Cloud-only pull-request task listing/fetching, read-only merge-check context fetching, and read-only status fetching, plus narrowly scoped Cloud pull-request comment creation and approve/unapprove actions. Tracker coverage includes Cloud-only issue listing/fetching, issue comment fetching, issue attachment metadata fetching, and confirmed issue-comment creation. The `partial` qualifier means this tool implements named contract operations but does not satisfy the complete contract and must not be counted as a complete/selectable backend. Broader pull-request review/mutation, broader issue writes, and linked Jira handoff coverage remain incomplete. |
| [`tools/fossil`](../tools/fossil/) | `contract:tracker` + `contract:source-control` | Fossil SCM forge bridge: integrates local SQLite-backed ticket tracking, wiki, and forum reads with the version-control shim |
| [`tools/github`](../tools/github/) | `contract:tracker` + `contract:source-control` + `contract:change-request` | GitHub REST / GraphQL tracker substrate (called by every lifecycle phase) plus the Git source-control binding documented in [`source-control.md`](../tools/github/source-control.md) (runnable backend in [`tools/vcs`](../tools/vcs/)) and the pull-request review/merge gate (`change-request`; the ASF default backend, alongside `tools/jira-patch/` and `tools/mail-patch/` for SVN-first projects) |
| [`tools/gitlab`](../tools/gitlab/) | `contract:tracker` + `contract:source-control` + `contract:change-request` | Coverage: `partial`. GitLab REST API v4 forge bridge foundation for repository metadata context under `contract:source-control`, issue listing/fetching under `contract:tracker`, and merge request discovery, diffs, commits, and CI pipeline status under `contract:change-request`. The `partial` qualifier means this tool implements named contract operations but does not satisfy the complete contract and must not be counted as a complete/selectable backend. Write operations, issue mutation, and merge request mutations remain out of scope for this foundation. |
| [`tools/github-body-field`](../tools/github-body-field/) | `contract:tracker` | Read or rewrite one `### Field` section of a GitHub issue body without bringing the body into agent context — substrate helper for the security-sync skills |
| [`tools/github-rollup`](../tools/github-rollup/) | `contract:tracker` | Append to (or create) the status-rollup comment on a GitHub issue without bringing the rollup body into agent context — substrate helper for every status-update-emitting skill |
| [`tools/gmail`](../tools/gmail/) | `contract:mail-source` + `contract:mail-create` + `contract:mail-archive` | Gmail API substrate — inbound report intake (`mail-source`), thread / archive reads (`mail-archive`), plus outbound courtesy-reply drafting (`mail-create`); read + draft only, never sends |
Expand Down
12 changes: 7 additions & 5 deletions docs/vendor-neutrality.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@ declare it under *Tools enabled*; no skill changes).

The forge/tracker extension points are open, labelled `good first
issue`, not hypothetical:
[GitLab](https://github.com/apache/magpie/issues/305),
[GitLab](https://github.com/apache/magpie/issues/305) (initial
[`tools/gitlab`](../tools/gitlab/) `partial-read-only` bridge;
full write and mutation coverage tracked there),
[Codeberg / Gitea / Forgejo](https://github.com/apache/magpie/issues/310),
[Pagure](https://github.com/apache/magpie/issues/312) (Fedora /
`pagure.io`),
Expand Down Expand Up @@ -503,7 +505,7 @@ coverage without pretending one team can implement an open-ended set.
|---|---|---|---|
| LLM backend | ✅ by construction | Claude Code, Ollama, vLLM, Apache-hosted, Bedrock, direct Anthropic | Any endpoint meeting the capability floor + privacy gate |
| Agentic harness | ✅ by construction (`AGENTS.md` standard) | Claude Code; OpenCode; [Codex adapter](adapters/codex.md) (experimental); [Gemini adapter](adapters/gemini.md) (experimental); community use under Cursor, Copilot, Kiro | Remaining runtime adapters [#314–#322](https://github.com/apache/magpie/issues?q=is%3Aissue+state%3Aopen+adapter+in%3Atitle) |
| Forge / tracker | ✅ by construction | GitHub, Jira, SourceHut; Bitbucket `partial-read-only` foundation excluded from complete-backend counts; CVE/scan/relay via adapter contracts | GitLab [#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [#310](https://github.com/apache/magpie/issues/310), Pagure [#312](https://github.com/apache/magpie/issues/312), full Bitbucket tracker/change-request/Jira coverage [#606](https://github.com/apache/magpie/issues/606), Bugzilla [#302](https://github.com/apache/magpie/issues/302) |
| Forge / tracker | ✅ by construction | GitHub, Jira, SourceHut; Bitbucket and GitLab `partial-read-only` foundations excluded from complete-backend counts; CVE/scan/relay via adapter contracts | Forgejo/Gitea [#310](https://github.com/apache/magpie/issues/310), Pagure [#312](https://github.com/apache/magpie/issues/312), full Bitbucket tracker/change-request/Jira coverage [#606](https://github.com/apache/magpie/issues/606), GitLab [#305](https://github.com/apache/magpie/issues/305), Bugzilla [#302](https://github.com/apache/magpie/issues/302) |
| Communication channels | ✅ by construction | PonyMail / mail-archive reads | mbox [#304](https://github.com/apache/magpie/issues/304), IMAP [#303](https://github.com/apache/magpie/issues/303), Mailman 3 [#306](https://github.com/apache/magpie/issues/306); Discourse [#307](https://github.com/apache/magpie/issues/307), Zulip [#308](https://github.com/apache/magpie/issues/308), Matrix [#309](https://github.com/apache/magpie/issues/309) |
| Source control (VCS) | ✅ by construction | **Git (complete)**, **Mercurial (complete)**; ASF SVN surface ([`tools/asf-svn`](../tools/asf-svn/): source control + dist.apache.org + authorization) | Subversion generic VCS binding [\#602](https://github.com/apache/magpie/issues/602) (detected); Jujutsu [\#603](https://github.com/apache/magpie/issues/603), Fossil [\#604](https://github.com/apache/magpie/issues/604), Perforce [\#605](https://github.com/apache/magpie/issues/605) (tracked) |
| Project governance | ✅ by construction | ASF + non-ASF adopter profiles | Adopter config (modes, thresholds) |
Expand Down Expand Up @@ -568,9 +570,9 @@ generated block below.

| Capability contract | Neutral? | Class | Backends today | Basis |
|---|---|---|---|---|
| `contract:tracker` | ✅ | vendor-backed | Atlassian, Fossil, GitHub, SourceHut | 4 backend vendors: Atlassian, Fossil, GitHub, SourceHut; partial foundation, not counted: bitbucket |
| `contract:source-control` | ✅ | vendor-backed | Fossil, Git, GitHub, SourceHut, Subversion | 5 backend vendors: Fossil, Git, GitHub, SourceHut, Subversion |
| `contract:change-request` | ✅ | vendor-backed | Atlassian, GitHub, email | 3 backend vendors: Atlassian, GitHub, email; partial foundation, not counted: bitbucket |
| `contract:tracker` | ✅ | vendor-backed | Atlassian, Fossil, GitHub, SourceHut | 4 backend vendors: Atlassian, Fossil, GitHub, SourceHut; partial foundation, not counted: bitbucket, gitlab |
| `contract:source-control` | ✅ | vendor-backed | Fossil, Git, GitHub, SourceHut, Subversion | 5 backend vendors: Fossil, Git, GitHub, SourceHut, Subversion; partial foundation, not counted: gitlab |
| `contract:change-request` | ✅ | vendor-backed | Atlassian, GitHub, email | 3 backend vendors: Atlassian, GitHub, email; partial foundation, not counted: bitbucket, gitlab |
| `contract:mail-archive` | ✅ | vendor-backed | ASF, Google, SourceHut | 3 backend vendors: ASF, Google, SourceHut |
| `contract:mail-source` | ✅ | vendor-backed | ASF, Google, Maildir | 3 backend vendors: ASF, Google, Maildir |
| `contract:mail-create` | ✅ | vendor-backed | Google, Maildir | 2 backend vendors: Google, Maildir |
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,5 @@ members = [
"tools/vetted-ops",
"tools/fossil",
"tools/sourcehut",
"tools/gitlab",
]
24 changes: 19 additions & 5 deletions tools/dev/tests/test_check_duplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,25 @@ def test_identical_text_inside_generated_regions_is_invisible() -> None:
`strip_generated_regions` exists. Reuses a real propagated block from the
live tree so the test tracks the real marker text, not a hand-written
stand-in."""
live_skill = next((REPO / "skills").glob("*/SKILL.md"))
text = live_skill.read_text()
match = MOD.PREFLIGHT_RE.search(text)
assert match, "expected the live skill to carry the auto pre-flight block"
block = match.group(0)
block = None
for pattern in (
"skills/*/SKILL.md",
"plugins/magpie-*/skills/*/SKILL.md",
"plugins/magpie-*/skills/*/*.md",
):
for path in REPO.glob(pattern):
try:
match = MOD.PREFLIGHT_RE.search(path.read_text(encoding="utf-8"))
if match:
block = match.group(0)
break
except OSError:
continue
if block:
break
if not block:
preflight_content = (REPO / "tools" / "dev" / "preflight-block.md").read_text(encoding="utf-8")
block = f"{MOD.PREFLIGHT_BEGIN}\n{preflight_content}\n{MOD.PREFLIGHT_END}\n"

paragraphs = MOD.extract_paragraphs(
Path("virtual.md"), text=f"# Heading\n\n{block}\n## Next\n\nSome unrelated text.\n"
Expand Down
84 changes: 84 additions & 0 deletions tools/gitlab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [GitLab bridge](#gitlab-bridge)
- [Prerequisites](#prerequisites)
- [Configuration](#configuration)
- [Operations](#operations)
- [Usage](#usage)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# GitLab bridge

**Capability:** contract:tracker + contract:source-control + contract:change-request

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking. No **Coverage:** partial line here. The adapter implements seven read-only GETs and no writes, so it is a partial foundation, not a complete tracker / source-control / change-request backend. Mirror tools/bitbucket/README.md, which carries **Coverage:** partial between Capability and Kind.


**Coverage:** `partial`

**Kind:** implementation

**Vendor:** GitLab

Read-only client for the GitLab REST API v4.

This bridge implements a `partial` read-only foundation for repository
metadata context under `contract:source-control`, issue listing and fetching
under `contract:tracker`, and merge request discovery, diffs, commits, and
CI pipeline status under `contract:change-request`.
Partial adapters may implement named contract verbs, but they do not satisfy
the complete contract and must not be advertised as complete/selectable backends.
Write operations and issue/MR mutations remain out of scope for this foundation.

## Prerequisites

- **Runtime:** Python 3.11+ via `uv`.
- **CLIs:** `uv`.
- **Credentials / auth:** `GITLAB_TOKEN` (Personal Access Token, OAuth Bearer token)
or `CI_JOB_TOKEN` with API access. Tokens are optional for unauthenticated reads
on public projects.
- **Auth scheme override:** `GITLAB_AUTH_SCHEME` (`PrivateToken`, `Bearer`, `JobToken`)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JobToken is rejected: _auth_headers lowercases to jobtoken, which isn't in ("job-token", "job_token") (client.py:166), so it raises Unsupported GITLAB_AUTH_SCHEME. Accept jobtoken and add a test for this spelling, or list the spellings the code accepts.

can be set to override header selection explicitly.
- **Network:** Access to the configured GitLab instance; `GITLAB_INSTANCE_URL`
defaults to `https://gitlab.com`.

## Configuration

Set `GITLAB_TOKEN` in your environment:

```bash
export GITLAB_TOKEN="glpat-..."
```

For self-hosted instances (e.g. Debian Salsa, GNOME):

```bash
export GITLAB_INSTANCE_URL="https://salsa.debian.org"
```

To explicitly force an authentication scheme (e.g. OAuth Bearer token vs Private Token):

```bash
export GITLAB_AUTH_SCHEME="Bearer"
```

## Operations

See [tool.md](tool.md) for the full operations catalogue and contract mapping.

## Usage

List open issues for a project:

```bash
uv run --project tools/gitlab magpie-gitlab issue list <project>
```

Get a merge request diff:

```bash
uv run --project tools/gitlab magpie-gitlab mr diff <project> <mr_iid>
```
25 changes: 25 additions & 0 deletions tools/gitlab/issue-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [GitLab Issue Template](#gitlab-issue-template)
- [Markdown Guidelines](#markdown-guidelines)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->

# GitLab Issue Template

Schema for GitLab issues and merge request bodies.

## Markdown Guidelines

GitLab Flavored Markdown (GLFM) is used across all issue and MR descriptions:
- **Checkboxes**: Formatted as `- [ ]` and `- [x]`.
- **References**: Issues are referenced with `#ID` and MRs with `!ID`.
- **Labels**: Scoped labels often use `::` (e.g., `workflow::in-review`).

Ensure that the adapter correctly parses these specific constructs
when reading issue bodies.
71 changes: 71 additions & 0 deletions tools/gitlab/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "magpie-gitlab"
version = "0.1.0"
description = "GitLab forge, issue tracker, and merge request bridge for Apache Magpie."
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
dependencies = []

[project.scripts]
magpie-gitlab = "magpie_gitlab.cli:main"

[tool.hatch.build.targets.wheel]
packages = ["src/magpie_gitlab"]

[tool.ruff]
line-length = 110
target-version = "py311"
src = ["src", "tests"]

[tool.ruff.lint]
select = ["E", "W", "F", "I", "B", "UP", "SIM", "C4", "RUF"]
ignore = ["E501"]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["B", "SIM"]

[tool.mypy]
python_version = "3.11"
files = ["src", "tests"]
warn_unused_ignores = true
warn_redundant_casts = true
warn_unreachable = true
check_untyped_defs = true
no_implicit_optional = true
disallow_untyped_defs = true
disallow_incomplete_defs = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
disallow_incomplete_defs = false

[tool.pytest.ini_options]
minversion = "8.0"
addopts = "-ra -q"
testpaths = ["tests"]

[dependency-groups]
dev = ["magpie-dev"]
24 changes: 24 additions & 0 deletions tools/gitlab/src/magpie_gitlab/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

"""GitLab forge, issue tracker, and merge request bridge."""

from __future__ import annotations

from .cli import main

__all__ = ["main"]
Loading