CI: build: fix ccache cache usage
[openwrt/openwrt.git] / .github / workflows / build.yml
index 8744bc7737a6635a28754037572420fb11651999..0c0c05f402b7048a290e320bab8d21c86dae15c0 100644 (file)
@@ -5,9 +5,15 @@ on:
     secrets:
       coverity_api_token:
     inputs:
+      container_name:
+        type: string
+        default: tools
       target:
         required: true
         type: string
+      subtarget:
+        required: true
+        type: string
       testing:
         type: boolean
       build_toolchain:
@@ -44,18 +50,28 @@ on:
           mbedtls
           wolfssl
           openssl
+      build_external_toolchain:
+        type: boolean
+      upload_external_toolchain:
+        type: boolean
+      use_ccache_cache:
+        type: boolean
+        default: true
+      ccache_type:
+        type: string
+        default: kernel
 
 permissions:
   contents: read
 
 jobs:
   setup_build:
-    name: Setup build ${{ inputs.target }}
+    name: Setup build ${{ inputs.target }}/${{ inputs.subtarget }}
     runs-on: ubuntu-latest
     outputs:
       owner_lc: ${{ steps.lower_owner.outputs.owner_lc }}
-      ccache_hash: ${{ steps.ccache_hash.outputs.ccache_hash }}
       container_tag: ${{ steps.determine_tools_container.outputs.container_tag }}
+      container_name: ${{ steps.determine_tools_container.outputs.container_name }}
 
     steps:
       - name: Checkout
@@ -73,13 +89,6 @@ jobs:
 
           echo "owner_lc=$OWNER_LC" >> $GITHUB_OUTPUT
 
-      - name: Generate ccache hash
-        id: ccache_hash
-        run: |
-          CCACHE_HASH=$(md5sum include/kernel-* | awk '{ print $1 }' \
-           | md5sum | awk '{ print $1 }')
-          echo "ccache_hash=$CCACHE_HASH" >> $GITHUB_OUTPUT
-
       # Per branch tools container tag
       # By default stick to latest
       # For official test targetting openwrt stable branch
@@ -89,6 +98,7 @@ jobs:
       - name: Determine tools container tag
         id: determine_tools_container
         run: |
+          CONTAINER_NAME=${{ inputs.container_name }}
           CONTAINER_TAG=latest
           if [ -n "${{ github.base_ref }}" ]; then
             if echo "${{ github.base_ref }}" | grep -q -E '^openwrt-[0-9][0-9]\.[0-9][0-9]$'; then
@@ -105,19 +115,34 @@ jobs:
               CONTAINER_TAG=openwrt-"$(echo ${{ github.ref_name }} | sed 's/^v\([0-9][0-9]\.[0-9][0-9]\)\..\+/\1/')"
             fi
           fi
-          echo "Tools container to use tools:$CONTAINER_TAG"
+
+          if [ "$CONTAINER_NAME" = "toolchain" ]; then
+            GHCR_TOKEN=$(echo ${{ secrets.GITHUB_TOKEN }} | base64)
+            GHCR_HEADER="Authorization: Bearer ${GHCR_TOKEN}"
+            GHCR_MANIFEST_LINK=https://ghcr.io/v2/${{ steps.lower_owner.outputs.owner_lc }}/${{ inputs.container_name }}/manifests/${{ inputs.target }}-${{ inputs.subtarget }}-"$CONTAINER_TAG"
+            # Check if container exist
+            if [ $(curl -s -o /dev/null -w "%{http_code}" -H "$GHCR_HEADER" -I "$GHCR_MANIFEST_LINK") = 200 ]; then
+              CONTAINER_TAG=${{ inputs.target }}-${{ inputs.subtarget }}-"$CONTAINER_TAG"
+            else
+              CONTAINER_NAME=tools
+            fi
+          fi
+
+          echo "Tools container to use $CONTAINER_NAME:$CONTAINER_TAG"
           echo "container_tag=$CONTAINER_TAG" >> $GITHUB_OUTPUT
+          echo "container_name=$CONTAINER_NAME" >> $GITHUB_OUTPUT
 
   build:
