Skip to content

Comments

Initial code#1

Merged
jetm merged 36 commits intomainfrom
feature/package-structure
Jan 10, 2026
Merged

Initial code#1
jetm merged 36 commits intomainfrom
feature/package-structure

Conversation

@jetm
Copy link
Owner

@jetm jetm commented Jan 10, 2026

No description provided.

jetm added 30 commits January 9, 2026 07:27
The project previously existed only as a standalone script without proper
packaging infrastructure. This made it difficult to install as a Python
package, distribute via PyPI, or integrate into larger projects. Shared
GitLab functionality was also duplicated across multiple scripts.

Introduce a standard Python package structure with src layout, pyproject.toml
configuration, and a shared gitlab_common module. The package structure
follows modern Python packaging conventions with setuptools, while the
shared module consolidates Git repository detection, project resolution,
and error handling logic that was previously scattered or duplicated.
This enables installation via pip while maintaining backward compatibility
with direct script execution.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
GitLab's Generic Package Registry enforces strict filename requirements
that are not immediately obvious to users. Uploads with non-ASCII
characters or special symbols fail with cryptic API errors, making it
difficult to diagnose why a package upload was rejected.

Introduce dedicated validation functions that check filenames against
GitLab's allowed character set and verify file accessibility before
attempting upload. Early validation with clear error messages helps
users identify and fix issues locally rather than discovering them
during the upload process.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The package upload workflow requires several file handling capabilities
that don't exist yet: calculating checksums for integrity verification,
mapping local filenames to different remote names during upload, and
collecting files from either explicit paths or directories.

Add utility functions that provide these foundational capabilities.
The checksum function uses chunked reading for memory efficiency with
large files. The file collection function supports two input modes
(explicit file list or directory scan) with batch error handling that
continues processing valid files when some fail validation. This
approach enables callers to report all validation issues at once rather
than failing on the first error.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The validators module only handles file validation, but the package upload
workflow also requires parsing Git remote URLs and retrieving GitLab tokens.
These operations are currently missing, forcing callers to implement their
own URL parsing and token resolution logic, which leads to inconsistent
error handling and duplicated validation code.

Add utility functions for Git URL parsing, GitLab URL normalization, and
token retrieval. The URL parsers handle both SSH and HTTPS formats,
extracting the GitLab instance URL and project path with consistent error
messages. Token retrieval follows a priority chain from CLI argument to
environment variable. This centralizes configuration logic in the validators
module where related validation already exists, ensuring uniform error
handling through ConfigurationError exceptions.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The validators module only handles file and URL validation, leaving
configuration validation (Python version, dependencies, tokens, Git
setup) scattered or missing entirely. Users encountering setup issues
receive generic errors without guidance on resolution, making
troubleshooting difficult and increasing support burden.

Add a suite of validation functions that check each configuration
aspect with detailed, actionable error messages. Each validator follows
a consistent pattern: detect the specific issue, explain what failed,
and provide platform-appropriate resolution steps. The orchestrating
validate_configuration function runs all checks in sequence with
appropriate handling for optional Git requirements, allowing callers to
validate their entire setup with a single call.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The package upload functionality currently lacks robust error handling and
duplicate detection. Network interruptions, rate limits, or server errors
cause immediate failures, requiring manual intervention and restart.
Additionally, re-uploading files without duplicate awareness leads to
wasted bandwidth and potential registry inconsistencies.

Introduce an upload orchestration module using tenacity for automatic
retry with exponential backoff. The retry logic distinguishes between
transient errors (timeouts, rate limits, server errors) and permanent
failures (authentication, validation) to avoid futile retry attempts.
Duplicate detection supports configurable policies (skip, replace, error)
to handle existing files gracefully, while checksum validation ensures
upload integrity before marking operations complete.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The CLI currently lacks proper handling of different output environments.
When output is piped to a file or consumed by another process, rich
terminal formatting with ANSI escape codes and Unicode characters
corrupts the output, making it unusable for automation pipelines.

