# Runner tags:
# - podman: use 'podman' to build multiplatform images

stages:
  - schedule
  - labels
  - quality
  - build
  - tests
  - release
  - deploy
  - deploy_readme

workflow:
  rules:
    - changes:
        - docker/Dockerfile
        - end2end-tests/**/*
        - node/**/*
        - pallets/**/*
        - runtime/**/*
        - .gitlab-ci.yml
        - Cargo.toml
        - Cargo.lock

sanity_tests:
  extends: .env
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TOPIC=="sanity-tests"'
    - when: never
  stage: schedule
  script:
    - cargo sanity-${CURRENCY}

check_labels:
  extends: .env
  stage: labels
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - when: never
  script:
    - ./scripts/check_labels.sh $CI_MERGE_REQUEST_LABELS $CI_MERGE_REQUEST_MILESTONE


check_metadata:
  extends: .env
  stage: tests
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - when: never
  script:
    - ./scripts/check_metadata.sh

.env:
  image: paritytech/ci-linux:production
  tags:
    - kepler

fmt_and_clippy:
  extends: .env
  rules:
    - if: $CI_COMMIT_REF_NAME =~ /^wip*$/
      when: manual
    - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH == "master"'
      when: never
    - if: '$CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/'
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
    - when: manual
  stage: quality
  script:
    - cargo fmt -- --version
    - cargo fmt -- --check
    - cargo clippy -- -V
    - cargo clippy --features runtime-benchmarks --all --tests -- -D warnings

run_benchmarks:
  extends: .env
  stage: tests
  rules:
    - if: $CI_COMMIT_REF_NAME =~ /^wip*$/
      when: manual
    - if: $CI_COMMIT_TAG
      when: never
    - if: '$CI_MERGE_REQUEST_ID || $CI_COMMIT_BRANCH == "master"'
    - when: manual
  script:
    - cargo build --release --features runtime-benchmarks
    - target/release/duniter benchmark storage --chain=dev --mul=2 --state-version=1
    - target/release/duniter benchmark overhead --chain=dev --wasm-execution=compiled --warmup=1 --repeat=100
    - target/release/duniter benchmark pallet --chain=dev --steps=5 --repeat=2 --pallet="*" --extrinsic="*" --wasm-execution=compiled
# FIXME: "gtest_build"
gdev_build:
  stage: build
  image: rust:1-bullseye
  rules:
    - if: $CI_COMMIT_REF_NAME =~ /^wip*$/
      when: manual
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
      when: never
    - if: '$CI_MERGE_REQUEST_ID || $CI_COMMIT_BRANCH == "master"'
    - when: manual
  variables:
    DEBIAN_FRONTEND: noninteractive
  script:
    - apt-get update
    - apt-get install -y clang cmake protobuf-compiler
    - cargo build --no-default-features --features gtest

gdev_srtool_build:
  stage: build
  rules:
    - if: $CI_COMMIT_REF_NAME =~ /^wip*$/
      when: manual
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
      when: never
    - if: '$CI_MERGE_REQUEST_ID || $CI_COMMIT_BRANCH == "master"'
    - when: manual
  image: paritytech/srtool:1.74.0-0.13.0
  variables:
    PACKAGE: gdev-runtime
    RUNTIME_DIR: runtime/gdev
    SRTOOL_OUTPUT: $CI_PROJECT_DIR/release/srtool_output_gdev.json
  script:
    - echo "Building runtime for gdev"
    - mkdir -p $CI_PROJECT_DIR/release
    - echo -e "[toolchain]\nchannel = \"`curl -s https://raw.githubusercontent.com/paritytech/srtool/master/RUSTC_VERSION`\"\ncomponents = [ \"rust-std\", \"rust-src\" ]" > $RUNTIME_DIR/rust-toolchain.toml # Workaround see !239
    # Copy sources to the expected directory of srtool
    - cp -R * /build/
    # Build the runtime
    - /srtool/build --app --json -cM | tee -a $SRTOOL_OUTPUT
    - mv /build/runtime/gdev/target/srtool/release/wbuild/gdev-runtime/gdev_runtime.compact.compressed.wasm $CI_PROJECT_DIR/release/
  tags:
    - kepler

