PivLabForm - GitLab as Code
Project description
PivLabForm - GitLab Configuration as Code
Manage GitLab groups, projects, and settings as code using YAML configuration files
📑 Table of Contents
- 🌟 Overview
- ⚡ Quick Start
- 📦 Installation
- 🔧 CLI Interface
- ⚙️ Configuration Models
- 📊 Configuration Examples
- 🔌 API Reference
- ⚠️ Error Handling
- 🛡️ Security Considerations
- 🔧 Troubleshooting
- 🤝 Contributing
- 📜 Licensing
🌟 Overview
PivLabForm is a configuration management tool for GitLab that allows you to manage GitLab groups, projects, and their settings as code using YAML configuration files.
⚡ Quick Start
- Install the tool:
pip install pivlabform
- Set up authentication:
export GITLAB_TOKEN="your-personal-access-token"
- Create a configuration file:
# config.yaml
groups:
- "sandbox/my-group"
group_config:
settings:
description: "My development group"
visibility: "private"
default_branch: "main"
- Apply the configuration:
pivlabform -c config.yaml
📦 Installation
From Source
# Clone the repository
git clone https://gitlab.com/pivlab/pivlabform.git
cd pivlabform
# Install with Poetry
poetry install
# Build and install globally
poetry build
pip install dist/pivlabform-*.whl
Using pip
pip install pivlabform
🔧 CLI Interface
Basic Usage
# Show help
pivlabform --help
# Apply configuration from file
pivlabform -c configurations/templates/global_template.yaml
# Manual configuration for specific entity
pivlabform --manual --group --path "sandbox/my-group" -c config.yaml
# Validate configuration without applying
pivlabform -c config.yaml -v
Command Line Options
| Option | Short | Description | Default |
|---|---|---|---|
--ci |
Run in CI mode (skip .env loading) | False |
|
--manual |
-m |
Manual run for single group/project | False |
--project |
Specify entity type as project | ||
--group |
Specify entity type as group | ||
--path |
GitLab path (e.g., sandbox/test/project-1) |
||
--id |
GitLab ID (e.g., 1001) |
||
--config-file |
-c |
Configuration file path | config.yaml |
--recursive |
-r |
Apply recursively to subgroups/projects | False |
--validate |
-v |
Only validate, don't apply changes | False |
--gitlab-host |
GitLab host URL | From env or default |
⚙️ Configuration Models
Configuration File Structure
# Root level configuration
group_config:
settings:
# Group settings (optional)
variables:
# Group variables (optional)
project_config:
settings:
# Project settings (optional)
variables:
# Project variables (optional)
protected_branches:
# Protected branches configuration (optional)
# Target entities (required)
groups:
- "sandbox/pivlabform-tests" # Group path
- 1234 # Group ID
projects:
- "sandbox/pivlabform-tests/test-project-2" # Project path
- 2306 # Project ID
Pydantic models:
Environment Variables
# Required for authentication
export GITLAB_TOKEN="your-personal-access-token"
# Optional: Override GitLab host
export CI_SERVER_HOST="https://gitlab.example.com"
# Optional: Enable debug logging
export DEBUG="true"
Group Settings
Basic Settings
group_config:
settings:
default_branch: "main"
description: "My group description"
visibility: "private" # private, internal, public
lfs_enabled: true
auto_devops_enabled: false
Security Settings
group_config:
settings:
require_two_factor_authentication: true
two_factor_grace_period: 48
prevent_sharing_groups_outside_hierarchy: true
Runner Settings
group_config:
settings:
shared_runners_setting: "disabled_and_unoverridable"
# Options:
# - "disabled_and_unoverridable"
# - "disabled_and_overridable"
# - "enabled"
Project Settings
Repository Settings
project_config:
settings:
default_branch: "main"
description: "Project description"
visibility: "internal"
merge_method: "merge" # merge, rebase_merge, ff
squash_option: "default_on" # always, never, default_on, default_off
Pipeline Settings
project_config:
settings:
ci_config_path: ".gitlab-ci.yml"
ci_default_git_depth: 50
auto_devops_enabled: false
shared_runners_enabled: true
Access Levels
project_config:
settings:
repository_access_level: "enabled" # disabled, private, enabled, public
issues_access_level: "enabled"
merge_requests_access_level: "enabled"
# Other access levels: wiki_access_level, snippets_access_level, etc.
Variables Configuration
Group Variables
group_config:
variables:
RELEASE_VERSION:
key: RELEASE_VERSION
value: "Q4_29"
description: "Current release version"
environment_scope: "production"
masked: false
protected: false
raw: false
variable_type: "env_var"
Project Variables
project_config:
variables:
PROJECT_VERSION:
key: PROJECT_VERSION
value: "1.0.0"
description: "Project version"
environment_scope: "*" # All environments
masked: true
protected: true
raw: false
variable_type: "env_var"
Protected Branches
project_config:
protected_branches:
master:
allow_force_push: false
merge_access_level: 40 # Maintainer (40), Developer (30)
push_access_level: 40
unprotect_access_level: 40
develop:
allow_force_push: true
merge_access_level: 30
push_access_level: 30
Access Level Values
0: No access10: Guest20: Reporter30: Developer40: Maintainer50: Owner
📊 Configuration Examples
Example 1: Basic Group Configuration
# config.yaml
group_config:
settings:
description: "Development group"
visibility: "private"
default_branch: "main"
auto_devops_enabled: false
variables:
ENVIRONMENT:
key: ENV
value: "development"
masked: false
groups:
- "development/my-team"
Apply configuration:
pivlabform -c config.yaml
Example 2: Multi-Project Configuration
# projects.yaml
project_config:
settings:
default_branch: "main"
merge_method: "ff"
squash_option: "default_on"
variables:
PROJECT_TYPE:
key: TYPE
value: "microservice"
description: "Project architecture type"
projects:
- "backend/services/api-gateway"
- "backend/services/user-service"
- "backend/services/auth-service"
Apply recursively:
pivlabform -c projects.yaml -r
Example 3: Mixed Configuration
# mixed-config.yaml
group_config:
settings:
description: "Infrastructure group"
shared_runners_setting: "disabled_and_unoverridable"
variables:
INFRA_ENV:
key: INFRA_ENVIRONMENT
value: "staging"
environment_scope: "staging"
project_config:
settings:
description: "Infrastructure project"
shared_runners_enabled: false
variables:
TF_VERSION:
key: TERRAFORM_VERSION
value: "1.5.0"
groups:
- "infrastructure"
projects:
- "infrastructure/terraform-modules"
🔌 API Reference
Core Classes
Pivlabform
Main class for configuration management.
import os
os.environ["DEBUG"] = "true"
os.environ["CI_SERVER_HOST"] = "pivlab.space"
from pivlabform import LOGGER, GitLab
from pivlabform.gitlab.gitlab import Entity
from pivlabform.gitlab.models import GroupSettings, ProjectSettings
from pivlabform.gitlab.models.entity_settings import MergeMethod
def configure_projects_in_group(group: str) -> None:
"""
Procedure for confugure all projects in group with settings:
- default_branch: master
- description: configuration from test_api.py
- for merge needs resolve all discussions and pipeline success
- merge strategy: fast-forward
:param group: target group path
:type group: str
"""
gl = GitLab()
project_settings_model = ProjectSettings(
default_branch="master",
description="configuration from test_api.py",
only_allow_merge_if_all_discussions_are_resolved=True,
only_allow_merge_if_pipeline_succeeds=True,
merge_method=MergeMethod.FF,
)
group_settings_model = GroupSettings(
default_branch="master",
)
group_id = gl.get_entity_id_from_url(group, Entity.GROUP)
groups = gl.get_all_groups_recursive(group_id)
projects = gl.get_all_projects_recursive(group_id)
LOGGER.info(f"projects for config: {projects}")
LOGGER.info(f"groups for config: {groups}")
for group_id in groups:
gl.confugure_entity(
entity_id=group_id,
entity_type=Entity.GROUP,
config=group_settings_model.to_api_json(),
)
for project_id in projects:
gl.confugure_entity(
entity_id=project_id,
entity_type=Entity.PROJECT,
config=project_settings_model.to_api_json(),
)
if __name__ == "__main__":
configure_projects_in_group("sandbox/pivlabform-tests")
GitLab
GitLab API client wrapper.
from pivlabform.gitlab.gitlab import GitLab
gl = GitLab("https://gitlab.example.com")
# Get entity ID from path
group_id = gl.get_entity_id_from_url("sandbox/test", "group")
# Get all projects recursively
projects = gl.get_all_projects_recursive(group_id)
# Update entity variables
gl.update_entity_variables(
entity_id=project_id,
entity_type="project",
config_variables=[...]
)
⚠️ Error Handling
Common Errors
- Authentication Error: Ensure
GITLAB_TOKENis set correctly - Permission Error: Token needs appropriate permissions
- Configuration Error: Validate YAML syntax and schema
- Network Error: Check GitLab host accessibility
Debug Mode
Enable debug logging:
export DEBUG=true
pivlabform -c config.yaml
🛡️ Security Considerations
- Store
GITLAB_TOKENsecurely (never in version control) - Use masked variables for sensitive data
- Set appropriate access levels
- Regularly rotate access tokens
- Review permission inheritance in group hierarchies
🔧 Troubleshooting
Configuration Not Applying
- Check entity paths/IDs are correct
- Verify token has write permissions
- Check GitLab API rate limits
- Validate YAML syntax
Variables Not Updating
- Check variable keys match exactly
- Verify environment scope settings
- Check for conflicting variables at different levels
- Validate variable masking settings
Permission Issues
- Token must have
apiscope - User must have maintainer/owner access
- Check group/project permission inheritance
- Verify token is not expired
🤝 Contributing
- Fork the repository
- Create feature branch
- Add tests for new features
- Update documentation
- Submit pull request
📜 Licensing
This software is available under a dual-licensing model:
1. For the Community and Open Source Projects: GNU Affero General Public License v3.0 (AGPL-3.0)
- You may freely use, study, modify, and distribute this library.
- If you modify the library and make it available over a network (e.g., as a web service or SaaS), you are obligated to make the complete source code of your modifications available to all users of your service.
- This is a classic strong copyleft free software license that ensures improvements remain open.
2. For Commercial and Proprietary Use: Commercial License
If the terms of the AGPL-3.0 are incompatible with your business model (for example, you do not wish to open-source your product's code), you may purchase a commercial license from the copyright holder.
The commercial license grants:
- The right to use the library in closed-source (proprietary) products.
- Exemption from the AGPL's source code disclosure requirements.
- Direct warranties and priority support.
- The possibility of requesting custom features.
To inquire about a commercial license:
📧 Email: studentq.work@yandex.ru
💬 Telegram: @pudge_vibes
Please include in your email: company name, intended use case, and approximate number of developers.
Copyright (c) 2025 PivLab. All rights reserved.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pivlabform-0.6.1.tar.gz.
File metadata
- Download URL: pivlabform-0.6.1.tar.gz
- Upload date:
- Size: 19.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.12.12 Linux/5.14.0-687.10.1.el9_8.0.1.x86_64
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0dc4348cd62d793dc4188637b9dd572e2c60e0481f9ce604e42ad87adb2c386f
|
|
| MD5 |
4f95f42041b5ffd801297a7dd04e60b3
|
|
| BLAKE2b-256 |
28d6f4e6589a10fe7805e7d1971911de1e440b6f750fb8a76f32a57aea6c7f8f
|
File details
Details for the file pivlabform-0.6.1-py3-none-any.whl.
File metadata
- Download URL: pivlabform-0.6.1-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.12.12 Linux/5.14.0-687.10.1.el9_8.0.1.x86_64
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47d4abc88a519c380228139a2dff1671239495d5e85eb47b3616314c8964baed
|
|
| MD5 |
3a091937e85ed56562fe2bc3cbd04121
|
|
| BLAKE2b-256 |
87dc6cf00905de91bacd584a66060cafe59ab5f4aeb8066a5f90fe999720e3f0
|