-    name: Build ${{ inputs.target }}
+    name: Build ${{ inputs.target }}/${{ inputs.subtarget }}
     needs: setup_build
     runs-on: ubuntu-latest
 
-    container: ghcr.io/${{ needs.setup_build.outputs.owner_lc }}/tools:${{ needs.setup_build.outputs.container_tag }}
+    container: ghcr.io/${{ needs.setup_build.outputs.owner_lc }}/${{ needs.setup_build.outputs.container_name }}:${{ needs.setup_build.outputs.container_tag }}
 
     permissions:
       contents: read
       packages: read
+      actions: write
 
     steps:
       - name: Checkout master directory
@@ -153,40 +178,16 @@ jobs:
           repository: openwrt/telephony
           path: openwrt/feeds/telephony
 
-      - name: Fix permission
-        run: |
-          chown -R buildbot:buildbot openwrt
-
-      - name: Initialization environment
-        run: |
-          TARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 1)
-          SUBTARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 2)
-          echo "TARGET=$TARGET" >> "$GITHUB_ENV"
-          echo "SUBTARGET=$SUBTARGET" >> "$GITHUB_ENV"
-
-      - name: Prepare prebuilt tools
-        shell: su buildbot -c "sh -e {0}"
-        working-directory: openwrt
-        run: |
-          mkdir -p staging_dir build_dir
-          ln -s /prebuilt_tools/staging_dir/host staging_dir/host
-          ln -s /prebuilt_tools/build_dir/host build_dir/host
-
-          ./scripts/ext-tools.sh --refresh
-
-      - name: Update & Install feeds
-        if: inputs.include_feeds == true
-        shell: su buildbot -c "sh -e {0}"
-        working-directory: openwrt
-        run: |
-          ./scripts/feeds update -a
-          ./scripts/feeds install -a
-
       - name: Parse toolchain file
         if: inputs.build_toolchain == false
         id: parse-toolchain
         working-directory: openwrt
         run: |
+          if [ -d /external-toolchain/ ]; then
+            echo "toolchain-type=external_container" >> $GITHUB_OUTPUT
+            exit 0
+          fi
+
           TOOLCHAIN_PATH=snapshots
 
           if [ -n "${{ github.base_ref }}" ]; then
@@ -213,7 +214,7 @@ jobs:
             fi
           fi
 
-          SUMS_FILE="https://downloads.cdn.openwrt.org/$TOOLCHAIN_PATH/targets/${{ env.TARGET }}/${{ env.SUBTARGET }}/sha256sums"
+          SUMS_FILE="https://downloads.cdn.openwrt.org/$TOOLCHAIN_PATH/targets/${{ inputs.target }}/${{ inputs.subtarget }}/sha256sums"
           if curl $SUMS_FILE | grep -q ".*openwrt-toolchain.*tar.xz"; then
             TOOLCHAIN_STRING="$( curl $SUMS_FILE | grep ".*openwrt-toolchain.*tar.xz")"
             TOOLCHAIN_FILE=$(echo "$TOOLCHAIN_STRING" | sed -n -e 's/.*\(openwrt-toolchain.*\).tar.xz/\1/p')
@@ -231,20 +232,44 @@ jobs:
           echo "TOOLCHAIN_FILE=$TOOLCHAIN_FILE" >> "$GITHUB_ENV"
           echo "TOOLCHAIN_PATH=$TOOLCHAIN_PATH" >> "$GITHUB_ENV"
 
-      - name: Cache ccache
-        uses: actions/cache@v3
+      - name: Fix permission
+        run: |
+          chown -R buildbot:buildbot openwrt
+
+      - name: Prepare prebuilt tools
+        shell: su buildbot -c "sh -e {0}"
+        working-directory: openwrt
+        run: |
+          mkdir -p staging_dir build_dir
+          ln -s /prebuilt_tools/staging_dir/host staging_dir/host
+          ln -s /prebuilt_tools/build_dir/host build_dir/host
+
+          ./scripts/ext-tools.sh --refresh
+
+      - name: Update & Install feeds
+        if: inputs.include_feeds == true
+        shell: su buildbot -c "sh -e {0}"
+        working-directory: openwrt
+        run: |
+          ./scripts/feeds update -a
+          ./scripts/feeds install -a
+
+      - name: Restore ccache cache
+        id: restore-ccache-cache
+        if: inputs.use_ccache_cache == true
+        uses: actions/cache/restore@v3
         with:
           path: openwrt/.ccache
