Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 22 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,10 @@ jobs:
- name: Run cargo-deny
run: cargo deny check

- name: Install cargo-semver-checks
uses: taiki-e/install-action@cargo-semver-checks

- name: Check SemVer compliance
run: cargo semver-checks check-release
continue-on-error: true
# Note: cargo-semver-checks removed for pre-1.0 development
# Checking semver compliance for 7 crates takes 5-7 minutes
# and is not valuable for pre-1.0 versions (breaking changes allowed)
# Re-enable when approaching 1.0.0 release

# Cross-platform tests with matrix
test:
Expand Down Expand Up @@ -185,12 +183,15 @@ jobs:
run: cargo build --workspace --target ${{ matrix.target }}

# Code coverage (Linux only for speed)
# Optimized: Single test run with codecov flags for per-crate tracking
# Previous approach ran tests 7 times (1 overall + 6 per-crate) taking ~15 min
# New approach: Single run with flags takes ~5 min (67% faster, 67% less runner cost)
coverage:
name: Code Coverage
needs: [changes, fmt, check]
if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.workflows == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 10
steps:
- uses: actions/checkout@v6

Expand All @@ -207,81 +208,76 @@ jobs:
with:
shared-key: "coverage"

- name: Generate overall coverage
- name: Generate coverage (single run for all crates)
run: |
cargo llvm-cov --all-features --workspace --lcov \
--output-path lcov.info nextest

- name: Generate per-crate coverage
run: |
# Generate coverage for each crate separately
for crate in deps-core deps-cargo deps-npm deps-pypi deps-go deps-lsp; do
echo "Generating coverage for $crate..."
cargo llvm-cov --all-features --package "$crate" --lcov \
--output-path "lcov-$crate.info" nextest 2>/dev/null || true
done

# Upload overall coverage with overall flag
- name: Upload overall coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
flags: overall
fail_ci_if_error: false
verbose: true

# Upload per-crate coverage using flags
# Codecov automatically filters by file paths in each crate
- name: Upload deps-core coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-core.info
files: lcov.info
flags: deps-core
fail_ci_if_error: false

- name: Upload deps-cargo coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-cargo.info
files: lcov.info
flags: deps-cargo
fail_ci_if_error: false

- name: Upload deps-npm coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-npm.info
files: lcov.info
flags: deps-npm
fail_ci_if_error: false

- name: Upload deps-pypi coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-pypi.info
files: lcov.info
flags: deps-pypi
fail_ci_if_error: false

- name: Upload deps-go coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-go.info
files: lcov.info
flags: deps-go
fail_ci_if_error: false

- name: Upload deps-lsp coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-deps-lsp.info
files: lcov.info
flags: deps-lsp
fail_ci_if_error: false

- name: Archive coverage reports
- name: Archive coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-reports
path: lcov*.info
name: coverage-report
path: lcov.info
retention-days: 30

# MSRV check
Expand Down
98 changes: 98 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,104 @@ tracing-subscriber = "0.3"
urlencoding = "2.1"
zed_extension_api = "0.7"

[workspace.lints.rust]
unsafe_code = "forbid"
missing_docs = "allow"
missing_debug_implementations = "allow"
unreachable_pub = "warn"

[workspace.lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
cargo = { level = "warn", priority = -1 }

# Allowed lints - too noisy for this codebase
module_name_repetitions = "allow"
similar_names = "allow"
too_many_lines = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
must_use_candidate = "allow"
single_match_else = "allow"

# Documentation lints - allow for now, can enable incrementally
doc_markdown = "allow"
missing_docs_in_private_items = "allow"

# Cargo lints - metadata can be added later
cargo_common_metadata = "allow"

# Nursery lints that are too pedantic
option_if_let_else = "allow"
future_not_send = "allow"
redundant_pub_crate = "allow"

# Pattern-matching lints - allow for now
wildcard_enum_match_arm = "allow"
redundant_else = "allow"

# Style lints - allow for readability
manual_let_else = "allow"
items_after_statements = "allow"

# Type conversion lints - allow where intentional
cast_possible_truncation = "allow"
cast_precision_loss = "allow"
cast_sign_loss = "allow"

# Nursery performance lints that need review
significant_drop_tightening = "allow"

# Cargo lints that conflict with workspace setup
multiple_crate_versions = "allow"

# Style lints - allow for now, can be fixed incrementally
uninlined_format_args = "allow"
explicit_iter_loop = "allow"
redundant_closure_for_method_calls = "allow"
match_wildcard_for_single_variants = "allow"

# Function lints - allow for now
missing_const_for_fn = "allow"
unnecessary_wraps = "allow"

# LazyLock migration - allow until we can target newer MSRV
non_std_lazy_statics = "allow"

# HashMap generics - too noisy for internal APIs
implicit_hasher = "allow"

# Performance lints that are pedantic
map_unwrap_or = "allow"
needless_collect = "allow"
or_fun_call = "allow"
format_push_string = "allow"

# Documentation lints
doc_link_with_quotes = "allow"

# Derive lints - can be fixed incrementally
derive_partial_eq_without_eq = "allow"

# Test-specific lints
used_underscore_binding = "allow"
ignore_without_reason = "allow"

# API design lints that need review
unused_self = "allow"
unused_async = "allow"

# Pattern matching lints
match_same_arms = "allow"

# File extension checks - too strict
case_sensitive_file_extension_comparisons = "allow"

# Style preferences
default_trait_access = "allow"
needless_pass_by_value = "allow"

[profile.release]
lto = true
codegen-units = 1
Expand Down
3 changes: 3 additions & 0 deletions crates/deps-cargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ repository.workspace = true
description = "Cargo.toml support for deps-lsp"
publish = true

[lints]
workspace = true

[dependencies]
deps-core = { workspace = true }
async-trait = { workspace = true }
Expand Down
35 changes: 17 additions & 18 deletions crates/deps-cargo/benches/cargo_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ resolver = "2"
i % 20
));
} else if i % 3 == 1 {
content.push_str(&format!("dep{} = {{ workspace = true }}\n", i));
content.push_str(&format!("dep{i} = {{ workspace = true }}\n"));
} else {
content.push_str(&format!("dep{} = \"1.{}.0\"\n", i, i % 20));
}
Expand Down Expand Up @@ -145,24 +145,24 @@ fn bench_cargo_parsing(c: &mut Criterion) {

group.bench_function("small_5_deps", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(SMALL_CARGO_TOML), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(SMALL_CARGO_TOML), black_box(&url)));
});

