stages:
  - setup
  - build
  - test
  - package
  - deploy

variables:
  CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
  RUST_BACKTRACE: "1"

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
    - if: $CI_COMMIT_BRANCH =~ /^feature\/.*/
    - if: $CI_COMMIT_BRANCH == "staging"

# Default image and settings for all jobs
default:
  image: rust:1.76
  interruptible: true
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

# Cache configuration
.cargo-cache:
  cache:
    key:
      files:
        - Cargo.lock
    paths:
      - ${CARGO_HOME}
      - target/
    policy: pull-push

# Job to initialize the environment
setup:
  stage: setup
  extends: .cargo-cache
  cache:
    policy: push
  script:
    - cargo --version
    - rustc --version
    - cargo fetch
  artifacts:
    paths:
      - Cargo.lock

# Matrix build for multiple platforms
.build-matrix:
  stage: build
  extends: .cargo-cache
  needs:
    - setup
  parallel:
    matrix:
      - TARGET:
          - x86_64-unknown-linux-gnu
          - x86_64-apple-darwin
          - aarch64-apple-darwin
          - x86_64-pc-windows-msvc
        RUST_VERSION:
          - "1.75"
          - "1.76"
  script:
    - rustup target add $TARGET
    - cargo build --release --target $TARGET
  artifacts:
    paths:
      - target/$TARGET/release/
    expire_in: 1 week
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_TAG
      when: always
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: manual
      allow_failure: true

# Regular build job for most cases
build:
  stage: build
  extends: .cargo-cache
  needs:
    - setup
  script:
    - cargo build --release
  artifacts:
    paths:
      - target/release/
    expire_in: 1 week
  rules:
    - if: $CI_COMMIT_BRANCH != "main" && !$CI_COMMIT_TAG
      when: always

# Test with different feature combinations
.test-template:
  stage: test
  extends: .cargo-cache
  needs:
    - build
  artifacts:
    reports:
      junit: test-results.xml
    when: always

test-default:
  extends: .test-template
  script:
    - cargo test -- -Z unstable-options --format json | tee test-output.json
    - cat test-output.json | jq -r '.[]' > test-results.xml
    
test-all-features:
  extends: .test-template
  script:
    - cargo test --all-features -- -Z unstable-options --format json | tee test-output.json
    - cat test-output.json | jq -r '.[]' > test-results.xml

test-no-features:
  extends: .test-template
  script:
    - cargo test --no-default-features -- -Z unstable-options --format json | tee test-output.json
    - cat test-output.json | jq -r '.[]' > test-results.xml

# Security scanning
security:
  stage: test
  extends: .cargo-cache
  needs:
    - build
  script:
    - cargo install cargo-audit || true
    - cargo audit
  allow_failure: true

# Linting
lint:
  stage: test
  extends: .cargo-cache
  script:
    - rustup component add clippy
    - cargo clippy -- -D warnings
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

# Package for different targets
package:
  stage: package
  extends: .cargo-cache
  needs:
    - job: build
      artifacts: true
    - test-default
    - test-all-features
  script:
    - mkdir -p packages
    - tar -czf packages/wrkflw-${CI_COMMIT_REF_SLUG}.tar.gz -C target/release wrkflw
  artifacts:
    paths:
      - packages/
  only:
    - main
    - tags

# Deploy to staging
deploy-staging:
  stage: deploy
  image: alpine
  needs:
    - package
  environment:
    name: staging
  script:
    - apk add --no-cache curl
    - curl -X POST -F "file=@packages/wrkflw-${CI_COMMIT_REF_SLUG}.tar.gz" ${STAGING_DEPLOY_URL}
  only:
    - staging

# Deploy to production
deploy-production:
  stage: deploy
  image: alpine
  needs:
    - package
  environment:
    name: production
  script:
    - apk add --no-cache curl
    - curl -X POST -F "file=@packages/wrkflw-${CI_COMMIT_REF_SLUG}.tar.gz" ${PROD_DEPLOY_URL}
  only:
    - tags
  when: manual 