Skip to content

chore(deps): bump iced from 0.13.1 to 0.14.0 #180

chore(deps): bump iced from 0.13.1 to 0.14.0

chore(deps): bump iced from 0.13.1 to 0.14.0 #180

Workflow file for this run

name: Master Pipeline
on:
push:
branches: [main]
tags: ['v*.*.*']
pull_request:
branches: [main]
workflow_dispatch:
inputs:
skip_tests:
description: 'Skip running tests'
type: boolean
default: false
skip_security:
description: 'Skip security audit'
type: boolean
default: false
skip_coverage:
description: 'Skip code coverage'
type: boolean
default: false
release_type:
description: 'Release type (only for manual runs)'
type: choice
options: [none, patch, minor, major]
default: none
rust_version:
description: 'Rust version to test'
type: choice
options: [stable, beta, nightly]
default: stable
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
SCCACHE_GHA_ENABLED: "true"
# RUSTC_WRAPPER set per-job after sccache installation
# Note: sccache may fail when GitHub cache service is unavailable
# The workflow includes fallback to direct compilation when this occurs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
# Phase 1: Quick validation (fail fast) and initial build
quick-checks:
name: Quick Checks & Build
runs-on: ubuntu-latest
outputs:
cache_key: ${{ steps.cache.outputs.cache_key }}
should_run_tests: ${{ steps.config.outputs.should_run_tests }}
should_run_security: ${{ steps.config.outputs.should_run_security }}
should_run_coverage: ${{ steps.config.outputs.should_run_coverage }}
should_run_release: ${{ steps.config.outputs.should_run_release }}
release_tag: ${{ steps.config.outputs.release_tag }}
steps:
- uses: actions/checkout@v6
# Setup cross-platform helper functions
- name: Load helper functions
shell: bash
run: |
cat >>"$GITHUB_ENV" <<'EOF'
BASH_ENV=$RUNNER_TEMP/ci_helpers.sh
EOF
cat >"$RUNNER_TEMP/ci_helpers.sh" <<'EOF'
run_with_timeout() {
local duration="$1"; shift
# Extract numeric value from duration (remove 's' suffix if present)
local numeric_duration="${duration%s}"
if [[ "${{ runner.os }}" == "macOS" ]]; then
# Use perl-based timeout for macOS (timeout command not available)
perl -e "alarm $numeric_duration; exec @ARGV" "$@"
else
# Use native timeout for Linux/Windows
timeout "$duration" "$@"
fi
}
export -f run_with_timeout
EOF
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
# Setup sccache with comprehensive resilience for GitHub cache service outages
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
id: sccache
with:
version: v0.10.0
- name: Configure sccache with GitHub cache service resilience
id: configure_sccache
shell: bash
env:
SCCACHE_LOG: error
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache.err.log
SCCACHE_NO_DAEMON: "1"
run: |
set -euo pipefail
sccache_available="false"
rustc_wrapper=""
if command -v sccache > /dev/null 2>&1; then
echo "sccache binary found, probing GitHub Actions cache backend..."
# Probe GHA backend health with comprehensive error handling
if sccache --start-server >/dev/null 2>>"$SCCACHE_ERROR_LOG"; then
echo "sccache GHA backend looks healthy"
# Additional verification with stats command
if run_with_timeout 10s sccache --show-stats > /dev/null 2>&1; then
sccache_available="true"
rustc_wrapper="sccache"
echo "sccache verified and will be used for compilation"
else
echo "sccache stats failed - backend may be degraded"
echo "Falling back to local disk cache mode"
# Configure local disk cache as fallback
echo "SCCACHE_GHA_ENABLED=false" >> $GITHUB_ENV
echo "SCCACHE_DIR=$HOME/.cache/sccache" >> $GITHUB_ENV
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
sccache_available="true"
rustc_wrapper="sccache"
fi
else
echo "sccache GHA backend not healthy; GitHub cache service may be experiencing issues"
echo "Falling back to local disk cache mode"
# Configure local disk cache as fallback
echo "SCCACHE_GHA_ENABLED=false" >> $GITHUB_ENV
echo "SCCACHE_DIR=$HOME/.cache/sccache" >> $GITHUB_ENV
echo "SCCACHE_CACHE_SIZE=10G" >> $GITHUB_ENV
sccache_available="true"
rustc_wrapper="sccache"
fi
# Print diagnostic information (but don't fail the job)
if [ -s "$SCCACHE_ERROR_LOG" ]; then
echo "---- sccache startup diagnostics ----"
cat "$SCCACHE_ERROR_LOG" || true
echo "------------------------------------"
fi
else
echo "sccache binary not found - using direct compilation"
fi
echo "sccache_available=$sccache_available" >> $GITHUB_OUTPUT
echo "rustc_wrapper=$rustc_wrapper" >> $GITHUB_OUTPUT
echo "Final sccache configuration: available=$sccache_available, wrapper='$rustc_wrapper'"
- name: Generate cache key
id: cache
run: |
cache_key="shared-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}-${{ github.run_id }}"
echo "cache_key=$cache_key" >> $GITHUB_OUTPUT
- uses: Swatinem/rust-cache@v2
with:
key: ${{ steps.cache.outputs.cache_key }}
shared-key: "master-pipeline"
save-if: true
- name: Format check
shell: bash
run: cargo fmt --all -- --check
env:
RUSTC_WRAPPER: ${{ steps.configure_sccache.outputs.rustc_wrapper }}
- name: Clippy check with enhanced resilience
shell: bash
run: |
# Enhanced clippy execution with timeout and robust error handling
if [ "${{ steps.configure_sccache.outputs.sccache_available }}" = "true" ]; then
echo "Running clippy with sccache (timeout: 10 minutes)..."
export RUSTC_WRAPPER="${{ steps.configure_sccache.outputs.rustc_wrapper }}"
if ! run_with_timeout 600s cargo clippy --all-targets --all-features -- -D warnings; then
echo "Clippy failed with sccache (timeout or error), retrying without sccache..."
unset RUSTC_WRAPPER
export RUSTC_WRAPPER=""
run_with_timeout 600s cargo clippy --all-targets --all-features -- -D warnings
fi
else
echo "Running clippy without sccache (timeout: 10 minutes)..."
export RUSTC_WRAPPER=""
run_with_timeout 600s cargo clippy --all-targets --all-features -- -D warnings
fi
env:
RUSTC_WRAPPER: ${{ steps.configure_sccache.outputs.rustc_wrapper }}
# Build once here to populate the cache for all subsequent jobs
- name: Build all targets with enhanced resilience
shell: bash
run: |
# Enhanced build execution with timeout and robust error handling
if [ "${{ steps.configure_sccache.outputs.sccache_available }}" = "true" ]; then
echo "Building with sccache (timeout: 15 minutes)..."
export RUSTC_WRAPPER="${{ steps.configure_sccache.outputs.rustc_wrapper }}"
if ! run_with_timeout 900s cargo build --all-features --all-targets --release; then
echo "Build failed with sccache (timeout or error), retrying without sccache..."
unset RUSTC_WRAPPER
export RUSTC_WRAPPER=""
echo "Retrying build without sccache (timeout: 15 minutes)..."
run_with_timeout 900s cargo build --all-features --all-targets --release
fi
else
echo "Building without sccache (timeout: 15 minutes)..."
export RUSTC_WRAPPER=""
run_with_timeout 900s cargo build --all-features --all-targets --release
fi
env:
RUSTC_WRAPPER: ${{ steps.configure_sccache.outputs.rustc_wrapper }}
# Upload build artifacts for other jobs to use
- name: Upload build artifacts
uses: actions/upload-artifact@v6
with:
name: build-artifacts-${{ runner.os }}
path: |
target/release/
target/debug/
retention-days: 1
compression-level: 0 # Fast upload, artifacts deleted after 1 day
- name: Configure pipeline
id: config
run: |
# Determine what should run based on trigger and inputs
should_run_tests="true"
should_run_security="true"
should_run_coverage="false"
should_run_release="false"
release_tag=""
# Manual workflow dispatch overrides
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
should_run_tests="${{ !inputs.skip_tests }}"
should_run_security="${{ !inputs.skip_security }}"
should_run_coverage="${{ !inputs.skip_coverage }}"
if [ "${{ inputs.release_type }}" != "none" ]; then
should_run_release="true"
# Generate release tag based on type
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
case "${{ inputs.release_type }}" in
patch)
new_tag=$(echo $latest_tag | awk -F. '{$NF = $NF + 1; print}' OFS=.)
;;
minor)
new_tag=$(echo $latest_tag | \
awk -F. '{$(NF-1) = $(NF-1) + 1; $NF = 0; print}' OFS=.)
;;
major)
new_tag=$(echo $latest_tag | \
awk -F. '{$1 = substr($1, 2) + 1; $2 = 0; $3 = 0; print "v" $0}' OFS=.)
;;
esac
release_tag="$new_tag"
fi
fi
# Tag push triggers release
if [[ "${{ github.ref }}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
should_run_release="true"
should_run_coverage="true" # Full coverage on releases
release_tag="${{ github.ref_name }}"
fi
# PR: skip coverage by default to speed up
if [ "${{ github.event_name }}" = "pull_request" ]; then
should_run_coverage="false"
fi
# Main branch: run coverage
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
should_run_coverage="true"
fi
echo "should_run_tests=$should_run_tests" >> $GITHUB_OUTPUT
echo "should_run_security=$should_run_security" >> $GITHUB_OUTPUT
echo "should_run_coverage=$should_run_coverage" >> $GITHUB_OUTPUT
echo "should_run_release=$should_run_release" >> $GITHUB_OUTPUT
echo "release_tag=$release_tag" >> $GITHUB_OUTPUT
echo "Pipeline Configuration:"
echo " Tests: $should_run_tests"
echo " Security: $should_run_security"
echo " Coverage: $should_run_coverage"
echo " Release: $should_run_release"
echo " Release Tag: $release_tag"
# Phase 2: Parallel execution of tests, security, and documentation
test-matrix:
name: Test Matrix
needs: quick-checks
if: needs.quick-checks.outputs.should_run_tests == 'true'
permissions:
contents: read
id-token: write # Required for codecov OIDC
issues: write # Required for security audit
security-events: write # Required for security audit
uses: ./.github/workflows/ci.yml
with:
rust_version: ${{ inputs.rust_version || 'stable' }}
skip_tests: false
cache_key: ${{ needs.quick-checks.outputs.cache_key }}
secrets: inherit
documentation:
name: Documentation
# Run in parallel - doesn't need quick-checks to complete
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: rust-docs
- uses: Swatinem/rust-cache@v2
with:
shared-key: "master-pipeline"
cache-targets: false # Don't cache build artifacts, just dependencies
- name: Build documentation
run: cargo doc --all-features --no-deps --document-private-items
env:
RUSTDOCFLAGS: "--warn missing-docs"
RUSTC_WRAPPER: "" # Disable sccache for documentation builds
# Note: Doctests are run in the test-matrix job to avoid duplication
# They run on all platforms as part of the comprehensive test suite
- name: Generate documentation index
run: |
cat > target/doc/index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>RustIRC Documentation</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 40px; }
h1 { color: #333; border-bottom: 2px solid #ddd; padding-bottom: 10px; }
.crate { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
.crate h2 { margin-top: 0; color: #0969da; }
a { color: #0969da; text-decoration: none; }
a:hover { text-decoration: underline; }
.description { color: #656d76; font-style: italic; margin-top: 5px; }
</style>
</head>
<body>
<h1>RustIRC Documentation</h1>
<p>Modern IRC client written in Rust</p>
<div class="crate">
<h2><a href="rustirc_core/index.html">rustirc-core</a></h2>
<div class="description">Core functionality and shared components</div>
</div>
<div class="crate">
<h2><a href="rustirc_protocol/index.html">rustirc-protocol</a></h2>
<div class="description">IRC protocol implementation with parsing and validation</div>
</div>
<div class="crate">
<h2><a href="rustirc_gui/index.html">rustirc-gui</a></h2>
<div class="description">Modern graphical user interface using Iced</div>
</div>
<div class="crate">
<h2><a href="rustirc_tui/index.html">rustirc-tui</a></h2>
<div class="description">Terminal-based user interface using ratatui</div>
</div>
<div class="crate">
<h2><a href="rustirc_scripting/index.html">rustirc-scripting</a></h2>
<div class="description">Lua and Python scripting engine</div>
</div>
<div class="crate">
<h2><a href="rustirc_plugins/index.html">rustirc-plugins</a></h2>
<div class="description">Plugin system for extensions</div>
</div>
</body>
</html>
EOF
- name: Upload documentation artifacts
uses: actions/upload-artifact@v6
with:
name: documentation
path: target/doc/
retention-days: 30
security-audit:
name: Security Audit
# Run in parallel - can check dependencies without waiting for build
if: github.event.inputs.skip_security != 'true'
permissions:
contents: read
issues: write
pull-requests: write
security-events: write
actions: read
uses: ./.github/workflows/security-audit.yml
with:
ignore_advisories: 'RUSTSEC-2024-0384,RUSTSEC-2024-0436'
create_issues: ${{ github.event_name != 'pull_request' }}
secrets: inherit
# Phase 3: Code coverage (only after tests pass)
coverage:
name: Code Coverage
needs: [quick-checks, test-matrix]
if: |
always() &&
needs.quick-checks.outputs.should_run_coverage == 'true' &&
needs.test-matrix.result == 'success'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
key: ${{ needs.quick-checks.outputs.cache_key }}
shared-key: "master-pipeline"
- name: Cache cargo tools
uses: actions/cache@v5
with:
path: |
~/.cargo/bin/cargo-tarpaulin
~/.cargo/.crates.toml
~/.cargo/.crates2.json
key: cargo-tools-${{ runner.os }}-tarpaulin
restore-keys: |
cargo-tools-${{ runner.os }}-
- name: Install tarpaulin
run: |
if ! command -v cargo-tarpaulin &> /dev/null; then
cargo install cargo-tarpaulin --locked
else
echo "cargo-tarpaulin already installed"
fi
- name: Generate coverage report
run: cargo tarpaulin --out Xml --all-features --timeout 300 --skip-clean
env:
RUSTC_WRAPPER: "" # Disable sccache for coverage to avoid conflicts
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./cobertura.xml
use_oidc: true
fail_ci_if_error: true
verbose: true
# Phase 4: Build artifacts for release (parallel with coverage)
build-artifacts:
name: Build Release Artifacts
needs: [quick-checks, test-matrix, security-audit]
if: |
always() &&
needs.quick-checks.outputs.should_run_release == 'true' &&
needs.test-matrix.result == 'success' &&
(needs.security-audit.result == 'success' || needs.security-audit.result == 'skipped')
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: rustirc-linux-amd64.tar.gz
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact_name: rustirc-linux-arm64.tar.gz
cross: true
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: rustirc-windows-amd64.exe.zip
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: rustirc-macos-amd64.tar.gz
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: rustirc-macos-arm64.tar.gz
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
# Install cross for cross-compilation
- name: Install cross
if: matrix.cross == true
run: |
# Install a stable version of cross to avoid GLIBC compatibility issues
cargo install cross --version 0.2.5 --locked
# Use shared cache from test phase when possible
- uses: Swatinem/rust-cache@v2
with:
key: ${{ needs.quick-checks.outputs.cache_key }}
shared-key: "master-pipeline"
# Save the cache only if we're building something new
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build release binary
shell: bash
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
# Use cross with proper configuration for ARM64 builds
cross build --release --target ${{ matrix.target }} --bin rustirc
else
cargo build --release --target ${{ matrix.target }} --bin rustirc
fi
env:
RUSTC_WRAPPER: "" # Disable sccache for cross-platform builds
CROSS_CONTAINER_OPTS: "--platform linux/amd64" # Ensure consistent platform for cross
- name: Package artifact (Unix)
if: "!contains(matrix.os, 'windows')"
run: |
cd target/${{ matrix.target }}/release
tar -czf ../../../${{ matrix.artifact_name }} rustirc
- name: Package artifact (Windows)
if: contains(matrix.os, 'windows')
run: |
cd target/${{ matrix.target }}/release
7z a ../../../${{ matrix.artifact_name }} rustirc.exe
shell: pwsh
- name: Upload build artifact
uses: actions/upload-artifact@v6
with:
name: ${{ matrix.artifact_name }}
path: ${{ matrix.artifact_name }}
retention-days: 30
# Phase 5: Release (only after all checks pass)
release:
name: Create Release
needs: [quick-checks, test-matrix, security-audit, build-artifacts]
if: |
always() &&
needs.quick-checks.outputs.should_run_release == 'true' &&
needs.test-matrix.result == 'success' &&
(needs.security-audit.result == 'success' ||
needs.security-audit.result == 'skipped') &&
needs.build-artifacts.result == 'success'
runs-on: ubuntu-latest
permissions:
contents: write
discussions: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v7
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release-assets
# Find only files (not directories) with proper parentheses for OR condition
find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" \) | while read file; do
echo "Processing: $file"
cp "$file" release-assets/
# Generate checksums
cd release-assets
filename="$(basename "$file")"
if command -v shasum >/dev/null; then
shasum -a 256 "$filename" > "$filename.sha256"
else
sha256sum "$filename" > "$filename.sha256"
fi
cd ..
done
echo "Release assets prepared:"
ls -la release-assets/
- name: Create or update release
run: |
tag_name="${{ needs.quick-checks.outputs.release_tag }}"
# Create build information section
cat > build_info.md << EOF
---
**Build Information:**
- Pipeline Run: [${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
- Commit: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
- Build Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
EOF
# Check if release already exists
if gh release view "$tag_name" >/dev/null 2>&1; then
echo "Release $tag_name already exists. Checking if we need to append build info..."
# Get existing release notes
existing_notes=$(gh release view "$tag_name" --json body -q '.body')
# Check if build info already exists in notes
if ! echo "$existing_notes" | grep -q "Build Information:"; then
echo "Appending build information to existing release notes..."
# Append build info to existing notes
echo "$existing_notes" > existing_notes.md
cat build_info.md >> existing_notes.md
# Update release with appended notes
gh release edit "$tag_name" --notes-file existing_notes.md
else
echo "Build information already exists in release notes."
fi
# Upload artifacts to existing release (will replace if they exist)
for file in release-assets/*; do
if [[ -f "$file" ]]; then
echo "Uploading $file to existing release..."
gh release upload "$tag_name" "$file" --clobber
fi
done
else
echo "Creating new release $tag_name..."
# Create minimal release notes for new release (preserves any manual notes that might be added later)
cat > release_notes.md << EOF
## Release $tag_name
### What's Changed
This release includes the latest improvements and bug fixes.
### Downloads
- **Linux x86_64**: \`rustirc-linux-amd64.tar.gz\`
- **Linux ARM64**: \`rustirc-linux-arm64.tar.gz\`
- **Windows x86_64**: \`rustirc-windows-amd64.exe.zip\`
- **macOS x86_64**: \`rustirc-macos-amd64.tar.gz\`
- **macOS ARM64 (M1/M2/M3)**: \`rustirc-macos-arm64.tar.gz\`
### Verification
All binaries include SHA256 checksums for verification.
### Installation
1. Download the appropriate binary for your platform
2. Extract the archive
3. Run the client: \`./rustirc\` (Unix) or \`rustirc.exe\` (Windows)
For detailed usage instructions, see the [README](https://github.com/doublegate/RustIRC#readme).
EOF
# Append build info to new release notes
cat build_info.md >> release_notes.md
# Create the new release
gh release create "$tag_name" \
--title "RustIRC $tag_name" \
--notes-file release_notes.md \
release-assets/*
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Status reporting job
pipeline-status:
name: Pipeline Status
if: always()
needs:
- quick-checks
- test-matrix
- security-audit
- documentation
- coverage
- build-artifacts
- release
runs-on: ubuntu-latest
steps:
- name: Report pipeline status
run: |
echo "## Master Pipeline Results"
echo ""
echo "| Phase | Status | Duration |"
echo "|-------|--------|----------|"
echo "| Quick Checks | ${{ needs.quick-checks.result }} | - |"
echo "| Tests | ${{ needs.test-matrix.result || 'skipped' }} | - |"
echo "| Security | ${{ needs.security-audit.result || 'skipped' }} | - |"
echo "| Documentation | ${{ needs.documentation.result || 'skipped' }} | - |"
echo "| Coverage | ${{ needs.coverage.result || 'skipped' }} | - |"
echo "| Build Artifacts | ${{ needs.build-artifacts.result || 'skipped' }} | - |"
echo "| Release | ${{ needs.release.result || 'skipped' }} | - |"
echo ""
# Calculate overall status
overall_status="success"
if [[ "${{ needs.quick-checks.result }}" == "failure" ]]; then
overall_status="failure"
elif [[ "${{ needs.test-matrix.result }}" == "failure" ]]; then
overall_status="failure"
elif [[ "${{ needs.security-audit.result }}" == "failure" ]]; then
overall_status="failure"
fi
echo "Overall pipeline status: $overall_status"
if [ "$overall_status" = "failure" ]; then
exit 1
fi