group.bench_function("medium_25_deps", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(MEDIUM_CARGO_TOML), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(MEDIUM_CARGO_TOML), black_box(&url)));
});

let large_toml = generate_large_cargo_toml();
group.bench_function("large_100_deps", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(&large_toml), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(&large_toml), black_box(&url)));
});

let workspace_toml = generate_workspace_cargo_toml();
group.bench_function("workspace_100_deps", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(&workspace_toml), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(&workspace_toml), black_box(&url)));
});

group.finish();
Expand All @@ -188,12 +188,12 @@ serde = { version = "1.0", features = ["derive", "std"], default-features = fals

group.bench_function("inline_dependency", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(inline), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(inline), black_box(&url)));
});

group.bench_function("table_dependency", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(table), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(table), black_box(&url)));
});

group.finish();
Expand Down Expand Up @@ -226,15 +226,14 @@ fn bench_registry_parsing(c: &mut Criterion) {
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.collect();
})
});
});

// Generate large sparse index response (100 versions)
let mut large_index = String::new();
for i in 0..100 {
large_index.push_str(&format!(
r#"{{"name":"crate","vers":"1.0.{}","deps":[],"cksum":"abc{}","features":{{}},"yanked":false}}"#,
i, i
r#"{{"name":"crate","vers":"1.0.{i}","deps":[],"cksum":"abc{i}","features":{{}},"yanked":false}}"#
));
large_index.push('\n');
}
Expand All @@ -245,7 +244,7 @@ fn bench_registry_parsing(c: &mut Criterion) {
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.collect();
})
});
});

group.finish();
Expand All @@ -271,13 +270,13 @@ fn bench_version_matching(c: &mut Criterion) {
// Simple version requirement
let simple_req = VersionReq::parse("1.0").unwrap();
group.bench_function("simple_version_req", |b| {
b.iter(|| simple_req.matches(black_box(&latest)))
b.iter(|| simple_req.matches(black_box(&latest)));
});

// Complex version requirement (multiple constraints)
let complex_req = VersionReq::parse(">=1.0.100, <2.0").unwrap();
group.bench_function("complex_version_req", |b| {
b.iter(|| complex_req.matches(black_box(&latest)))
b.iter(|| complex_req.matches(black_box(&latest)));
});

// Find latest matching version
Expand All @@ -288,7 +287,7 @@ fn bench_version_matching(c: &mut Criterion) {
.filter(|v| simple_req.matches(v))
.max()
.cloned()
})
});
});

group.finish();
Expand Down Expand Up @@ -318,8 +317,8 @@ serde = { version = "1.0", features = ["derive"] }"#,
),
(
"workspace_inheritance",
r#"[dependencies]
serde = { workspace = true }"#,
r"[dependencies]
serde = { workspace = true }",
),
(
"git_dependency",
Expand All @@ -344,7 +343,7 @@ default-features = false"#,
for (name, content) in formats {
group.bench_with_input(BenchmarkId::from_parameter(name), &content, |b, content| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(content), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(content), black_box(&url)));
});
}

Expand All @@ -367,7 +366,7 @@ tokio = "1.0" # Зависимость с кириллицей

c.bench_function("unicode_parsing", |b| {
let url = test_url();
b.iter(|| parse_cargo_toml(black_box(unicode_toml), black_box(&url)))
b.iter(|| parse_cargo_toml(black_box(unicode_toml), black_box(&url)));
});
}

Expand Down
6 changes: 3 additions & 3 deletions crates/deps-cargo/src/ecosystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ mod tests {
}

fn uri(&self) -> &Uri {
static URI: once_cell::sync::Lazy<Uri> =
once_cell::sync::Lazy::new(|| Uri::from_file_path("/test/Cargo.toml").unwrap());
static URI: std::sync::LazyLock<Uri> =
std::sync::LazyLock::new(|| Uri::from_file_path("/test/Cargo.toml").unwrap());
&URI
}

Expand Down Expand Up @@ -734,6 +734,6 @@ mod tests {
// Real packages with special characters
let results = ecosystem.complete_package_names("tokio-ut").await;
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.label.contains("-")));
assert!(results.iter().any(|r| r.label.contains('-')));
}
}
Loading