Introduce a dedicated formatting module that detects terminal
capabilities at runtime and adapts output accordingly. The module
supports three output modes: rich console output with colors and Unicode
for interactive terminals, structured JSON for machine consumption, and
plain ASCII text for non-TTY environments. This separation ensures the
tool integrates cleanly into CI/CD pipelines while maintaining a good
user experience in interactive sessions.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The formatters module lacked test coverage, making it difficult to
refactor output formatting logic or verify behavior across different
terminal environments. Without tests, changes to terminal detection,
color support, or output rendering could silently break user-facing
output.

Introduce a complete test suite covering terminal detection, rich
console output, JSON output, plain text output, error formatting, and
progress display. Mock Rich console and spinner dependencies to ensure
tests run reliably without real terminal rendering, enabling consistent
CI execution regardless of environment.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The previous CLI module was a placeholder that delegated to an external
script via runpy. This approach prevented proper package installation
and made the tool unusable when installed via pip, as the standalone
script path resolution failed outside the development environment.

Replace the placeholder implementation with a complete argparse-based
CLI that handles all argument parsing, validation, and shell completion
natively. This enables standard package distribution while providing
comprehensive flag validation with user-friendly error messages. The
implementation follows a phased approach, with project resolution and
upload orchestration marked as TODO items for subsequent work.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The CLI previously required manual project specification for every
invocation, forcing users to provide full project URLs or paths even
when running from within a Git repository that already contains this
information in its remotes.

Introduce GitAutoDetector to discover Git repositories and extract
GitLab project information from configured remotes, prioritizing the
origin remote when multiple GitLab remotes exist. Add ProjectResolver
to validate project paths against the GitLab API and resolve them to
project IDs. The auto-detection gracefully skips known non-GitLab hosts
like GitHub and Bitbucket, falling back to manual specification with
actionable error messages when detection fails.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The CLI module uses ad-hoc print statements for logging and lacks a
unified upload context, making it difficult to control output verbosity
and pass configuration state to downstream upload components.

Introduce RichHandler-based logging that respects verbosity flags and
routes output to stderr when JSON mode is enabled, preserving stdout for
machine-readable output. Add UploadContextBuilder to construct a fully
validated UploadContext containing the GitLab client, configuration, and
duplicate detector, which subsequent upload phases will consume.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The CLI previously stopped after resolving the GitLab project context,
leaving file collection, upload execution, and result formatting as
unimplemented TODO items. Users could not actually upload packages
despite the command accepting all necessary arguments.

Complete the main function by wiring together file collection, upload
execution via the uploader module, and result formatting. Exit codes
now consistently derive from exception classes where available, with a
centralized mapping table for standard Python exceptions. This ensures
predictable exit behavior for scripting and CI integration while
keeping error handling logic maintainable.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The gitlab-pkg-upload package lacks unit test coverage for its core data
structures and validation logic. Without tests, regressions in model
behavior, exception handling, or input validation could go undetected,
making the codebase fragile as it evolves.

Introduce a complete unit test suite covering the models module
(dataclasses, enums, exception hierarchy, and error enhancement
functions) and the validators module (file validation, Git URL parsing,
token handling, and configuration validation). All tests are isolated
using mocks for external dependencies like filesystem, subprocess, and
GitPython, ensuring fast and reliable execution without requiring actual
GitLab API access or specific system configurations.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The duplicate detection module lacked test coverage, making it risky to
refactor or extend its functionality. Without tests, regressions in
session-level tracking or remote GitLab API interactions could go
unnoticed until runtime failures occur in production uploads.

Add a complete unit test suite covering the DuplicateDetector class and
its helper functions. The tests validate SHA256 calculation edge cases,
retry logic behavior, session registry management, and remote duplicate
detection via mocked GitLab API responses. All external dependencies
are mocked to ensure test isolation and fast execution.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The uploader module previously lacked test coverage, making it difficult
to verify correctness of upload orchestration, retry behavior, duplicate
detection, and error handling. Without tests, regressions could go
unnoticed during refactoring or feature additions.

