Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Enhanced Repository Discovery

Refactor DSL provides advanced repository discovery and filtering capabilities, enabling you to target specific repositories in large organizations based on dependencies, frameworks, metrics, and languages.

Overview

The discovery module extends basic Git repository filtering with:

  • Dependency filtering - Find repos using specific packages
  • Framework detection - Identify repos using React, Rails, Spring, etc.
  • Metrics filtering - Filter by lines of code, file count, complexity
  • Language detection - Target repos by primary programming language

Quick Start

#![allow(unused)]
fn main() {
use refactor::prelude::*;

// Find all React 17+ projects with over 1000 lines of code
Codemod::from_github_org("acme-corp", token)
    .repositories(|r| r
        .has_dependency("react", ">=17.0")
        .uses_framework(Framework::React)
        .lines_of_code(ComparisonOp::GreaterThan, 1000.0))
    .apply(upgrade_operation)
    .execute()?;
}

Filter Types

Dependency Filters

Filter by package dependencies:

#![allow(unused)]
fn main() {
.repositories(|r| r
    // NPM packages
    .has_dependency("react", ">=17.0")
    .has_dependency("typescript", "*")

    // Cargo crates
    .has_dependency("tokio", ">=1.0")

    // Python packages
    .has_dependency("django", ">=3.0")
)
}

Framework Filters

Filter by detected frameworks:

#![allow(unused)]
fn main() {
.repositories(|r| r
    .uses_framework(Framework::NextJs)
    // or
    .uses_framework(Framework::Rails)
    // or
    .uses_framework(Framework::Spring)
)
}

Metrics Filters

Filter by code metrics:

#![allow(unused)]
fn main() {
.repositories(|r| r
    .lines_of_code(ComparisonOp::GreaterThan, 1000.0)
    .file_count(ComparisonOp::LessThan, 100.0)
    .complexity(ComparisonOp::LessThan, 20.0)
)
}

Language Filters

Filter by primary language:

#![allow(unused)]
fn main() {
.repositories(|r| r
    .primary_language("rust")
    // Or by percentage
    .language_percentage("typescript", ComparisonOp::GreaterThan, 50.0)
)
}

Combining Filters

Filters combine with AND logic:

#![allow(unused)]
fn main() {
Codemod::from_github_org("company", token)
    .repositories(|r| r
        // All conditions must be true
        .primary_language("typescript")
        .uses_framework(Framework::React)
        .has_dependency("react", ">=18.0")
        .lines_of_code(ComparisonOp::GreaterThan, 5000.0)
    )
    .apply(migration)
    .execute()?;
}

For OR logic, use multiple discovery passes:

#![allow(unused)]
fn main() {
// Find repos using either React OR Vue
let react_repos = discover_repos()
    .uses_framework(Framework::React)
    .collect()?;

let vue_repos = discover_repos()
    .uses_framework(Framework::Vue)
    .collect()?;

let all_frontend_repos: HashSet<_> = react_repos.union(&vue_repos).collect();
}

Discovery Sources

GitHub Organization

#![allow(unused)]
fn main() {
Codemod::from_github_org("organization-name", github_token)
    .repositories(|r| r.has_file("Cargo.toml"))
    .apply(transform)
    .execute()?;
}

GitHub User

#![allow(unused)]
fn main() {
Codemod::from_github_user("username", github_token)
    .repositories(|r| r.primary_language("rust"))
    .apply(transform)
    .execute()?;
}

Local Directory

#![allow(unused)]
fn main() {
Codemod::from_directory("./workspace")
    .repositories(|r| r.uses_framework(Framework::Django))
    .apply(transform)
    .execute()?;
}

Custom Sources

#![allow(unused)]
fn main() {
let repos = vec![
    PathBuf::from("./project-a"),
    PathBuf::from("./project-b"),
    PathBuf::from("./project-c"),
];

Codemod::from_paths(repos)
    .repositories(|r| r.has_dependency("lodash", "*"))
    .apply(transform)
    .execute()?;
}

Advanced Repository Filter

Use AdvancedRepoFilter for complex filtering:

#![allow(unused)]
fn main() {
use refactor::discovery::AdvancedRepoFilter;

let filter = AdvancedRepoFilter::new()
    // Base Git filters
    .branch("main")
    .has_file("package.json")
    .recent_commits(30)

    // Dependency filters
    .dependency(DependencyFilter::npm("react", ">=17"))
    .dependency(DependencyFilter::npm("typescript", "*"))

    // Framework detection
    .framework(FrameworkFilter::new(Framework::NextJs))

    // Metrics
    .metric(MetricFilter::lines_of_code(ComparisonOp::GreaterThan, 1000.0))

    // Language
    .language(LanguageFilter::primary("typescript"));

// Apply filter
let matching_repos = filter.discover("./workspace")?;
}

Caching and Performance

Discovery operations cache results for performance:

#![allow(unused)]
fn main() {
Codemod::from_github_org("large-org", token)
    .repositories(|r| r
        .cache_duration(Duration::from_secs(3600))  // Cache for 1 hour
        .parallel_discovery(true)  // Parallel analysis
        .has_dependency("react", "*"))
    .apply(transform)
    .execute()?;
}

Error Handling

#![allow(unused)]
fn main() {
use refactor::error::RefactorError;

match Codemod::from_github_org("org", token)
    .repositories(|r| r.has_dependency("react", "*"))
    .apply(transform)
    .execute()
{
    Ok(results) => {
        println!("Processed {} repositories", results.len());
    }
    Err(RefactorError::GithubApiError(msg)) => {
        println!("GitHub API error: {}", msg);
    }
    Err(RefactorError::RateLimited(retry_after)) => {
        println!("Rate limited. Retry after {} seconds", retry_after);
    }
    Err(e) => return Err(e.into()),
}
}

Use Cases

Organization-Wide Dependency Updates

#![allow(unused)]
fn main() {
// Update lodash to v4.17.21 across all JS projects
Codemod::from_github_org("company", token)
    .repositories(|r| r
        .has_dependency("lodash", "<4.17.21"))
    .apply(|ctx| {
        ctx.update_dependency("lodash", "4.17.21")
    })
    .create_prs(true)
    .execute()?;
}

Framework Migration

#![allow(unused)]
fn main() {
// Find all Create React App projects for Next.js migration
Codemod::from_github_org("company", token)
    .repositories(|r| r
        .has_dependency("react-scripts", "*")
        .lines_of_code(ComparisonOp::LessThan, 10000.0))  // Small projects first
    .collect_repos()?;
}

Security Auditing

#![allow(unused)]
fn main() {
// Find repos with vulnerable dependency versions
Codemod::from_github_org("company", token)
    .repositories(|r| r
        .has_dependency("log4j", "<2.17.0"))  // Vulnerable version
    .apply(|ctx| {
        ctx.create_security_issue()
    })
    .execute()?;
}

Language Standardization

#![allow(unused)]
fn main() {
// Find all TypeScript projects not using strict mode
Codemod::from_github_org("company", token)
    .repositories(|r| r
        .primary_language("typescript")
        .has_file("tsconfig.json"))
    .apply(|ctx| {
        ctx.ensure_strict_mode()
    })
    .execute()?;
}

See Also