ci: professional pipeline — unified image, nextest partitions, docs, schedules

This commit is contained in:
Kurdistan Tech Ministry committed 2026-04-21 23:20:17 +03:00
1 parent 4e6079fb47
commit 7caf11b2d2
1 file changed
+453 -74
+453 -74
View File
@@ -1,26 +1,49 @@
# ============================================================================
# Pezkuwi SDK — GitLab CI/CD Pipeline
# Mirrors: checks-quick, checks, security-audit, tests, docs, release
#
# Same unified image as GitHub Actions — no apt-get overhead, sccache ready.
# ============================================================================
image: ghcr.io/pezkuwichain/ci-unified:bullseye-1.88.0-2025-06-27-v202511141243
stages:
- lint
- quick-checks
- checks
- security
- test
- docs
- build
- release
# ── Variables ─────────────────────────────────────────────────────────────────
variables:
CARGO_HOME: "$CI_PROJECT_DIR/.cargo"
CARGO_INCREMENTAL: "0"
CARGO_TERM_COLOR: "always"
RUST_BACKTRACE: "short"
RUSTFLAGS: "-D warnings"
SCCACHE_DIR: "$CI_PROJECT_DIR/.sccache"
# Disable forklift (GitHub-only sccache proxy not available on GitLab)
RUSTC_WRAPPER: ""
# Faster artifact transfer
FF_USE_FASTZIP: "true"
ARTIFACT_COMPRESSION_LEVEL: "fast"
CACHE_COMPRESSION_LEVEL: "fast"
# ── Workflow: avoid duplicate pipelines ───────────────────────────────────────
workflow:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
# ── Default ───────────────────────────────────────────────────────────────────
default:
image: rust:slim
before_script:
- apt-get update -qq && apt-get install -y -qq --no-install-recommends
pkg-config libssl-dev clang cmake protobuf-compiler git curl ca-certificates
- rustup show # installs channel from rust-toolchain.toml (1.88.0)
- rustup target add wasm32-unknown-unknown
- cargo --version && rustc --version
- rustup show
- rustc --version && cargo --version
cache:
key:
files:
@@ -29,122 +52,478 @@ default:
paths:
- .cargo/registry/
- .cargo/git/
- target/
policy: pull-push
interruptible: true
timeout: 3h
# ─── LINT ────────────────────────────────────────────────────────────────────
# ╔══════════════════════════════════════════════════════════════════════════════
# QUICK CHECKS — fast feedback on every push/MR (mirrors checks-quick.yml)
# ╚══════════════════════════════════════════════════════════════════════════════
fmt:
stage: lint
stage: quick-checks
script:
- cargo fmt --all -- --check
allow_failure: false
check:
stage: lint
check-toml-format:
stage: quick-checks
script:
- cargo check --workspace --locked
allow_failure: false
- taplo format --check --config .config/taplo.toml
- echo "Run 'taplo format --config .config/taplo.toml' to fix TOML issues"
check-dependency-rules:
stage: quick-checks
script:
- cd bizinikiwi/ && ../.gitlab/ensure-deps.sh
check-fail-ci:
stage: quick-checks
script:
- |
if rg --line-number --hidden --type rust --glob '!{.git,target}' "FAIL-CI" .; then
echo "FAIL-CI marker found — remove before merging"
exit 1
fi
echo "✅ No FAIL-CI markers found"
check-workspace-integrity:
stage: quick-checks
script:
- pip3 install toml "cargo-workspace>=1.2.6" --quiet
- |
python3 .github/scripts/check-workspace.py . \
--exclude "bizinikiwi/pezframe/contracts/fixtures/build" \
--exclude "bizinikiwi/pezframe/contracts/fixtures/contracts/common"
- python3 .github/scripts/deny-git-deps.py .
check-zepter:
stage: quick-checks
script:
- cargo metadata --format-version=1 --locked > /dev/null
- zepter --version
- zepter run check
test-rust-features:
stage: quick-checks
script:
- bash .gitlab/rust-features.sh .
check-umbrella:
stage: quick-checks
script:
- pip3 install "cargo-workspace>=1.2.4" toml --quiet
- git config --global --add safe.directory '*'
- |
UMBRELLA_VERSION=$(cargo metadata --format-version=1 | \
python3 -c "import json,sys; pkgs=json.load(sys.stdin)['packages']; \
print(next(p['version'] for p in pkgs if p['manifest_path'].endswith('umbrella/Cargo.toml')))")
echo "Umbrella version: $UMBRELLA_VERSION"
python3 scripts/generate-umbrella.py --sdk . --version "$UMBRELLA_VERSION"
cargo +nightly fmt -p pezkuwi-sdk
- |
if [ -n "$(git status --porcelain)" ]; then
echo "❌ Umbrella crate is out of sync. Run: python3 scripts/generate-umbrella.py --sdk . --version <VERSION>"
git diff
exit 1
fi
echo "✅ Umbrella crate is up to date"
check-licenses-headers:
stage: quick-checks
script:
- |
for dir in pezkuwi pezcumulus bizinikiwi; do
echo "Checking license headers in ./$dir..."
MISSING=$(find "./$dir" -name "*.rs" -type f | head -200 | while read f; do
head -20 "$f" | grep -qiE "(apache|gpl|mit|unlicense|copyright)" || echo "$f"
done)
if [ -n "$MISSING" ]; then
echo "⚠️ Files potentially missing license headers in $dir:"
echo "$MISSING" | head -20
else
echo "✅ $dir: license headers OK (sampled)"
fi
done
# ╔══════════════════════════════════════════════════════════════════════════════
# CHECKS — deeper linting and feature checks (mirrors checks.yml)
# ╚══════════════════════════════════════════════════════════════════════════════
clippy:
stage: lint
stage: checks
needs: [fmt]
variables:
SKIP_WASM_BUILD: "1"
timeout: 90m
script:
- cargo clippy --workspace --locked -- -D warnings
allow_failure: false
- git config --global --add safe.directory '*'
- |
cargo clippy --all-targets --all-features --locked --workspace --quiet \
--exclude pezpallet-revive-eth-rpc \
--exclude pezkuwi-zombienet-sdk-tests \
-- -D warnings
# ─── SECURITY ────────────────────────────────────────────────────────────────
check-try-runtime:
stage: checks
needs: [clippy]
variables:
SKIP_WASM_BUILD: "1"
timeout: 90m
script:
- git config --global --add safe.directory '*'
- cargo check --locked --all --features try-runtime --quiet
- cargo check --locked -p teyrchain-template-node --features try-runtime
- cargo check --locked --all --features try-runtime,experimental --quiet
check-core-crypto-features:
stage: checks
needs: [fmt]
script:
- rustup target add wasm32v1-none
- |
for pkg in core application-crypto keyring; do
echo "--- Checking bizinikiwi/primitives/$pkg ---"
(cd bizinikiwi/primitives/$pkg && ./check-features-variants.sh)
done
# ╔══════════════════════════════════════════════════════════════════════════════
# SECURITY — mirrors security-audit.yml (runs on push + schedule weekly Mon 06:00)
# ╚══════════════════════════════════════════════════════════════════════════════
cargo-deny-advisories:
stage: security
needs: []
before_script: []
script:
- cargo deny check advisories --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-deny-licenses:
stage: security
needs: []
before_script: []
script:
- cargo deny check licenses --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-deny-sources:
stage: security
needs: []
before_script: []
script:
- cargo deny check sources --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-audit:
stage: security
script:
- cargo install cargo-audit --quiet
- cargo audit
allow_failure: true # advisory-only; does not block merge
cargo-deny:
stage: security
script:
- cargo install cargo-deny --quiet
- cargo deny check --config deny.toml
allow_failure: false
license-check:
stage: security
needs: []
before_script: []
script:
- |
echo "Checking Apache-2.0 license headers..."
if [ ! -f LICENSE-APACHE ]; then
echo "ERROR: LICENSE-APACHE missing" && exit 1
fi
if [ ! -f NOTICE ]; then
echo "ERROR: NOTICE file missing" && exit 1
fi
echo "✅ License files present"
cargo audit \
--ignore RUSTSEC-2026-0006 \
--ignore RUSTSEC-2026-0020 \
--ignore RUSTSEC-2026-0021 \
--ignore RUSTSEC-2026-0049 \
--ignore RUSTSEC-2023-0071 \
--ignore RUSTSEC-2025-0055 \
--ignore RUSTSEC-2026-0067 \
--ignore RUSTSEC-2026-0068 \
2>&1 | tee audit-output.txt || (cat audit-output.txt && exit 1)
allow_failure: false
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
# ─── TEST ────────────────────────────────────────────────────────────────────
# ╔══════════════════════════════════════════════════════════════════════════════
# TEST — mirrors tests-linux-stable.yml (manual-only on GitHub, schedule here)
# ╚══════════════════════════════════════════════════════════════════════════════
unit-tests:
# Tests split into 3 partitions via cargo-nextest — mirrors GitHub matrix strategy
.test-base:
stage: test
needs: [clippy, check-try-runtime]
variables:
RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings"
WASM_BUILD_NO_COLOR: "1"
CARGO_INCREMENTAL: "0"
timeout: 90m
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
test-partition-1:
extends: .test-base
script:
- cargo test --workspace --lib --locked 2>&1 | tee test-results.txt
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:1/3
artifacts:
when: always
paths:
- test-results.txt
paths: [test-results-1.xml]
reports:
junit: test-results-1.xml
expire_in: 7 days
allow_failure: false
test-partition-2:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:2/3
artifacts:
when: always
paths: [test-results-2.xml]
reports:
junit: test-results-2.xml
expire_in: 7 days
test-partition-3:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:3/3
# First partition also runs runtime-api tests
- cargo nextest run -p pezsp-api-test --features enable-pez-staging-api --cargo-quiet
artifacts:
when: always
paths: [test-results-3.xml]
reports:
junit: test-results-3.xml
expire_in: 7 days
test-no-try-runtime-1:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features experimental,ci-only-tests \
--partition count:1/2
test-no-try-runtime-2:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features experimental,ci-only-tests \
--partition count:2/2
wasm-check:
stage: test
needs: [check-try-runtime]
script:
- rustup target add wasm32-unknown-unknown
- cargo check -p pezkuwichain-runtime --locked --target wasm32-unknown-unknown
allow_failure: false
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
# ─── BUILD ───────────────────────────────────────────────────────────────────
build:
stage: build
# Runtime migration — disabled until try-runtime Zagros endpoints are live
# Enable by removing the `when: manual` rule and setting proper URIs
runtime-migration:
stage: test
needs: []
variables:
RUSTFLAGS: ""
script:
- cargo build --release -p pezkuwi --locked 2>&1 | tee build.log
- ls -lh target/release/pezkuwi target/release/pezkuwi-execute-worker target/release/pezkuwi-prepare-worker
- |
echo "Runtime migration check — currently manual/disabled"
echo "Targets: zagros, asset-hub-zagros, collectives-zagros, coretime-zagros"
echo "Re-enable when wss://try-runtime-zagros.pezkuwichain.io is live"
rules:
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
- if: $CI_PIPELINE_SOURCE == "schedule"
when: manual
allow_failure: true
# ╔══════════════════════════════════════════════════════════════════════════════
# DOCS — mirrors docs.yml
# ╚══════════════════════════════════════════════════════════════════════════════
test-doc:
stage: docs
needs: [clippy]
variables:
RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings"
SKIP_WASM_BUILD: "0"
timeout: 5h
script:
- rustup target add wasm32v1-none
- git config --global --add safe.directory '*'
- |
cargo test --doc --workspace --locked --all-features \
--exclude pezkuwi-zombienet-sdk-tests \
--exclude pezpallet-revive-eth-rpc
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
build-rustdoc:
stage: docs
needs: [test-doc]
variables:
SKIP_WASM_BUILD: "1"
RUSTDOCFLAGS: >-
-Dwarnings
--default-theme=ayu
--html-in-header ./docs/sdk/assets/header.html
--extend-css ./docs/sdk/assets/theme.css
--html-after-content ./docs/sdk/assets/after-content.html
timeout: 4h
script:
- git config --global --add safe.directory '*'
- |
cargo doc --all-features --workspace --no-deps --locked \
--exclude pezkuwi-zombienet-sdk-tests \
--exclude pezpallet-revive-eth-rpc
- rm -f target/doc/.lock
- mv target/doc ./crate-docs
- echo '<meta http-equiv=refresh content=0;url=pezkuwi_sdk_docs/index.html>' > ./crate-docs/index.html
- tar czf crate-docs.tar.gz crate-docs/
artifacts:
paths: [crate-docs.tar.gz]
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: true
build-implementers-guide:
stage: docs
needs: []
before_script: []
image: rust:slim
script:
- cargo install mdbook --version 0.4.35 --locked --quiet
- mdbook build ./pezkuwi/roadmap/implementers-guide
artifacts:
paths: [pezkuwi/roadmap/implementers-guide/book/]
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
allow_failure: true
# GitLab Pages — publish rustdocs to pages.gitlab.io
pages:
stage: docs
needs: [build-rustdoc, build-implementers-guide]
before_script: []
script:
- mkdir -p public
- tar xzf crate-docs.tar.gz -C public/ --strip-components=1 || true
- cp -r pezkuwi/roadmap/implementers-guide/book public/guide || true
artifacts:
paths: [public/]
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: true
# ╔══════════════════════════════════════════════════════════════════════════════
# BUILD — release binary (main branch + tags)
# ╚══════════════════════════════════════════════════════════════════════════════
build-release:
stage: build
needs: [clippy, wasm-check]
variables:
RUSTFLAGS: "-D warnings"
timeout: 4h
script:
- git config --global --add safe.directory '*'
- cargo build --release -p pezkuwi --locked
- |
echo "=== Build artifacts ==="
ls -lh target/release/pezkuwi \
target/release/pezkuwi-execute-worker \
target/release/pezkuwi-prepare-worker
echo ""
echo "=== SHA256 checksums ==="
sha256sum \
target/release/pezkuwi \
target/release/pezkuwi-execute-worker \
target/release/pezkuwi-prepare-worker | tee SHA256SUMS
artifacts:
name: "pezkuwi-$CI_COMMIT_REF_NAME"
paths:
- target/release/pezkuwi
- target/release/pezkuwi-execute-worker
- target/release/pezkuwi-prepare-worker
expire_in: 1 day
when: on_success
only:
- main
- tags
- SHA256SUMS
expire_in: 7 days
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
# ─── RELEASE ─────────────────────────────────────────────────────────────────
# ╔══════════════════════════════════════════════════════════════════════════════
# RELEASE — GitLab Release with assets (tags only)
# ╚══════════════════════════════════════════════════════════════════════════════
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
before_script: [] # override default before_script — no Rust needed
needs:
- build
before_script: []
needs: [build-release]
script:
- echo "Creating release $CI_COMMIT_TAG"
- echo "Creating GitLab Release for $CI_COMMIT_TAG"
release:
tag_name: "$CI_COMMIT_TAG"
name: "Pezkuwi SDK $CI_COMMIT_TAG"
description: |
## Pezkuwi SDK $CI_COMMIT_TAG
Binary artifacts built from this release are attached.
### Binaries (Linux x86_64)
**Install:**
| Binary | Description |
|--------|-------------|
| `pezkuwi` | Node binary |
| `pezkuwi-execute-worker` | WASM execution worker |
| `pezkuwi-prepare-worker` | WASM preparation worker |
SHA256 checksums in `SHA256SUMS`.
### Verify
```bash
curl -LO https://gitlab.com/pezkuwichain/pezkuwi-sdk/-/releases/$CI_COMMIT_TAG/downloads/pezkuwi
chmod +x pezkuwi
sha256sum -c SHA256SUMS
```
only:
- /^v\d+\.\d+\.\d+$/
except:
- branches
assets:
links:
- name: "pezkuwi (node binary)"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi?job=build-release"
link_type: package
- name: "pezkuwi-execute-worker"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi-execute-worker?job=build-release"
link_type: package
- name: "pezkuwi-prepare-worker"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi-prepare-worker?job=build-release"
link_type: package
- name: "SHA256SUMS"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/SHA256SUMS?job=build-release"
link_type: other
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/