Introduce a complete unit test suite covering all public functions in
the uploader module. The tests validate transient error classification
for retry logic, single file upload with dry-run support, checksum
validation including case-insensitive comparison and path variations,
duplicate handling across all policy modes (skip, replace, error), file
deletion from the registry with proper error recovery, and the main
upload orchestration including fail-fast behavior. All external
dependencies are mocked to ensure test isolation and fast execution.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The CLI module lacked unit test coverage, making it difficult to verify
argument parsing, flag validation, Git repository auto-detection, and
the main orchestration flow. Without tests, refactoring or extending
CLI functionality risks introducing regressions that would only surface
during manual testing or production use.

Introduce a complete test suite covering all CLI components including
verbosity determination, logging setup, argument parsing, flag conflict
detection, GitAutoDetector for repository discovery, ProjectResolver
for GitLab project resolution, UploadContextBuilder for context
creation, and the main function error handling paths. Each test class
isolates a specific component with mocked dependencies to ensure fast,
deterministic execution.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Currently, integration testing for the GitLab package upload CLI relies
on subprocess execution, which introduces overhead, complicates test
isolation, and makes debugging harder. Tests spawn separate processes
for each CLI invocation, capture output via pipes, and parse results
from stdout/stderr. This approach is slower and provides less control
over the execution environment.

Introduce a comprehensive integration test suite that calls the CLI
main() function directly instead of using subprocess. The new test
infrastructure captures stdout/stderr via context managers, handles
SystemExit exceptions to extract exit codes, and provides structured
test helpers for common operations. This approach improves test speed,
simplifies debugging, and enables better isolation while maintaining
full coverage of CLI functionality including single/multiple file
uploads, directory uploads, duplicate handling policies, project
resolution, and error scenarios.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The test suite imports utilities from the legacy monolithic gitlab_common
module, which has been refactored into the modular gitlab_pkg_upload
package. Tests fail to run because the expected import paths no longer
exist, and error handling returns generic exceptions rather than typed
ones that match the new exception hierarchy.

Update all test imports to use the new package structure, pulling CLI
utilities from gitlab_pkg_upload.cli and data models from
gitlab_pkg_upload.models. Replace bare exception handlers in GitLab API
helpers with typed exception handling that distinguishes authentication,
project resolution, and network failures. Switch the script executor
from subprocess-based execution to direct module invocation, enabling
proper exception propagation and eliminating process overhead during
test runs. Reuse the validators module for checksum calculation to
avoid duplicate implementations.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Integration tests previously performed token validation independently in
each test module, leading to duplicated code and inconsistent error
messages when the environment was misconfigured. Users running tests
without proper setup received cryptic skip messages that did not explain
how to resolve the issue.

Introduce a session-scoped autouse fixture that validates all
environment requirements once before any integration tests execute. This
centralizes the validation logic and provides detailed, actionable error
messages that guide users through the exact steps needed to configure
their environment. The fixture checks for GITLAB_TOKEN, verifies the
presence of a Git repository, and confirms GitLab remotes are
configured.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Currently, the upload script exists as a standalone script
(gitlab-pkg-upload.py) that cannot be easily imported, tested, or
distributed. The monolithic structure makes it difficult to maintain,
test individual components, and package for distribution.

Restructure the codebase into a proper Python package under
src/gitlab_pkg_upload/ with modular components (cli.py, models.py,
uploader.py, validators.py). Add package metadata in pyproject.toml
with entry point for gitlab-pkg-upload command. Update documentation
to reflect the new installation model using 'uv pip install -e .'
before running tests. Reorganize test structure to separate unit
tests (tests/unit/) from integration tests (tests/integration/).
Simplify run_tests.py to delegate to 'uv run pytest' instead of
managing dependencies directly. Remove obsolete standalone scripts
(gitlab-pkg-upload.py, gitlab_common.py) and redundant integration
test files. Update test helpers to import from the installed package
instead of subprocess execution of scripts. Add uv.lock for
reproducible dependency resolution. Add pytest-instafail to test
dependencies for immediate failure reporting.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The project currently lacks continuous integration, meaning tests must
be run manually on each developer's machine. This makes it easy for
regressions to slip through during code review and creates uncertainty
about whether code works across different Python versions.

