|
| 1 | +# Case Study: Issue #135 — CI/CD Failures in Rust and C# Pipelines |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +- **Issue:** [#135](https://github.com/linksplatform/Numbers/issues/135) |
| 6 | +- **Failing Runs:** |
| 7 | + - Rust: [23398717024](https://github.com/linksplatform/Numbers/actions/runs/23398717024) |
| 8 | + - C#: [23398717023](https://github.com/linksplatform/Numbers/actions/runs/23398717023) |
| 9 | +- **Date:** 2026-03-22 |
| 10 | +- **Status:** Root causes identified and fixed. |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## Timeline / Sequence of Events |
| 15 | + |
| 16 | +1. Commit `bde6c03` was pushed to `main` (merge of PR #134). |
| 17 | +2. Both the Rust CI/CD Pipeline and the C# workflow were triggered. |
| 18 | +3. **Rust:** All jobs passed except **Auto Release** — the "Determine bump type from changelog fragments" step failed. |
| 19 | +4. **C#:** All jobs passed except **pushNuGetPackageToGitHubPackageRegistry** — the `nuget source Add` command failed. |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Root Cause Analysis |
| 24 | + |
| 25 | +### Rust CI Failure: Unused Import in get-bump-type.rs |
| 26 | + |
| 27 | +**Primary Root Cause:** |
| 28 | + |
| 29 | +In `scripts/get-bump-type.rs`, line 30 contained: |
| 30 | + |
| 31 | +```rust |
| 32 | +use std::process::exit; |
| 33 | +``` |
| 34 | + |
| 35 | +This import is **never used** anywhere in the file. All other scripts that import `exit` do call it; only `get-bump-type.rs` does not. |
| 36 | + |
| 37 | +**Why It Became a Fatal Error:** |
| 38 | + |
| 39 | +The CI workflow (`rust.yml`, line 48) sets: |
| 40 | + |
| 41 | +```yaml |
| 42 | +env: |
| 43 | + RUSTFLAGS: -Dwarnings |
| 44 | +``` |
| 45 | +
|
| 46 | +The `-Dwarnings` flag promotes all Rust compiler warnings to errors. The `unused-imports` lint (normally a warning) became a compile error, preventing `rust-script` from building and running the script. |
| 47 | + |
| 48 | +**Fix:** Remove the unused import from `scripts/get-bump-type.rs`. |
| 49 | + |
| 50 | +### C# CI Failure: Mono Not Found on Ubuntu 24.04 |
| 51 | + |
| 52 | +**Primary Root Cause:** |
| 53 | + |
| 54 | +The `pushNuGetPackageToGitHubPackageRegistry` job used `nuget/setup-nuget@v1` to install `nuget.exe`, then ran: |
| 55 | + |
| 56 | +```yaml |
| 57 | +nuget source Add -Name "GitHub" -Source "https://nuget.pkg.github.com/linksplatform/index.json" ... |
| 58 | +nuget push **/*.nupkg -Source "GitHub" -SkipDuplicate |
| 59 | +``` |
| 60 | + |
| 61 | +On Linux, `nuget.exe` is a .NET Framework executable that requires **Mono** to run. Ubuntu 24.04 GitHub-hosted runners **do not have Mono pre-installed**, resulting in: |
| 62 | + |
| 63 | +``` |
| 64 | +/opt/hostedtoolcache/nuget.exe/7.3.0/x64/nuget: 2: mono: not found |
| 65 | +##[error]Process completed with exit code 127. |
| 66 | +``` |
| 67 | + |
| 68 | +**How Long This Has Been Broken:** |
| 69 | + |
| 70 | +This same failure occurred in CI run [16390287640](https://github.com/linksplatform/Numbers/actions/runs/16390287640) on **2025-07-19**, confirming the issue has persisted for at least **8 months**. |
| 71 | + |
| 72 | +**Fix:** Replace `nuget.exe` CLI commands with `dotnet nuget` commands, which are part of the .NET SDK already installed on the runner: |
| 73 | + |
| 74 | +```yaml |
| 75 | +# Before (requires Mono): |
| 76 | +- uses: nuget/setup-nuget@v1 |
| 77 | +- run: | |
| 78 | + nuget source Add -Name "GitHub" -Source "..." -UserName ... -Password ... |
| 79 | + nuget push **/*.nupkg -Source "GitHub" -SkipDuplicate |
| 80 | +
|
| 81 | +# After (uses dotnet SDK directly): |
| 82 | +- run: | |
| 83 | + dotnet nuget add source "..." --name "GitHub" --username ... --password ... --store-password-in-clear-text |
| 84 | + dotnet nuget push ./**/*.nupkg --source "GitHub" --skip-duplicate |
| 85 | +``` |
| 86 | + |
| 87 | +### Additional Issues Fixed in C# Workflow |
| 88 | + |
| 89 | +| Issue | Before | After | Why | |
| 90 | +|-------|--------|-------|-----| |
| 91 | +| Outdated checkout action | `actions/checkout@v1` | `actions/checkout@v4` | v1 is 5+ years old, missing security fixes and features | |
| 92 | +| Outdated changed-files action | `tj-actions/changed-files@v21` | `tj-actions/changed-files@v46` | v21 is outdated, potential security/compatibility issues | |
| 93 | +| Deprecated set-output syntax | `::set-output name=...::` | `>> "$GITHUB_OUTPUT"` | set-output was deprecated in Oct 2022, will be removed | |
| 94 | +| Node.js 20 deprecation | `nuget/setup-nuget@v1` | Removed (not needed) | Node.js 20 actions deprecated, forced to Node.js 24 from June 2026 | |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +## Impact |
| 99 | + |
| 100 | +### Rust |
| 101 | +- Auto Release job blocked on every push to `main`. |
| 102 | +- Automated versioning and crate publishing could not proceed. |
| 103 | +- No production code or tests were affected — only the release automation script. |
| 104 | + |
| 105 | +### C# |
| 106 | +- GitHub Package Registry publishing has been broken since at least July 2025. |
| 107 | +- NuGet.org publishing (`pusnToNuget` job) was **not affected** — it uses `dotnet nuget push` and continued to work. |
| 108 | +- The failure did not block other C# CI jobs (test, release, NuGet.org publish all succeeded). |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## CI Log Evidence |
| 113 | + |
| 114 | +### Rust (run 23398717024) |
| 115 | + |
| 116 | +From `ci-logs/rust-23398717024.log`: |
| 117 | + |
| 118 | +``` |
| 119 | +error: unused import: `std::process::exit` |
| 120 | + --> /home/runner/work/Numbers/Numbers/scripts/get-bump-type.rs:30:5 |
| 121 | + | |
| 122 | +30 | use std::process::exit; |
| 123 | + | ^^^^^^^^^^^^^^^^^^ |
| 124 | + | |
| 125 | + = note: `-D unused-imports` implied by `-D warnings` |
| 126 | + |
| 127 | +error: could not compile `get-bump-type_412c20687aa3a320be6ee72f` due to 1 previous error |
| 128 | +error: Could not execute cargo |
| 129 | +``` |
| 130 | +
|
| 131 | +### C# (run 23398717023) |
| 132 | +
|
| 133 | +From `ci-logs/csharp-23398717023.log`: |
| 134 | + |
| 135 | +``` |
| 136 | +Successfully created package '/home/runner/work/Numbers/Numbers/csharp/Platform.Numbers/bin/Release/Platform.Numbers.0.9.0.nupkg'. |
| 137 | +Successfully created package '/home/runner/work/Numbers/Numbers/csharp/Platform.Numbers/bin/Release/Platform.Numbers.0.9.0.snupkg'. |
| 138 | +/opt/hostedtoolcache/nuget.exe/7.3.0/x64/nuget: 2: mono: not found |
| 139 | +##[error]Process completed with exit code 127. |
| 140 | +``` |
| 141 | +
|
| 142 | +--- |
| 143 | +
|
| 144 | +## Additional Notes |
| 145 | +
|
| 146 | +### Node.js 20 Deprecation Warnings |
| 147 | +
|
| 148 | +Both workflows contained annotations about Node.js 20 actions being deprecated. |
| 149 | +GitHub will force Node.js 24 by default starting **June 2nd, 2026**. |
| 150 | +The C# workflow fix addresses this by removing the `nuget/setup-nuget@v1` dependency |
| 151 | +and updating all actions to their latest versions. |
| 152 | +
|
| 153 | +### Possible Future Improvements |
| 154 | +
|
| 155 | +1. **Rust:** Consider adding a lint step that compiles all scripts to catch import issues earlier. |
| 156 | +2. **C#:** Consider adding a PR-triggered CI check (currently C# workflow only runs on push to main). |
| 157 | +3. **C#:** The `pusnToNuget` and `publiseRelease` job names contain typos — consider renaming for clarity in a future PR. |
0 commit comments