tests:
  stage: tests
  image: rust:1-bullseye
  rules:
    - if: $CI_COMMIT_REF_NAME =~ /^wip*$/
      when: manual
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
      when: never
    - if: '$CI_MERGE_REQUEST_ID || $CI_COMMIT_BRANCH == "master"'
    - when: manual
  variables:
    DEBIAN_FRONTEND: noninteractive
  script:
    - apt-get update
    - apt-get install -y clang cmake protobuf-compiler
    - cargo tu
    - cargo cucumber-build
    - cargo cucumber

.deploy_docker_multiplatform:
  stage: build
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
      when: manual
    #      changes:
    #        - node/specs/$CHAIN-raw.json
    - when: never
  before_script:
    - sh -c "[ -n '$DUNITERTEAM_PASSWD' ] || ( echo No access to environment variable 'DUNITERTEAM_PASSWD'; exit 1 )"
    - podman login -u "duniterteam" -p "$DUNITERTEAM_PASSWD" docker.io
  script:
    - export MILESTONE=$(echo $CI_COMMIT_BRANCH | sed -e "s/release\///g")
    - echo $MILESTONE
    - export MANIFEST=localhost/manifest-$IMAGE_NAME:$MILESTONE
    - echo $MANIFEST
    - podman manifest rm "$MANIFEST" 2>/dev/null || true
    - podman build --layers --platform linux/amd64,linux/arm64 --manifest "$MANIFEST" -f docker/Dockerfile $PODMAN_BUILD_OPTIONS .
    - podman manifest push --all "$MANIFEST" "docker://docker.io/$IMAGE_NAME:$MILESTONE"
    - podman manifest push --all "$MANIFEST" "docker://docker.io/$IMAGE_NAME:latest"
  after_script:
    - podman manifest rm "$MANIFEST"
  variables:
    IMAGE_NAME: "duniter/duniter-v2s-$CHAIN"
    PODMAN_BUILD_OPTIONS: "--build-arg chain=$CHAIN"
  tags:
    - podman

gdev_docker_deploy:
  extends: .deploy_docker_multiplatform
  variables:
    CHAIN: gdev

gtest_docker_deploy:
  extends: .deploy_docker_multiplatform
  variables:
    CHAIN: gtest

readme_docker_release_tag:
  stage: deploy_readme
  rules:
    - if: "$CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^(v|runtime-)[0-9].*/"
    - when: never
  image:
    name: chko/docker-pushrm
    entrypoint: ["/bin/sh", "-c", "/docker-pushrm"]
  variables:
    DOCKER_USER: duniterteam
    DOCKER_PASS: "$DUNITERTEAM_PASSWD"
    PUSHRM_SHORT: "Duniter v2 based on Substrate framework"
    PUSHRM_TARGET: "docker.io/duniter/duniter-v2s"
    PUSHRM_DEBUG: 1
    PUSHRM_FILE: "$CI_PROJECT_DIR/docker/README.md"
  script: "/bin/true"

############## SRTOOL ##############

