diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4a1983601ee1e177a8339098ff2507a84f9ee4fb..188878c08944a85ad2f2f57818b4755a4d3e5bbc 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,6 +13,7 @@ env:
   DOCKER_REPO: renovate/renovate
   YARN_CACHE_KEY: v1
   BUILDX_VERSION: v0.3.1
+  NODE_VERSION: 12
   # https://github.com/chalk/supports-color/issues/106
   FORCE_COLOR: true
 
@@ -40,7 +41,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
-        node-version: [10, 12]
+        node-version: [12, 10]
         python-version: [3.8]
         java-version: [11]
         exclude:
@@ -49,26 +50,29 @@ jobs:
 
     env:
       coverage: ${{ matrix.os == 'ubuntu-latest' && matrix.node-version == 12 }}
+      NODE_VERSION: ${{ matrix.node-version }}
+      PYTHON_VERSION: ${{ matrix.python-version }}
+      JAVA_VERSION: ${{ matrix.java-version }}
 
     steps:
-      - name: Set up Node.js ${{ matrix.node-version }}
+      - name: Set up Node.js ${{ env.NODE_VERSION }}
         uses: actions/setup-node@v1
         with:
-          node-version: ${{ matrix.node-version }}
+          node-version: ${{ env.NODE_VERSION }}
 
-      - name: Set up Python ${{ matrix.python-version }}
+      - name: Set up Python ${{ env.PYTHON_VERSION }}
         uses: actions/setup-python@v1
         with:
-          python-version: ${{ matrix.python-version }}
+          python-version: ${{ env.PYTHON_VERSION }}
 
-      - name: Set up Java ${{ matrix.java-version }}
-        if: matrix.node-version == 12 && github.ref != 'refs/heads/master'
+      - name: Set up Java  ${{ env.JAVA_VERSION }}
+        if: env.NODE_VERSION == '12'
         uses: actions/setup-java@v1
         with:
-          java-version: ${{ matrix.java-version }}
+          java-version: ${{ env.JAVA_VERSION }}
 
       - name: Skip Java tests
-        if: matrix.node-version != 12 || github.ref == 'refs/heads/master'
+        if: env.NODE_VERSION != '12'
         run: echo "::set-env name=SKIP_JAVA_TESTS::true"
 
       - name: Init platform
@@ -101,18 +105,18 @@ jobs:
         uses: actions/cache@v1
         with:
           path: node_modules
-          key: ${{ runner.os }}-${{ matrix.node-version }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          key: ${{ runner.os }}-${{ env.NODE_VERSION }}-yarn-${{ hashFiles('**/yarn.lock') }}
           restore-keys: |
-            ${{ runner.os }}-${{ matrix.node-version }}-yarn-
+            ${{ runner.os }}-${{ env.NODE_VERSION }}-yarn-
 
       - name: Cache pip packages
         id: pip_cache_packages
         uses: actions/cache@v1
         with:
           path: ${{ steps.init.outputs.pip_cache }}
-          key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('**/requirements.txt') }}
+          key: ${{ runner.os }}-${{ env.PYTHON_VERSION }}-pip-${{ hashFiles('**/requirements.txt') }}
           restore-keys: |
-            ${{ runner.os }}-${{ matrix.python-version }}-pip-
+            ${{ runner.os }}-${{ env.PYTHON_VERSION }}-pip-
 
       # Clear caches on cache miss, otherwise they will grow indefinitely
       - name: Clear yarn cache
@@ -154,21 +158,17 @@ jobs:
         run: yarn test-e2e
 
   lint:
-    runs-on: ${{ matrix.os }}
+    needs: [cleanup]
+    runs-on: ubuntu-latest
 
     # lint shouldn't need more than 10 min
     timeout-minutes: 10
 
-    strategy:
-      matrix:
-        os: [ubuntu-latest]
-        node-version: [12]
-
     steps:
-      - name: Set up Node.js ${{ matrix.node-version }}
+      - name: Set up Node.js ${{ env.NODE_VERSION }}
         uses: actions/setup-node@v1
         with:
-          node-version: ${{ matrix.node-version }}
+          node-version: ${{ env.NODE_VERSION }}
 
       - name: Init platform
         id: init
@@ -198,9 +198,9 @@ jobs:
         uses: actions/cache@v1
         with:
           path: node_modules
