Repository: MDAnalysis/membrane-curvature (language: python)

Issue:
Set up continuous integration
This repository uses GitHub actions to run tests. To check that the tests added for issue #10 work, the CI suite will need to be set up. The workflow is in `CI.yaml` here: https://github.com/MDAnalysis/membrane-curvature/blob/main/.github/workflows/CI.yaml

In case you're not familiar with GH actions, I've annotated the file with some notes:

```
name: CI
```
Pretty self-explanatory, it's the name that shows up in the [Actions](https://github.com/MDAnalysis/membrane-curvature/actions/workflows/CI.yaml) tab.

```
on:
  # GitHub has started calling new repo's first branch "main" https://github.com/github/renaming
  # Existing codes likely still have "master" as the primary branch
  # Both are tracked here to keep legacy and new codes working
  push:
    branches:
      - "master"
      - "main"
  pull_request:
    branches:
      - "master"
      - "main"
  schedule:
    # Nightly tests run on master by default:
    #   Scheduled workflows run on the latest commit on the default or base branch.
    #   (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule)
    - cron: "0 0 * * *"
```
The `on` section specifies when the CI suite runs. Here it runs whenever you push to branches called "master" or "main". It also runs when a pull request is made to "master" or "main", and then again nightly on "main". You could switch this one off if you want to save some energy.


```
jobs:
  test:
    name: Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [macOS-latest, ubuntu-latest, windows-latest]
        python-version: [3.7, 3.8, 3.9]

    steps:
    - uses: actions/checkout@v1

    - name: Additional info about the build
      shell: bash
      run: |
        uname -a
        df -h
        ulimit -a


    # More info on options: https://github.com/conda-incubator/setup-miniconda
    - uses: conda-incubator/setup-miniconda@v2
      with:
        python-version: ${{ matrix.python-version }}
        environment-file: devtools/conda-envs/test_env.yaml

        channels: conda-forge,defaults

        activate-environment: test
        auto-update-conda: false
        auto-activate-base: false
        show-channel-urls: true

    - name: Install package

      # conda setup requires this special shell
      shell: bash -l {0}
      run: |
        python -m pip install . --no-deps
        conda list


    - name: Run tests

      # conda setup requires this special shell
      shell: bash -l {0}

      run: |
        pytest -v --cov=mdakit_membcurv --cov-report=xml --color=yes mdakit_membcurv/tests/

    - name: CodeCov
      uses: codecov/codecov-action@v1
      with:
        file: ./coverage.xml
        flags: unittests
        name: codecov-${{ matrix.os }}-py${{ matrix.python-version }}
```

The `jobs` section specifies which jobs are actually run. The first test job is called `Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}`, using [variable substitution](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions) to make names like `Test on macOS-latest, Python 3.7`. The `runs-on` tells GH which machine or operating system to run the test on. The `strategy` and `matrix` tells GH which potential options to use for `matrix.python-version` and `matrix.os`. 

The next part of the job specification, `steps`, is a list of steps that starts from `- uses: actions/checkout@v1` and encompasses the rest of the file. In the yaml format, `-` denotes an item in a list and `:` denotes a key-value pair like a dictionary, so each item in the `steps` list is a dictionary that can have keys and values in any order. Therefore it's a bit random which key is shown for each step, although defining the `name` first is probably best for readability.

1. `- uses: actions/checkout@v1`
This checks out the current branch of the repository, so tests are being run with your updated code.

2. `- name: Additional info about the build`
In this step the commands ``uname -a; df -h ; ulimit -a`` are run in a bash shell to tell us more about the machine. This is very helpful for troubleshooting if tests are failing for an unexpected reason.

