The format is based on Keep a Changelog. The project uses semantic versioning (see semver).
- New "deleter" PatchDriver, deletes file(s) specified if found.
- Uncaught exceptions of the CLI are no longer shamefully hidden.
- The under-cooked "precommit" PatchDriver is removed, useless and left broken
for a long time. If you need it, use a ShellDriver with
pre-commit autoupdatecommand instead
- Add
GlobFileEditor.before_run()to run arbitrary code before processing the first file - New function
replace_manyinpatchdrivers.brick, to replace many patterns in a string at once. Perfect for the kind of filesedreplacement PatchDriverPydantic base class now allows extra fields (Pydantic Extra fields)
ShellDrivercrash caused by incorrect construction ofPatchOutcomeobject.
- New
SingleFileEditor, derived fromPatchDriver, for editing single files.- Parameter
target_file, will be fed its text content toprocess_file(). - Use via
from mass_driver.drivers.bricks import SingleFileEditor.
- Parameter
- New
GlobFileEditor, similarly for editing multiple files from glob pattern.- Use via
from mass_driver.drivers.bricks import GlobFileEditor.
- Use via
- Update
pyGithubto2.1.1, now throttles Github API to avoid ratelimits
- Catch and log import errors during activity loading, previously silent crashes
- Completing an activity (source, migration, forge) now summarizes results
- Breakdown of repo count per outcome type, then sorted list of repos per type
- FASTER: Optional, experimental multi-threaded per-repo processsing!
Handling of clone, scan, patching is done as individual thread per repo, with
N=8 pooled threads.
- Early data shows a x6 improvement in performance, as cloning one repo doesn't block others anymore.
- Enable via new experimental flag
run --parallel, defaulting toFalse
- BREAKING: Renamed
RepotoSourcedRepoinmass_driver.models.repository- This exposes better the idea of "a Repo as it was Source-d", in contrast to
ClonedRepo"a Repo after it was cloned". - Also avoids clashes with
git.Repoobject from gitpython dependency.
- This exposes better the idea of "a Repo as it was Source-d", in contrast to
- Replaced all
print()calls tologgingmodule - Loggers used are mostly nested:
- from
root(default) - to
run(or other file-activity-based) - to
run.repo.<repo-id>for logs for a specific repo's processing - to subloggers like
run.repo.<repo-id>.driver.<driver-plugin-name>
- from
PatchDrivernow has aloggerobj for such customized logging: Repo-processing setsPatchdriver.loggernamedrun.repo.<repo-id>.driver.<driver-plugin-name>- ACTION: Please replace any
printwithself.logger.info!
- ACTION: Please replace any
- Attempting to run a Forge activity with
git_push_first=True, without migration or scan activity, no longer causes exit without processing any repos. Clone step invoked properly mean remote-clone URLs are now supported, converted to local filepaths internally. make docsnow works again withsphinx-autodoc2: Pinnedastroiddep to2.15.8(< 3.0.0) to avoid the regression caused by unpinnedastroid.
ShellDriverno longer crashes due to irrelevant dataclass import- Updated
pyGithub, fixes "missing cryptography" error - Error messages for bad config file for Sources no longer insist wrongly about "Forge config error". Now detecting the validation error's model properly.
- Failing to load a scanner that was selected in config now throws
ImportErroron the first plugin-load failure, instead of silently skipping the scanner.
- Updated to python-template v1.3.0 (from 1.1.0)
github-appforge no longer crashes due to type confusion on a param.
- Formatting of the % of PR per status back to 2 digits precision not 11.
Breaking interface of Forge to facilitate new view-pr feature.
- New
view-prfeature for bulk reviewing the status of PRs that already exist.
- BREAKING: New
Forge.get_pr_status(), required from derived classes, returning a string status, used as key to group PRs together for summary purposes. - BREAKING: New
Forge.pr_statusesproperty, required from derived classes, returning a list of all possible string statuses ofForge.get_pr_status(), sorted from most complete (e.g. merged) to least complete (e.g. not merged, has merge-conflicts).
- BREAKING: Removed
Forge.get_pr(), which had unclear return type anyway.
Major break of interface: Rework of the cloning system, merges migration/scan
codepaths, enabling use of Source-discovered information in PatchDriver.run.
- BREAKING:
PatchDriver.run()passesClonedRepoobj, notpathlib.Path.- Any use of
repoin yourPatchDriver.run()should userepo.cloned_path. - See
ClonedRepodocs, contains information derived fromSource, such aspatch_datafield, arbitrary source-issued information dict.
- Any use of
- BREAKING:
tests.fixtures.massdrive()now returns 3-item-tuple, not 2.- Returned tuple:
PatchResult,ForgeResult,ScanResult(orNone) - Any tests using
fixtures.massdriveshould now setmig, forge, scan =... - Swap
fixtures.massdrive_scanwithfixtures.massdriveaccepting 2 junk arg
- Returned tuple:
- BREAKING:
mass-driver scanCLI removed, now part ofmass-driver run. Activity flow forruncommand is now:- Source discovery phase (if any, or from CLI), generating
Repolist - Main phase, iterating over each Repo, first to clone them =
ClonedRepolist - Inside main phase, scan (if any), generating
ScanResult - Inside main phase, migrate (if any), generating
MigrationResult - After main phase, interactively pause for review if requested
- Forge activity, iterating over each repo again, creating
ForgeResult
- Source discovery phase (if any, or from CLI), generating
- BREAKING:
models.sourcemodule renamed tomodels.repository.
- Scan+Migration+Forge can now ALL happen in one run command:
- Clones one repo, then scanning it, then migrating it, then next repo
- Can thus do all of Source -> [Clone] -> Scan -> Migrate -> Forge
- New
csv-filelistSource for importing repos in CSV file format - New
tests.fixture.massdrive_runlocal()func to enable source testing
- Secret tokens for Github plugins no longer leak on config dump
(
--json-outfileflag), by replacingstrwithpydantic.SecretStr.- Docs updated to warn downstream devs about this risk.
- Pin
pydanticto1.*, as breaking version2.0was just released.
- New
sourcefeature for discovering what repos to patch/scan.Sources are plugins withdiscover()method, returningRepos by ID.- Alternative
sourcessubcommand to list and detail them - New TOML file entry
[mass-driver.source], with subkeysource_nameused to select which source plugin to enable. - Simple sources provided:
repo-listfor in-activity-file repository listrepo-filelistto point to a separate file listing repostemplate-filelistto expand a template against a file listing repos
github-searchandgithub-app-searchSources for Github Repository search- CLI args
--repo-pathand--repo-fileliststill available, overriding any source, so thatmassdriver.sourceis only required if lacking CLI args
- CI (pytest, pre-commit) set up via Github Actions: PR #1
- New
file_ownershipparameter forstamper, defaulting to0664.
- Exit codes harmonized:
0for success1for failures during the main function2for argument parsing errors
stamperdriver now creates any missing parent folder to the target- Remove test depending on
git clonefrom Github: Faster, offline tests now
scancommand now uses--json-outfileas expected
- New
scanfeature for scanning repos with arbitrary python functions. See new "Scanning" docs:- Scanners are plugins declared under
mass-driver.scanners, linking to functions likemy_scanner(repo: Path) -> dict[str, Any] - Alternative
scannerscommand to list out detected, available scanners - New TOML file entry
[mass-driver.scan], with subkeyscanner_namesused to select which scanner plugins to enable. - Simple scanners
root-filesanddockerfile-fromprovided for reference - New fixture
massdriver_scanandmassdriver_scan_checkfor testing scanners
- Scanners are plugins declared under
- New optional CLI parameter
--json-outfileforrunandscan, to save the activity outcome to JSON files for analysis
- Test fixture
massdrive_check_filenow returns uncheckedresultandreferenceblobs for equality assertion (assert result == reference) to be done by the caller. This enables plugins likepytest-clarityto show colorful diff. Users ofmassdrive_check_fileneed to change (on pain of lack of test assertion):
- massdrive_check_file(workdir)
+ result, reference = massdrive_check_file(workdir)
+ assert result == reference, "Massdriver result should match reference"- Auto-detect repo's base branch for Forge: parameter
base_branchnow optional, defaulting to repo's default branch
- New
github-appforge plugin for creating PRs on Github when running mass-driver as a Github App - New Forge params:
forge_configdict, for Forge-specific non-sensitive config to keep in config file, complementing envvars. Similar todriver_configfor Migration.interactive_pause_everyint, for blocking the Forge, pausing for confirmation interactively every few PRs generated. Disabled by default, set to 1 to block every PR, or 5 every 5...
- Unused
migration_namefield of Migration now removed
Forgesubclasses can now grab config via envvars prefixedFORGE_. Observe thatForgenow derives frompydantic.BaseSettings, see BaseSettings docs.- New, simpler testing fixture
massdrive_check_filefor PatchDriver that affect single files
- New optional Migration params:
commit_author_name+commit_author_email, used to override the git commit author.
- New file type
ActivitycombinesMigrationandForge - New
Forgenameddummyfor testing purposes - New
git_push_firstboolean param in Forge to disable git pushing. - New
ActivityOutcometo capture the full result of a migration/forge sequence
- Replace commands
run-migration+run-forgeby newrun, using theActivityfile type with optionals. - Internals refactored: all Pydantic objects now under
mass_driver.models(PatchDriver,Forge,Activity)
- Options
--really-commit-changesand--dry-run
- New
ROADMAP.mdto clarify The Plan.
- Upgrade minimum Python version to 3.11 to use
tomllib - Replace
tomlkitwith stdlibtomllib
- Migrations, once loaded from TOML, are now proper dict again
PatchDriverinstance now independent across repos
- Upgrade pre-commit dependencies + poetry in Dockerfile
- Update pyproject.toml for release to Pypi
- Forges now discovered via setuptools
- New "run-forge" subcommand for creating PRs for on-disk branches
- Implemented GithubForge for PR creation on Github
- New "Stamper"
PatchDriverfor "stamping" new files on repos
- Incorrect Repo creation causing silent cloning errors on some devices
- New plugin system for including third-party PatchDrivers, based on the setuptools "entrypoints" system.
- CLI Subcommands for inspecting drivers, running migrations...
- PatchDriver test harness, for ease of plugin development.
- Project objectives (gherkin features in
features/) now part of docs
PatchDrivernow inherits Pydantic BaseModel (allows serialization)PatchDriverfunc prototype:run(repo: Path) -> PatchResult
- Complex PatchDrivers (the ones requiring package dependencies) removed, moved to separate "plugins" repo.
- New
JsonpatchDriver, for applying an RFC6902 JSON Patch - New
PreCommitDriver, for runningpre-commit autoupdate - New
ShellDriverfor running arbitrary shell commands - New
mass-driver(1)man page output tomake docs
- PatchDriver API simplified, now using single func for detect + patch:
called via
PatchDriver.run(repo: Path, dry_run: bool). - CLI simplified when exposing
PatchDriver.run(), now uses either--dry-run(the default setup) or--really-commit-changesfor committing (not pushing)
- Poetry Driver stub for major version of packages in
pyproject.toml. Showcases JSON Pointers (RFC6901) for structured fields modification.
- Basic clone/detect/patch/commit workflow, with basic Github support
- New python module
mass_driver, exposed as shell commandmass-driver