diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dd5bf99a534f8b3d7cec5173b8332a8af93233ae
--- /dev/null
+++ b/.github/workflows/moodle-ci.yml
@@ -0,0 +1,171 @@
+name: Moodle Plugin CI
+
+on: [push, pull_request]
+
+jobs:
+  static:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        php: ['7.4']
+        moodle-branch: ['MOODLE_311_STABLE']
+        database: ['pgsql']
+
+    steps:
+      - name: Start PostgreSQL
+        run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:9.6
+
+      - name: Check out repository code
+        uses: actions/checkout@v2
+        with:
+          path: plugin
+
+      - name: Setup PHP ${{ matrix.php }}
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          coverage: none
+
+      - name: Get composer cache directory
+        id: composer-cache
+        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+      - name: Composer cache
+        uses: actions/cache@v2
+        with:
+          path: ${{ steps.composer-cache.outputs.dir }}
+          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-composer-
+
+      - name: npm cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-node-
+
+      - name: Initialise moodle-plugin-ci
+        run: |
+          composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
+          echo $(cd ci/bin; pwd) >> $GITHUB_PATH
+          echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
+          sudo locale-gen en_AU.UTF-8
+          echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV
+
+      - name: Install moodle-plugin-ci
+        run: |
+          moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 --no-init
+        env:
+          DB: ${{ matrix.database }}
+          MOODLE_BRANCH: ${{ matrix.moodle-branch }}
+
+      - name: PHP Lint
+        if: ${{ always() }}
+        run: moodle-plugin-ci phplint
+
+      - name: PHP Copy/Paste Detector
+        if: ${{ always() }}
+        run: moodle-plugin-ci phpcpd
+
+      - name: PHP Mess Detector
+        if: ${{ always() }}
+        run: moodle-plugin-ci phpmd
+
+      - name: Moodle Code Checker
+        if: ${{ always() }}
+        run: moodle-plugin-ci codechecker
+
+      - name: Moodle PHPDoc Checker
+        if: ${{ always() }}
+        run: moodle-plugin-ci phpdoc
+
+      - name: Validating
+        if: ${{ always() }}
+        run: moodle-plugin-ci validate
+
+      - name: Check upgrade savepoints
+        if: ${{ always() }}
+        run: moodle-plugin-ci savepoints
+
+      - name: Mustache Lint
+        if: ${{ always() }}
+        run: moodle-plugin-ci mustache
+
+      - name: Grunt
+        if: ${{ always() }}
+        run: moodle-plugin-ci grunt
+
+  test:
+    runs-on: ubuntu-latest
+    needs: static
+
+    strategy:
+      fail-fast: false
+      matrix:
+        php: ['7.3', '7.4']
+        moodle-branch: ['MOODLE_39_STABLE', 'MOODLE_310_STABLE', 'MOODLE_311_STABLE']
+        database: ['mariadb', 'pgsql']
+
+    steps:
+      - name: Start MariaDB
+        if: matrix.database == 'mariadb'
+        run: docker run -p 3306:3306 -e MYSQL_USER=root -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mariadb:10
+
+      - name: Start PostgreSQL
+        if: matrix.database == 'pgsql'
+        run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:9.6
+
+      - name: Check out repository code
+        uses: actions/checkout@v2
+        with:
+          path: plugin
+
+      - name: Setup PHP ${{ matrix.php }}
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          coverage: none
+
+      - name: Get composer cache directory
+        id: composer-cache
+        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+      - name: Composer cache
+        uses: actions/cache@v2
+        with:
+          path: ${{ steps.composer-cache.outputs.dir }}
+          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-composer-
+      - name: npm cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-node-
+
+      - name: Initialise moodle-plugin-ci
+        run: |
+          composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
+          echo $(cd ci/bin; pwd) >> $GITHUB_PATH
+          echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
+          sudo locale-gen en_AU.UTF-8
+          echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV
+
+      - name: Install moodle-plugin-ci
+        run: |
+          moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1
+        env:
+          DB: ${{ matrix.database }}
+          MOODLE_BRANCH: ${{ matrix.moodle-branch }}
+
+      - name: PHPUnit tests
+        if: ${{ always() }}
+        run: moodle-plugin-ci phpunit
+
+      - name: Behat features
+        if: ${{ always() }}
+        run: moodle-plugin-ci behat --profile chrome
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1e94b2598ea3da1ed7f773415bbde0b30b89875a..0000000000000000000000000000000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-language: php
-os: linux
-dist: xenial
-
-addons:
-  postgresql: "9.6"
-
-cache:
-  directories:
-    - $HOME/.composer/cache
-    - $HOME/.npm
-
-services:
-  - mysql
-  - docker
-
-php:
-  - 7.2
-  - 7.3
-  - 7.4
-
-env:
-  jobs:
-    - DB=pgsql MOODLE_BRANCH=MOODLE_35_STABLE
-    - DB=pgsql MOODLE_BRANCH=MOODLE_38_STABLE
-    - DB=pgsql MOODLE_BRANCH=MOODLE_39_STABLE
-    - DB=pgsql MOODLE_BRANCH=MOODLE_310_STABLE
-    - DB=pgsql MOODLE_BRANCH=master
-    - DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
-    - DB=mysqli MOODLE_BRANCH=MOODLE_38_STABLE
-    - DB=mysqli MOODLE_BRANCH=MOODLE_39_STABLE
-    - DB=mysqli MOODLE_BRANCH=MOODLE_310_STABLE
-    - DB=mysqli MOODLE_BRANCH=master
-
-before_install:
-  - phpenv config-rm xdebug.ini
-  - cd ../..
-  - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
-  - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
-
-jobs:
-  fast_finish: true
-  include:
-    # Prechecks against latest Moodle stable only.
-    - stage: static
-      php: 7.4
-      env: DB=mysqli MOODLE_BRANCH=MOODLE_310_STABLE
-      install:
-        - moodle-plugin-ci install --no-init
-      script:
-        - moodle-plugin-ci phpdoc
-        - moodle-plugin-ci phplint
-        - moodle-plugin-ci phpcpd
-        - moodle-plugin-ci phpmd
-        - moodle-plugin-ci codechecker
-        - moodle-plugin-ci validate
-        - moodle-plugin-ci savepoints
-        - moodle-plugin-ci mustache
-        - moodle-plugin-ci grunt
-    # Smaller build matrix for development builds
-    - stage: develop
-      php: 7.4
-      env: DB=mysqli MOODLE_BRANCH=MOODLE_310_STABLE
-  exclude:
-    - php: 7.3
-      env: DB=pgsql MOODLE_BRANCH=MOODLE_35_STABLE
-    - php: 7.3
-      env: DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
-    - php: 7.4
-      env: DB=pgsql MOODLE_BRANCH=MOODLE_35_STABLE
-    - php: 7.4
-      env: DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
-
-# Unit tests and behat tests against full matrix.
-install:
-  - moodle-plugin-ci install
-script:
-  - moodle-plugin-ci phpunit --coverage-clover
-  - moodle-plugin-ci behat
-after_success:
-  - bash <(curl -s https://codecov.io/bash)
-
-stages:
-  - static
-  - name: develop
-    if: branch != master AND (type != pull_request OR head_branch != master) AND (tag IS blank)
-  - name: test
-    if: branch = master OR (type = pull_request AND head_branch = master) OR (tag IS present)
diff --git a/codecov.yml b/codecov.yml
deleted file mode 100644
index 82b29138263a1ae3f7d10c2b5f49b4a99767f21f..0000000000000000000000000000000000000000
--- a/codecov.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-fixes:
-	- "moodle/admin/tool/lifecycle/::"
-ignore:
-    # artificial/Moodle API files
-    - "classes/plugininfo/*"
-    - "tests/**/*"
-    - "lang/**/*"
-    - "db/**/*"
-    - "db/.*"
-    - "version.php"
-    - "step/**/lang"
-    - "step/**/db"
-    - "step/**/settings.php"
-    - "step/**/version.php"
-    - "trigger/**/db"
-    - "trigger/**/lang"
-    - "trigger/**/settings.php"
-    - "trigger/**/version.php"
-    # UI classes
-    - "classes/table/*"
-    - "activeprocesses.php"
-    - "coursebackups.php"
-    - "renderer.php"
-    - "restore.php"
-    - "settings.php"
-    - "adminsettings.php"
-    - "view.php"
\ No newline at end of file