Data Flow¶
How data moves through releasio.
Release Workflow¶
The complete release flow:
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User
participant CLI as CLI
participant Git as Git Repository
participant Core as Core Engine
participant GH as GitHub
participant PyPI as PyPI
U->>CLI: releasio release
CLI->>Git: Get commits since last tag
Git-->>CLI: Commit list
CLI->>Core: Parse commits
Core-->>CLI: Parsed commits
CLI->>Core: Calculate version bump
Core-->>CLI: New version
CLI->>Core: Generate changelog
Core-->>CLI: Changelog content
CLI->>Git: Create tag
CLI->>GH: Create release
GH-->>CLI: Release URL
CLI->>PyPI: Publish package
PyPI-->>CLI: Success
CLI->>U: Release complete
Command Data Flows¶
check Command¶
Preview release without changes:
%%{init: {'theme': 'neutral'}}%%
graph LR
A[Config] --> B[Load Config]
B --> C[Git Repo]
C --> D[Get Commits]
D --> E[Parse Commits]
E --> F[Calculate Bump]
F --> G[Display Preview]
Data transformations:
- Config → Validated
ReleasePyConfig - Git log → List of
Commitobjects - Commits → List of
ParsedCommitobjects - Parsed commits →
BumpType(major/minor/patch) - Current version + bump → New
Version
update Command¶
Update version and changelog locally:
%%{init: {'theme': 'neutral'}}%%
graph LR
A[check flow] --> B[Calculate New Version]
B --> C[Update pyproject.toml]
C --> D[Update Version Files]
D --> E[Generate Changelog]
E --> F[Write CHANGELOG.md]
F --> G[Commit Changes]
File modifications:
pyproject.toml → version = "1.2.0"
__init__.py → __version__ = "1.2.0"
CHANGELOG.md → ## [1.2.0] - 2024-01-15
release-pr Command¶
Create a pull request:
%%{init: {'theme': 'neutral'}}%%
graph TB
A[update flow] --> B[Create Branch]
B --> C[Commit Changes]
C --> D[Push Branch]
D --> E[Create PR via API]
E --> F[Return PR URL]
API calls:
POST /repos/{owner}/{repo}/pulls- Create PR
release Command¶
Tag and publish:
%%{init: {'theme': 'neutral'}}%%
graph TB
A[Validate State] --> B[Create Git Tag]
B --> C[Push Tag]
C --> D[Create GitHub Release]
D --> E[Upload Assets]
E --> F[Build Package]
F --> G[Publish to PyPI]
G --> H[Complete]
API calls:
POST /repos/{owner}/{repo}/releases- Create releasePOST /releases/{id}/assets- Upload each asset- PyPI upload via build tool
Commit Parsing Pipeline¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[Raw Commit] --> B[Extract Subject]
B --> C{Matches Convention?}
C -->|Yes| D[Parse Type/Scope]
C -->|No| E[Try Custom Parsers]
D --> F[Check Breaking]
E --> F
F --> G[ParsedCommit]
Parsing Rules¶
# Input: "feat(api)!: add user endpoint"
# Step 1: Match pattern
pattern = r"^(?P<type>\w+)(\((?P<scope>[^)]+)\))?(?P<breaking>!)?:\s*(?P<desc>.+)$"
# Step 2: Extract groups
type = "feat"
scope = "api"
breaking = True # from "!"
description = "add user endpoint"
# Step 3: Create ParsedCommit
ParsedCommit(
commit=commit,
commit_type="feat",
scope="api",
description="add user endpoint",
is_breaking=True,
is_conventional=True,
)
Version Calculation¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[ParsedCommits] --> B{Any Breaking?}
B -->|Yes| C[Major Bump]
B -->|No| D{Any feat?}
D -->|Yes| E[Minor Bump]
D -->|No| F{Any fix/docs/perf?}
F -->|Yes| G[Patch Bump]
F -->|No| H[No Bump]
C --> I[New Version]
E --> I
G --> I
H --> I
Bump Priority¶
def calculate_bump(commits: list[ParsedCommit]) -> BumpType:
if any(c.is_breaking for c in commits):
return BumpType.MAJOR
if any(c.commit_type == "feat" for c in commits):
return BumpType.MINOR
if any(c.commit_type in PATCH_TYPES for c in commits):
return BumpType.PATCH
return BumpType.NONE
Changelog Generation¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[ParsedCommits] --> B[Group by Type]
B --> C[Sort Groups]
C --> D[Format Entries]
D --> E[Apply Template]
E --> F[Prepend to File]
Grouping¶
# Input commits
commits = [
ParsedCommit(type="feat", desc="add dashboard"),
ParsedCommit(type="fix", desc="resolve bug"),
ParsedCommit(type="feat", desc="add settings"),
]
# Grouped
groups = {
"feat": [
ParsedCommit(desc="add dashboard"),
ParsedCommit(desc="add settings"),
],
"fix": [
ParsedCommit(desc="resolve bug"),
],
}
Template Application¶
Configuration Loading¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[Start] --> B{.releasio.toml exists?}
B -->|Yes| C[Load .releasio.toml]
B -->|No| D{releasio.toml exists?}
D -->|Yes| E[Load releasio.toml]
D -->|No| F{pyproject.toml has tool.releasio?}
F -->|Yes| G[Load from pyproject.toml]
F -->|No| H[Use Defaults]
C --> I[Validate with Pydantic]
E --> I
G --> I
H --> I
I --> J[ReleasePyConfig]
Merge Strategy¶
# Defaults < pyproject.toml < releasio.toml < .releasio.toml
config = ReleasePyConfig() # Defaults
config = merge(config, pyproject_config)
config = merge(config, releasio_config)
config = merge(config, dotreleasio_config)
Publishing Pipeline¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[Start] --> B[Run Hooks: pre_release]
B --> C{Hooks Passed?}
C -->|No| X[Abort]
C -->|Yes| D[Build Package]
D --> E[Validate Package]
E --> F{Valid?}
F -->|No| X
F -->|Yes| G{Trusted Publishing?}
G -->|Yes| H[Request OIDC Token]
G -->|No| I[Use API Token]
H --> J[Upload to PyPI]
I --> J
J --> K{Success?}
K -->|No| X
K -->|Yes| L[Run Hooks: post_release]
L --> M[Complete]
Build Commands¶
| Tool | Build | Publish |
|---|---|---|
| uv | uv build |
uv publish |
| poetry | poetry build |
poetry publish |
| pdm | pdm build |
pdm publish |
GitHub Release Creation¶
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant R as releasio
participant G as GitHub API
R->>G: POST /repos/{owner}/{repo}/releases
Note right of R: body: tag_name, name, body, prerelease
G-->>R: 201 Created (release_id)
loop For each asset
R->>G: POST /releases/{id}/assets
Note right of R: file content
G-->>R: 201 Created
end
R->>R: Complete
Request Payload¶
{
"tag_name": "v1.2.0",
"name": "v1.2.0",
"body": "## What's Changed\n\n- Added dashboard\n- Fixed bug",
"draft": false,
"prerelease": false
}
Error Propagation¶
%%{init: {'theme': 'neutral'}}%%
graph TD
A[Operation] --> B{Success?}
B -->|No| C[Raise Exception]
C --> D{Recoverable?}
D -->|Yes| E[Log Warning]
D -->|No| F[Log Error]
F --> G[Exit with Code 1]
E --> H[Continue]
B -->|Yes| H
Exception Hierarchy¶
ReleaseError
├── ConfigError
├── GitError
│ ├── TagExistsError
│ └── PushError
├── GitHubError
│ ├── AuthenticationError
│ └── RateLimitError
└── PublishError
├── BuildError
└── UploadError
See Also¶
- System Overview - Component architecture
- Configuration - Config options
- API Reference - Code documentation