-          key: ccache-kernel-${{ env.TARGET }}/${{ env.SUBTARGET }}-${{ needs.setup_build.outputs.ccache_hash }}
+          key: ccache-${{ inputs.ccache_type }}-${{ inputs.target }}/${{ inputs.subtarget }}-${{ hashFiles('openwrt/include/kernel-**') }}
           restore-keys: |
-            ccache-kernel-${{ env.TARGET }}/${{ env.SUBTARGET }}-
+            ccache-${{ inputs.ccache_type }}-${{ inputs.target }}/${{ inputs.subtarget }}-
 
       - name: Download external toolchain/sdk
-        if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type != 'internal'
+        if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type != 'internal' && steps.parse-toolchain.outputs.toolchain-type != 'external_container'
         shell: su buildbot -c "sh -e {0}"
         working-directory: openwrt
         run: |
-          wget -O - https://downloads.cdn.openwrt.org/${{ env.TOOLCHAIN_PATH }}/targets/${{ env.TARGET }}/${{ env.SUBTARGET }}/${{ env.TOOLCHAIN_FILE }}.tar.xz \
+          wget -O - https://downloads.cdn.openwrt.org/${{ env.TOOLCHAIN_PATH }}/targets/${{ inputs.target }}/${{ inputs.subtarget }}/${{ env.TOOLCHAIN_FILE }}.tar.xz \
             | tar --xz -xf -
 
       - name: Configure testing kernel
@@ -277,6 +302,37 @@ jobs:
           echo CONFIG_TARGET_PER_DEVICE_ROOTFS=y >> .config
           echo CONFIG_TARGET_ALL_PROFILES=y >> .config
 
+        # ccache for some reason have problem detecting compiler type
+        # with external toolchain. This cause the complete malfunction
+        # of ccache with the result of tons of unsupported compiler
+        # option error.
+        # To fix this force compiler type to gcc.
+      - name: Configure ccache and apply fixes
+        if: inputs.use_ccache_cache == true
+        shell: su buildbot -c "sh -e {0}"
+        working-directory: openwrt
+        env:
+          SYSTEM_CCACHE_CONF: staging_dir/host/etc/ccache.conf
+        run: |
+          touch $SYSTEM_CCACHE_CONF
+
+          echo compiler_type=gcc >> $SYSTEM_CCACHE_CONF
+
+          echo CONFIG_CCACHE=y >> .config
+
+      - name: Configure external toolchain in container
+        if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_container'
+        shell: su buildbot -c "sh -e {0}"
+        working-directory: openwrt
+        run: |
+          echo CONFIG_DEVEL=y >> .config
+          echo CONFIG_AUTOREMOVE=y >> .config
+
+          ./scripts/ext-toolchain.sh \
+            --toolchain /external-toolchain/$(ls /external-toolchain/ | grep openwrt-toolchain)/toolchain-* \
+            --overwrite-config \
+            --config ${{ inputs.target }}/${{ inputs.subtarget }}
+
       - name: Configure external toolchain
         if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_toolchain'
         shell: su buildbot -c "sh -e {0}"
@@ -284,12 +340,11 @@ jobs:
         run: |
           echo CONFIG_DEVEL=y >> .config
           echo CONFIG_AUTOREMOVE=y >> .config
-          echo CONFIG_CCACHE=y >> .config
 
           ./scripts/ext-toolchain.sh \
             --toolchain ${{ env.TOOLCHAIN_FILE }}/toolchain-* \
             --overwrite-config \
-            --config ${{ env.TARGET }}/${{ env.SUBTARGET }}
+            --config ${{ inputs.target }}/${{ inputs.subtarget }}
 
       - name: Adapt external sdk to external toolchain format
         if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_sdk'
