Diff of /.circleci/config.yml [000000] .. [7f9fb8]

Switch to unified view

a b/.circleci/config.yml
1
# By default, for PRs CircleCI will build only examples that have changed.
2
# For main commits, builds are skipped entirely, as we only do full builds
3
# scheduled for one time daily.
4
#
5
# Tagging a commit with the following overrides these behaviors:
6
# - [circle front] will run the front page examples and perform test-doc
7
# - [circle full] will run all examples and perform test-doc
8
# - [circle linkcheck] will run our linkcheck job
9
# - [circle deploy] on a main or maint/* commit will try to immediately build
10
#   and deploy docs rather than waiting for the nightly build
11
12
version: 2.1
13
14
_check_skip: &check_skip
15
  name: Check-skip
16
  command: |
17
    set -e
18
    export COMMIT_MESSAGE=$(git log --format=oneline -n 1);
19
    if [[ "$CIRCLE_PULL_REQUEST" != "" ]] && ([[ "$COMMIT_MESSAGE" == *"[skip circle]"* ]] || [[ "$COMMIT_MESSAGE" == *"[circle skip]"* ]]); then
20
      echo "Skip detected, exiting job ${CIRCLE_JOB} for PR ${CIRCLE_PULL_REQUEST}."
21
      circleci-agent step halt;
22
    fi
23
24
jobs:
25
  build_docs:
26
    parameters:
27
      scheduled:
28
        type: string
29
        default: "false"
30
    machine:
31
      image: ubuntu-2404:current
32
    # large 4 vCPUs 15GB mem
33
    # https://discuss.circleci.com/t/changes-to-remote-docker-reporting-pricing/47759
34
    resource_class: large
35
    steps:
36
      - restore_cache:
37
          keys:
38
            - source-cache
39
      - checkout
40
      - run:
41
          name: Complete checkout
42
          command: |
43
            set -e
44
            if ! git remote -v | grep upstream; then
45
              git remote add upstream https://github.com/mne-tools/mne-python.git
46
            fi
47
            git remote set-url upstream https://github.com/mne-tools/mne-python.git
48
            git fetch upstream
49
      - save_cache:
50
          key: source-cache
51
          paths:
52
            - ".git"
53
      - run:
54
          <<: *check_skip
55
      - run:
56
          name: Merge with upstream and triage run
57
          command: |
58
            set -e
59
            echo $(git log -1 --pretty=%B) | tee gitlog.txt