-          key: ${{ runner.os }}-${{ matrix.node-version }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          key: ${{ runner.os }}-${{ env.NODE_VERSION }}-yarn-${{ hashFiles('**/yarn.lock') }}
           restore-keys: |
-            ${{ runner.os }}-${{ matrix.node-version }}-yarn-
+            ${{ runner.os }}-${{ env.NODE_VERSION }}-yarn-
 
       # Clear caches on cache miss, otherwise they will grow indefinitely
       - name: Clear yarn cache
@@ -256,6 +256,68 @@ jobs:
   release:
     needs: [lint, test, test-docker]
     runs-on: ubuntu-latest
-    timeout-minutes: 5
+    # release shouldn't need more than 30 min
+    timeout-minutes: 30
+
     steps:
-      - run: echo "Release"
+      - name: Set up Node.js ${{ env.NODE_VERSION }}
+        uses: actions/setup-node@v1
+        with:
+          node-version: ${{ env.NODE_VERSION }}
+
+      - name: Init platform
+        id: init
+        run: |
+          echo "::set-output name=yarn_cache::$(yarn cache dir)"
+          git config --global core.autocrlf false
+          git config --global core.symlinks true
+          git config --global user.email 'bot@renovateapp.com'
+          git config --global user.name  'Renovate Bot'
+          yarn config set version-git-tag false
+
+      - uses: actions/checkout@v2
+
+      - name: Cache Yarn packages
+        id: yarn_cache_packages
+        uses: actions/cache@v1
+        with:
+          path: ${{ steps.init.outputs.yarn_cache }}
+          key: ${{ env.YARN_CACHE_KEY }}-${{ runner.os }}-yarn_cache-${{ hashFiles('**/yarn.lock') }}
+
+      - name: Cache node_modules
+        uses: actions/cache@v1
+        with:
+          path: node_modules
+          key: ${{ runner.os }}-${{ env.NODE_VERSION }}-yarn-${{ hashFiles('**/yarn.lock') }}
+
+      - name: Installing dependencies
+        run: yarn install --frozen-lockfile --link-duplicates
+
+      - name: Build
+        run: yarn build
+
+      - name: Set up Docker Buildx ${{ env.BUILDX_VERSION }}
+        uses: crazy-max/ghaction-docker-buildx@v1
+        with:
+          version: ${{ env.BUILDX_VERSION }}
+
+      - name: Docker registry login
+        run: echo "${{ secrets.DOCKER_RENOVATERELEASE_TOKEN }}" | docker login -u renovaterelease --password-stdin
+
+      - name: Update Docker images cache
+        continue-on-error: true
+        if: ${{github.ref == 'refs/heads/master'}}
+        run: |
+          docker buildx bake \
+            --file docker/bake.hcl \
+            --set latest.cache-to=type=registry,ref=renovate/docker-build-cache:renovate-latest,mode=max \
+            --set slim.cache-to=type=registry,ref=renovate/docker-build-cache:renovate-slim,mode=max \
+            default
+
+      - name: semantic-release
+        run: |
+          echo '//registry.yarnpkg.com/:_authToken=${NPM_TOKEN}' > ~/.npmrc
+          yarn semantic-release --dry-run ${{github.ref != 'refs/heads/master'}}
+        env:
+          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
+          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 9d5c56481730b77e3c9bfb03edf2353ad4bad9e9..0000000000000000000000000000000000000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-name: Release CI
-
-on:
-  push:
-    branches:
-      - master
-
-env:
-  PLATFORM: linux/amd64
-  DOCKER_REPO: renovate/renovate
-  SKIP_JAVA_TESTS: true
-  BUILDX_VERSION: v0.3.1
-  # https://github.com/chalk/supports-color/issues/106
-  FORCE_COLOR: true
-
-jobs:
-  semantic-release:
-    name: semantic-release
-    runs-on: ubuntu-latest
-
-    # release shouldn't need more than 30 min
-    timeout-minutes: 30
-
-    steps:
-      - name: Set up Node.js
-        uses: actions/setup-node@v1
-        with:
-          node-version: 12
-
-      - name: Set up Python
-        uses: actions/setup-python@v1
-        with:
-          python-version: 3.8
-
-      - name: Init platform
-        id: init
-        shell: bash
-        run: |
-          echo "::set-output name=yarn_cache::$(yarn cache dir)"
-          git config --global core.autocrlf false
-          git config --global core.symlinks true
-          git config --global user.email 'bot@renovateapp.com'
-          git config --global user.name  'Renovate Bot'
-          yarn config set version-git-tag false
-          echo "Node $(node --version)"
-          python --version
-          echo "Yarn $(yarn --version)"
-          pip --version
-
-      - uses: actions/checkout@v2
-
-      - name: Cache Yarn packages
-        id: yarn_cache_packages
-        uses: actions/cache@v1
-        with:
-          path: ${{ steps.init.outputs.yarn_cache }}
-          key: v1-${{ runner.os }}-yarn_cache-${{ hashFiles('**/yarn.lock') }}
-
-      - name: Installing dependencies
-        shell: bash
-        run: |
-          python -m pip install --upgrade pip
-          yarn install --frozen-lockfile --link-duplicates
-          pip install --user -r requirements.txt
-
-      - name: Lint
-        run: yarn lint
-
-      - name: Test schema
-        run: yarn test-schema
-
-      - name: Type check
-        run: yarn type-check
-
-      - name: Build
-        run: yarn build
-
-      - name: Unit tests
-        run: yarn jest --maxWorkers=2 --ci --coverageReporters=text-summary
-
-      - name: Set up Docker Buildx ${{ env.BUILDX_VERSION }}
-        id: buildx
-        uses: crazy-max/ghaction-docker-buildx@v1
-        with:
-          version: ${{ env.BUILDX_VERSION }}
-
-      - name: Docker registry login
-        run: echo "${{ secrets.DOCKER_RENOVATERELEASE_TOKEN }}" | docker login -u renovaterelease --password-stdin
-
-      - name: Build the Docker images cache
-        continue-on-error: true
-        run: |
-          docker buildx bake \
-            --file docker/bake.hcl \
-            --set latest.cache-to=type=registry,ref=renovate/docker-build-cache:renovate-latest,mode=max \
-            --set slim.cache-to=type=registry,ref=renovate/docker-build-cache:renovate-slim,mode=max \
-            default
-
-      - name: semantic-release
-        run: |
-          echo '//registry.yarnpkg.com/:_authToken=${NPM_TOKEN}' > ~/.npmrc
-          yarn semantic-release
-        env:
-          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
-          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
-          SHA: ${{github.sha}}