Skip to content

Commit 860f47c

Browse files
fix(flake-info): fail group import when any member fails (#1238)
The 2-hourly flake import previously exited 0 even when individual group members failed to evaluate, leaving CI green and hiding the failure until a user reported it. `flake-info group` now still pushes the successfully evaluated members to Elasticsearch, but propagates a non-zero exit afterwards so the workflow fails. The `import-flakes` job in the 2-hourly workflow also gains the same `Create issue if failed` step that `import-nixpkgs` already has, so a tracking issue is opened on failure. Closes #1233
1 parent 1eb6dd4 commit 860f47c

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

.github/workflows/import-to-elasticsearch.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ jobs:
102102
group:
103103
- "manual"
104104

105+
permissions:
106+
issues: write
107+
105108
env:
106109
RUST_LOG: debug
107110
FI_ES_EXISTS_STRATEGY: recreate
@@ -131,3 +134,19 @@ jobs:
131134
do
132135
curl -sS ${{ secrets.ELASTICSEARCH_URL2 }}/latest-$(nix eval --raw --file ./version.nix import)-group-${{ matrix.group }}/_search | jq -c '.took // .'
133136
done
137+
138+
- name: Create issue if failed
139+
if: failure()
140+
env:
141+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
142+
GH_REPO: ${{ github.repository }}
143+
shell: sh
144+
run: |
145+
TITLE="Failing import for ${{ matrix.group }} group"
146+
147+
if [ "$(gh issue list --state open --search "in:title $TITLE" -L 1 --json id --jq length)" -eq 0 ]; then
148+
gh issue create \
149+
--title "$TITLE" \
150+
--label "prio:blocker" \
151+
--body "This issue was triggered by ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
152+
fi

flake-info/src/bin/flake-info.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,19 @@ async fn main() -> Result<()> {
194194
"at least one of --push or --json must be specified"
195195
);
196196

197-
let (exports, ident) = run_command(args.command, args.kind, &args.extra).await?;
197+
let (exports, ident, partial_error) = run_command(args.command, args.kind, &args.extra).await?;
198198

199199
if args.elastic.enable {
200200
push_to_elastic(&args.elastic, exports, ident).await?;
201201
} else if args.elastic.json {
202202
println!("{}", serde_json::to_string(&exports()?)?);
203203
}
204+
205+
// Surface partial failures (e.g. some group members failed to evaluate) as a
206+
// non-zero exit so CI does not report success while data is missing.
207+
if let Some(error) = partial_error {
208+
return Err(error.into());
209+
}
204210
Ok(())
205211
}
206212

@@ -223,7 +229,14 @@ async fn run_command(
223229
command: Command,
224230
kind: Kind,
225231
extra: &[String],
226-
) -> Result<(LazyExports, (String, String, String)), FlakeInfoError> {
232+
) -> Result<
233+
(
234+
LazyExports,
235+
(String, String, String),
236+
Option<FlakeInfoError>,
237+
),
238+
FlakeInfoError,
239+
> {
227240
flake_info::commands::check_nix_version(env!("MIN_NIX_VERSION"))?;
228241

229242
match command {
@@ -249,7 +262,7 @@ async fn run_command(
249262
info.revision.unwrap_or("latest".into()),
250263
);
251264

252-
Ok((Box::new(|| Ok(exports)), ident))
265+
Ok((Box::new(|| Ok(exports)), ident, None))
253266
}
254267
Command::Nixpkgs {
255268
channel,
@@ -284,6 +297,7 @@ async fn run_command(
284297
.map_err(FlakeInfoError::Nixpkgs)
285298
}),
286299
ident,
300+
None,
287301
))
288302
}
289303
Command::NixpkgsArchive {
@@ -316,6 +330,7 @@ async fn run_command(
316330
.map_err(FlakeInfoError::Nixpkgs)
317331
}),
318332
ident,
333+
None,
319334
))
320335
}
321336
Command::Group {
@@ -369,7 +384,7 @@ async fn run_command(
369384
.map(Result::unwrap_err) // each result is_err
370385
.collect::<Vec<_>>();
371386

372-
if !errors.is_empty() {
387+
let partial_error = if !errors.is_empty() {
373388
let error = FlakeInfoError::Group(name.clone(), errors);
374389
if exports.is_empty() {
375390
return Err(error);
@@ -383,7 +398,11 @@ async fn run_command(
383398
let mut file = File::create("report.txt").await?;
384399
file.write_all(format!("{}", error).as_bytes()).await?;
385400
}
386-
}
401+
402+
Some(error)
403+
} else {
404+
None
405+
};
387406

388407
let hash = {
389408
let mut sha = sha2::Sha256::new();
@@ -395,7 +414,7 @@ async fn run_command(
395414

396415
let ident = ("group".to_owned(), name, hash);
397416

398-
Ok((Box::new(|| Ok(exports)), ident))
417+
Ok((Box::new(|| Ok(exports)), ident, partial_error))
399418
}
400419
}
401420
}

0 commit comments

Comments
 (0)