Introduce a GitHub Actions workflow that runs the test suite on Python
3.11, 3.12, and 3.13 for every push and pull request. Unit tests run
unconditionally while integration tests only execute when GitLab
credentials are available, allowing the workflow to function in
contexts where secrets are not configured.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The project lacks automated quality checks and a release pipeline. Without
CI workflows, code style violations, documentation issues, and broken links
can slip into the codebase undetected, and publishing to PyPI requires
manual intervention.

Introduce three GitHub Actions workflows to automate these concerns. The
lint workflow runs Ruff and Mypy on every push and pull request to catch
style and type errors early. The docs workflow validates markdown formatting
and link integrity in README files. The publish workflow triggers on GitHub
releases to build and upload the package to PyPI automatically, removing the
need for manual release steps.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Manual code quality enforcement before commits relies on developers
remembering to run linting, formatting, and type checking commands
individually. This creates inconsistency between local development and
CI/CD pipeline results, leading to failed builds and unnecessary review
cycles.

Introduce pre-commit configuration that automatically runs ruff linting,
ruff formatting, and mypy type checking on staged files. This catches
issues at commit time rather than in CI, reducing feedback loops and
ensuring code quality standards are enforced consistently across all
contributors.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Currently there is no standardized way to manage version numbers across
the project. Updating versions requires manual edits to multiple files,
which is error-prone and inconsistent with semantic versioning best
practices.

Integrate bump-my-version as a dev dependency with configuration to
automatically synchronize version updates between pyproject.toml and the
package init file. This approach ensures single-command version bumps
that create git commits and tags, following the standard release
workflow pattern used by modern Python projects.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Signed-off-by: Javier Tia <javier.tia@linaro.org>
The test suite previously had no coverage tracking, making it difficult
to identify untested code paths and ensure adequate test coverage as the
project evolves. Additionally, integration tests could run unexpectedly
in CI environments where GitLab credentials were misconfigured, leading
to confusing failures.

Integrate pytest-cov with dual coverage thresholds: a 90% failure
threshold that blocks merges with insufficient coverage, and a 95%
warning threshold that surfaces coverage regressions early without
blocking development. Require explicit RUN_INTEGRATION_TESTS=1 opt-in
for integration tests to prevent accidental execution and make the test
environment requirements explicit. This separation ensures unit tests
run quickly in all environments while integration tests only execute
when deliberately enabled with proper credentials.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Users currently have no convenient way to enable tab completion for
glpkg commands. Setting up shell completions manually requires
understanding argcomplete internals and knowing the correct paths and
configuration for each shell, creating unnecessary friction for new
users.

Add an --install-completion flag that generates and installs the
appropriate completion script for bash or zsh. This leverages argcomplete
to generate shell-specific scripts and places them in conventional
locations (~/.bash_completion.d/ or ~/.zsh/completion/), then displays
the necessary shell configuration commands. The approach follows
established patterns used by other CLI tools and supports the two most
common shells without requiring global argcomplete activation.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Currently the package can only be distributed through PyPI as a wheel or
source distribution. Users who want a single-file executable or who
prefer not to use pip must either install from source or build manually,
which complicates deployment in restricted environments and CI pipelines.

Introduce a build script that generates self-contained .pyz archives
using Shiv or PEX. These zipapp binaries bundle the package and all
dependencies into a single executable file that runs on any system with
a compatible Python interpreter. The CI workflow now builds and uploads
this artifact alongside standard distributions during releases, giving
users a portable installation option that requires no package manager.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The documentation CI workflow only validated README.md and tests/README.md,
leaving newly added documentation files unchecked. This creates a gap
where broken links or markdown issues in contribution guides, release
procedures, and shell completion documentation would go undetected until
users encounter them.

