diff --git a/.github/actions/preload-img-cache/action.yml b/.github/actions/preload-img-cache/action.yml new file mode 100644 index 0000000..073fb33 --- /dev/null +++ b/.github/actions/preload-img-cache/action.yml @@ -0,0 +1,47 @@ +name: Preload img cache +inputs: + device: + description: 'Device name' + required: true + filename: + description: 'Name of file in workdir' + required: true + test-db-path: + description: 'Path to test database' + required: true +outputs: + cache-hit: + description: 'Did we hit the cache?' + value: ${{ steps.cache-img.outputs.cache-hit }} + +runs: + using: "composite" + steps: + - uses: actions/cache@v3 + id: cache-img + with: + key: img-${{ hashFiles(inputs.test-db-path) }}-${{ inputs.device }} + path: | + workdir/${{ inputs.filename }} + - if: ${{ ! steps.cache-img.outputs.cache-hit }} + uses: awalsh128/cache-apt-pkgs-action@v1 + with: + packages: python3-lz4 python3-protobuf + - if: ${{ ! steps.cache-img.outputs.cache-hit }} + uses: awalsh128/cache-apt-pkgs-action@v1 + with: + packages: python3-tomlkit + - name: Creating workdir + if: ${{ ! steps.cache-img.outputs.cache-hit }} + shell: sh + run: mkdir -p workdir + - name: Downloading device image for ${{ inputs.device }} + if: ${{ ! steps.cache-img.outputs.cache-hit }} + shell: sh + run: | + ./tests_ci/dummy_image.py \ + download \ + --no-compress \ + --db ${{ inputs.test-db-path }} \ + --output workdir/${{ inputs.filename }} \ + ${{ inputs.device }} diff --git a/.github/actions/preload-magisk-cache/action.yml b/.github/actions/preload-magisk-cache/action.yml new file mode 100644 index 0000000..a83676f --- /dev/null +++ b/.github/actions/preload-magisk-cache/action.yml @@ -0,0 +1,27 @@ +name: Preload Magisk +inputs: + cache-key: + description: 'Magisk cache-key' + required: true + url: + description: 'Magisk URL' + required: true + +runs: + using: "composite" + steps: + - uses: actions/cache@v3 + id: cache-magisk + with: + key: ${{ inputs.cache-key }} + path: | + workdir/magisk.apk + - name: Creating workdir + if: ${{ ! steps.cache-magisk.outputs.cache-hit }} + shell: sh + run: mkdir -p workdir + - name: Downloading Magisk + if: ${{ ! steps.cache-magisk.outputs.cache-hit }} + shell: sh + run: | + curl -L -o workdir/magisk.apk ${{ inputs.url }} diff --git a/.github/actions/preload-tox-cache/action.yml b/.github/actions/preload-tox-cache/action.yml new file mode 100644 index 0000000..0275087 --- /dev/null +++ b/.github/actions/preload-tox-cache/action.yml @@ -0,0 +1,24 @@ +name: Preload tox cache +inputs: + python-version: + description: 'Python version' + required: true + +runs: + using: "composite" + steps: + - uses: actions/cache@v3 + with: + key: tox-${{ hashFiles('tox.ini') }}-${{ inputs.python-version }} + restore-keys: | + tox- + path: | + .tox/ + ~/.cache/pip + - uses: awalsh128/cache-apt-pkgs-action@v1 + with: + packages: tox + - uses: actions/setup-python@v4 + with: + python-version: | + ${{ fromJson('{ "py39": "3.9", "py310": "3.10", "py311": "3.11" }')[inputs.python-version] }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1c66043 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,163 @@ +name: CI +on: push + +env: + test-db-path: tests_ci/test_db.toml + +# This allows a subsequently queued workflow run to interrupt previous runs +concurrency: + group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' + cancel-in-progress: true + +jobs: + setup: + name: Prepare workflow data + runs-on: ubuntu-latest + timeout-minutes: 2 + permissions: + # Default + contents: read + packages: read + # Custom, for API cache access + actions: read + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + outputs: + device-db: ${{ steps.load-db.outputs.device-db }} + device-list: ${{ steps.load-db.outputs.device-list }} + magisk-key: ${{ steps.get-magisk-cache.outputs.magisk-key }} + magisk-url: ${{ steps.load-db.outputs.magisk-url }} + hit-img: ${{ steps.get-img-cache.outputs.img-hit }} + hit-tox: ${{ steps.get-tox-cache.outputs.tox-hit }} + steps: + - uses: actions/checkout@v3 + - uses: awalsh128/cache-apt-pkgs-action@v1 + with: + packages: python3-tomlkit + - name: Checking for cached tox environments + id: get-tox-cache + run: | + echo "tox-hit=$(gh api \ + --method GET \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + -f 'key=tox-${{ hashFiles('tox.ini') }}-py3' \ + /repos/${{ github.repository }}/actions/caches)" >> $GITHUB_OUTPUT + - name: Checking for cached device images + id: get-img-cache + run: | + echo "img-hit=$(gh api \ + --method GET \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + -f 'key=img-${{ hashFiles(env.test-db-path) }}-' \ + /repos/${{ github.repository }}/actions/caches)" >> $GITHUB_OUTPUT + - name: Checking for cached magisk apk + id: get-magisk-cache + env: + magisk-key: magisk-${{ hashFiles(env.test-db-path) }} + run: | + echo "magisk-key=${{ env.magisk-key }}" >> $GITHUB_OUTPUT + echo "magisk-hit=$(gh api \ + --method GET \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + -f 'key=${{ env.magisk-key }}' \ + /repos/${{ github.repository }}/actions/caches)" >> $GITHUB_OUTPUT + - name: Loading device test database + id: load-db + shell: python + run: | + import os + import tomlkit + + with open('${{ env.test-db-path }}') as f: + db = tomlkit.load(f) + + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write(f"device-db={db['device']}" + '\n') + f.write(f"device-list={[i for i in db['device']]}" + '\n') + f.write(f"magisk-url={db['magisk']['url']}" + '\n') + - uses: ./.github/actions/preload-magisk-cache + if: ${{ fromJSON(steps.get-magisk-cache.outputs.magisk-hit).total_count == 0 }} + with: + cache-key: ${{ steps.get-magisk-cache.outputs.magisk-key }} + url: ${{ steps.load-db.outputs.magisk-url }} + + preload-img: + name: Preload device images + runs-on: ubuntu-latest + needs: setup + timeout-minutes: 5 + # Assume that preloading always succesfully cached all images before. + # If for some reason only some got cached, on the first run, the cache will not be preloaded + # which will result in some being downloaded multiple times when running the tests. + if: ${{ fromJSON(needs.setup.outputs.hit-img).total_count == 0 }} + strategy: + matrix: + device: ${{ fromJSON(needs.setup.outputs.device-list) }} + env: + filename: ${{ fromJSON(needs.setup.outputs.device-db)[matrix.device]['filename'] }} + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: ./.github/actions/preload-img-cache + with: + device: ${{ matrix.device }} + filename: ${{ env.filename }} + test-db-path: ${{ env.test-db-path }} + + preload-tox: + name: Preload tox environments + runs-on: ubuntu-latest + needs: setup + timeout-minutes: 5 + # Assume that preloading always succesfully cached all tox environments before. + # If for some reason only some got cached, on the first run, the cache will not be preloaded + # which will result in some being downloaded multiple times when running the tests. + if: ${{ fromJSON(needs.setup.outputs.hit-tox).total_count == 0 }} + strategy: + matrix: + python: [py39, py310, py311] + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/preload-tox-cache + with: + python-version: ${{ matrix.python }} + - name: Generating tox environment + run: tox -e ${{ matrix.python }} --notest + + tests: + name: Run test for ${{ matrix.device }} with ${{ matrix.python }} + runs-on: ubuntu-latest + needs: [setup, preload-img, preload-tox] + timeout-minutes: 5 + # Continue on skipped but not on failures or cancels + if: ${{ always() && ! failure() && ! cancelled() }} + strategy: + matrix: + device: ${{ fromJSON(needs.setup.outputs.device-list) }} + python: [py39, py310, py311] + env: + filename: ${{ fromJSON(needs.setup.outputs.device-db)[matrix.device]['filename'] }} + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: ./.github/actions/preload-magisk-cache + with: + cache-key: ${{ needs.setup.outputs.magisk-key }} + url: ${{ needs.setup.outputs.magisk-url }} + - uses: ./.github/actions/preload-img-cache + with: + device: ${{ matrix.device }} + filename: ${{ env.filename }} + test-db-path: ${{ env.test-db-path }} + - uses: ./.github/actions/preload-tox-cache + with: + python-version: ${{ matrix.python }} + + # Finally run tests + - name: Run test for ${{ matrix.device }} with ${{ matrix.python }} + run: tox -e ${{ matrix.python }} -- -d ${{ matrix.device }} --db ${{ env.test-db-path }} --workdir workdir