3. `- uses: conda-incubator/setup-miniconda@v2`
This installs a conda environment from `devtools/conda-envs/test_env.yaml` (https://github.com/MDAnalysis/membrane-curvature/blob/main/devtools/conda-envs/test_env.yaml) . When you start using packages like numpy, you'll need to add them to that conda environment so that they'll get installed in the test environment.

4. `- name: Install package`
This installs the membrane-curvature package from `setup.py`.

5. `- name: Run tests`
This actually runs the tests in the test suite!

6. `- name: CodeCov`
This uses codecov to check how much of the code is covered by tests.


Most of the suite has already been set up in this file. However there are some changes you can make:

- [x] Update https://github.com/MDAnalysis/membrane-curvature/blob/main/devtools/conda-envs/test_env.yaml to include the packages you'll need
- [x] Add `fail-fast: false` to the `strategy` section, like in the MDAnalysis repo: https://github.com/MDAnalysis/mdanalysis/blob/a6d4ffc26375a44d4aaa53de88d193b9e1e645e9/.github/workflows/gh-ci.yaml#L35
- [x] Add `concurrency` groups, like in the MDAnalysis repo: https://github.com/MDAnalysis/mdanalysis/blob/a6d4ffc26375a44d4aaa53de88d193b9e1e645e9/.github/workflows/gh-ci.yaml#L12-L17


(The MDAnalysis GH actions file is a lot messier than this one, but luckily this repo doesn't need all that complexity).

The `fail-fast` addition means that even if one test run fails, the others don't get cancelled immediately. The `concurrency` addition means that if you push to a branch before the tests have finished running, those running tests get cancelled in favour of the updated code. Running the tests does require electricity so this will save a 🌴 or two.


Discussion / hints:
I thought I had written this earlier but it looks like I forgot to post it 🙃 

Just two follow things that I would suggest doing (after the things @lilyminium has mentioned).

1. As detailed in @lilyminium's explanation `master` isn't really applicable to new repositories such as this one (older repositories used to have their primary branch named `master` by default). To maintain a CI file that's easier to read for others I would suggest removing `master` branch entries.

2. At least for now, the majority of your CI runner time will be spent doing environment setup. It is likely worth testing if adding `mamba-version: "*"` to `uses: conda-incubator/setup-miniconda@v2`'s `with` section speeds things up. **Note: using `mamba` instead of `conda` for CI is a balancing act since `mamba` takes longer to install but installs dependencies faster**.


Fix patch:
diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml
index 8aff918..9f6a552 100644
--- a/.github/workflows/CI.yaml
+++ b/.github/workflows/CI.yaml
@@ -1,28 +1,28 @@
 name: CI
 
 on:
-  # GitHub has started calling new repo's first branch "main" https://github.com/github/renaming
-  # Existing codes likely still have "master" as the primary branch
-  # Both are tracked here to keep legacy and new codes working
   push:
     branches:
-      - "master"
       - "main"
   pull_request:
     branches:
-      - "master"
       - "main"
-  schedule:
+  # schedule:
     # Nightly tests run on master by default:
     #   Scheduled workflows run on the latest commit on the default or base branch.
     #   (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule)
-    - cron: "0 0 * * *"
+    # - cron: "0 0 * * *"
+
+concurrency:
+  group: "${{ github.ref }}-${{ github.head_ref }}"
+  cancel-in-progress: true
 
 jobs:
   test:
     name: Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}
     runs-on: ${{ matrix.os }}
     strategy:
+      fail-fast: false
       matrix:
         os: [macOS-latest, ubuntu-latest, windows-latest]
         python-version: [3.7, 3.8, 3.9]
@@ -43,8 +43,8 @@ jobs:
       with:
         python-version: ${{ matrix.python-version }}
         environment-file: devtools/conda-envs/test_env.yaml
-
-        channels: conda-forge,defaults
+        mamba-version: "*"
+        channels: conda-forge, defaults
 
         activate-environment: test
         auto-update-conda: false


Test patch:
diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml
index c79a37b..1ccbb07 100644
--- a/devtools/conda-envs/test_env.yaml
+++ b/devtools/conda-envs/test_env.yaml
@@ -1,13 +1,14 @@
 name: test
 channels:
-
   - conda-forge
-
   - defaults
 dependencies:
-    # Base depends
   - python
   - pip
+  - numpy
+  - MDAnalysis
+  - mdtraj # temporary; remove after refactoring
+  - sphinx
 
     # Testing
   - pytest