This project has been archived by its maintainers, and is no longer receiving any updates.
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.
Release files for pivlabform 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pivlabform-0.6.1.tar.gz | 19.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pivlabform-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.7 kB
Release files / pivlabform-0.6.1.tar.gz
| Download URL | pivlabform-0.6.1.tar.gz |
|---|---|
| Size | 19.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0dc4348cd62d793dc4188637b9dd572e2c60e0481f9ce604e42ad87adb2c386f
|
|
BLAKE2b-256 checksum How to use checksums |
28d6f4e6589a10fe7805e7d1971911de1e440b6f750fb8a76f32a57aea6c7f8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|
Release files / pivlabform-0.6.1-py3-none-any.whl
| Download URL | pivlabform-0.6.1-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
47d4abc88a519c380228139a2dff1671239495d5e85eb47b3616314c8964baed
|
|
BLAKE2b-256 checksum How to use checksums |
87dc6cf00905de91bacd584a66060cafe59ab5f4aeb8066a5f90fe999720e3f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|