.srtool:
  stage: build
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
  image: paritytech/srtool:1.74.0-0.13.0
  variables:
    PACKAGE: $RUNTIME-runtime
    RUNTIME_DIR: runtime/$RUNTIME
    SRTOOL_OUTPUT: $CI_PROJECT_DIR/release/srtool_output_$RUNTIME.json
  script:
    - echo "Building runtime for $RUNTIME"
    - echo $CI_COMMIT_BRANCH | sed -e "s/release\///g"
    - mkdir -p $CI_PROJECT_DIR/release
    - echo -e "[toolchain]\nchannel = \"`curl -s https://raw.githubusercontent.com/paritytech/srtool/master/RUSTC_VERSION`\"\ncomponents = [ \"rust-std\", \"rust-src\" ]" > $RUNTIME_DIR/rust-toolchain.toml # Workaround see !239
    # Copy sources to the expected directory of srtool
    - cp -R * /build/
    # Build the runtime
    - /srtool/build --app --json -cM | tee -a $SRTOOL_OUTPUT
    - mv /build/runtime/$RUNTIME/target/srtool/release/wbuild/$RUNTIME-runtime/${RUNTIME}_runtime.compact.compressed.wasm $CI_PROJECT_DIR/release/
  artifacts:
    name: "runtime"
    paths:
      - $CI_PROJECT_DIR/release
  tags:
    - kepler

gdev_srtool:
  extends: .srtool
  variables:
    RUNTIME: gdev

gtest_srtool:
  extends: .srtool
  variables:
    RUNTIME: gtest

############## SPECS ##############

