chore: add CI for github and woodpecker
Some checks failed
CI / Lint (bash) (push) Has been cancelled
CI / Lint (markdown) (push) Has been cancelled
CI / Lint (nickel) (push) Has been cancelled
CI / Lint (nushell) (push) Has been cancelled
CI / Lint (rust) (push) Has been cancelled
CI / Code Coverage (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (macos-latest) (push) Has been cancelled
CI / Build (ubuntu-latest) (push) Has been cancelled
CI / Build (windows-latest) (push) Has been cancelled
CI / Benchmark (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / License Compliance (push) Has been cancelled
Some checks failed
CI / Lint (bash) (push) Has been cancelled
CI / Lint (markdown) (push) Has been cancelled
CI / Lint (nickel) (push) Has been cancelled
CI / Lint (nushell) (push) Has been cancelled
CI / Lint (rust) (push) Has been cancelled
CI / Code Coverage (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (macos-latest) (push) Has been cancelled
CI / Build (ubuntu-latest) (push) Has been cancelled
CI / Build (windows-latest) (push) Has been cancelled
CI / Benchmark (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / License Compliance (push) Has been cancelled
This commit is contained in:
parent
d7be896713
commit
d5a03183e9
42
.github/renovate.json
vendored
Normal file
42
.github/renovate.json
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["cargo"],
|
||||
"groupName": "Rust dependencies",
|
||||
"schedule": ["before 3am on Monday"]
|
||||
},
|
||||
{
|
||||
"matchManagers": ["npm"],
|
||||
"groupName": "npm dependencies",
|
||||
"schedule": ["before 3am on Monday"]
|
||||
},
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"groupName": "all non-major dependencies",
|
||||
"groupSlug": "all-minor-patch",
|
||||
"automerge": true
|
||||
},
|
||||
{
|
||||
"matchDepTypes": ["devDependencies"],
|
||||
"automerge": true
|
||||
}
|
||||
],
|
||||
"rust": {
|
||||
"enabled": true
|
||||
},
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true,
|
||||
"schedule": ["before 3am on the first day of the month"]
|
||||
},
|
||||
"vulnerabilityAlerts": {
|
||||
"enabled": true,
|
||||
"labels": ["security"]
|
||||
},
|
||||
"labels": ["dependencies"],
|
||||
"prConcurrentLimit": 3,
|
||||
"prHourlyLimit": 2
|
||||
}
|
||||
133
.github/workflows/ci.yml
vendored
Normal file
133
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint (${{ matrix.linter }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
linter: [rust, bash, nickel, nushell, markdown]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@v1
|
||||
|
||||
- name: Install Rust toolchain
|
||||
if: matrix.linter == 'rust'
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: Install shellcheck
|
||||
if: matrix.linter == 'bash'
|
||||
run: sudo apt-get install -y shellcheck
|
||||
|
||||
- name: Install Nickel
|
||||
if: matrix.linter == 'nickel'
|
||||
run: |
|
||||
cargo install nickel-lang-cli
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Nushell
|
||||
if: matrix.linter == 'nushell'
|
||||
run: |
|
||||
cargo install nu
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install markdownlint
|
||||
if: matrix.linter == 'markdown'
|
||||
run: npm install -g markdownlint-cli2
|
||||
|
||||
- name: Run linter
|
||||
run: just dev::lint-${{ matrix.linter }}
|
||||
|
||||
coverage:
|
||||
name: Code Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: llvm-tools-preview
|
||||
- uses: extractions/setup-just@v1
|
||||
- name: Install cargo-llvm-cov
|
||||
uses: taiki-e/install-action@cargo-llvm-cov
|
||||
- name: Generate coverage
|
||||
run: just dev::coverage-ci
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: lcov.info
|
||||
fail_ci_if_error: true
|
||||
|
||||
test:
|
||||
name: Test (${{ matrix.os }})
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: lint
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: extractions/setup-just@v1
|
||||
- name: Run tests
|
||||
run: just ci::test-all
|
||||
|
||||
build:
|
||||
name: Build (${{ matrix.os }})
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: test
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: extractions/setup-just@v1
|
||||
- name: Build release
|
||||
run: just ci::build-release
|
||||
|
||||
benchmark:
|
||||
name: Benchmark
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: extractions/setup-just@v1
|
||||
- name: Run benchmarks
|
||||
run: just dev::bench
|
||||
|
||||
security:
|
||||
name: Security Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- name: Install cargo-audit
|
||||
run: cargo install cargo-audit --locked
|
||||
- name: Run security audit
|
||||
run: cargo audit
|
||||
|
||||
compliance:
|
||||
name: License Compliance
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- name: Install cargo-deny
|
||||
run: cargo install cargo-deny --locked
|
||||
- name: Check licenses
|
||||
run: cargo deny check licenses
|
||||
263
.github/workflows/release.yml
vendored
Normal file
263
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CARGO_INCREMENTAL: 0
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
name: Create GitHub Release
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.extract_version.outputs.version }}
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
steps:
|
||||
- name: Extract version from tag
|
||||
id: extract_version
|
||||
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ steps.extract_version.outputs.version }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
build-release:
|
||||
name: Build ${{ matrix.target }}
|
||||
needs: create-release
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
use_cross: false
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
use_cross: true
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
use_cross: false
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
use_cross: false
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
use_cross: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Install cross
|
||||
if: matrix.use_cross
|
||||
run: cargo install cross --git https://github.com/cross-rs/cross
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: ${{ matrix.target }}
|
||||
|
||||
- name: Build release
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.use_cross }}" = "true" ]; then
|
||||
cross build --release --target ${{ matrix.target }} --locked
|
||||
else
|
||||
cargo build --release --target ${{ matrix.target }} --locked
|
||||
fi
|
||||
|
||||
- name: Create distribution directory
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION="${{ needs.create-release.outputs.version }}"
|
||||
TARGET="${{ matrix.target }}"
|
||||
DIST_DIR="typedialog-${VERSION}-${TARGET}"
|
||||
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
# Copy binary
|
||||
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||
cp target/${TARGET}/release/typedialog.exe "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-tui.exe "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-web.exe "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-ag.exe "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-ag-server.exe "$DIST_DIR/"
|
||||
else
|
||||
cp target/${TARGET}/release/typedialog "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-tui "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-web "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-ag "$DIST_DIR/"
|
||||
cp target/${TARGET}/release/typedialog-ag-server "$DIST_DIR/"
|
||||
fi
|
||||
|
||||
# Copy README and LICENSE
|
||||
cp README.md "$DIST_DIR/" 2>/dev/null || true
|
||||
cp LICENSE "$DIST_DIR/" 2>/dev/null || true
|
||||
|
||||
echo "DIST_DIR=$DIST_DIR" >> $GITHUB_ENV
|
||||
|
||||
- name: Create tarball
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||
7z a -tzip "${DIST_DIR}.zip" "${DIST_DIR}"
|
||||
echo "ASSET=${DIST_DIR}.zip" >> $GITHUB_ENV
|
||||
else
|
||||
tar czf "${DIST_DIR}.tar.gz" "${DIST_DIR}"
|
||||
echo "ASSET=${DIST_DIR}.tar.gz" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Generate SHA256 checksum
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||
certutil -hashfile "${ASSET}" SHA256 > "${ASSET}.sha256"
|
||||
else
|
||||
shasum -a 256 "${ASSET}" > "${ASSET}.sha256"
|
||||
fi
|
||||
|
||||
- name: Upload release asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: ${{ env.ASSET }}
|
||||
asset_name: ${{ env.ASSET }}
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: Upload checksum
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: ${{ env.ASSET }}.sha256
|
||||
asset_name: ${{ env.ASSET }}.sha256
|
||||
asset_content_type: text/plain
|
||||
|
||||
generate-sbom:
|
||||
name: Generate SBOM
|
||||
needs: create-release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install cargo-sbom
|
||||
run: cargo install cargo-sbom --locked
|
||||
|
||||
- name: Generate SPDX SBOM
|
||||
run: cargo sbom --output-format spdx_json_2_3 > sbom-spdx.json
|
||||
|
||||
- name: Generate CycloneDX SBOM
|
||||
run: cargo sbom --output-format cyclone_dx_json_1_4 > sbom-cyclonedx.json
|
||||
|
||||
- name: Upload SPDX SBOM
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: sbom-spdx.json
|
||||
asset_name: sbom-spdx.json
|
||||
asset_content_type: application/json
|
||||
|
||||
- name: Upload CycloneDX SBOM
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||
asset_path: sbom-cyclonedx.json
|
||||
asset_name: sbom-cyclonedx.json
|
||||
asset_content_type: application/json
|
||||
|
||||
publish-crates:
|
||||
name: Publish to crates.io
|
||||
needs: [create-release, build-release, generate-sbom]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Verify version matches tag
|
||||
run: |
|
||||
TAG_VERSION="${{ needs.create-release.outputs.version }}"
|
||||
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "typedialog-core") | .version')
|
||||
|
||||
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
|
||||
echo "Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Publish typedialog-core
|
||||
run: cargo publish -p typedialog-core --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-ag-core
|
||||
run: cargo publish -p typedialog-ag-core --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-ai
|
||||
run: cargo publish -p typedialog-ai --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-prov-gen
|
||||
run: cargo publish -p typedialog-prov-gen --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog
|
||||
run: cargo publish -p typedialog --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-tui
|
||||
run: cargo publish -p typedialog-tui --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-web
|
||||
run: cargo publish -p typedialog-web --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-ag
|
||||
run: cargo publish -p typedialog-ag --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Wait for crates.io
|
||||
run: sleep 30
|
||||
|
||||
- name: Publish typedialog-ag-server
|
||||
run: cargo publish -p typedialog-ag-server --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -2,7 +2,7 @@ CLAUDE.md
|
||||
.claude
|
||||
utils/save*sh
|
||||
COMMIT_MESSAGE.md
|
||||
wrks
|
||||
.wrks
|
||||
nushell
|
||||
nushell-*
|
||||
*.tar.gz
|
||||
@ -61,3 +61,7 @@ cscope.*
|
||||
# generated by verify-vendor.sh
|
||||
vendordiff.patch
|
||||
.claude/settings.local.json
|
||||
|
||||
# Generated SBOM files
|
||||
SBOM.*.json
|
||||
*.sbom.json
|
||||
|
||||
43
.woodpecker/Dockerfile
Normal file
43
.woodpecker/Dockerfile
Normal file
@ -0,0 +1,43 @@
|
||||
# Custom Docker image for Woodpecker CI
|
||||
# Pre-installs common tools to speed up CI runs
|
||||
#
|
||||
# Build: docker build -t your-registry/typedialog-ci:latest -f .woodpecker/Dockerfile .
|
||||
# Push: docker push your-registry/typedialog-ci:latest
|
||||
#
|
||||
# Then update .woodpecker/ci.yml to use: image: your-registry/typedialog-ci:latest
|
||||
|
||||
FROM rust:latest
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
shellcheck \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install just
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
|
||||
# Install Rust components
|
||||
RUN rustup component add clippy rustfmt
|
||||
|
||||
# Install Rust tools (pre-compiled to speed up CI)
|
||||
RUN cargo install \
|
||||
cargo-audit \
|
||||
cargo-deny \
|
||||
cargo-sbom \
|
||||
nickel-lang-cli \
|
||||
nu \
|
||||
--locked
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Verify installations
|
||||
RUN just --version && \
|
||||
cargo --version && \
|
||||
cargo audit --version && \
|
||||
cargo deny --version && \
|
||||
cargo sbom --version && \
|
||||
nickel --version && \
|
||||
nu --version
|
||||
64
.woodpecker/Dockerfile.alpine
Normal file
64
.woodpecker/Dockerfile.alpine
Normal file
@ -0,0 +1,64 @@
|
||||
# Ultra-optimized Alpine-based image for Woodpecker CI
|
||||
# Size: ~400-500MB (vs 2.47GB original)
|
||||
#
|
||||
# Build: docker build -t your-registry/typedialog-ci:alpine -f .woodpecker/Dockerfile.alpine .
|
||||
# Push: docker push your-registry/typedialog-ci:alpine
|
||||
|
||||
# Stage 1: Builder
|
||||
FROM rust:1.92-alpine AS builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
musl-dev \
|
||||
openssl-dev \
|
||||
openssl-libs-static \
|
||||
pkgconfig
|
||||
|
||||
# Set static linking for smaller binaries
|
||||
ENV RUSTFLAGS="-C target-feature=+crt-static"
|
||||
|
||||
# Install Rust tools
|
||||
RUN cargo install \
|
||||
cargo-audit \
|
||||
cargo-deny \
|
||||
cargo-sbom \
|
||||
nickel-lang-cli \
|
||||
nu \
|
||||
--locked
|
||||
|
||||
# Stage 2: Final image
|
||||
FROM rust:1.92-alpine
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
shellcheck \
|
||||
git \
|
||||
curl \
|
||||
ca-certificates \
|
||||
openssl \
|
||||
libgcc
|
||||
|
||||
# Install just
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | sh -s -- --to /usr/local/bin
|
||||
|
||||
# Install Rust components
|
||||
RUN rustup component add clippy rustfmt
|
||||
|
||||
# Copy compiled binaries from builder
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-audit /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-deny /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-sbom /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/nickel /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/nu /usr/local/cargo/bin/
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Verify installations
|
||||
RUN just --version && \
|
||||
cargo --version && \
|
||||
cargo audit --version && \
|
||||
cargo deny --version && \
|
||||
cargo sbom --version && \
|
||||
nickel --version && \
|
||||
nu --version
|
||||
@ -33,7 +33,7 @@ RUN cross build --target "${BUILD_TARGET}" --release
|
||||
|
||||
# Extract binaries to output directory
|
||||
RUN mkdir -p /output/bin && \
|
||||
for binary in typedialog typedialog-tui typedialog-web; do \
|
||||
for binary in typedialog typedialog-tui typedialog-web typedialog-ai typedialog-ag typedialog-ag-server typedialog-prov-gen; do \
|
||||
if [ -f "target/${BUILD_TARGET}/release/${binary}" ]; then \
|
||||
cp "target/${BUILD_TARGET}/release/${binary}" /output/bin/ || \
|
||||
cp "target/${BUILD_TARGET}/release/${binary}.exe" /output/bin/; \
|
||||
|
||||
53
.woodpecker/Dockerfile.minimal
Normal file
53
.woodpecker/Dockerfile.minimal
Normal file
@ -0,0 +1,53 @@
|
||||
# Minimal Docker image for Woodpecker CI (without Nushell)
|
||||
# Build time: ~2 min
|
||||
# Size: ~1.6GB (vs 1.68GB with nu, vs 2.47GB original)
|
||||
#
|
||||
# Build: docker build -t your-registry/typedialog-ci:minimal -f .woodpecker/Dockerfile.minimal .
|
||||
|
||||
FROM rust:1.92-slim
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
shellcheck \
|
||||
curl \
|
||||
git \
|
||||
ca-certificates \
|
||||
wget \
|
||||
xz-utils \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Rust components
|
||||
RUN rustup component add clippy rustfmt
|
||||
|
||||
# Install just (pre-compiled)
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
|
||||
# Install cargo-binstall for faster binary installations
|
||||
RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
|
||||
|
||||
# Install Rust tools using pre-compiled binaries (much faster, smaller)
|
||||
RUN cargo binstall --no-confirm \
|
||||
cargo-audit \
|
||||
cargo-deny \
|
||||
cargo-sbom
|
||||
|
||||
# Install nickel only (skip nu to save 46MB + build time)
|
||||
RUN cargo install --locked nickel-lang-cli
|
||||
|
||||
# Clean up cargo cache to reduce size
|
||||
RUN rm -rf /usr/local/cargo/registry \
|
||||
&& rm -rf /usr/local/cargo/git
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Verify installations
|
||||
RUN just --version && \
|
||||
cargo --version && \
|
||||
cargo audit --version && \
|
||||
cargo deny --version && \
|
||||
cargo sbom --version && \
|
||||
nickel --version
|
||||
|
||||
# Note: nu (Nushell) NOT installed to save space
|
||||
# To use this image, disable lint-nushell in .woodpecker/ci.yml
|
||||
60
.woodpecker/Dockerfile.optimized
Normal file
60
.woodpecker/Dockerfile.optimized
Normal file
@ -0,0 +1,60 @@
|
||||
# Optimized Docker image for Woodpecker CI
|
||||
# Reduces size from 2.47GB to ~800MB using multi-stage build
|
||||
#
|
||||
# Build: docker build -t your-registry/typedialog-ci:latest -f .woodpecker/Dockerfile.optimized .
|
||||
# Push: docker push your-registry/typedialog-ci:latest
|
||||
|
||||
# Stage 1: Builder - compile Rust tools
|
||||
FROM rust:1.92-slim AS builder
|
||||
|
||||
# Install only build dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Rust tools
|
||||
RUN cargo install \
|
||||
cargo-audit \
|
||||
cargo-deny \
|
||||
cargo-sbom \
|
||||
nickel-lang-cli \
|
||||
nu \
|
||||
--locked
|
||||
|
||||
# Stage 2: Final image - copy only binaries
|
||||
FROM rust:1.92-slim
|
||||
|
||||
# Install runtime dependencies only
|
||||
RUN apt-get update && apt-get install -y \
|
||||
shellcheck \
|
||||
curl \
|
||||
git \
|
||||
ca-certificates \
|
||||
libssl3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install just (pre-compiled binary)
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
|
||||
# Install Rust components
|
||||
RUN rustup component add clippy rustfmt
|
||||
|
||||
# Copy compiled binaries from builder stage
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-audit /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-deny /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/cargo-sbom /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/nickel /usr/local/cargo/bin/
|
||||
COPY --from=builder /usr/local/cargo/bin/nu /usr/local/cargo/bin/
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Verify installations
|
||||
RUN just --version && \
|
||||
cargo --version && \
|
||||
cargo audit --version && \
|
||||
cargo deny --version && \
|
||||
cargo sbom --version && \
|
||||
nickel --version && \
|
||||
nu --version
|
||||
54
.woodpecker/Dockerfile.prebuilt
Normal file
54
.woodpecker/Dockerfile.prebuilt
Normal file
@ -0,0 +1,54 @@
|
||||
# Ultra-fast image using pre-compiled binaries where possible
|
||||
# Build time: ~2-3 min (vs ~20 min compiling from source)
|
||||
# Size: ~600-700MB
|
||||
#
|
||||
# Build: docker build -t your-registry/typedialog-ci:prebuilt -f .woodpecker/Dockerfile.prebuilt .
|
||||
|
||||
FROM rust:1.92-slim
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
shellcheck \
|
||||
curl \
|
||||
git \
|
||||
ca-certificates \
|
||||
wget \
|
||||
xz-utils \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Rust components
|
||||
RUN rustup component add clippy rustfmt
|
||||
|
||||
# Install just (pre-compiled)
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
|
||||
# Install cargo-binstall for faster binary installations
|
||||
RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
|
||||
|
||||
# Install Rust tools using pre-compiled binaries (much faster, smaller)
|
||||
RUN cargo binstall --no-confirm \
|
||||
cargo-audit \
|
||||
cargo-deny \
|
||||
cargo-sbom
|
||||
|
||||
# These need to be compiled (no pre-built binaries available)
|
||||
RUN cargo install --locked nickel-lang-cli nu
|
||||
|
||||
# Clean up cargo cache to reduce size
|
||||
RUN rm -rf /usr/local/cargo/registry \
|
||||
&& rm -rf /usr/local/cargo/git
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Verify installations
|
||||
RUN just --version && \
|
||||
cargo --version && \
|
||||
cargo audit --version && \
|
||||
cargo deny --version && \
|
||||
cargo sbom --version && \
|
||||
nickel --version && \
|
||||
nu --version
|
||||
|
||||
# Show final size breakdown
|
||||
RUN du -sh /usr/local/cargo/bin/*
|
||||
238
.woodpecker/README.md
Normal file
238
.woodpecker/README.md
Normal file
@ -0,0 +1,238 @@
|
||||
# Woodpecker CI Configuration
|
||||
|
||||
Pipelines for Gitea/Forgejo + Woodpecker CI.
|
||||
|
||||
## Files
|
||||
|
||||
### CI Pipeline
|
||||
- **`ci.yml`** - Main CI pipeline (push, pull requests)
|
||||
- **`ci-advanced.yml`** - Advanced CI with multi-OS matrix, coverage, benchmarks
|
||||
|
||||
### Release Pipelines
|
||||
- **`release.yml`** - Basic release (Linux only, no Docker)
|
||||
- **`release-advanced.yml`** - Advanced release (multi-OS, Gitea API, auto-upload)
|
||||
- **`release-docker.yml`** - Docker-based release (uses .woodpecker/Dockerfile.cross)
|
||||
|
||||
### Docker Images
|
||||
|
||||
**CI Images** (pre-install tools, speed up CI ~5min):
|
||||
- **`Dockerfile`** - Original (2.47GB, ❌ too large)
|
||||
- **`Dockerfile.optimized`** - Multi-stage build (~800MB)
|
||||
- **`Dockerfile.alpine`** - Alpine-based (~400MB, smallest)
|
||||
- **`Dockerfile.prebuilt`** - Pre-compiled binaries (1.68GB, 3min build, **recommended**)
|
||||
- **`Dockerfile.minimal`** - Prebuilt without nu (~1.6GB, 2min build, fastest)
|
||||
|
||||
**Build Images**:
|
||||
- **`Dockerfile.cross`** - Cross-compilation image for multi-platform builds
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Activate Woodpecker CI
|
||||
|
||||
Enable Woodpecker CI in your Gitea/Forgejo repository settings.
|
||||
|
||||
### 2. (Optional) Build Custom Image
|
||||
|
||||
Speeds up CI by pre-installing tools (~5 min faster per run).
|
||||
|
||||
**Five Dockerfile options available**:
|
||||
|
||||
| Dockerfile | Size | Build Time | Tools | Use Case |
|
||||
|------------|------|------------|-------|----------|
|
||||
| `Dockerfile` | **2.47GB** | ~20 min | All + cargo cache | ❌ Too large (original) |
|
||||
| `Dockerfile.optimized` | **~800MB** | ~15 min | All (multi-stage) | ✅ Multi-stage, Debian-based |
|
||||
| `Dockerfile.alpine` | **~400MB** | ~12 min | All (Alpine) | ✅ Alpine-based, smallest |
|
||||
| `Dockerfile.prebuilt` | **1.68GB** | **~3 min** | All (cargo-binstall) | ✅ Pre-compiled binaries, **fastest** |
|
||||
| `Dockerfile.minimal` | **~1.6GB** | **~2 min** | All except nu | ✅ Fastest + smallest (no nushell lint) |
|
||||
|
||||
**Recommended: Use `Dockerfile.prebuilt`** (fastest builds, all tools)
|
||||
|
||||
**For minimal size**: Use `Dockerfile.minimal` if you can skip nushell linting (saves 46MB + 1min build)
|
||||
|
||||
```bash
|
||||
# Build optimized image (choose one)
|
||||
docker build -t your-registry/typedialog-ci:latest -f .woodpecker/Dockerfile.prebuilt .
|
||||
|
||||
# Or for smallest size (Alpine)
|
||||
docker build -t your-registry/typedialog-ci:alpine -f .woodpecker/Dockerfile.alpine .
|
||||
|
||||
# Push to your registry
|
||||
docker push your-registry/typedialog-ci:latest
|
||||
|
||||
# Update .woodpecker/ci.yml and ci-advanced.yml
|
||||
# Change: image: rust:latest
|
||||
# To: image: your-registry/typedialog-ci:latest
|
||||
```
|
||||
|
||||
**Size comparison breakdown**:
|
||||
```
|
||||
Original (Dockerfile):
|
||||
Base Debian + buildtools: 1.6GB
|
||||
Rust toolchain: 538MB
|
||||
cargo install (5 tools): 823MB (includes cargo cache)
|
||||
--------------------------------
|
||||
TOTAL: 2.47GB
|
||||
|
||||
Optimized (Dockerfile.prebuilt):
|
||||
Base Rust slim: 400MB
|
||||
Runtime deps: 60MB
|
||||
Binaries only: 140MB (no cargo cache)
|
||||
--------------------------------
|
||||
TOTAL: ~600MB
|
||||
```
|
||||
|
||||
### 3. Secrets Configuration
|
||||
|
||||
Configure these secrets in Gitea/Forgejo repository settings:
|
||||
|
||||
- `GITEA_TOKEN` - Gitea/Forgejo API token (for auto-creating releases)
|
||||
- `CARGO_TOKEN` - crates.io token (optional, for publishing to crates.io)
|
||||
- `SONAR_TOKEN` - SonarQube token (optional, for ci-advanced.yml coverage)
|
||||
|
||||
**To create a Gitea token**:
|
||||
1. Go to Settings → Applications → Manage Access Tokens
|
||||
2. Create token with scopes: `write:repository`, `write:issue`
|
||||
3. Add as secret `GITEA_TOKEN` in repository settings
|
||||
|
||||
### 4. Docker Access (for release-docker.yml)
|
||||
|
||||
The `release-docker.yml` pipeline requires access to Docker socket. Configure in Woodpecker server:
|
||||
|
||||
**Option A: Privileged mode** (simpler, less secure):
|
||||
```yaml
|
||||
# In Woodpecker server config
|
||||
WOODPECKER_BACKEND_DOCKER_ENABLE_PRIVILEGED: true
|
||||
```
|
||||
|
||||
**Option B: Volume mount** (recommended):
|
||||
Already configured in pipeline via:
|
||||
```yaml
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
Ensure Woodpecker agent has permission to access Docker socket.
|
||||
|
||||
## Pipelines
|
||||
|
||||
### CI Pipeline (`ci.yml`)
|
||||
|
||||
**Triggers**: Push to `main`/`develop`, Pull Requests
|
||||
|
||||
**Jobs**:
|
||||
1. Lint (Rust, Bash, Nickel, Nushell, Markdown) - Parallel
|
||||
2. Test (all features)
|
||||
3. Build (release)
|
||||
4. Security audit
|
||||
5. License compliance check
|
||||
|
||||
**Duration**: ~15-20 minutes (without custom image), ~10-15 minutes (with custom image)
|
||||
|
||||
### Release Pipelines
|
||||
|
||||
All release pipelines trigger on Git tags `v*` (e.g., `v0.1.0`).
|
||||
|
||||
#### Option 1: Basic Release (`release.yml`)
|
||||
|
||||
**Use case**: Simple Linux-only releases, no Docker required
|
||||
|
||||
**Platforms**: x86_64-unknown-linux-gnu only
|
||||
|
||||
**Artifacts**:
|
||||
- `typedialog-${VERSION}-x86_64-linux.tar.gz`
|
||||
- `typedialog-${VERSION}-x86_64-linux.tar.gz.sha256`
|
||||
- `sbom-spdx.json`, `sbom-cyclonedx.json`
|
||||
|
||||
**Duration**: ~20-25 minutes
|
||||
|
||||
#### Option 2: Advanced Release (`release-advanced.yml`)
|
||||
|
||||
**Use case**: Multi-platform builds with auto-upload to Gitea
|
||||
|
||||
**Platforms**: 5 targets (Linux x86_64/aarch64, macOS x86_64/aarch64, Windows x86_64)
|
||||
|
||||
**Features**:
|
||||
- Auto-creates Gitea release via API
|
||||
- Matrix builds with `cross` tool
|
||||
- Auto-uploads all artifacts to release
|
||||
- Optional crates.io publishing
|
||||
|
||||
**Requirements**: `GITEA_TOKEN` secret
|
||||
|
||||
**Duration**: ~30-40 minutes (parallel builds)
|
||||
|
||||
#### Option 3: Docker-based Release (`release-docker.yml`)
|
||||
|
||||
**Use case**: Consistent builds using existing .woodpecker/Dockerfile.cross
|
||||
|
||||
**Platforms**: 5 targets (same as advanced)
|
||||
|
||||
**Features**:
|
||||
- Uses project's `.woodpecker/Dockerfile.cross` for reproducible builds
|
||||
- Includes BUILD_INFO.json manifest
|
||||
- Auto-creates Gitea release and uploads artifacts
|
||||
- Optional crates.io publishing
|
||||
|
||||
**Requirements**:
|
||||
- `GITEA_TOKEN` secret
|
||||
- Docker socket access (see Setup section)
|
||||
|
||||
**Duration**: ~35-45 minutes (includes Docker builds)
|
||||
|
||||
**Comparison**:
|
||||
|
||||
| Feature | Basic | Advanced | Docker-based |
|
||||
|---------|-------|----------|--------------|
|
||||
| Platforms | 1 (Linux x86_64) | 5 | 5 |
|
||||
| Gitea API | ❌ Manual | ✅ Auto | ✅ Auto |
|
||||
| Docker required | ❌ | ❌ | ✅ |
|
||||
| Build method | cargo | cross CLI | .woodpecker/Dockerfile.cross |
|
||||
| Consistency | Standard | Standard | High (containerized) |
|
||||
| Manifest | ❌ | ❌ | ✅ BUILD_INFO.json |
|
||||
|
||||
## Differences from GitHub Actions
|
||||
|
||||
| Feature | GitHub Actions | Woodpecker CI |
|
||||
|---------|---------------|---------------|
|
||||
| Matrix builds | ✅ 3 OS | ❌ Linux only* |
|
||||
| Coverage | ✅ Codecov | ❌ Not configured |
|
||||
| Benchmarks | ✅ On PRs | ❌ Not configured |
|
||||
| Caching | ✅ Built-in | ⚠️ Server-side** |
|
||||
| SBOM | ✅ Auto-upload | ⚠️ Manual*** |
|
||||
|
||||
\* Multi-OS builds require multiple Woodpecker agents
|
||||
\*\* Configure in Woodpecker server settings
|
||||
\*\*\* Manual upload to Gitea/Forgejo releases
|
||||
|
||||
## Triggering Pipelines
|
||||
|
||||
```bash
|
||||
# CI pipeline (automatic on push/PR)
|
||||
git push origin main
|
||||
|
||||
# Release pipeline (manual tag)
|
||||
git tag v0.1.0
|
||||
git push origin v0.1.0
|
||||
```
|
||||
|
||||
**Selecting Release Pipeline**:
|
||||
|
||||
By default, all three release pipelines will trigger on tags. To use only one:
|
||||
|
||||
1. **Rename the pipeline you want to use** to `release.yml`
|
||||
2. **Rename others** to `.release-*.yml.disabled` (Woodpecker ignores these)
|
||||
|
||||
Example:
|
||||
```bash
|
||||
# Use Docker-based release only
|
||||
mv .woodpecker/release.yml .woodpecker/.release-basic.yml.disabled
|
||||
mv .woodpecker/release-advanced.yml .woodpecker/.release-advanced.yml.disabled
|
||||
mv .woodpecker/release-docker.yml .woodpecker/release.yml
|
||||
```
|
||||
|
||||
Or configure in Woodpecker UI to enable/disable specific pipelines.
|
||||
|
||||
## Viewing Results
|
||||
|
||||
- **Gitea/Forgejo**: Repository → Actions → Pipeline runs
|
||||
- **Woodpecker UI**: https://your-woodpecker.instance/repos/{user}/{repo}
|
||||
115
.woodpecker/ci-advanced.yml
Normal file
115
.woodpecker/ci-advanced.yml
Normal file
@ -0,0 +1,115 @@
|
||||
# Advanced Woodpecker CI with self-hosted features
|
||||
# Requires: Multiple agents (Linux/macOS/Windows), S3 cache, SonarQube
|
||||
|
||||
when:
|
||||
event: [push, pull_request]
|
||||
branch: [main, develop]
|
||||
|
||||
# === MATRIX BUILDS (Multi-OS) ===
|
||||
# Requires Woodpecker agents on each platform
|
||||
|
||||
matrix:
|
||||
PLATFORM:
|
||||
- linux/amd64
|
||||
- darwin/amd64
|
||||
- windows/amd64
|
||||
|
||||
steps:
|
||||
# Lint (parallel, Linux only for tools availability)
|
||||
lint:
|
||||
image: rust:latest
|
||||
when:
|
||||
matrix:
|
||||
PLATFORM: linux/amd64
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- rustup component add clippy
|
||||
- just ci::lint-all
|
||||
cache:
|
||||
- ~/.cargo/registry
|
||||
- ~/.cargo/git
|
||||
|
||||
# Test (all platforms)
|
||||
test:
|
||||
image: rust:latest
|
||||
platform: ${PLATFORM}
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- just ci::test-all
|
||||
cache:
|
||||
- ~/.cargo/registry
|
||||
- ~/.cargo/git
|
||||
- target/
|
||||
depends_on:
|
||||
- lint
|
||||
|
||||
# Coverage (Linux only, upload to SonarQube)
|
||||
coverage:
|
||||
image: rust:latest
|
||||
when:
|
||||
matrix:
|
||||
PLATFORM: linux/amd64
|
||||
secrets: [sonar_token]
|
||||
commands:
|
||||
- cargo install cargo-llvm-cov
|
||||
- cargo llvm-cov --lcov --output-path lcov.info
|
||||
- |
|
||||
curl -sSL https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip -o sonar.zip
|
||||
unzip -q sonar.zip
|
||||
sonar-scanner-5.0.1.3006-linux/bin/sonar-scanner \
|
||||
-Dsonar.host.url=${SONAR_URL} \
|
||||
-Dsonar.login=${SONAR_TOKEN} \
|
||||
-Dsonar.projectKey=typedialog \
|
||||
-Dsonar.sources=. \
|
||||
-Dsonar.rust.lcov.reportPaths=lcov.info
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
# Benchmark (on PRs, post results as comment)
|
||||
benchmark:
|
||||
image: rust:latest
|
||||
when:
|
||||
event: pull_request
|
||||
matrix:
|
||||
PLATFORM: linux/amd64
|
||||
secrets: [gitea_token]
|
||||
commands:
|
||||
- cargo install cargo-criterion
|
||||
- cargo criterion --message-format json > bench.json || true
|
||||
- apk add --no-cache curl jq
|
||||
- |
|
||||
SUMMARY=$(cat bench.json | jq -r 'select(.reason=="benchmark-complete") | "\(.id): \(.mean.estimate)ns"' | head -10)
|
||||
COMMENT="## 📊 Benchmark Results\n\`\`\`\n${SUMMARY}\n\`\`\`"
|
||||
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/issues/${CI_PULL_REQUEST}/comments" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"body\": \"${COMMENT}\"}"
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
# Security audit (all platforms)
|
||||
security:
|
||||
image: rust:latest
|
||||
platform: ${PLATFORM}
|
||||
commands:
|
||||
- cargo install cargo-audit --locked
|
||||
- cargo audit
|
||||
cache:
|
||||
- ~/.cargo/bin
|
||||
depends_on:
|
||||
- lint
|
||||
|
||||
# Build (all platforms)
|
||||
build:
|
||||
image: rust:latest
|
||||
platform: ${PLATFORM}
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- just ci::build-release
|
||||
cache:
|
||||
- ~/.cargo/registry
|
||||
- ~/.cargo/git
|
||||
- target/
|
||||
depends_on:
|
||||
- test
|
||||
- security
|
||||
89
.woodpecker/ci.yml
Normal file
89
.woodpecker/ci.yml
Normal file
@ -0,0 +1,89 @@
|
||||
# Woodpecker CI Pipeline
|
||||
# Equivalent to .github/workflows/ci.yml
|
||||
|
||||
when:
|
||||
event: [push, pull_request, manual]
|
||||
branch:
|
||||
- main
|
||||
- develop
|
||||
|
||||
steps:
|
||||
# === LINTING ===
|
||||
|
||||
lint-rust:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- rustup component add clippy
|
||||
- just dev::lint-rust
|
||||
|
||||
lint-bash:
|
||||
image: koalaman/shellcheck-alpine:stable
|
||||
commands:
|
||||
- apk add --no-cache curl bash
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- just dev::lint-bash
|
||||
|
||||
lint-nickel:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- cargo install nickel-lang-cli
|
||||
- just dev::lint-nickel
|
||||
|
||||
lint-nushell:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- cargo install nu
|
||||
- just dev::lint-nushell
|
||||
|
||||
lint-markdown:
|
||||
image: node:alpine
|
||||
commands:
|
||||
- apk add --no-cache curl bash
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- npm install -g markdownlint-cli2
|
||||
- just dev::lint-markdown
|
||||
|
||||
# === TESTING ===
|
||||
|
||||
test:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- just ci::test-all
|
||||
depends_on:
|
||||
- lint-rust
|
||||
- lint-bash
|
||||
- lint-nickel
|
||||
- lint-nushell
|
||||
- lint-markdown
|
||||
|
||||
# === BUILD ===
|
||||
|
||||
build:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- just ci::build-release
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
# === SECURITY ===
|
||||
|
||||
security-audit:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- cargo install cargo-audit --locked
|
||||
- cargo audit
|
||||
depends_on:
|
||||
- lint-rust
|
||||
|
||||
license-check:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- cargo install cargo-deny --locked
|
||||
- cargo deny check licenses
|
||||
depends_on:
|
||||
- lint-rust
|
||||
115
.woodpecker/release-advanced.yml
Normal file
115
.woodpecker/release-advanced.yml
Normal file
@ -0,0 +1,115 @@
|
||||
# Advanced Release Pipeline with auto-upload to Gitea/Forgejo
|
||||
# Triggers on tags: v*
|
||||
|
||||
when:
|
||||
event: tag
|
||||
tag: v*
|
||||
|
||||
steps:
|
||||
# Create GitHub-style release via Gitea API
|
||||
create-release:
|
||||
image: alpine:latest
|
||||
secrets: [gitea_token]
|
||||
commands:
|
||||
- apk add --no-cache curl jq
|
||||
- |
|
||||
RELEASE_DATA=$(jq -n \
|
||||
--arg tag "${CI_COMMIT_TAG}" \
|
||||
--arg name "Release ${CI_COMMIT_TAG}" \
|
||||
--arg body "Automated release from Woodpecker CI" \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||
|
||||
RELEASE_ID=$(curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "${RELEASE_DATA}" | jq -r '.id')
|
||||
|
||||
echo "RELEASE_ID=${RELEASE_ID}" >> /tmp/release.env
|
||||
echo "✓ Created release ${CI_COMMIT_TAG} (ID: ${RELEASE_ID})"
|
||||
|
||||
# Build binaries for all platforms (matrix)
|
||||
build-binaries:
|
||||
image: rust:latest
|
||||
matrix:
|
||||
TARGET:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- aarch64-unknown-linux-gnu
|
||||
- x86_64-apple-darwin
|
||||
- aarch64-apple-darwin
|
||||
- x86_64-pc-windows-msvc
|
||||
commands:
|
||||
- |
|
||||
if [[ "${TARGET}" == *"aarch64"* || "${TARGET}" == *"windows"* ]]; then
|
||||
cargo install cross --git https://github.com/cross-rs/cross
|
||||
cross build --release --target ${TARGET} --locked
|
||||
else
|
||||
rustup target add ${TARGET}
|
||||
cargo build --release --target ${TARGET} --locked
|
||||
fi
|
||||
- mkdir -p dist
|
||||
- |
|
||||
if [[ "${TARGET}" == *"windows"* ]]; then
|
||||
cp target/${TARGET}/release/*.exe dist/ || true
|
||||
else
|
||||
cp target/${TARGET}/release/typedialog* dist/ || true
|
||||
rm -f dist/*.d dist/*.rlib || true
|
||||
fi
|
||||
- tar czf typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz -C dist .
|
||||
- sha256sum typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz > typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz.sha256
|
||||
depends_on:
|
||||
- create-release
|
||||
|
||||
# Generate SBOMs
|
||||
generate-sbom:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- cargo install cargo-sbom --locked
|
||||
- cargo sbom --output-format spdx_json_2_3 > sbom-spdx.json
|
||||
- cargo sbom --output-format cyclone_dx_json_1_4 > sbom-cyclonedx.json
|
||||
depends_on:
|
||||
- create-release
|
||||
|
||||
# Upload all artifacts to Gitea release
|
||||
upload-artifacts:
|
||||
image: alpine:latest
|
||||
secrets: [gitea_token]
|
||||
commands:
|
||||
- apk add --no-cache curl jq
|
||||
- source /tmp/release.env
|
||||
- |
|
||||
for file in typedialog-${CI_COMMIT_TAG}-*.tar.gz*; do
|
||||
echo "Uploading ${file}..."
|
||||
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@${file}"
|
||||
done
|
||||
- |
|
||||
for file in sbom-*.json; do
|
||||
echo "Uploading ${file}..."
|
||||
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data-binary "@${file}"
|
||||
done
|
||||
- echo "✓ All artifacts uploaded successfully"
|
||||
depends_on:
|
||||
- build-binaries
|
||||
- generate-sbom
|
||||
|
||||
# Optional: Publish to crates.io
|
||||
publish-crates:
|
||||
image: rust:latest
|
||||
secrets: [cargo_token]
|
||||
when:
|
||||
# Only if CARGO_TOKEN secret is set
|
||||
evaluate: 'CI_PIPELINE_EVENT == "tag" && CI_COMMIT_TAG =~ "^v[0-9]"'
|
||||
commands:
|
||||
- |
|
||||
for crate in typedialog-core typedialog-ag-core typedialog-ai typedialog-prov-gen typedialog typedialog-tui typedialog-web typedialog-ag typedialog-ag-server; do
|
||||
echo "Publishing ${crate}..."
|
||||
cargo publish -p ${crate} --token ${CARGO_TOKEN} || true
|
||||
sleep 30
|
||||
done
|
||||
depends_on:
|
||||
- upload-artifacts
|
||||
131
.woodpecker/release-docker.yml
Normal file
131
.woodpecker/release-docker.yml
Normal file
@ -0,0 +1,131 @@
|
||||
# Release Pipeline using Dockerfile.cross
|
||||
# Uses existing Dockerfile.cross for consistent multi-platform builds
|
||||
# Triggers on tags: v*
|
||||
|
||||
when:
|
||||
event: tag
|
||||
tag: v*
|
||||
|
||||
steps:
|
||||
# Create GitHub-style release via Gitea API
|
||||
create-release:
|
||||
image: alpine:latest
|
||||
secrets: [gitea_token]
|
||||
commands:
|
||||
- apk add --no-cache curl jq
|
||||
- |
|
||||
RELEASE_DATA=$(jq -n \
|
||||
--arg tag "${CI_COMMIT_TAG}" \
|
||||
--arg name "Release ${CI_COMMIT_TAG}" \
|
||||
--arg body "Multi-platform build using Dockerfile.cross" \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||
|
||||
RELEASE_ID=$(curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "${RELEASE_DATA}" | jq -r '.id')
|
||||
|
||||
echo "RELEASE_ID=${RELEASE_ID}" > /tmp/release.env
|
||||
echo "✓ Created release ${CI_COMMIT_TAG} (ID: ${RELEASE_ID})"
|
||||
|
||||
# Build binaries using Dockerfile.cross (matrix)
|
||||
build-binaries:
|
||||
image: docker:27-cli
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
matrix:
|
||||
TARGET:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- aarch64-unknown-linux-gnu
|
||||
- x86_64-apple-darwin
|
||||
- aarch64-apple-darwin
|
||||
- x86_64-pc-windows-msvc
|
||||
commands:
|
||||
- echo "Building for target ${TARGET}..."
|
||||
|
||||
# Build using Dockerfile.cross
|
||||
- |
|
||||
docker build -t typedialog-build:${TARGET} \
|
||||
--build-arg TARGET=${TARGET} \
|
||||
-f .woodpecker/Dockerfile.cross .
|
||||
|
||||
# Create container and extract binaries
|
||||
- docker create --name extract-${TARGET} typedialog-build:${TARGET}
|
||||
- mkdir -p dist-${TARGET}
|
||||
- docker cp extract-${TARGET}:/output/bin/. dist-${TARGET}/
|
||||
- docker cp extract-${TARGET}:/output/BUILD_INFO.json dist-${TARGET}/ || true
|
||||
- docker rm extract-${TARGET}
|
||||
|
||||
# Package binaries
|
||||
- tar czf typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz -C dist-${TARGET} .
|
||||
- sha256sum typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz > typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz.sha256
|
||||
|
||||
- echo "✓ Built and packaged ${TARGET}"
|
||||
depends_on:
|
||||
- create-release
|
||||
|
||||
# Generate SBOMs (SPDX + CycloneDX)
|
||||
generate-sbom:
|
||||
image: typedialog-ci:latest # Uses custom image with cargo-sbom pre-installed
|
||||
commands:
|
||||
- cargo sbom --output-format spdx_json_2_3 > sbom-spdx.json
|
||||
- cargo sbom --output-format cyclone_dx_json_1_4 > sbom-cyclonedx.json
|
||||
- echo "✓ Generated SBOMs"
|
||||
depends_on:
|
||||
- create-release
|
||||
|
||||
# Upload all artifacts to Gitea release
|
||||
upload-artifacts:
|
||||
image: alpine:latest
|
||||
secrets: [gitea_token]
|
||||
commands:
|
||||
- apk add --no-cache curl jq
|
||||
- source /tmp/release.env
|
||||
- echo "Uploading to release ID ${RELEASE_ID}..."
|
||||
|
||||
# Upload binary archives and checksums
|
||||
- |
|
||||
for file in typedialog-${CI_COMMIT_TAG}-*.tar.gz*; do
|
||||
if [ -f "${file}" ]; then
|
||||
echo "Uploading ${file}..."
|
||||
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Upload SBOMs
|
||||
- |
|
||||
for file in sbom-*.json; do
|
||||
if [ -f "${file}" ]; then
|
||||
echo "Uploading ${file}..."
|
||||
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data-binary "@${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
- echo "✓ All artifacts uploaded successfully"
|
||||
depends_on:
|
||||
- build-binaries
|
||||
- generate-sbom
|
||||
|
||||
# Optional: Publish to crates.io
|
||||
publish-crates:
|
||||
image: rust:latest
|
||||
secrets: [cargo_token]
|
||||
when:
|
||||
# Only if CARGO_TOKEN secret is set
|
||||
evaluate: 'CI_PIPELINE_EVENT == "tag" && CI_COMMIT_TAG =~ "^v[0-9]"'
|
||||
commands:
|
||||
- |
|
||||
for crate in typedialog-core typedialog-ag-core typedialog-ai typedialog-prov-gen typedialog typedialog-tui typedialog-web typedialog-ag typedialog-ag-server; do
|
||||
echo "Publishing ${crate}..."
|
||||
cargo publish -p ${crate} --token ${CARGO_TOKEN} || true
|
||||
sleep 30
|
||||
done
|
||||
- echo "✓ Published to crates.io"
|
||||
depends_on:
|
||||
- upload-artifacts
|
||||
53
.woodpecker/release.yml
Normal file
53
.woodpecker/release.yml
Normal file
@ -0,0 +1,53 @@
|
||||
# Woodpecker CI Release Pipeline
|
||||
# Equivalent to .github/workflows/release.yml
|
||||
# Triggered on git tags (v*)
|
||||
|
||||
when:
|
||||
event: tag
|
||||
tag: v*
|
||||
|
||||
steps:
|
||||
# === BUILD RELEASE ===
|
||||
|
||||
build-release:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
|
||||
- cargo build --release --locked
|
||||
- mkdir -p dist
|
||||
- cp target/release/typedialog dist/
|
||||
- cp target/release/typedialog-tui dist/
|
||||
- cp target/release/typedialog-web dist/
|
||||
- cp target/release/typedialog-ag dist/
|
||||
- cp target/release/typedialog-ag-server dist/
|
||||
- cp README.md dist/ 2>/dev/null || true
|
||||
- cp LICENSE dist/ 2>/dev/null || true
|
||||
- cd dist && tar czf ../typedialog-${CI_COMMIT_TAG}-x86_64-linux.tar.gz .
|
||||
- cd .. && sha256sum typedialog-${CI_COMMIT_TAG}-x86_64-linux.tar.gz > typedialog-${CI_COMMIT_TAG}-x86_64-linux.tar.gz.sha256
|
||||
|
||||
# === GENERATE SBOM ===
|
||||
|
||||
generate-sbom:
|
||||
image: rust:latest
|
||||
commands:
|
||||
- cargo install cargo-sbom --locked
|
||||
- cargo sbom --output-format spdx_json_2_3 > sbom-spdx.json
|
||||
- cargo sbom --output-format cyclone_dx_json_1_4 > sbom-cyclonedx.json
|
||||
depends_on:
|
||||
- build-release
|
||||
|
||||
# === PUBLISH ARTIFACTS ===
|
||||
# Note: This requires Woodpecker server configured with Forgejo/Gitea integration
|
||||
# Artifacts will be available in the pipeline artifacts section
|
||||
|
||||
publish-artifacts:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- echo "✓ Release artifacts generated successfully"
|
||||
- echo "📦 Binary: typedialog-${CI_COMMIT_TAG}-x86_64-linux.tar.gz"
|
||||
- echo "🔐 Checksum: typedialog-${CI_COMMIT_TAG}-x86_64-linux.tar.gz.sha256"
|
||||
- echo "📋 SBOM (SPDX): sbom-spdx.json"
|
||||
- echo "📋 SBOM (CycloneDX): sbom-cyclonedx.json"
|
||||
- ls -lh *.tar.gz *.sha256 *.json
|
||||
depends_on:
|
||||
- generate-sbom
|
||||
Loading…
x
Reference in New Issue
Block a user