Skip to content

Commit 913f2f2

Browse files
ndbroadbentclaude
andcommitted
fix: handle CircleCI run.command format in GitHub Actions generator
Enhanced step parser to convert CircleCI run steps to GitHub Actions native syntax 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 53ccb1b commit 913f2f2

File tree

5 files changed

+215
-91
lines changed

5 files changed

+215
-91
lines changed

.cigen/workflows/ci/jobs/clippy.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ image: rust:latest
22
source_files: "@rust"
33

44
steps:
5-
- name: Clippy check
6-
run: cargo clippy --all-targets --all-features -- -D warnings
5+
- run:
6+
name: Clippy check
7+
command: cargo clippy --all-targets --all-features -- -D warnings

.cigen/workflows/ci/jobs/fmt.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ image: rust:latest
22
source_files: "@rust"
33

44
steps:
5-
- name: Format check
6-
run: cargo fmt -- --check
5+
- run:
6+
name: Format check
7+
command: cargo fmt -- --check

.cigen/workflows/ci/jobs/test.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ source_files:
55
- "@examples"
66

77
steps:
8-
- name: Run tests
9-
run: cargo test --all-features
8+
- run:
9+
name: Run tests
10+
command: cargo test --all-features

.github/workflows/ci.yml

Lines changed: 175 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,182 @@
1-
name: CI
2-
1+
name: ci
32
on:
4-
push:
5-
branches: [main]
63
pull_request:
7-
branches: [main]
8-
9-
env:
10-
CARGO_TERM_COLOR: always
11-
4+
branches:
5+
- main
6+
push:
7+
branches:
8+
- main
129
jobs:
1310
test:
14-
name: Test
1511
runs-on: ubuntu-latest
16-
container:
17-
image: rust:1.88.0
1812
steps:
19-
- uses: actions/checkout@v4
20-
21-
- name: Install Node.js
22-
uses: actions/setup-node@v4
23-
with:
24-
node-version: "20"
25-
26-
- name: Install pnpm
27-
uses: pnpm/action-setup@v4
28-
with:
29-
version: 10
30-
31-
- name: Install rustfmt and clippy
32-
run: |
33-
rustup component add rustfmt clippy
34-
35-
- name: Get pnpm store directory
36-
id: pnpm-cache
37-
run: |
38-
echo "STORE_PATH=$(pnpm store path)" >> "$GITHUB_OUTPUT"
39-
40-
- name: Cache pnpm dependencies
41-
uses: actions/cache@v4
42-
with:
43-
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
44-
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
45-
restore-keys: |
46-
${{ runner.os }}-pnpm-
47-
48-
- name: Cache Nx
49-
uses: actions/cache@v4
50-
with:
51-
path: .nx
52-
key: ${{ runner.os }}-nx-${{ github.sha }}
53-
restore-keys: |
54-
${{ runner.os }}-nx-
55-
56-
- name: Cache cargo dependencies and build artifacts
57-
uses: actions/cache@v4
58-
with:
59-
path: |
60-
~/.cargo
61-
target/
62-
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
63-
restore-keys: |
64-
${{ runner.os }}-cargo-
65-
66-
- name: Install pnpm dependencies
67-
run: pnpm install --frozen-lockfile
68-
69-
- name: Add node_modules/.bin to PATH
70-
run: echo "$PWD/node_modules/.bin" >> "$GITHUB_PATH"
71-
72-
- name: Verify Nx installation
73-
run: nx --version
74-
75-
- name: Download cargo dependencies
76-
run: cargo fetch --locked
77-
78-
- name: Check formatting
79-
run: nx run cigen:format -- -- --check
80-
81-
- name: Run linting
82-
run: nx run cigen:lint
83-
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
- id: calculate_hash
16+
name: Calculate source file hash
17+
run: |-
18+
set -e
19+
echo 'Calculating source file hash...'
20+
TEMP_HASH_FILE="/tmp/source_files_for_hash"
21+
rm -f "$TEMP_HASH_FILE"
22+
23+
find . -path './src/**/*.rs' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
24+
find . -path './Cargo.toml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
25+
find . -path './Cargo.lock' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
26+
find . -path './tests/**/*.rs' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
27+
find . -path './tests/**/*.yml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
28+
find . -path './tests/**/*.trycmd' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
29+
find . -path './examples/**/*.yml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
30+
find . -path './examples/**/*.yaml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
31+
32+
if [ -s "$TEMP_HASH_FILE" ]; then
33+
# Calculate hash of file contents
34+
JOB_HASH=$(xargs -I{{}} sh -c 'cat "{{}}"' < "$TEMP_HASH_FILE" | sha256sum | cut -d' ' -f1)
35+
echo "Hash calculated: $JOB_HASH"
36+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
37+
else
38+
JOB_HASH="empty"
39+
echo "No source files found, using empty hash"
40+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
41+
fi
42+
shell: bash
43+
- id: check_skip
44+
name: Check if job should be skipped
45+
run: |-
46+
set -e
47+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
48+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
49+
50+
if [ -f "$SKIP_MARKER" ]; then
51+
echo "✓ Job already completed successfully for this file hash. Skipping..."
52+
exit 0
53+
else
54+
echo "→ No previous successful run found. Proceeding with job..."
55+
mkdir -p "$SKIP_CACHE_DIR"
56+
fi
57+
shell: bash
8458
- name: Run tests
85-
run: nx run cigen:test
86-
87-
- name: Build
88-
run: nx run cigen:build
89-
90-
- name: Run integration tests
91-
run: nx run cigen:integration
59+
run: cargo test --all-features
60+
- id: record_completion
61+
name: Record job completion
62+
run: |-
63+
set -e
64+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
65+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
66+
67+
echo "Recording successful completion for hash ${{JOB_HASH}}"
68+
mkdir -p "$SKIP_CACHE_DIR"
69+
echo "$(date): Job completed successfully" > "$SKIP_MARKER"
70+
shell: bash
71+
clippy:
72+
runs-on: ubuntu-latest
73+
steps:
74+
- name: Checkout code
75+
uses: actions/checkout@v4
76+
- id: calculate_hash
77+
name: Calculate source file hash
78+
run: |-
79+
set -e
80+
echo 'Calculating source file hash...'
81+
TEMP_HASH_FILE="/tmp/source_files_for_hash"
82+
rm -f "$TEMP_HASH_FILE"
83+
84+
find . -path './src/**/*.rs' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
85+
find . -path './Cargo.toml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
86+
find . -path './Cargo.lock' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
87+
88+
if [ -s "$TEMP_HASH_FILE" ]; then
89+
# Calculate hash of file contents
90+
JOB_HASH=$(xargs -I{{}} sh -c 'cat "{{}}"' < "$TEMP_HASH_FILE" | sha256sum | cut -d' ' -f1)
91+
echo "Hash calculated: $JOB_HASH"
92+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
93+
else
94+
JOB_HASH="empty"
95+
echo "No source files found, using empty hash"
96+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
97+
fi
98+
shell: bash
99+
- id: check_skip
100+
name: Check if job should be skipped
101+
run: |-
102+
set -e
103+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
104+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
105+
106+
if [ -f "$SKIP_MARKER" ]; then
107+
echo "✓ Job already completed successfully for this file hash. Skipping..."
108+
exit 0
109+
else
110+
echo "→ No previous successful run found. Proceeding with job..."
111+
mkdir -p "$SKIP_CACHE_DIR"
112+
fi
113+
shell: bash
114+
- name: Clippy check
115+
run: cargo clippy --all-targets --all-features -- -D warnings
116+
- id: record_completion
117+
name: Record job completion
118+
run: |-
119+
set -e
120+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
121+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
122+
123+
echo "Recording successful completion for hash ${{JOB_HASH}}"
124+
mkdir -p "$SKIP_CACHE_DIR"
125+
echo "$(date): Job completed successfully" > "$SKIP_MARKER"
126+
shell: bash
127+
fmt:
128+
runs-on: ubuntu-latest
129+
steps:
130+
- name: Checkout code
131+
uses: actions/checkout@v4
132+
- id: calculate_hash
133+
name: Calculate source file hash
134+
run: |-
135+
set -e
136+
echo 'Calculating source file hash...'
137+
TEMP_HASH_FILE="/tmp/source_files_for_hash"
138+
rm -f "$TEMP_HASH_FILE"
139+
140+
find . -path './src/**/*.rs' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
141+
find . -path './Cargo.toml' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
142+
find . -path './Cargo.lock' -type f 2>/dev/null | sort >> "$TEMP_HASH_FILE" || true
143+
144+
if [ -s "$TEMP_HASH_FILE" ]; then
145+
# Calculate hash of file contents
146+
JOB_HASH=$(xargs -I{{}} sh -c 'cat "{{}}"' < "$TEMP_HASH_FILE" | sha256sum | cut -d' ' -f1)
147+
echo "Hash calculated: $JOB_HASH"
148+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
149+
else
150+
JOB_HASH="empty"
151+
echo "No source files found, using empty hash"
152+
echo "JOB_HASH=$JOB_HASH" >> $GITHUB_ENV
153+
fi
154+
shell: bash
155+
- id: check_skip
156+
name: Check if job should be skipped
157+
run: |-
158+
set -e
159+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
160+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
161+
162+
if [ -f "$SKIP_MARKER" ]; then
163+
echo "✓ Job already completed successfully for this file hash. Skipping..."
164+
exit 0
165+
else
166+
echo "→ No previous successful run found. Proceeding with job..."
167+
mkdir -p "$SKIP_CACHE_DIR"
168+
fi
169+
shell: bash
170+
- name: Format check
171+
run: cargo fmt -- --check
172+
- id: record_completion
173+
name: Record job completion
174+
run: |-
175+
set -e
176+
SKIP_CACHE_DIR="/tmp/cigen_skip_cache"
177+
SKIP_MARKER="$SKIP_CACHE_DIR/job_${{JOB_HASH}}_amd64"
178+
179+
echo "Recording successful completion for hash ${{JOB_HASH}}"
180+
mkdir -p "$SKIP_CACHE_DIR"
181+
echo "$(date): Job completed successfully" > "$SKIP_MARKER"
182+
shell: bash