create_g1_data:
  stage: build
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
  image: python:3.9.18
  variables:
    DEBIAN_FRONTEND: noninteractive
    LEVELDB_PATH: /dump/duniter_default/data/leveldb
  script:
    # Duniter 1.8.7 dump
    - mkdir /dump
    - cd /dump
    # Export file constructed using Duniter 1.8.7:
    #  - bin/duniter sync g1.cgeek.fr --store-txs --nointeractive --mdb 1.8.7
    #  - mkdir -p /tmp/backup-g1-duniter-1.8.7
    #  - cp -R $HOME/.config/duniter/1.8.7/data /tmp/backup-g1-duniter-1.8.7
    #  - cp -R $HOME/.config/duniter/1.8.7/g1 /tmp/backup-g1-duniter-1.8.7
    #  - cp -R $HOME/.config/duniter/1.8.7/txs.db /tmp/backup-g1-duniter-1.8.7
    #  - tar -cvzf /tmp/backup-g1-duniter-1.8.7.tgz /tmp/backup-g1-duniter-1.8.7
    # Then the file is uploaded to dl.cgeek.fr manually
    - curl https://dl.cgeek.fr/public/backup-g1-duniter-1.8.7.tgz -o g1-dump.tgz
    - tar xvzf g1-dump.tgz
    - rm g1-dump.tgz
    - mv tmp/backup-g1-duniter-1.8.7 duniter_default
    # py-g1-migrator conversion
    - git clone https://git.duniter.org/tools/py-g1-migrator.git -b import_identities_from_leveldb /py-g1-migrator
    - cd /py-g1-migrator
    - rm -rf inputs/*
    - apt-get update
    - apt-get install -y sqlite3 libleveldb-dev jq
    - pip install -r requirements.txt
    # Export identities and wallets
    - ./main.py
    # Export transaction history
    - sqlite3 /dump/duniter_default/txs.db --json "select time,comment,issuers,outputs from txs;" > inputs/transactions_history.json 2>> inputs/txs.err
    - ./generate_transactions_history.py
    # Merge in one file
    - 'jq -s "{ identities: .[0].identities, wallets: .[0].wallets, initial_monetary_mass: .[0].initial_monetary_mass, current_block: .[0].current_block, transactions_history: .[1] }" output/gtest_genesis.json output/history.json > output/g1-data.json'
    # Make the exported file available for next jobs
    - mkdir -p $CI_PROJECT_DIR/release/
    - cp output/g1-data.json $CI_PROJECT_DIR/release/
  artifacts:
    paths:
      - $CI_PROJECT_DIR/release/
  tags:
    - kepler

.build_specs:
  stage: build
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
  image: rust:1-bullseye
  variables:
    WASM_FILE: $CI_PROJECT_DIR/release/${RUNTIME}_runtime.compact.compressed.wasm
    DUNITER_GENESIS_DATA: $CI_PROJECT_DIR/release/g1-data.json
    DUNITER_GENESIS_EXPORT: $CI_PROJECT_DIR/release/${RUNTIME}-indexer.json
    DEBIAN_FRONTEND: noninteractive
  script:
    - apt-get update
    - apt-get install -y clang cmake protobuf-compiler
    - cargo run ${FEATURES} -- build-spec --chain=${RUNTIME}_live > release/${RUNTIME}.json
    - cargo run ${FEATURES} -- build-spec --chain=release/${RUNTIME}.json --disable-default-bootnode --raw > release/${RUNTIME}-raw.json
    - cp node/specs/${RUNTIME}_client-specs.yaml release/
  artifacts:
    name: "runtime"
    paths:
      - $CI_PROJECT_DIR/release
  tags:
    - kepler

gdev_specs:
  extends: .build_specs
  needs:
    - gdev_srtool
    - create_g1_data
  variables:
    RUNTIME: gdev

gtest_specs:
  extends: .build_specs
  needs:
    - gtest_srtool
    - create_g1_data
  variables:
    RUNTIME: gtest
    FEATURES: --features gtest --no-default-features

############## RELEASE ##############

create_release:
  stage: release
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
      needs: ["create_g1_data", "gdev_srtool", "gtest_srtool"]
      when: manual
  image: rust:1-bullseye
  variables:
    SRTOOL_OUTPUT_GDEV: $CI_PROJECT_DIR/release/srtool_output_gdev.json
    SRTOOL_OUTPUT_GTEST: $CI_PROJECT_DIR/release/srtool_output_gtest.json
    SRTOOL_OUTPUT_G1: $CI_PROJECT_DIR/release/srtool_output_g1.json
  script:
    # Release creation
    - export MILESTONE=$(echo $CI_COMMIT_BRANCH | sed -e "s/release\///g")
    - cargo xtask release-runtime $MILESTONE $CI_COMMIT_BRANCH
    # We always ship runtimes: this is both a proof and a convenience
    - cargo xtask create-asset-link $MILESTONE g1-data.json https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/g1-data.json
    - cargo xtask create-asset-link $MILESTONE gdev_runtime.compact.compressed.wasm https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/gdev_runtime.compact.compressed.wasm
    - cargo xtask create-asset-link $MILESTONE gtest_runtime.compact.compressed.wasm https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/gtest_runtime.compact.compressed.wasm
    - cargo xtask create-asset-link $MILESTONE gdev_client-specs.yaml https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/gdev_client-specs.yaml
    - cargo xtask create-asset-link $MILESTONE gtest_client-specs.yaml https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/gtest_client-specs.yaml
  artifacts:
    paths:
      - $CI_PROJECT_DIR/release/
  tags:
    - kepler

# ------ RELEASE: ADD SPECS ------

.release_specs:
  stage: release
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH =~ /^(release\/runtime-)[0-9].*/
  image: rust:1-bullseye
  script:
    - export MILESTONE=$(echo $CI_COMMIT_BRANCH | sed -e "s/release\///g")
    - cargo xtask create-asset-link $MILESTONE ${RUNTIME}.json https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/${RUNTIME}.json
    - cargo xtask create-asset-link $MILESTONE ${RUNTIME}-raw.json https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/${RUNTIME}-raw.json
    - cargo xtask create-asset-link $MILESTONE ${RUNTIME}-indexer.json https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/$CI_JOB_ID/artifacts/release/${RUNTIME}-indexer.json
    - echo "Release Docker file..."
  artifacts:
    paths:
      - $CI_PROJECT_DIR/release/
  tags:
    - kepler

release_gdev_specs:
  extends: .release_specs
  needs:
    - create_release
    - gdev_specs
  variables:
    RUNTIME: gdev

release_gtest_specs:
  extends: .release_specs
  needs:
    - create_release
    - gtest_specs
  variables:
    RUNTIME: gtest
