stages:
    - test
    - build
    - analyse
    - build-docs
    - deploy
    - zenodo

## Template for all OpenSCAD jobs to ensure they run the same
.scad-job:
    image: ubuntu:22.04

    variables:
      # prevents config waiting for user input, e.g. for tzdata
      DEBIAN_FRONTEND: noninteractive
      DEBCONF_NONINTERACTIVE_SEEN: "true"

    # Install everything needed for all OpenSCAD jobs so they run in a consistent environment
    before_script:
      - apt-get update -qq
      - apt-get -o DPkg::Options::=--force-confdef -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates python3-pip python-is-python3 git xvfb imagemagick unzip inkscape wget
      - wget http://archive.ubuntu.com/ubuntu/pool/universe/o/openscad/openscad_2021.01-4build1_amd64.deb -O /tmp/openscad_2021.01-4build1_amd64.deb
      - apt -o DPkg::Options::=--force-confdef -y -qq install /tmp/openscad_2021.01-4build1_amd64.deb
      - pip3 install -r requirements.txt

# Unit testing of the scad library functions
scad-lib-tests:
    extends: .scad-job
    stage: test

    script:
      - openscad/libs/test/test_dict.py

    only:
      - tags
      - merge_requests
      - web
      - master

# Code quality runs SCA2D to do static analysis of the .scad code 
code_quality:
    stage: test
    image: python:3.12
    allow_failure: true
    script:
      - pip install sca2d
      - sca2d --colour --gitlab-report openscad/
    artifacts:
        reports:
            codequality:
              - gl-code-quality-report.json
        expire_in: 1 week
    # Note this runs more often than others, this is to make sure that the result
    # both the head and base of merge requests have code quality reports to allow the
    # MR quality changes to display
    only:
      - tags
      - merge_requests
      - web
      - branches
      - master

lint_build_system:
    stage: test
    image: python:3.12
    script:
      - pip install -r requirements.txt
      - ./lint_build_system.py
    only:
      - tags
      - merge_requests
      - web
      - master