@@ -326,12 +381,11 @@ jobs:
         run: |
           echo CONFIG_DEVEL=y >> .config
           echo CONFIG_AUTOREMOVE=y >> .config
-          echo CONFIG_CCACHE=y >> .config
 
           ./scripts/ext-toolchain.sh \
             --toolchain ${{ env.TOOLCHAIN_FILE }}/staging_dir/toolchain-* \
             --overwrite-config \
-            --config ${{ env.TARGET }}/${{ env.SUBTARGET }}
+            --config ${{ inputs.target }}/${{ inputs.subtarget }}
 
       - name: Configure internal toolchain
         if: inputs.build_toolchain == true || steps.parse-toolchain.outputs.toolchain-type == 'internal'
@@ -340,10 +394,9 @@ jobs:
         run: |
           echo CONFIG_DEVEL=y >> .config
           echo CONFIG_AUTOREMOVE=y >> .config
-          echo CONFIG_CCACHE=y >> .config
 
-          echo "CONFIG_TARGET_${{ env.TARGET }}=y" >> .config
-          echo "CONFIG_TARGET_${{ env.TARGET }}_${{ env.SUBTARGET }}=y" >> .config
+          echo "CONFIG_TARGET_${{ inputs.target }}=y" >> .config
+          echo "CONFIG_TARGET_${{ inputs.target }}_${{ inputs.subtarget }}=y" >> .config
 
           make defconfig
 
@@ -380,6 +433,12 @@ jobs:
         working-directory: openwrt
         run: make -j$(nproc) BUILD_LOG=1 || ret=$? .github/workflows/scripts/show_build_failures.sh
 
+      - name: Build external toolchain
+        if: inputs.build_external_toolchain == true
+        shell: su buildbot -c "sh -e {0}"
+        working-directory: openwrt
+        run: make target/toolchain/compile -j$(nproc) BUILD_LOG=1 || ret=$? .github/workflows/scripts/show_build_failures.sh
+
       - name: Coverity prepare toolchain
         if: inputs.coverity_check_packages != ''
         shell: su buildbot -c "sh -e {0}"
@@ -435,5 +494,38 @@ jobs:
         if: failure()
         uses: actions/upload-artifact@v3
         with:
-          name: ${{ env.TARGET }}-${{ env.SUBTARGET }}-logs
+          name: ${{ inputs.target }}-${{ inputs.subtarget }}-logs
           path: "openwrt/logs"
+
+      - name: Delete already present ccache cache
+        if: steps.restore-ccache-cache.outputs.cache-hit == 'true' && inputs.use_ccache_cache == true
+        uses: octokit/request-action@v2.x
+        with:
+          route: DELETE /repos/{repository}/actions/caches?key={key}
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          INPUT_REPOSITORY: ${{ github.repository }}
+          INPUT_KEY: ${{ steps.restore-ccache-cache.outputs.cache-primary-key }}
+
+      - name: Save ccache cache
+        if: inputs.use_ccache_cache == true
+        uses: actions/cache/save@v3
+        with:
+          path: openwrt/.ccache
+          key: ${{ steps.restore-ccache-cache.outputs.cache-primary-key }}
+
+      - name: Find external toolchain name
+        id: get-toolchain-name
+        if: inputs.upload_external_toolchain == true
+        working-directory: openwrt
+        run: |
+          TOOLCHAIN_NAME=$(ls bin/targets/${{inputs.target }}/${{ inputs.subtarget }} | grep toolchain)
+          echo "toolchain-name=$TOOLCHAIN_NAME" >> $GITHUB_OUTPUT
+
+      - name: Upload prebuilt toolchain
+        if: inputs.upload_external_toolchain == true
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ inputs.target }}-${{ inputs.subtarget }}-external-toolchain
+          path: openwrt/bin/targets/${{ inputs.target }}/${{ inputs.subtarget }}/${{ steps.get-toolchain-name.outputs.toolchain-name }}
+          retention-days: 1