mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
feat(tui): highlight executed commands as bash; show inline duration
- Apply shell syntax highlighting to executed command lines in history cells - Append running duration dimmed inline on the first command line - Render full command via highlighter instead of plain text - Prune obsolete local docs and test artifact files Refs: fix/strip-osc8-in-markdown
This commit is contained in:
@@ -1 +0,0 @@
|
||||
ok
|
||||
@@ -1,154 +0,0 @@
|
||||
# Sccache Cache Hit Investigation Report
|
||||
|
||||
## Issue Summary
|
||||
The GitHub Actions workflow is showing 0% cache hits despite using `mozilla-actions/[email protected]` with proper configuration. The cache location shows `ghac` (GitHub Actions Cache) with a consistent hash: `8a6df4cb573bcfbf8c8e0bad63dc2287eedbfcc340fd86fbbdfa3b71d52e1c25`.
|
||||
|
||||
## Current Configuration Analysis
|
||||
|
||||
### Workflow Setup (release.yml)
|
||||
```yaml
|
||||
# Line 124-128: Setup sccache action
|
||||
- name: Setup sccache (GHA backend)
|
||||
uses: mozilla-actions/[email protected]
|
||||
with:
|
||||
version: v0.10.0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Line 131-148: Environment configuration
|
||||
- Sets SCCACHE_GHA_ENABLED=true
|
||||
- Sets SCCACHE_IDLE_TIMEOUT=1800
|
||||
- Sets RUSTC_WRAPPER=sccache
|
||||
- Configures OS-specific SCCACHE_DIR
|
||||
|
||||
# Line 151-155: Export GH cache credentials
|
||||
- Exports ACTIONS_CACHE_URL
|
||||
- Exports ACTIONS_RUNTIME_TOKEN
|
||||
|
||||
# Line 228-240: Build process
|
||||
- Restarts sccache server to avoid race conditions
|
||||
- Falls back to local cache if GHAC fails
|
||||
- Shows stats before and after build
|
||||
```
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### 1. **Hash Consistency Issue**
|
||||
The hash `8a6df4cb573bcfbf8c8e0bad63dc2287eedbfcc340fd86fbbdfa3b71d52e1c25` appears to be the same across all builds. This suggests it's NOT a compilation hash but rather a **cache namespace/version identifier**.
|
||||
|
||||
### 2. **Missing Cache Key Configuration**
|
||||
The workflow is missing critical cache key configuration:
|
||||
- **SCCACHE_GHA_CACHE_TO**: Not set (determines where to write cache)
|
||||
- **SCCACHE_GHA_CACHE_FROM**: Not set (determines where to read cache)
|
||||
- **SCCACHE_GHA_VERSION**: Not set (used for cache busting)
|
||||
|
||||
Without these, sccache might be:
|
||||
- Writing to a default location that changes per run
|
||||
- Unable to read from previous cache entries
|
||||
- Using a cache key that's too specific (includes run-specific data)
|
||||
|
||||
### 3. **GitHub Actions Cache Service Behavior**
|
||||
The GitHub Actions cache service is **immutable** - once a (key, version) pair is reserved, it cannot be overwritten. This means:
|
||||
- If the cache key is too specific (includes timestamps, run IDs), every build creates a new cache entry
|
||||
- Subsequent builds can't find matching cache entries
|
||||
|
||||
### 4. **Path Dependencies**
|
||||
Sccache requires **absolute paths to match** for cache hits. In GitHub Actions:
|
||||
- The workspace path includes the run number: `/home/runner/work/code/code`
|
||||
- If paths vary between runs, cache hits won't occur
|
||||
|
||||
### 5. **Incremental Compilation Interference**
|
||||
The workflow sets `CARGO_INCREMENTAL="0"` (line 215), which is correct. However, certain crate types cannot be cached:
|
||||
- bin crates (which is what's being built)
|
||||
- proc-macro crates
|
||||
- cdylib/dylib crates
|
||||
|
||||
## Recommended Solutions
|
||||
|
||||
### Solution 1: Configure Cache Keys Explicitly
|
||||
```yaml
|
||||
- name: Setup sccache (GHA backend)
|
||||
uses: mozilla-actions/[email protected]
|
||||
with:
|
||||
version: v0.10.0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure sccache cache keys
|
||||
shell: bash
|
||||
run: |
|
||||
# Use a stable cache key based on target and Rust version
|
||||
CACHE_KEY="sccache-${{ matrix.target }}-rust-1.89"
|
||||
echo "SCCACHE_GHA_CACHE_TO=${CACHE_KEY}" >> "$GITHUB_ENV"
|
||||
echo "SCCACHE_GHA_CACHE_FROM=${CACHE_KEY}" >> "$GITHUB_ENV"
|
||||
# Version for cache busting when needed
|
||||
echo "SCCACHE_GHA_VERSION=v1" >> "$GITHUB_ENV"
|
||||
```
|
||||
|
||||
### Solution 2: Use Stable Build Paths
|
||||
```yaml
|
||||
- name: Setup stable build path
|
||||
shell: bash
|
||||
run: |
|
||||
# Create a stable build directory
|
||||
sudo mkdir -p /opt/rust-build
|
||||
sudo chown -R $USER:$USER /opt/rust-build
|
||||
# Symlink or copy project there
|
||||
cp -r . /opt/rust-build/
|
||||
cd /opt/rust-build
|
||||
```
|
||||
|
||||
### Solution 3: Focus on Library Caching
|
||||
Since binary crates have limited caching potential, focus on caching dependencies:
|
||||
```yaml
|
||||
env:
|
||||
# Only cache dependencies, not workspace members
|
||||
SCCACHE_CACHE_MULTIARCH: "1"
|
||||
# Increase cache size for better hit rates
|
||||
SCCACHE_CACHE_SIZE: "10G"
|
||||
```
|
||||
|
||||
### Solution 4: Diagnostic Improvements
|
||||
Add better diagnostics to understand what's happening:
|
||||
```yaml
|
||||
- name: Detailed sccache diagnostics
|
||||
shell: bash
|
||||
run: |
|
||||
# Enable verbose logging
|
||||
export RUST_LOG=sccache=debug
|
||||
export SCCACHE_LOG=debug
|
||||
|
||||
# Show detailed stats
|
||||
sccache --show-stats --stats-format json > sccache-stats.json
|
||||
|
||||
# Check what's being hashed
|
||||
echo "Checking hash inputs..."
|
||||
env | grep -E "^(CARGO_|RUST|SCCACHE_)" | sort
|
||||
```
|
||||
|
||||
## The Consistent Hash Mystery
|
||||
|
||||
The hash `8a6df4cb573bcfbf8c8e0bad63dc2287eedbfcc340fd86fbbdfa3b71d52e1c25` is likely:
|
||||
1. **A namespace identifier** derived from the repository or workflow context
|
||||
2. **Not changing between builds** because it's based on stable inputs
|
||||
3. **Not the compilation hash** but rather the cache storage prefix
|
||||
|
||||
This suggests the cache backend IS working, but cache entries aren't being matched due to key mismatches.
|
||||
|
||||
## Immediate Action Items
|
||||
|
||||
1. **Add cache key configuration** (SCCACHE_GHA_CACHE_TO/FROM)
|
||||
2. **Enable debug logging** to see why cache misses occur
|
||||
3. **Consider using Swatinem/rust-cache** alongside sccache for dependency caching
|
||||
4. **Test with a simple library crate** to verify sccache works at all
|
||||
|
||||
## Alternative: Rely More on Swatinem/rust-cache
|
||||
|
||||
The workflow already uses `Swatinem/rust-cache` (line 111-117) which handles:
|
||||
- Cargo registry caching
|
||||
- Target directory caching
|
||||
- Proper cache key generation
|
||||
|
||||
Consider removing sccache temporarily and optimizing Swatinem/rust-cache configuration instead, as it's specifically designed for Rust and handles GitHub Actions caching properly.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The 0% cache hit rate is most likely due to missing `SCCACHE_GHA_CACHE_TO` and `SCCACHE_GHA_CACHE_FROM` configuration, causing sccache to use dynamic cache keys that never match between runs. The consistent hash in the output is a red herring - it's a namespace identifier, not the cache key being used for compilation artifacts.
|
||||
@@ -1139,7 +1139,10 @@ fn exec_render_parts_generic(
|
||||
) -> (Vec<Line<'static>>, Vec<Line<'static>>) {
|
||||
let mut pre: Vec<Line<'static>> = Vec::new();
|
||||
let command_escaped = strip_bash_lc_and_escape(command);
|
||||
let mut cmd_lines = command_escaped.lines();
|
||||
// Highlight the full command as a bash snippet; we will append
|
||||
// the running duration (when applicable) to the first visual line.
|
||||
let mut highlighted_cmd: Vec<Line<'static>> =
|
||||
crate::syntax_highlight::highlight_code_block(&command_escaped, Some("bash"));
|
||||
|
||||
let header_line = match output {
|
||||
None => {
|
||||
@@ -1170,30 +1173,18 @@ fn exec_render_parts_generic(
|
||||
),
|
||||
};
|
||||
|
||||
if let Some(first) = cmd_lines.next() {
|
||||
let duration_str = if output.is_none() && start_time.is_some() {
|
||||
pre.push(header_line.clone());
|
||||
if let Some(first) = highlighted_cmd.first_mut() {
|
||||
// Append duration (dim) to the first highlighted line when running
|
||||
if output.is_none() && start_time.is_some() {
|
||||
let elapsed = start_time.unwrap().elapsed();
|
||||
format!(" ({})", format_duration(elapsed))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
pre.push(header_line.clone());
|
||||
pre.push(Line::from(vec![
|
||||
Span::styled(
|
||||
first.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
),
|
||||
duration_str.dim(),
|
||||
]));
|
||||
} else {
|
||||
pre.push(header_line);
|
||||
}
|
||||
for cont in cmd_lines {
|
||||
pre.push(Line::styled(
|
||||
cont.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
let duration_str = format!(" ({})", format_duration(elapsed));
|
||||
first
|
||||
.spans
|
||||
.push(Span::styled(duration_str, Style::default().fg(crate::colors::text_dim())));
|
||||
}
|
||||
}
|
||||
pre.extend(highlighted_cmd);
|
||||
|
||||
// Output: always include for generic exec
|
||||
let out = output_lines(output, false, false);
|
||||
@@ -1503,10 +1494,20 @@ fn exec_render_parts_parsed(
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
spans.push(Span::styled(
|
||||
line_text.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
// Apply shell syntax highlighting to executed command lines.
|
||||
// We highlight the single logical line as bash and append its spans inline.
|
||||
let mut hl = crate::syntax_highlight::highlight_code_block(line_text, Some("bash"));
|
||||
if let Some(mut first) = hl.pop() {
|
||||
// `highlight_code_block` returns exactly one line for single-line input.
|
||||
// Append the highlighted spans inline after the prefix.
|
||||
spans.extend(first.spans.drain(..));
|
||||
} else {
|
||||
// Fallback: plain text if highlighting yields nothing.
|
||||
spans.push(Span::styled(
|
||||
line_text.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
pre.push(Line::from(spans));
|
||||
@@ -3736,12 +3737,16 @@ fn new_parsed_command(
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// For executed commands (Run/Test/Lint/etc.), show the command text
|
||||
// in normal text color rather than dimmed.
|
||||
spans.push(Span::styled(
|
||||
line_text.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
// For executed commands (Run/Test/Lint/etc.), use shell syntax highlighting.
|
||||
let mut hl = crate::syntax_highlight::highlight_code_block(line_text, Some("bash"));
|
||||
if let Some(mut first) = hl.pop() {
|
||||
spans.extend(first.spans.drain(..));
|
||||
} else {
|
||||
spans.push(Span::styled(
|
||||
line_text.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3765,7 +3770,9 @@ fn new_exec_command_generic(
|
||||
) -> Vec<Line<'static>> {
|
||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||
let command_escaped = strip_bash_lc_and_escape(command);
|
||||
let mut cmd_lines = command_escaped.lines();
|
||||
// Highlight the command as bash and then append a dimmed duration to the
|
||||
// first visual line while running.
|
||||
let mut highlighted_cmd = crate::syntax_highlight::highlight_code_block(&command_escaped, Some("bash"));
|
||||
|
||||
let header_line = match output {
|
||||
None => {
|
||||
@@ -3800,33 +3807,17 @@ fn new_exec_command_generic(
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(first) = cmd_lines.next() {
|
||||
let duration_str = if output.is_none() && start_time.is_some() {
|
||||
lines.push(header_line.clone());
|
||||
if let Some(first) = highlighted_cmd.first_mut() {
|
||||
if output.is_none() && start_time.is_some() {
|
||||
let elapsed = start_time.unwrap().elapsed();
|
||||
format!(" ({})", format_duration(elapsed))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
lines.push(header_line.clone());
|
||||
// Show the command itself in standard text color; keep the duration dimmed
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(
|
||||
first.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
),
|
||||
duration_str.dim(),
|
||||
]));
|
||||
} else {
|
||||
lines.push(header_line);
|
||||
}
|
||||
|
||||
for cont in cmd_lines {
|
||||
lines.push(Line::styled(
|
||||
cont.to_string(),
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
let duration_str = format!(" ({})", format_duration(elapsed));
|
||||
first
|
||||
.spans
|
||||
.push(Span::styled(duration_str, Style::default().fg(crate::colors::text_dim())));
|
||||
}
|
||||
}
|
||||
lines.extend(highlighted_cmd);
|
||||
|
||||
lines.extend(output_lines(output, false, true));
|
||||
lines
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# Fix for CARGO_PKG_VERSION Not Being Set During Releases
|
||||
|
||||
## Problem
|
||||
|
||||
The `CARGO_PKG_VERSION` environment variable was always showing "0.0.0" in release builds because:
|
||||
|
||||
1. The workspace `Cargo.toml` had `version = "0.0.0"` hardcoded
|
||||
2. All packages inherited this version with `version = { workspace = true }`
|
||||
3. The release process updated the version only in a tag/branch, not in the actual build environment
|
||||
|
||||
This caused issues with:
|
||||
- Version checks in the application
|
||||
- Update notifications showing incorrect versions
|
||||
- MCP server version reporting
|
||||
|
||||
## Solution
|
||||
|
||||
The fix involves updating the GitHub Actions workflow to dynamically set the version from the release tag during the build process.
|
||||
|
||||
### Changes Made
|
||||
|
||||
#### 1. Updated GitHub Actions Workflow (`.github/workflows/rust-release.yml`)
|
||||
|
||||
The workflow now:
|
||||
- Extracts the version from the tag name (e.g., `rust-v0.21.0` → `0.21.0`)
|
||||
- Updates the `version` field in `codex-rs/Cargo.toml` before building
|
||||
- Ensures all binaries are built with the correct version embedded
|
||||
|
||||
Key changes:
|
||||
- Modified `tag-check` job to output the version
|
||||
- Added "Update version in Cargo.toml" step in the `build` job
|
||||
- Version is updated using `sed` before compilation
|
||||
|
||||
#### 2. Simplified Release Script (`codex-rs/scripts/create_github_release.sh`)
|
||||
|
||||
The script now:
|
||||
- Only creates and pushes a tag (no branch or commit needed)
|
||||
- Validates the version format
|
||||
- Provides clear feedback about what will happen
|
||||
- The actual version update happens in GitHub Actions
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Developer runs release script:**
|
||||
```bash
|
||||
./codex-rs/scripts/create_github_release.sh 0.21.0
|
||||
```
|
||||
|
||||
2. **Script creates and pushes tag:**
|
||||
- Validates version format
|
||||
- Creates tag `rust-v0.21.0`
|
||||
- Pushes to GitHub
|
||||
|
||||
3. **GitHub Actions workflow triggers:**
|
||||
- Extracts version from tag (`0.21.0`)
|
||||
- Updates `Cargo.toml`: `version = "0.21.0"`
|
||||
- Builds all binaries with correct version
|
||||
- Creates GitHub release with artifacts
|
||||
|
||||
4. **Binary contains correct version:**
|
||||
- `env!("CARGO_PKG_VERSION")` returns `"0.21.0"`
|
||||
- Version checks work correctly
|
||||
- Update notifications show proper versions
|
||||
|
||||
### Testing
|
||||
|
||||
To test the version embedding locally:
|
||||
|
||||
```bash
|
||||
# Run the test script
|
||||
./test-version-embedding.sh
|
||||
```
|
||||
|
||||
This script simulates what the GitHub Actions workflow does and verifies that `CARGO_PKG_VERSION` gets set correctly.
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **No manual version updates needed** - Version is derived from the tag
|
||||
2. **Single source of truth** - The tag name determines the version
|
||||
3. **Consistent versioning** - All binaries in a release have the same version
|
||||
4. **Simpler release process** - No need to commit version changes
|
||||
|
||||
### Important Notes
|
||||
|
||||
- The workspace `Cargo.toml` remains at `version = "0.0.0"` in the main branch
|
||||
- The version is only updated during the release build process
|
||||
- Local development builds will show "0.0.0" (this is expected)
|
||||
- Release binaries will show the correct version from the tag
|
||||
|
||||
### Rollback
|
||||
|
||||
If you need to revert these changes:
|
||||
|
||||
1. Restore the original `create_github_release.sh` that updates and commits the version
|
||||
2. Modify the workflow to expect the version to already be in `Cargo.toml`
|
||||
3. Remove the "Update version in Cargo.toml" step from the workflow
|
||||
|
||||
### Future Improvements
|
||||
|
||||
Consider:
|
||||
- Using a version management tool like `cargo-release`
|
||||
- Implementing version bumping based on conventional commits
|
||||
- Adding version validation to prevent accidental downgrades
|
||||
Reference in New Issue
Block a user