src/providers/github_actions/generator.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,37 @@ impl GitHubActionsGenerator {
313313

314314
// Try to extract common step fields from the YAML value
315315
if let Some(mapping) = step_value.as_mapping() {
316-
// Check if it's a run step
316+
// Check if it's a CircleCI run step with command
317+
if let Some(run_mapping) = mapping.get("run")
318+
&& let Some(run_map) = run_mapping.as_mapping()
319+
{
320+
let name = run_map
321+
.get("name")
322+
.and_then(|v| v.as_str())
323+
.map(|s| s.to_string());
324+
let command = run_map
325+
.get("command")
326+
.and_then(|v| v.as_str())
327+
.map(|s| s.to_string());
328+
329+
if let Some(cmd) = command {
330+
return Ok(Step {
331+
id: None,
332+
name,
333+
uses: None,
334+
run: Some(cmd),
335+
with: None,
336+
env: None,
337+
condition: None,
338+
working_directory: None,
339+
shell: None,
340+
continue_on_error: None,
341+
timeout_minutes: None,
342+
});
343+
}
344+
}
345+
346+
// Check if it's a native GitHub Actions run step
317347
if let Some(name_val) = mapping.get("name")
318348
&& let Some(run_val) = mapping.get("run")
319349
{

0 commit comments

Comments
 (0)