wetwire-gitlab 1.1.0
GitLab integration for wetwire
Requires Python: >=3.11
Keywords: automation, gitlab, wetwire

# wetwire-gitlab

[![CI](https://github.com/lex00/wetwire-gitlab-python/actions/workflows/ci.yml/badge.svg)](https://github.com/lex00/wetwire-gitlab-python/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/wetwire-gitlab)](https://pypi.org/project/wetwire-gitlab/)
[![Python](https://img.shields.io/badge/python-3.11+-blue)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![codecov](https://codecov.io/gh/lex00/wetwire-gitlab-python/branch/main/graph/badge.svg)](https://codecov.io/gh/lex00/wetwire-gitlab-python)

A Python library for generating GitLab CI/CD configuration from typed Python declarations.

## Wetwire Pattern

This project follows the [Wetwire Specification](https://github.com/lex00/wetwire/blob/main/docs/WETWIRE_SPEC.md)
for infrastructure-as-code. See also:
- [Feature Matrix](https://github.com/lex00/wetwire/blob/main/docs/FEATURE_MATRIX.md)
- [Architecture](https://github.com/lex00/wetwire/blob/main/docs/ARCHITECTURE.md)

## Installation

```bash
pip install wetwire-gitlab
```

## Quick Start

Define your pipeline using typed Python dataclasses:

```python
from wetwire_gitlab.pipeline import *
from wetwire_gitlab.intrinsics import *
from wetwire_gitlab.serialize import build_pipeline_yaml

# Define jobs
build = Job(
    name="build",
    stage="build",
    script=["make build"],
    artifacts=Artifacts(paths=["build/"]),
)

test = Job(
    name="test",
    stage="test",
    script=["pytest"],
    needs=["build"],
)

deploy = Job(
    name="deploy",
    stage="deploy",
    script=["make deploy"],
    rules=[Rule(if_=f"{CI.COMMIT_BRANCH} == {CI.DEFAULT_BRANCH}")],
    needs=["test"],
)

# Define pipeline
pipeline = Pipeline(stages=["build", "test", "deploy"])

# Generate YAML
yaml_output = build_pipeline_yaml(pipeline, [build, test, deploy])
print(yaml_output)
```

## Features

### Pipeline Types

Typed dataclasses for all GitLab CI/CD configuration:

- `Job` - Job configuration with script, rules, artifacts, cache, etc.
- `Pipeline` - Top-level pipeline with stages, workflow, includes
- `Rule` - Conditional execution rules
- `Artifacts` - Build artifact configuration
- `Cache` - Cache configuration with keys and policies
- `Include` - Include local, remote, template, or component files
- `Workflow` - Pipeline-level rules and name

### Intrinsics

Pre-defined CI/CD variables and constants:

```python
from wetwire_gitlab.intrinsics import *

# CI variables
CI.COMMIT_SHA          # $CI_COMMIT_SHA
CI.COMMIT_BRANCH       # $CI_COMMIT_BRANCH
CI.DEFAULT_BRANCH      # $CI_DEFAULT_BRANCH
CI.PIPELINE_SOURCE     # $CI_PIPELINE_SOURCE

# User context
GitLab.USER_LOGIN      # $GITLAB_USER_LOGIN
GitLab.USER_EMAIL      # $GITLAB_USER_EMAIL

# Merge request context
MR.SOURCE_BRANCH       # $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
MR.TARGET_BRANCH       # $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

# Pre-defined rules
Rules.ON_DEFAULT_BRANCH
Rules.ON_TAG
Rules.ON_MERGE_REQUEST
Rules.MANUAL
```

### Serialization

Convert typed objects to YAML:

```python
from wetwire_gitlab.serialize import *

# Single object
yaml_str = to_yaml(job)

# Full pipeline with jobs
yaml_str = build_pipeline_yaml(pipeline, jobs)
```

### AST Discovery

Discover Job and Pipeline declarations in Python source files:

```python
from wetwire_gitlab.discover import *

# Discover all jobs and pipelines in a directory
result = discover_in_directory(Path("src/"))
print(f"Found {len(result.jobs)} jobs and {len(result.pipelines)} pipelines")

# Discover jobs in a single file
jobs = discover_jobs(Path("ci/jobs.py"))
```

### Linting

Check pipeline definitions for common issues:

```python
from wetwire_gitlab.linter import *

# Lint a single file
result = lint_file(Path("ci/jobs.py"))
for issue in result.issues:
    print(f"{issue.code}: {issue.message} at line {issue.line_number}")

# Lint a directory
result = lint_directory(Path("src/"))
```

Lint rules:
- `WGL001` - Use typed component wrappers
- `WGL002` - Use Rule dataclass instead of raw dict
- `WGL003` - Use predefined variables from intrinsics
- `WGL004` - Use Cache dataclass instead of raw dict
- `WGL005` - Use Artifacts dataclass instead of raw dict
- `WGL006` - Use typed stage constants
- `WGL007` - Duplicate job names
- `WGL008` - File contains too many jobs

### YAML Import

Parse existing `.gitlab-ci.yml` files:

```python
from wetwire_gitlab.importer import *

pipeline = parse_gitlab_ci_file(Path(".gitlab-ci.yml"))
print(f"Stages: {pipeline.stages}")
for job in pipeline.jobs:
    print(f"Job: {job.name}, Stage: {job.stage}")
```

### Validation

Validate pipelines using the GitLab CLI:

```python
from wetwire_gitlab.validation import *

if is_glab_installed():
    result = validate_pipeline(yaml_content)
    if result.valid:
        print("Pipeline is valid!")
    else:
        for error in result.errors:
            print(f"Error: {error}")
```

### Template Building

Order jobs by dependencies for YAML generation:

```python
from wetwire_gitlab.template import *

# Check for circular dependencies
has_cycle, cycle_nodes = detect_cycle(dependency_graph)

# Order jobs so dependencies come first
ordered_jobs = order_jobs_for_yaml(discovered_jobs)
```

## Examples

The `examples/` directory contains 5 complete example projects:

| Example | Description |
|---------|-------------|
| `python-app` | Basic Python CI/CD with multi-version testing |
| `docker-build` | Docker build & push with registry integration |
| `multi-stage` | Complex DAG pipeline with environments |
| `kubernetes-deploy` | Helm-based multi-environment deployment |
| `monorepo` | Dynamic child pipelines with change detection |

See [docs/EXAMPLES.md](docs/EXAMPLES.md) for detailed documentation.

## CLI

```bash
# Build pipeline YAML from Python definitions
wetwire-gitlab build

# Validate pipeline
wetwire-gitlab validate

# Lint pipeline definitions
wetwire-gitlab lint

# List discovered jobs and pipelines
wetwire-gitlab list

# Import existing .gitlab-ci.yml
wetwire-gitlab import .gitlab-ci.yml
```

## Development

```bash
# Install dev dependencies
uv sync --group dev

# Run tests
uv run pytest

# Run linter
uv run ruff check src tests

# Run type checker
uv run ty check src
```

## License

MIT