60
            echo ${CI_PULL_REQUEST//*pull\//} | tee merge.txt
61
            if [[ $(cat merge.txt) != "" ]]; then
62
              echo "Merging $(cat merge.txt)";
63
              git pull --ff-only upstream "refs/pull/$(cat merge.txt)/merge";
64
            else
65
              if [[ "$CIRCLE_BRANCH" == "main" ]]; then
66
                KIND=dev
67
              else
68
                KIND=stable
69
              fi
70
              export COMMIT_MESSAGE=$(git log --format=oneline -n 1);
71
              if [[ "<< parameters.scheduled >>" == "true" ]]; then
72
                echo "Scheduled full build detected, checking if it's required."
73
                wget https://mne.tools/${KIND}/_version.txt;
74
                REMOTE_VERSION=$(cat _version.txt)
75
                THIS_VERSION=$(git rev-parse HEAD)
76
                echo "Current ${KIND} SHA: ${REMOTE_VERSION}"
77
                echo "This    ${KIND} SHA: ${THIS_VERSION}"
78
                if [[ "${THIS_VERSION}" != "${REMOTE_VERSION}" ]]; then
79
                  echo "Rebuild required."
80
                else
81
                  echo "Rebuild skipped."
82
                  circleci-agent step halt;
83
                fi
84
              elif [[ "$COMMIT_MESSAGE" == *"[circle deploy]"* ]]; then
85
                echo "Forced deployed build detected, building and deploying docs";
86
              else
87
                echo "Waiting until scheduled run to build ${KIND} docs, exiting job ${CIRCLE_JOB}."
88
                circleci-agent step halt;
89
              fi
90
            fi
91
92
      - run:
93
          name: Set BASH_ENV
94
          command: ./tools/circleci_bash_env.sh
95
96
      - run:
97
          name: check neuromag2ft
98
          command: |
99
            neuromag2ft --version
100
101
      - run:
102
          name: Install fonts needed for diagrams
103
          command: |
104
            mkdir -p $HOME/.fonts
105
            echo "Source Code Pro"
106
            curl https://codeload.github.com/adobe-fonts/source-code-pro/tar.gz/2.038R-ro/1.058R-it/1.018R-VAR | tar xz -C $HOME/.fonts
107
            echo "Source Sans Pro"
108
            curl https://codeload.github.com/adobe-fonts/source-sans/tar.gz/3.028R | tar xz -C $HOME/.fonts
109
            fc-cache -f
110
111
      # Load pip cache
112
      - restore_cache:
113
          keys:
114
            - pip-cache-0
115
      - restore_cache:
116
          keys:
117
            - user-install-bin-cache-310
118
119
      # Hack in uninstalls of libraries as necessary if pip doesn't do the right thing in upgrading for us...
120
      - run:
121
          name: Get Python running
122
          command: |
123
            ./tools/circleci_dependencies.sh
124
125
      - save_cache:
126
          key: pip-cache-0
127
          paths:
128
            - ~/.cache/pip
129
      - save_cache:
130
          key: user-install-bin-cache-310
131
          paths:
132
            - ~/.local/lib/python3.10/site-packages
133
            - ~/.local/bin
134
135
      - run:
136
          name: Check Qt
137
          command: |
138
            ./tools/check_qt_import.sh PyQt6
139
      # Load tiny cache so that ~/.mne does not need to be created below
140
      - restore_cache:
141
          keys:
142
            - data-cache-tiny-0
143
144
      # Look at what we have and fail early if there is some library conflict
145
      - run:
146
          name: Check installation
147
          command: |
148
              which python
149
              QT_DEBUG_PLUGINS=1 mne sys_info -pd
150
              python -c "import numpy; numpy.show_config()"
151
              python -c "import dipy.align.metrics"
152
              LIBGL_DEBUG=verbose python -c "import pyvistaqt; pyvistaqt.BackgroundPlotter(show=True)"
153
              python -c "import mne; mne.set_config('MNE_USE_CUDA', 'false')"  # this is needed for the config tutorial
154
              python -c "import mne; mne.set_config('MNE_LOGGING_LEVEL', 'info')"
155
              python -c "import mne; level = mne.get_config('MNE_LOGGING_LEVEL'); assert level.lower() == 'info', repr(level)"
156
      - run:
157
          name: List packages
158
          command: python -m pip list
159
160
      # Figure out if we should run a full build or specify a pattern
161
      - restore_cache:
162
          keys:
163
            - data-cache-tiny-1
164
      - restore_cache:
165
          keys:
166
            - data-cache-multimodal
167
      - restore_cache:
168
          keys:
169
            - data-cache-limo
170
      - restore_cache:
171
          keys:
172
            - data-cache-fsaverage
173
      - restore_cache:
174
          keys:
175
            - data-cache-bst-raw
176
      - restore_cache:
177
          keys:
178
            - data-cache-bst-phantom-ctf
179
      - restore_cache:
180
          keys:
181
            - data-cache-bst-phantom-elekta
182
      - restore_cache:
183
          keys:
184
            - data-cache-bst-phantom-kernel
185
      - restore_cache:
186
          keys:
187
            - data-cache-bst-auditory
188
      - restore_cache:
189
          keys:
190
            - data-cache-bst-resting
191
      - restore_cache:
192
          keys:
193
            - data-cache-fieldtrip
194
      - restore_cache:
195
          keys:
196
            - data-cache-somato
197
      - restore_cache:
198
          keys:
199
            - data-cache-hf-sef
200
      - restore_cache:
201
          keys:
202
            - data-cache-opm
203
      - restore_cache:
204
          keys:
205
            - data-cache-sample
206
      - restore_cache:
207
          keys:
208
            - data-cache-spm-face
209
      - restore_cache:
210
          keys:
211
            - data-cache-testing
212
      - restore_cache:
213
          keys:
214
            - data-cache-visual
215
      - restore_cache:
216
          keys:
217
            - data-cache-ucl-opm-auditory
218
      - restore_cache:
219
          keys:
220
            - data-cache-phantom-kit
221
      - restore_cache:
222
          keys:
223
            - data-cache-ds004388
224
      - run:
225
          name: Get data
226
          # This limit could be increased, but this is helpful for finding slow ones
227
          # (even ~2GB datasets should be downloadable in this time from good
228
          # providers)
229
          no_output_timeout: 10m
230
          command: |
231
            ./tools/circleci_download.sh
232
      - run:
233
          name: Verify build type
234
          command: |
235
            echo "PATTERN=$(cat pattern.txt)"
236
            echo "BUILD=$(cat build.txt)"
237
            ls -al ~/mne_data;
238
239
      # Run doctest (if it's full or front) before building the docs
240
      - run:
241
          name: make test-doc
242
          command: |
243
            if [[ $(cat gitlog.txt) == *"[circle front]"* ]] || [[ $(cat build.txt) == "html-memory" ]] ; then
244
              make test-doc;
245
              mkdir -p doc/_build/test-results/test-doc;
246
              cp junit-results.xml doc/_build/test-results/test-doc/junit.xml;
247
            fi;
248
      # Build docs
249
      - run:
250
          name: make html
251
          command: |  # we have -o pipefail in #BASH_ENV so we should be okay
252
            set -x
253
            PATTERN=$(cat pattern.txt) make -C doc $(cat build.txt) 2>&1 | tee sphinx_log.txt
254
      - run:
255
          name: Check sphinx log for warnings (which are treated as errors)
256
          when: always
257
          command: |
258
            ! grep "^.*\(WARNING\|ERROR\): " sphinx_log.txt
259
      - run:
260
          name: Show profiling output
261
          when: always
262
          command: |
263
            if compgen -G "doc/*.dat" > /dev/null; then
264
              mkdir -p doc/generated
265
              mprof plot doc/*.dat --output doc/generated/memory.png
266
            else
267
              echo "No profile data found in doc/"
268
            fi
269
      - run:
270
          name: Sanity check system state
271
          command: |
272
            python -c "import mne; level = mne.get_config('MNE_LOGGING_LEVEL'); assert level.lower() == 'info', repr(level)"
273
274
      # Reduce upload time of artifacts we will (almost) never look at
275
      - run:
276
          name: Reduce artifact upload time
277
          command: |
278
            if grep -q html-pattern-memory build.txt; then
279
              zip -rm doc/_build/html/_downloads.zip doc/_build/html/_downloads
280
            fi
281
            for NAME in generated auto_tutorials auto_examples; do
282
              zip -rm doc/${NAME}.zip doc/${NAME}
283
            done
284
285
      # Save the JUnit file
286
      - store_test_results:
287
          path: doc/_build/test-results
288
      - store_artifacts:
289
          path: doc/_build/test-results
290
          destination: test-results
291
      # Save the SG RST
292
      - store_artifacts:
293
          path: doc/auto_examples.zip
294
      - store_artifacts:
295
          path: doc/auto_tutorials.zip
296
      - store_artifacts:
297
          path: doc/generated.zip
298
      # Save the HTML
299
      - store_artifacts:
300
          path: doc/_build/html/
301
          destination: html
302
      - persist_to_workspace:
303
          root: doc/_build
304
          paths:
305
            - html
306
307
      # Keep these separate, maybe better in terms of size limitations (?)
308
      - save_cache:
309
          key: data-cache-tiny-0  # < 100 M, might as well combine
310
          paths:
311
            - ~/.mne
312
            - ~/mne_data/MNE-kiloword-data  # (28 M)
313
            - ~/mne_data/MNE-eegbci-data  # (35 M)
314
            - ~/mne_data/MNE-misc-data  # (39 M)
315
            - ~/mne_data/mTRF_1.5  # (56 M)
316
            - ~/mne_data/MNE-phantom-4DBTi  # (77 M)
317
      - save_cache:
318
          key: data-cache-tiny-1  # more to combine
319
          paths:
320
            - ~/mne_data/MNE-fNIRS-motor-data  # (71 M)
321
            - ~/mne_data/MNE-refmeg-noise-data  # (93 M)
322
            - ~/mne_data/physionet-sleep-data  # (95 M)
323
      - save_cache:
324
          key: data-cache-multimodal
325
          paths:
326
            - ~/mne_data/MNE-multimodal-data  # (240 M)
327
      - save_cache:
328
          key: data-cache-limo
329
          paths:
330
            - ~/mne_data/MNE-limo-data  # (244 M)
331
      - save_cache:
332
          key: data-cache-fsaverage
333
          paths:
334
            - ~/mne_data/MNE-fsaverage-data  # (762 M)
335
      - save_cache:
336
          key: data-cache-bst-raw
337
          paths:
338
            - ~/mne_data/MNE-brainstorm-data/bst_raw  # (830 M)
339
      - save_cache:
340
          key: data-cache-bst-phantom-ctf
341
          paths:
342
            - ~/mne_data/MNE-brainstorm-data/bst_phantom_ctf  # (177 M)
343
      - save_cache:
344
          key: data-cache-bst-phantom-elekta
345
          paths:
346
            - ~/mne_data/MNE-brainstorm-data/bst_phantom_elekta  # (1.4 G)
347
      - save_cache:
348
          key: data-cache-bst-phantom-kernel
349
          paths:
350
            - ~/mne_data/MNE-phantom-kernel-data  # (362 M)
351
      - save_cache:
352
          key: data-cache-bst-auditory
353
          paths:
354
            - ~/mne_data/MNE-brainstorm-data/bst_auditory  # (2.9 G)
355
      - save_cache:
356
          key: data-cache-bst-resting
357
          paths:
358
            - ~/mne_data/MNE-brainstorm-data/bst_resting  # (4.5 G)
359
      - save_cache:
360
          key: data-cache-fieldtrip
361
          paths:
362
            - ~/mne_data/MNE-fieldtrip_cmc-data  # (699 M)
363
      - save_cache:
364
          key: data-cache-somato
365
          paths:
366
            - ~/mne_data/MNE-somato-data  # (750 M)
367
      - save_cache:
368
          key: data-cache-hf-sef
369
          paths:
370
            - ~/mne_data/HF_SEF  # (1.3 G)
371
      - save_cache:
372
          key: data-cache-opm
373
          paths:
374
            - ~/mne_data/MNE-OPM-data  # (1.9 G)
375
      - save_cache:
376
          key: data-cache-sample
377
          paths:
378
            - ~/mne_data/MNE-sample-data  # (3.2 G)
379
      - save_cache:
380
          key: data-cache-spm-face
381
          paths:
382
            - ~/mne_data/MNE-spm-face  # (1.5 G)
383
      - save_cache:
384
          key: data-cache-testing
385
          paths:
386
            - ~/mne_data/MNE-testing-data  # (2.5 G)
387
      - save_cache:
388
          key: data-cache-visual
389
          paths:
390
            - ~/mne_data/MNE-visual_92_categories-data  # (6 G)
391
      - save_cache:
392
          key: data-cache-ucl-opm-auditory
393
          paths:
394
            - ~/mne_data/auditory_OPM_stationary  # (4 G)
395
      - save_cache:
396
          key: data-cache-phantom-kit
397
          paths:
398
            - ~/mne_data/MNE-phantom-KIT-data  # (1 G)
399
      - save_cache:
400
          key: data-cache-ds004388
401
          paths:
402
            - ~/mne_data/ds004388  # (1.8 G)
403
404
405
  linkcheck:
406
    # there are a few files excluded from this for expediency, see Makefile
407
    parameters:
408
      scheduled:
409
        type: string
410
        default: "false"
411
    machine:
412
      image: ubuntu-2404:current
413
    resource_class: large
414
    steps:
415
      - restore_cache:
416
          keys:
417
            - source-cache
418
      - checkout
419
      - run:
420
          name: Check-skip
421
          command: |
422
            export COMMIT_MESSAGE=$(git log --format=oneline -n 1);
423
            if [[ "$COMMIT_MESSAGE" != *"[circle linkcheck]"* ]] && [ "<< parameters.scheduled >>" != "true" ]; then
424
              echo "Skip detected, exiting job ${CIRCLE_JOB}."
425
              circleci-agent step halt;
426
            fi
427
      - run:
428
          name: Set BASH_ENV
429
          command: ./tools/circleci_bash_env.sh
430
      - restore_cache:
431
          keys:
432
            - pip-cache-0
433
      - run:
434
          name: Get Python running
435
          command: |
436
            ./tools/circleci_dependencies.sh
437
      - run:
438
          name: Check installation
439
          command: |
440
            mne sys_info -pd
441
      - run:
442
          name: make linkcheck
443
          no_output_timeout: 40m
444
          command: |
445
            make -C doc linkcheck
446
      - store_artifacts:
447
          path: doc/_build/linkcheck
448
          destination: linkcheck
449
450
451
  deploy:
452
    machine:
453
      image: ubuntu-2404:current
454
    steps:
455
      - attach_workspace:
456
          at: /tmp/build
457
      - restore_cache:
458
          keys:
459
            - website-cache
460
      - run:
461
          name: Set BASH_ENV
462
          command: |
463
            set -e
464
            echo "set -e" >> $BASH_ENV
465
      # Don't try to deploy if nothing is there or not on the right branch
466
      - run:
467
          name: Check docs
468
          command: |
469
            if [ ! -f /tmp/build/html/index.html ] ; then
470
              echo "No files found to upload (build: ${CIRCLE_BRANCH}).";
471
              circleci-agent step halt;
472
            fi;
473
      - run:
474
          name: Fetch docs
475
          command: |
476
            mkdir -p ~/.ssh
477
            echo -e "Host *\nStrictHostKeyChecking no" > ~/.ssh/config
478
            chmod og= ~/.ssh/config
479
            if [ ! -d ~/mne-tools.github.io ]; then
480
              git clone git@github.com:/mne-tools/mne-tools.github.io.git ~/mne-tools.github.io --depth=1
481
            fi
482
      - run:
483
          name: Deploy docs
484
          command: |
485
            git config --global user.email "circle@mne.tools";
486
            git config --global user.name "Circle CI";
487
            cd ~/mne-tools.github.io;
488
            git checkout main
489
            git remote -v
490
            git fetch origin
491
            git reset --hard origin/main
492
            git clean -xdf
493
            if [ "${CIRCLE_BRANCH}" == "main" ]; then
494
              echo "Deploying dev docs for ${CIRCLE_BRANCH}.";
495
              rm -Rf dev;
496
              cp -a /tmp/build/html dev;
497
              git add -A;
498
              git commit -m "CircleCI update of dev docs (${CIRCLE_BUILD_NUM}).";
499
            else
500
              echo "Deploying stable docs for ${CIRCLE_BRANCH}.";
501
              rm -Rf stable;
502
              cp -a /tmp/build/html stable;
503
              git add -A;
504
              git commit -m "CircleCI update of stable docs (${CIRCLE_BUILD_NUM}).";
505
            fi;
506
            git push origin main;
507
      - save_cache:
508
          key: website-cache
509
          paths:
510
            - ~/mne_data/MNE-visual_92_categories-data
511
512
workflows:
513
  default:
514
    jobs:
515
      - build_docs:
516
          name: build_docs
517
      - linkcheck:
518
          name: linkcheck
519
      - deploy:
520
          name: deploy
521
          requires:
522
            - build_docs
523
          filters:
524
            branches:
525
              only:
526
                - main
527
                - /maint\/.*/
528
529
  main:
530
    jobs:
531
      - build_docs:
532
          scheduled: "true"
533
          name: build_docs_main
534
      - deploy:
535
          name: deploy_main
536
          requires:
537
            - build_docs_main
538
    triggers:
539
      - schedule:
540
          # "At 6:00 AM GMT every day"
541
          cron: "0 6 * * *"
542
          filters:
543
            branches:
544
              only:
545
                - main
546
547
  monthly:
548
    jobs:
549
      - linkcheck:
550
          name: linkcheck_monthly
551
          scheduled: "true"
552
    triggers:
553
      - schedule:
554
          # "At 6:00 AM GMT on the first day of each month"
555
          cron: "0 6 1 * *"
556
          filters:
557
            branches:
558
              only:
559
                - main