Files
orca/src/main/gitlab/project-ref-parser.test.ts
T
JinjingandOrca f72c22532a Support GitLab MR unlinking and AI generation in ChecksPanel (#5204)
* feat: support GitLab MR unlinking and AI generation in ChecksPanel

Integrate GitLab merge request actions alongside GitHub pull requests in
the sidebar checks panel. This includes unlinking GitLab MRs, enabling
AI-driven title and body generation for GitLab, and dynamically adapting
menu labels (e.g. "More MR actions" vs "More PR actions") depending on
the active provider.

* fix: handle null base ref in hosted review creation and add tests

Co-authored-by: Orca <help@stably.ai>

* Extract sub-components and hooks from renderer components

To improve component focus and maintainability, extract large inline
sub-components, custom hooks, and logic helpers into dedicated files:

- Extract `HeroPaired` from `MobileHero` to `MobileHeroPairedDevices`.
- Move `ChromePreview` from `ThemeStep` to `theme-chrome-preview`.
- Refactor `HostedReviewActions` to use `useHostedReviewActions` hook.
- Move MCP config loading from `McpConfigSection` to helper file.

* Refactor usage panes to extract shared formatters and tables

Extract duplicated formatting utilities to a shared helper module. Move
the large, inline recent sessions tables into dedicated sub-components to
reduce duplication and simplify the parent pane components.

* Support self-hosted GitLab instances for MR creation eligibility

* Extract and check the remote host against `glab auth status` to
  dynamically recognize and authenticate self-hosted GitLab instances
  without requiring them to be in a hardcoded list.
* Refactor stats usage panes by extracting reusable breakdown sections
  and sessions tables to eliminate duplication.
* Suggest Linear prompts only if the launcher can resolve the CLI.

* Extract GitLab project ref tests and update usage stats translations

- Move GitLab project ref parsing tests into a dedicated test file to
  keep modules focused and add tests for candidate parsing.
- Add missing translations for the usage sessions table and breakdown
  section across multiple locales.

* Optimize GitLab ref parsing, deduplicate formatters, and add locales

- Clean up GitLab ref parsing by extracting normalized known hosts.
- Fix an escaped newline sequence in the self-hosted GitLab mock test.
- Deduplicate stats helper functions into a single shared file.
- Translate path status message strings across ES, JA, KO, and ZH.

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-11 20:18:28 -07:00

100 lines
3.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { parseGitLabProjectRef, parseRemoteProjectRefCandidate } from './project-ref-parser'
describe('gitlab project ref parsing', () => {
it('parses HTTPS and SSH GitLab.com remotes', () => {
expect(parseGitLabProjectRef('https://gitlab.com/acme/widgets.git')).toEqual({
host: 'gitlab.com',
path: 'acme/widgets'
})
expect(parseGitLabProjectRef('git@gitlab.com:stablyai/orca.git')).toEqual({
host: 'gitlab.com',
path: 'stablyai/orca'
})
})
it('preserves nested group paths', () => {
expect(parseGitLabProjectRef('git@gitlab.com:group/subgroup/project.git')).toEqual({
host: 'gitlab.com',
path: 'group/subgroup/project'
})
expect(parseGitLabProjectRef('https://gitlab.com/g1/g2/g3/proj.git')).toEqual({
host: 'gitlab.com',
path: 'g1/g2/g3/proj'
})
})
it('returns null for non-GitLab hosts when host not in knownHosts', () => {
expect(parseGitLabProjectRef('git@github.com:stablyai/orca.git')).toBeNull()
expect(parseGitLabProjectRef('git@example.com:foo/bar.git')).toBeNull()
})
it('matches self-hosted hosts when included in knownHosts', () => {
expect(
parseGitLabProjectRef('git@gitlab.example.com:team/api.git', [
'gitlab.com',
'gitlab.example.com'
])
).toEqual({ host: 'gitlab.example.com', path: 'team/api' })
})
it('parses GitLab remotes with non-standard ports without treating the port as a path segment', () => {
expect(
parseGitLabProjectRef('ssh://git@gitlab.example.com:2222/team/api.git', [
'gitlab.com',
'gitlab.example.com'
])
).toEqual({ host: 'gitlab.example.com', path: 'team/api' })
expect(
parseGitLabProjectRef('https://gitlab.example.com:8443/team/api.git', [
'gitlab.com',
'gitlab.example.com'
])
).toEqual({ host: 'gitlab.example.com', path: 'team/api' })
})
it('rejects single-segment paths (host root or user-only)', () => {
expect(parseGitLabProjectRef('git@gitlab.com:foo.git')).toBeNull()
expect(parseGitLabProjectRef('https://gitlab.com/foo.git')).toBeNull()
})
it('handles missing .git suffix', () => {
expect(parseGitLabProjectRef('https://gitlab.com/acme/widgets')).toEqual({
host: 'gitlab.com',
path: 'acme/widgets'
})
})
it('strips trailing slashes after .git suffixes', () => {
expect(parseGitLabProjectRef('https://gitlab.com/acme/widgets.git/')).toEqual({
host: 'gitlab.com',
path: 'acme/widgets'
})
expect(parseGitLabProjectRef('ssh://git@gitlab.com/acme/widgets.git/')).toEqual({
host: 'gitlab.com',
path: 'acme/widgets'
})
})
it('preserves git protocol remote support', () => {
expect(parseGitLabProjectRef('git://gitlab.com/acme/widgets.git')).toEqual({
host: 'gitlab.com',
path: 'acme/widgets'
})
})
})
describe('gitlab remote project ref candidates', () => {
it('extracts self-hosted candidates before the host is trusted', () => {
expect(parseRemoteProjectRefCandidate('git@gitlab.internal:team/orca.git')).toEqual({
host: 'gitlab.internal',
path: 'team/orca'
})
})
it('rejects non-git URLs and single-segment project paths', () => {
expect(parseRemoteProjectRefCandidate('file:///tmp/repo')).toBeNull()
expect(parseRemoteProjectRefCandidate('git@gitlab.internal:team.git')).toBeNull()
})
})