Skip to content

ci: align failure artifact retention with repo default (30 days) #14

ci: align failure artifact retention with repo default (30 days)

ci: align failure artifact retention with repo default (30 days) #14

Workflow file for this run

name: CI
on:
push:
branches: [ dev, feature/**, bugfix/**, chore/** ]
pull_request:
branches: [ dev ]
jobs:
build:
runs-on: macos-14
env:
SCHEME: Avro Keyboard # Default equals target name in this repo
TARGET: Avro Keyboard # Fallback target if no shared scheme
CONFIG: Debug
LOG_DIR: ci-logs # Directory for CI logs and summaries
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Xcode version
run: |
xcodebuild -version
sw_vers
- name: Prepare logs directory
run: |
rm -rf "$LOG_DIR" && mkdir -p "$LOG_DIR"
- name: Install xcpretty
run: |
gem install xcpretty --no-document
- name: Install CocoaPods
run: |
gem install cocoapods --no-document
- name: Install Subversion (for RegexKitLite)
run: |
brew update
brew install subversion
- name: Pod install
run: |
pod install --repo-update --silent || pod install
- name: Detect project or workspace
shell: bash
run: |
set -euo pipefail
ROOT=$(pwd -P)
WS="AvroKeyboard.xcworkspace"
PRJ="AvroKeyboard.xcodeproj"
if [[ -d "$WS" && -d "Pods" && -f "Pods/Pods.xcodeproj/project.pbxproj" ]]; then
echo "KIND=workspace" >> "$GITHUB_ENV"
echo "WORKSPACE=$ROOT/$WS" >> "$GITHUB_ENV"
elif [[ -d "$PRJ" ]]; then
echo "KIND=project" >> "$GITHUB_ENV"
echo "PROJECT=$ROOT/$PRJ" >> "$GITHUB_ENV"
else
echo "No Xcode workspace or project found"; ls -la; exit 1
fi
- name: Resolve scheme
shell: bash
run: |
set -euo pipefail
export LC_ALL=C
WANT_SCHEME="${SCHEME:-}"
list_cmd() {
if [[ "${KIND:-}" == "workspace" ]]; then
xcodebuild -list -workspace "${WORKSPACE}" 2>/dev/null
else
xcodebuild -list -project "${PROJECT}" 2>/dev/null
fi
}
LIST_TRIMMED=$(list_cmd \
| sed -n '/Schemes:/,$p' \
| tail -n +2 \
| sed 's/\r$//' \
| awk '{gsub(/^[ \t]+|[ \t]+$/,""); if (length) print}')
echo "Available schemes:"; printf '%s\n' "$LIST_TRIMMED"
SEL=""
WANT_SCHEME_TRIM=$(printf '%s' "$WANT_SCHEME" | awk '{gsub(/^[ \t]+|[ \t]+$/,""); print}')
if [[ -n "$WANT_SCHEME_TRIM" ]] && printf '%s\n' "$LIST_TRIMMED" | grep -Fxq "$WANT_SCHEME_TRIM"; then
SEL="$WANT_SCHEME_TRIM"
else
SEL=$(printf '%s\n' "$LIST_TRIMMED" | head -n1)
fi
if [[ -z "$SEL" ]]; then
echo "No shared schemes found"; exit 1
fi
echo "Resolved scheme: '$SEL'"
echo "SCHEME_RESOLVED=$SEL" >> "$GITHUB_ENV"
- name: Build
shell: bash
run: |
set -euo pipefail
if [[ "${KIND:-}" == "workspace" ]]; then
xcodebuild \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME_RESOLVED}" \
-configuration "$CONFIG" \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
build 2>&1 | tee "$LOG_DIR/build.log" | xcpretty
else
xcodebuild \
-project "${PROJECT}" \
-scheme "${SCHEME_RESOLVED}" \
-configuration "$CONFIG" \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
build 2>&1 | tee "$LOG_DIR/build.log" | xcpretty || {
echo "Scheme build failed; retrying with target '$TARGET'";
xcodebuild \
-project "${PROJECT}" \
-target "$TARGET" \
-configuration "$CONFIG" \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
build 2>&1 | tee -a "$LOG_DIR/build.log" | xcpretty;
}
fi
env:
NSUnbufferedIO: "YES"
continue-on-error: false
- name: Run unit tests (if any)
shell: bash
run: |
set -euo pipefail
HAS_TESTS=$( { grep -R --include='*.m' --include='*.swift' -n "XCTestCase" . || true; } | wc -l | tr -d '[:space:]')
if [[ "$HAS_TESTS" -gt "0" ]]; then
if [[ "${KIND:-}" == "workspace" ]]; then
# Only run tests with a scheme; if no shared scheme, skip.
if xcodebuild -list -workspace "${WORKSPACE}" | grep -q "Schemes:"; then
xcodebuild \
-workspace "${WORKSPACE}" \
-scheme "${SCHEME_RESOLVED}" \
-configuration "$CONFIG" \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
test 2>&1 | tee "$LOG_DIR/test.log" | xcpretty
else
echo "No shared scheme detected; skipping XCTest run."
fi
else
if xcodebuild -list -project "${PROJECT}" | grep -q "Schemes:"; then
xcodebuild \
-project "${PROJECT}" \
-scheme "${SCHEME_RESOLVED}" \
-configuration "$CONFIG" \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO \
test 2>&1 | tee "$LOG_DIR/test.log" | xcpretty
else
echo "No shared scheme detected; skipping XCTest run."
fi
fi
else
echo "No XCTest targets detected; skipping test step."
fi
- name: Summarize failure (Option B)
if: failure()
shell: bash
run: |
set -euo pipefail
SUMMARY="$LOG_DIR/ci_summary.txt"
{
echo "CI Failure Summary"
echo "Kind: ${KIND:-unknown}"
echo "Workspace: ${WORKSPACE:-n/a}"
echo "Project: ${PROJECT:-n/a}"
echo "Scheme: ${SCHEME_RESOLVED:-n/a}"
echo
if [[ -f "$LOG_DIR/build.log" ]]; then
echo "=== Build Errors (top hits) ==="
grep -nE "xcodebuild: error:|\\berror:|Undefined symbols|Command PhaseScriptExecution failed|exit code 65|ld: error" "$LOG_DIR/build.log" | head -n 100 || true
echo
echo "=== Build Log Tail (200 lines) ==="
tail -n 200 "$LOG_DIR/build.log" || true
echo
else
echo "No build.log captured."
fi
if [[ -f "$LOG_DIR/test.log" ]]; then
echo "=== Test Errors (top hits) ==="
grep -nE "\\berror:|failing|Assertion failed|Test Failed|Failures:" "$LOG_DIR/test.log" | head -n 100 || true
echo
echo "=== Test Log Tail (200 lines) ==="
tail -n 200 "$LOG_DIR/test.log" || true
echo
fi
} > "$SUMMARY"
echo "## CI Failure Summary" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo '\`\`\`' >> "$GITHUB_STEP_SUMMARY"
tail -n 200 "$SUMMARY" >> "$GITHUB_STEP_SUMMARY" || true
echo '\`\`\`' >> "$GITHUB_STEP_SUMMARY"
- name: Upload logs (Option A fallback)
if: failure()
uses: actions/upload-artifact@v4
with:
name: ci-logs
retention-days: 30
path: |
ci-logs/**
- name: Regression tests (optional; skip if file missing)
shell: bash
run: |
if [[ -f "Tests/Regression/phrases.tsv" && -x "Tools/run_regression.sh" ]]; then
Tools/run_regression.sh Tests/Regression/phrases.tsv
else
echo "Regression harness not present yet; skipping."
fi