# Build STL files
build:
    extends: .scad-job
    stage: build

    script:
      - git clone --depth=1 https://gitlab.com/openflexure/openflexure-microscope-extra
      # Some files seem to appear changed even though they shouldn't be which
      # messes up our auto version-string embeddeding, so we do a hard git reset
      # see https://gitlab.com/gitlab-org/gitlab/-/issues/325299
      - git reset --hard
      # Build STL files with OpenSCAD
      - mkdir -p /root/.local/share
      - ./build.py --include-extra-files --force-clean
      - python3 -m build_system.hash_csg_files docs/models -o docs/models/dependency_hashes.yaml
      - ./archive_stls.py
    
    cache:
      - key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
        paths:
          - docs/models/**/*.stl
          - docs/models/dependency_hashes.yaml

    artifacts:
      expire_in: 1 week
      name: "${CI_PROJECT_NAME}-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}"
      paths:
        - docs/models/**/*.stl
        - docs/all-stls.zip
        - docs/models/*.yaml

    only:
      - tags
      - merge_requests
      - web
      - master

archive-source:
    stage: build
    image: python:3.12

    script:
      - git clean -dfX
      - rm -rf .git
      - python3 -c "import shutil; shutil.make_archive('/tmp/source', 'zip', '.')"
      - mv /tmp/source.zip docs/

    artifacts:
      expire_in: 1 week
      name: "${CI_PROJECT_NAME}-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}"
      paths:
        - docs/source.zip

    only:
      - tags
      - merge_requests
      - web
      - master

check_stls:
    stage: analyse
    # This is Python 3.7 still as admesh is not compiled for newer python
    image: python:3.7
    needs: ["build"]
    dependencies: ["build"]
    allow_failure: true
    variables:
      # prevents config waiting for user input, e.g. for tzdata
      DEBIAN_FRONTEND: noninteractive
      DEBCONF_NONINTERACTIVE_SEEN: "true"
    before_script:
      - apt-get update -qq
      - apt-get -o DPkg::Options::=--force-confdef -y -qq install admesh
    script:
      - pip install colorama==0.4.3
      - pip install admesh==0.98.9
      - ./check_stls.py docs/models/
    only:
      - tags
      - merge_requests
      - web
      - master
    artifacts:
      when: always
      reports:
        junit: admesh_report.xml

# render assemblies - uses xvfb as a virtual x-server
render:
    extends: .scad-job
    stage: build
    dependencies: ["build"]
    needs: ["build"]

    script:
      - xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" ./render.py
      - mkdir -p docs/gltf
      - pip install scad2gltf
      - cd rendering
      - scad2gltf complete_microscope_rms.scad
      - scad2gltf complete_microscope_low_cost.scad
      - cp complete_microscope_*.glb ../docs/gltf/

    artifacts:
      expire_in: 1 week
      name: "${CI_PROJECT_NAME}-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}-renders"
      paths:
        - docs/renders/*.png
        - docs/gltf/*

    only:
      - tags
      - merge_requests
      - web
      - master


# Build docs- this is at a later stage so it has access to the models
build-docs:
    stage: build-docs
    dependencies:
      - build
      - render
      - archive-source
    needs: ["build", "render", "archive-source"]
    image: "python:3.12"

    before_script:
      - python --version
      #This can be removed onece we update to GitBuilding 0.15
      - pip install setuptools
      - pip install "gitbuilding>=0.14.0"

    script:
      - cd docs
      # The .yaml extension confuses gitbuilding, for now I'll just gzip it to get around that.
      - gzip models/dependency_hashes.yaml
      - gitbuilding build-html --hardwarnings
      - cd ..
      - mv docs/_site builds
      - echo "JOB_ID=$CI_JOB_ID" > build-docs.env

    artifacts:
      expire_in: 1 week
      name: "${CI_PROJECT_NAME}-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}-docs"
      paths:
        - builds/
      reports:
        dotenv: build-docs.env

    # This exposes a link to the built docs.  The mechanism is intended to support deployment to an 
    # external server, but I don't think that should be necessary here, as it's just a static
    # site.
    environment:
      name: review/$CI_COMMIT_REF_SLUG
      url: https://openflexure.gitlab.io/-/openflexure-microscope/-/jobs/$JOB_ID/artifacts/builds/index.html

    only:
      - tags
      - merge_requests
      - web
      - master


# Deploy to builds.openflexure.org
deploy:
  stage: deploy
  dependencies:
    - build
    - render
    - build-docs
  image: ubuntu:latest

  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - chmod 400 "$OPENFLEXURE_BUILD_SERVER_SSH_KEY"
    - ssh-add "$OPENFLEXURE_BUILD_SERVER_SSH_KEY"
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host buildserver\n\tHostname build.openflexure.org\n\tUser gitlab-ci-user\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config

  script:
    # Install rsync if not already installed
    - 'which rsync || ( apt-get update -y && apt-get install rsync -y )'

    # Upload the builds folder to openflexure-microscope builds
    - rsync -hrvz -e ssh builds/ buildserver:builds/openflexure-microscope/${CI_COMMIT_REF_NAME} --delete

    # Zip the builds folder and upload it to the openflexure-microscope build root
    - 'which zip || ( apt-get update -y && apt-get install zip -y )'
    - (cd builds && zip -r "../${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip" .)
    - rsync -hrvz -e ssh "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip" buildserver:builds/openflexure-microscope/

    # Run update-latest.py on the build server
    - ssh -t buildserver "~/update-latest.sh"

  artifacts:
    expire_in: 1 week
    name: "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip"
    paths:
      - "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip"

  only:
    - tags
    - web
    - master

zenodo:
  stage: zenodo
  image: ubuntu:18.04
  dependencies:
    - deploy
  before_script:
    - apt-get update -qq
    - apt-get -y -qq install git python3-pip
    - pip3 install -r scripts/zenodo/requirements.txt
  variables:
    ZENODO_USE_SANDBOX: "false"
  script:
    - mv "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip" "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-outputs.zip"
    - git archive "${CI_COMMIT_REF_NAME}" --format=zip --output="${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-source.zip"
    - python3 scripts/zenodo/upload_to_zenodo.py "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-source.zip" "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-outputs.zip"
  artifacts:
    # this is only a small html link, let's just keep it forever
    # gitlab doesn't understand "expire_in: never" yet though
    expire_in: 100000 years
    name: zenodo-${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-link.html
    paths:
      - zenodo-link.html
  only:
    - tags
