Skip to content

Commit dd879b1

Browse files
authored
feat: make it work (#2)
This PR takes the basic implementation of this app (which I made while I was still allowed to push to main) and iterates on it in tandem with the work in grafbase/grafbase#2090 (see that PR for context) I've also added some CI that'll build releases. Once this is merged I'll update the grafbase repo to use the binaries instead of building on every CI run.
1 parent 2a17577 commit dd879b1

File tree

7 files changed

+323
-90
lines changed

7 files changed

+323
-90
lines changed

.github/workflows/release.yaml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Create release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
create-release:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Create Release
15+
uses: taiki-e/create-gh-release-action@v1
16+
with:
17+
token: ${{ secrets.GITHUB_TOKEN }}
18+
19+
upload-artifacts:
20+
strategy:
21+
matrix:
22+
os:
23+
- ubuntu-latest
24+
- macos-latest
25+
- windows-latest
26+
27+
runs-on: ${{ matrix.os }}
28+
steps:
29+
- uses: actions/checkout@v4
30+
31+
- name: Upload binaries
32+
uses: taiki-e/upload-rust-binary-action@v1
33+
with:
34+
bin: what-rust-changed
35+
token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/rust.yml

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
COLUMNS: 250
11+
CARGO_INCREMENTAL: 0
12+
RUSTFLAGS: "-W rust-2021-compatibility -D warnings"
13+
RUST_BACKTRACE: short
14+
NEXTEST_PROFILE: ci
15+
CI: 1
16+
17+
jobs:
18+
build-rust:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- uses: dtolnay/[email protected]
25+
with:
26+
components: rustfmt
27+
28+
- uses: Swatinem/rust-cache@v2
29+
30+
- name: Check formatting
31+
shell: bash
32+
run: cargo fmt --check
33+
34+
- name: Build
35+
shell: bash
36+
run: cargo build

Cargo.lock

+56-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ determinator = "0.12"
88
guppy = "0.17"
99
itertools = "0.13"
1010
serde = "1"
11-
serde_json = "1"
11+
serde_json = "1"
12+
toml = "0.8"

src/config.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::fs::read_to_string;
2+
3+
pub fn load() -> Config {
4+
do_load().unwrap_or_default()
5+
}
6+
7+
fn do_load() -> Option<Config> {
8+
let path = std::env::var("WHAT_RUST_CHANGED_CONFIG").ok()?;
9+
10+
eprintln!("Loading config from {path}");
11+
12+
let data = read_to_string(path).expect("to be able to read named config file");
13+
14+
toml::from_str(&data).expect("invalid config format")
15+
}
16+
17+
#[derive(serde::Serialize, serde::Deserialize, Default)]
18+
#[serde(rename_all = "kebab-case")]
19+
pub struct Config {
20+
/// Packages that shouldn't automatically be included in test runs
21+
pub ignore_test_packages: Vec<String>,
22+
23+
/// Packages that require docker for their tests and should be put
24+
/// into a separate section of the output
25+
pub docker_test_packages: Vec<String>,
26+
27+
#[serde(flatten)]
28+
pub determinator_rules: determinator::rules::DeterminatorRules,
29+
}

src/guppy_ext.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use guppy::graph::{BuildTarget, BuildTargetKind};
2+
3+
pub trait PackageMetadataExt {
4+
fn has_test_targets(&self) -> bool;
5+
fn binary_targets(&self) -> Vec<BuildTarget<'_>>;
6+
}
7+
8+
impl PackageMetadataExt for guppy::graph::PackageMetadata<'_> {
9+
fn has_test_targets(&self) -> bool {
10+
let package_root_path = self
11+
.manifest_path()
12+
.parent()
13+
.expect("all packages to have manifests with one parent");
14+
15+
self.build_targets()
16+
.filter(|target| {
17+
matches!(
18+
target.kind(),
19+
BuildTargetKind::Binary | BuildTargetKind::LibraryOrExample(_)
20+
)
21+
})
22+
.any(|target| {
23+
let relative_path = target
24+
.path()
25+
.strip_prefix(package_root_path)
26+
.expect("targets to live inside package");
27+
28+
let Some(root_folder) = relative_path.components().next() else {
29+
return false;
30+
};
31+
32+
let root_folder = root_folder.as_str();
33+
34+
// Unfortunately doesn't seem to be any way to tell whether something rooted in
35+
// src actually has tests or not, so best to just assume they do
36+
root_folder == "tests" || root_folder == "src"
37+
})
38+
}
39+
40+
fn binary_targets(&self) -> Vec<BuildTarget<'_>> {
41+
let package_root_path = self
42+
.manifest_path()
43+
.parent()
44+
.expect("all packages to have manifests with one parent");
45+
46+
self.build_targets()
47+
.filter(|target| matches!(target.kind(), BuildTargetKind::Binary))
48+
.filter(|target| {
49+
let relative_path = target
50+
.path()
51+
.strip_prefix(package_root_path)
52+
.expect("targets to live inside package");
53+
54+
let Some(root_folder) = relative_path.components().next() else {
55+
return false;
56+
};
57+
58+
root_folder.as_str() == "src" && relative_path.file_name() == Some("main.rs")
59+
})
60+
.collect()
61+
}
62+
}

0 commit comments

Comments
 (0)