Skip to content

Commit 48108d2

Browse files
ndbroadbentclaude
andcommitted
feat: implement GitHub Actions job skipping system (Phase 4)
Implemented source-file-based job skipping with early exit pattern for GitHub Actions, since it doesn't support CircleCI's dynamic continuation. Key features: - SHA-256 hash calculation of source files - Early exit with 'exit 0' when job already completed for hash - Skip cache stored in /tmp/cigen_skip_cache - Architecture-aware skip markers - Support for @group references and inline patterns - Completion recording for successful runs Implementation: - Created src/providers/github_actions/job_skip.rs with JobSkipGenerator - Integrated skip steps into workflow generator - Three-step pattern: calculate hash → check skip → record completion - Full test coverage with 3 test cases How it works: 1. Calculate hash of source files and store in $GITHUB_ENV 2. Check if skip marker exists, exit 0 if found (saves ~5-30 sec) 3. Run job normally if not skipped 4. Record completion marker on success Difference from CircleCI: - CircleCI: Can completely skip job before container boots (saves minutes) - GitHub Actions: Job starts but exits early (saves seconds) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 98c1048 commit 48108d2

File tree

3 files changed

+380
-10
lines changed

3 files changed

+380
-10
lines changed

src/providers/github_actions/generator.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::cache::CacheGenerator;
2+
use super::job_skip::JobSkipGenerator;
23
use super::schema::{Job as GHJob, RunsOn, Step, Workflow};
34
use crate::models::{Command, Config, Job};
45
use miette::{IntoDiagnostic, Result};
@@ -8,12 +9,14 @@ use std::path::Path;
89

910
pub struct GitHubActionsGenerator {
1011
cache_generator: CacheGenerator,
12+
job_skip_generator: JobSkipGenerator,
1113
}
1214

1315
impl GitHubActionsGenerator {
1416
pub fn new() -> Self {
1517
Self {
1618
cache_generator: CacheGenerator::new(),
19+
job_skip_generator: JobSkipGenerator::new(),
1720
}
1821
}
1922

@@ -248,7 +251,6 @@ impl GitHubActionsGenerator {
248251
});
249252
}
250253

251-
// Add automatic cache restoration
252254
// Determine architecture - use first from architectures or default to amd64
253255
let architecture = job
254256
.architectures
@@ -257,16 +259,47 @@ impl GitHubActionsGenerator {
257259
.map(|s| s.as_str())
258260
.unwrap_or("amd64");
259261

260-
let cache_steps = self
261-
.cache_generator
262-
.generate_cache_steps(config, job, architecture)?;
263-
steps.extend(cache_steps);
262+
// Add job skip logic if source_files are defined
263+
let skip_steps = self
264+
.job_skip_generator
265+
.generate_skip_steps(config, job, architecture)?;
266+
267+
if let Some((hash_step, skip_check_step, completion_step)) = skip_steps {
268+
// Add hash calculation step
269+
steps.push(hash_step);
270+
271+
// Add skip check step
272+
steps.push(skip_check_step);
273+
274+
// Add automatic cache restoration
275+
let cache_steps =
276+
self.cache_generator
277+
.generate_cache_steps(config, job, architecture)?;
278+
steps.extend(cache_steps);
279+
280+
// Convert cigen steps to GitHub Actions steps
281+
if let Some(job_steps) = &job.steps {
282+
for cigen_step in job_steps {
283+
let step = self.build_step(cigen_step)?;
284+
steps.push(step);
285+
}
286+
}
264287

265-
// Convert cigen steps to GitHub Actions steps
266-
if let Some(job_steps) = &job.steps {
267-
for cigen_step in job_steps {
268-
let step = self.build_step(cigen_step)?;
269-
steps.push(step);
288+
// Add completion recording step at the end
289+
steps.push(completion_step);
290+
} else {
291+
// No skip logic - add cache and user steps normally
292+
let cache_steps =
293+
self.cache_generator
294+
.generate_cache_steps(config, job, architecture)?;
295+
steps.extend(cache_steps);
296+
297+
// Convert cigen steps to GitHub Actions steps
298+
if let Some(job_steps) = &job.steps {
299+
for cigen_step in job_steps {
300+
let step = self.build_step(cigen_step)?;
301+
steps.push(step);
302+
}
270303
}
271304
}
272305

0 commit comments

Comments
 (0)