Extend the markdown linting and link checking steps to include
CONTRIBUTING.md, docs/RELEASING.md, and docs/SHELL_COMPLETION.md. This
ensures all user-facing documentation maintains consistent quality and
link validity through automated verification.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The original package name "glpkg" may conflict with existing packages or
reserved names on PyPI, preventing publication to the public registry.
A unique, descriptive name ensures the package can be published and
discovered by users searching for GitLab package registry tools.

Rename the distribution package to "glpkg-cli" while preserving the
"glpkg" command name for end users. This follows the common convention
of using a "-cli" suffix for command-line tool distributions, avoiding
namespace conflicts while maintaining a clean user experience. The
documentation is updated to reflect the new installation commands and
includes additional guidance for manual releases and binary installation.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
jetm added 4 commits January 10, 2026 16:21
The project lacks centralized documentation for its CI/CD pipeline,
requiring developers to read through individual workflow YAML files to
understand the build and deployment process. This makes onboarding
harder and increases the risk of misconfiguring secrets or triggering
workflows incorrectly.

Add comprehensive workflow documentation covering all four GitHub
Actions workflows (test, lint, publish, docs), including their
triggers, required secrets, debugging tips, and future improvement
recommendations. Include status badges in the README to provide
at-a-glance pipeline health visibility, and add the new documentation
file to the docs workflow link checker for validation.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Long lines in documentation files make diffs harder to review and
conflict resolution more tedious when multiple contributors edit the
same sections. Markdown files also display inconsistently across
different editors and terminals when lines exceed standard widths.

Apply consistent line wrapping at approximately 72 characters across
all markdown documentation. This follows the conventional commit message
and prose formatting standard, improving readability in terminals,
simplifying three-way merges, and ensuring predictable rendering across
tools. Tables are reformatted for column alignment and code blocks are
adjusted to fit within the standard width.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
Static analysis tools report multiple type safety issues throughout the
codebase, including untyped function signatures, missing generic type
parameters, and improperly typed callables. Additionally, several
strings exceed the recommended line length limits, making the code
harder to read and causing linter warnings.

Add explicit type annotations to function parameters and return types,
particularly for generic containers and callable signatures. This
enables mypy to perform proper type checking and catch potential bugs
at development time rather than runtime. Reformat long strings by
splitting them across multiple lines or extracting variables to improve
readability while maintaining the same runtime behavior.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The existing test suite lacks coverage for several important code paths
including error handling in execute_upload, edge cases in terminal
detection, duplicate handling scenarios, and transient error
classification. This gaps make it difficult to verify correct behavior
during refactoring and could allow regressions to slip through.

Extend the test suite with targeted tests for previously uncovered
functionality. The execute_upload tests validate the complete flow from
project resolution through file upload, including all exception types
mapped in EXCEPTION_EXIT_CODE_MAP. The formatter tests cover ConEmu
color detection on Windows and duplicate metadata display in both rich
and plain output modes. The uploader tests verify GitlabError response
code classification for transient vs permanent errors and the fail_fast
behavior with remote duplicates.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
@jetm jetm changed the title Feature/package structure Initial code Jan 10, 2026
jetm added 2 commits January 10, 2026 16:40
The README workflow status badges reference placeholder repository
paths that do not correspond to an actual GitHub repository. This
causes broken badge images and prevents users from seeing the real
CI status at a glance.

Point all badge URLs to the actual jetm/glpkg repository where the
workflows are defined and executed. This ensures badge images resolve
correctly and accurately reflect the current build status.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
The workflows currently use pip's built-in caching through setup-python,
but dependencies are installed via uv. This mismatch means the cache
never benefits actual installs since uv maintains its own separate cache
directory, resulting in unnecessary network fetches on every CI run.

Enable uv's native caching mechanism in setup-uv instead. This ensures
the cache aligns with the package manager actually performing installs,
reducing CI execution time and network overhead.

Signed-off-by: Javier Tia <javier.tia@linaro.org>
@jetm jetm merged commit bfbf5d8 into main Jan 10, 2026
2 of 4 checks passed
@jetm jetm deleted the feature/package-structure branch January 11, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant