Tool to bump static assets based on a configuration file
Project description
BMYC - Bump Me if You Can
A powerful CLI tool to automatically manage and update static assets from various CDN providers (GitHub, CDNjs, jsDelivr, and Unpkg) in your project.
Overview
BMYC (Bump Me if You Can) is a Python-based command-line tool designed to simplify the management of external JavaScript, CSS, and other static assets. Instead of manually tracking versions and updating file paths, BMYC automates the process by:
- Fetching the latest versions from multiple CDN providers
- Downloading and saving updated assets to your project
- Managing asset versions with version pinning support
- Validating your asset configuration
- Generating summary reports of updates
Features
- ๐ Multi-Provider Support: Seamlessly work with GitHub, CDNjs, jsDelivr (npm), and Unpkg
- ๐ Version Pinning: Lock assets to specific versions with the
holdflag - โ๏ธ Flexible Configuration: Define assets in JSON or YAML format
- ๐ Async Processing: Efficiently fetch and process multiple assets concurrently
- ๐ Detailed Reporting: Generate summary reports of all updates
- ๐ GitHub Token Support: Securely authenticate with GitHub for private repositories
- ๐ง Force Updates: Override version locks when needed
- ๐ Configuration Validation: Automatic validation of your configuration files using Pydantic
Installation
From Source
# Clone the repository
git clone https://github.com/jgazeau/bmyc.git
cd bmyc
# Install dependencies using Poetry
poetry install
# Build and install
poetry build
pip install dist/bmyc-*.whl
Via Pip (when published)
pip install bmyc
Quick Start
1. Create a Configuration File
Create a .bmycconfig.json or .bmycconfig.yaml file in your project root:
{
"jquery": {
"library": {
"local_path": "assets/js/jquery.min.js",
"hold": false,
"cdnjs": {
"library": "jquery",
"file_path": "jquery.min.js"
}
}
},
"bootstrap": {
"css": {
"local_path": "assets/css/bootstrap.min.css",
"jsdelivr": {
"cdn": "npm",
"package": "bootstrap",
"file_path": "dist/css/bootstrap.min.css"
}
}
}
}
2. Run BMYC
bmyc --configuration .bmycconfig.json
BMYC will:
- Fetch the latest version of each asset from its provider
- Download the files to their specified local paths
- Update the configuration file with the new versions
- Generate a summary report
Configuration Format
Configuration Structure
Your configuration file is organized in a hierarchical structure:
Configuration
โโโ Package (e.g., "jquery", "bootstrap")
โโโ Asset (e.g., "library", "css")
โโโ local_path: Where to save the file
โโโ hold: Lock version (optional, default: false)
โโโ current_version: Current version (required if hold=true)
โโโ provider: Asset source
Asset Configuration
Each asset requires:
local_path(required): Relative or absolute path where the asset will be savedhold(optional): Boolean flag to lock the asset to a specific version (default:false)current_version(required ifhold=true): The version to pin toprovider(required): Provider configuration (see below)
Supported Providers
CDNjs
For assets hosted on CDNjs:
{
"package_name": {
"asset_name": {
"local_path": "assets/lib.min.js",
"cdnjs": {
"library": "library-name",
"file_path": "relative/path/to/file.min.js"
}
}
}
}
Provider Fields:
library: The library name on CDNjsfile_path: The path to the specific file within the library
jsDelivr
For npm packages via jsDelivr:
{
"package_name": {
"asset_name": {
"local_path": "assets/lib.min.js",
"jsdelivr": {
"cdn": "npm",
"package": "package-name",
"file_path": "dist/file.min.js"
}
}
}
}
Provider Fields:
cdn: The CDN type (currently supports"npm")package: The npm package namefile_path: The path to the specific file within the package
GitHub
For files hosted in GitHub repositories:
{
"package_name": {
"asset_name": {
"local_path": "assets/lib.min.js",
"github": {
"owner": "repository-owner",
"repository": "repository-name",
"file_path": "path/to/file.min.js"
}
}
}
}
Provider Fields:
owner: GitHub repository owner usernamerepository: GitHub repository namefile_path: Path to the file within the repository
Note: For GitHub, you may need to provide a GitHub token via the --github-token option for authentication.
Unpkg
For npm packages via Unpkg:
{
"package_name": {
"asset_name": {
"local_path": "assets/lib.min.js",
"unpkg": {
"library": "package-name",
"file_path": "dist/file.min.js"
}
}
}
}
Provider Fields:
library: The npm package namefile_path: The path to the specific file within the package
Version Pinning
Lock an asset to a specific version:
{
"package_name": {
"critical_asset": {
"local_path": "assets/critical.min.js",
"current_version": "2.1.0",
"hold": true,
"cdnjs": {
"library": "some-library",
"file_path": "some-library.min.js"
}
}
}
}
When hold is true, BMYC will skip updating this asset unless forced with the --force flag.
Command Line Interface
Basic Usage
bmyc [OPTIONS]
Options
-c, --configuration PATH
Path to the configuration file (JSON or YAML).
- Type: File path
- Default:
.bmycconfig.json - Required: Yes
- Example:
bmyc --configuration config.yaml
-s, --summary PATH
Path where the summary report will be saved.
- Type: File path
- Default:
bmyc-summary.md - Example:
bmyc --summary update-report.md
-f, --force
Force update of all assets, including those marked with hold: true.
- Type: Flag
- Default: Off
- Example:
bmyc --force
-i, --insecure
Allow insecure TLS connections (not recommended for production).
- Type: Flag
- Default: Off
- Example:
bmyc --insecure
--github-token TOKEN
GitHub API token for authenticating with GitHub when fetching assets.
- Type: String
- Environment Variable:
BMYC_GITHUB_TOKEN - Example:
bmyc --github-token ghp_xxxxxxxxxxxx
-v, --verbose
Increase verbosity level (can be used multiple times: -v, -vv, -vvv).
- Type: Flag (repeatable)
- Default: Level 2 (INFO)
- Levels:
- No flag: ERROR
-v: WARNING-vv: INFO-vvv: DEBUG
- Example:
bmyc -vvfor INFO level logs
-h, --help
Display help message.
CLI Examples
Basic update
bmyc --configuration .bmycconfig.json
Update with a custom summary file
bmyc --configuration assets-config.json --summary updates.md
Force update all assets (including pinned versions)
bmyc --force --configuration .bmycconfig.json
Update with GitHub token via environment variable
export BMYC_GITHUB_TOKEN=ghp_xxxxxxxxxxxx
bmyc --configuration .bmycconfig.json
Update with GitHub token via CLI
bmyc --configuration .bmycconfig.json --github-token ghp_xxxxxxxxxxxx
Debug mode with maximum verbosity
bmyc --configuration .bmycconfig.json -vvv
Update without certificate verification (use with caution)
bmyc --configuration .bmycconfig.json --insecure
Workflow Example
Here's a complete example of using BMYC in a web project:
Step 1: Create Configuration
Create .bmycconfig.json:
{
"jquery": {
"library": {
"local_path": "public/vendor/jquery.min.js",
"cdnjs": {
"library": "jquery",
"file_path": "jquery.min.js"
}
}
},
"bootstrap": {
"css": {
"local_path": "public/vendor/bootstrap.min.css",
"hold": true,
"current_version": "5.1.3",
"jsdelivr": {
"cdn": "npm",
"package": "bootstrap",
"file_path": "dist/css/bootstrap.min.css"
}
},
"js": {
"local_path": "public/vendor/bootstrap.min.js",
"hold": true,
"current_version": "5.1.3",
"jsdelivr": {
"cdn": "npm",
"package": "bootstrap",
"file_path": "dist/js/bootstrap.min.js"
}
}
},
"popper": {
"library": {
"local_path": "public/vendor/popper.min.js",
"unpkg": {
"library": "@popperjs/core",
"file_path": "dist/umd/popper.min.js"
}
}
},
"highlight": {
"css": {
"local_path": "public/vendor/highlight.min.css",
"cdnjs": {
"library": "highlight.js",
"file_path": "styles/atom-one-dark.min.css"
}
},
"js": {
"local_path": "public/vendor/highlight.min.js",
"cdnjs": {
"library": "highlight.js",
"file_path": "highlight.min.js"
}
}
}
}
Step 2: Run BMYC
bmyc --configuration .bmycconfig.json --summary bmyc-update.md
Step 3: Review Summary
Check bmyc-update.md to see what was updated:
# BMYC Summary Report
## Bootstrap
- **css**: Updated from 5.1.3 โ 5.3.0 (held)
- **js**: Updated from 5.1.3 โ 5.3.0 (held)
## jQuery
- **library**: Updated from 3.6.0 โ 3.7.1
## Popper
- **library**: Updated from 2.11.8 โ 2.11.8
## Highlight
- **css**: Updated from 11.8.0 โ 11.9.0
- **js**: Updated from 11.8.0 โ 11.9.0
Step 4: Force Update Pinned Assets
bmyc --force --configuration .bmycconfig.json
Summary Report
After running BMYC, a summary report is generated (default: bmyc-summary.md) containing:
- List of all packages processed
- Assets within each package
- Version updates (previous โ new)
- Status of each asset (updated, held, error)
- Timestamps and processing details
Configuration Validation
BMYC validates your configuration file and provides detailed error messages for:
- Invalid file paths
- Missing required provider fields
- Invalid provider types
- Duplicate local paths
- Missing
current_versionwhenhold: true - Malformed JSON/YAML
Development
Setup Development Environment
# Install Poetry
pip install poetry
# Clone and navigate to project
git clone https://github.com/jgazeau/bmyc.git
cd bmyc
# Install dependencies
poetry install
Available Development Tasks
# Run tests with coverage
poetry run poe test
# Run tests only
poetry run poe test:coverage
# Generate HTML coverage report
poetry run poe test:coverage-html
# Lint and format code
poetry run poe lint
# Format with Black
poetry run poe format:black
# Check with Black
poetry run poe lint:black
# Sort imports with isort
poetry run poe lint:isort
# Check with flake8
poetry run poe lint:flake8
Running Locally
poetry run bmyc --help
poetry run bmyc --configuration tests/resources/model/config-valid.json
Project Structure
bmyc/
โโโ src/bmyc/ # Main package
โ โโโ __init__.py
โ โโโ cli.py # CLI entry point
โ โโโ cli_context.py # CLI context management
โ โโโ processor.py # Main processing logic
โ โโโ results_handler.py # Result handling and reporting
โ โโโ commons/ # Common utilities
โ โ โโโ bmyc_error.py # Custom exceptions
โ โ โโโ common_constants.py # Constants
โ โ โโโ helpers.py # Helper functions
โ โ โโโ json.py # JSON utilities
โ โ โโโ logging.py # Logging configuration
โ โ โโโ singleton.py # Singleton pattern
โ โ โโโ yaml.py # YAML utilities
โ โโโ model/ # Data models
โ โโโ asset.py # Asset model
โ โโโ asset_status_enum.py # Asset status enumeration
โ โโโ bmyc_configuration.py # Configuration model
โ โโโ package.py # Package model
โ โโโ providers/ # Provider implementations
โ โโโ provider.py # Base provider class
โ โโโ cdnjs.py # CDNjs provider
โ โโโ github.py # GitHub provider
โ โโโ jsdelivr.py # jsDelivr provider
โ โโโ unpkg.py # Unpkg provider
โโโ tests/ # Test suite
โ โโโ test_processor.py
โ โโโ test_results_handler.py
โ โโโ resources/ # Test fixtures and config examples
โ โโโ test_commons/
โ โโโ test_helpers.py
โ โโโ test_json.py
โ โโโ test_logging.py
โ โโโ test_yaml.py
โโโ pyproject.toml # Project configuration
โโโ poetry.lock # Locked dependencies
โโโ README.md # This file
Running Tests
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=src/bmyc tests/
# Run specific test file
poetry run pytest tests/test_processor.py
# Run with verbose output
poetry run pytest -v
Error Handling
BMYC provides clear error messages for common issues:
Configuration Errors
Error: Configuration validation failed
- Invalid provider type: 'npmjs' (expected: cdnjs, github, jsdelivr, unpkg)
- Missing required field: 'library' in cdnjs provider
- Duplicate local_path: 'assets/lib.min.js'
Network Errors
Error: Failed to fetch latest version for jquery from Cdnjs
- Connection timeout while reaching api.cdnjs.com
- Ensure your internet connection is stable
Authentication Errors
Error: GitHub API authentication failed
- Invalid or expired GitHub token
- Set BMYC_GITHUB_TOKEN environment variable or use --github-token option
Troubleshooting
GitHub Token Issues
If you get authentication errors when fetching from GitHub:
-
Generate a GitHub Personal Access Token:
- Go to GitHub Settings โ Developer Settings โ Personal Access Tokens
- Create a new token with
reposcope - Copy the token
-
Provide the token to BMYC:
export BMYC_GITHUB_TOKEN=your_token_here bmyc --configuration .bmycconfig.json
SSL/TLS Errors
If you encounter SSL certificate errors:
# Use the --insecure flag (not recommended for production)
bmyc --insecure --configuration .bmycconfig.json
File Path Issues
Ensure all local_path values are:
- Relative to your project root, OR
- Absolute paths
- Parent directories exist or will be created by BMYC
Slow Updates
For better performance with many assets:
- Ensure your internet connection is stable
- Check provider API rate limits
- Use verbose mode to identify slow operations:
bmyc -vv
Performance Considerations
- Concurrent Processing: BMYC processes multiple assets concurrently for efficiency
- Caching: No caching is implemented; each run fetches fresh data
- Network: Update speed depends primarily on CDN provider response times
- Disk I/O: Files are saved with streaming to minimize memory usage
Security
- BMYC validates all configuration inputs
- GitHub tokens should never be committed to version control
- Use environment variables or secure secrets management for tokens
- TLS verification is enabled by default
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Jordan Gazeau - GitHub
Support
For issues, questions, or suggestions, please open an issue on the GitHub repository.
Changelog
Version 0.1.0
Initial release with support for:
- CDNjs provider
- GitHub provider
- jsDelivr provider
- Unpkg provider
- YAML and JSON configuration
- Version pinning
- Summary reporting
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 bmyc-0.1.0.tar.gz.
File metadata
- Download URL: bmyc-0.1.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fb8aeaf79e0fe0828a798c1ed13bf2a4ceaf99c0539d1905cea028965839c6f
|
|
| MD5 |
1c18cf46ee60ff514939bf346ff9981e
|
|
| BLAKE2b-256 |
9e7932a0e4406e1c79a7169f0aa4837a3a81b7b4e3e5d337587095a3e407bfe8
|
Provenance
The following attestation bundles were made for bmyc-0.1.0.tar.gz:
Publisher:
publish.yml on jgazeau/bmyc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bmyc-0.1.0.tar.gz -
Subject digest:
0fb8aeaf79e0fe0828a798c1ed13bf2a4ceaf99c0539d1905cea028965839c6f - Sigstore transparency entry: 1340467758
- Sigstore integration time:
-
Permalink:
jgazeau/bmyc@88657df33f8cee9d6a16ce78a7b3610d0f8d3d24 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jgazeau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@88657df33f8cee9d6a16ce78a7b3610d0f8d3d24 -
Trigger Event:
release
-
Statement type:
File details
Details for the file bmyc-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bmyc-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f52911589607d14bcf7729cafc7b421aaf4e1d0a6232084e82ea5e0ad3e2350
|
|
| MD5 |
76ae8e622c4e4e913c777e4ed7ed1b8a
|
|
| BLAKE2b-256 |
a08915c5b4128efae09d8c37bde0215f97a39ec5154cb637d3b32f2aeac92b48
|
Provenance
The following attestation bundles were made for bmyc-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on jgazeau/bmyc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bmyc-0.1.0-py3-none-any.whl -
Subject digest:
4f52911589607d14bcf7729cafc7b421aaf4e1d0a6232084e82ea5e0ad3e2350 - Sigstore transparency entry: 1340467761
- Sigstore integration time:
-
Permalink:
jgazeau/bmyc@88657df33f8cee9d6a16ce78a7b3610d0f8d3d24 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jgazeau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@88657df33f8cee9d6a16ce78a7b3610d0f8d3d24 -
Trigger Event:
release
-
Statement type: