Split workflow processes. (#588)

* Split workflow processes.

* fix
This commit is contained in:
Nerivec
2024-11-01 02:04:23 +01:00
committed by GitHub
parent 0f1b5bd4e2
commit 2da322c5b0
24 changed files with 698 additions and 404 deletions

45
.github/workflows/check_ota_pr.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Check OTA PR
on:
pull_request:
types: [opened, synchronize, reopened, edited]
branches: [master]
paths: ['images/**']
jobs:
check-ota-pr:
runs-on: ubuntu-latest
# don't run if PR was closed without merge, or explicitly disabled
if: |
!contains(github.event.pull_request.labels.*.name, 'ignore-ota-workflow')
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Check OTA PR
uses: actions/github-script@v7
with:
script: |
const {checkOtaPR} = await import("${{ github.workspace }}/dist/ghw_check_ota_pr.js")
await checkOtaPR(github, core, context)
- uses: actions/upload-artifact@v4
if: always()
with:
name: pr
path: pr/

View File

@@ -11,22 +11,28 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Lint
run: |
pnpm run format:check
pnpm run eslint
- name: Test
# NOTE: see jest.config.ts `collectCoverageFrom`
run: pnpm run coverage

View File

@@ -13,18 +13,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Concat CACerts
uses: actions/github-script@v7
with:
@@ -32,6 +37,7 @@ jobs:
const {concatCaCerts} = await import("${{ github.workspace }}/dist/ghw_concat_cacerts.js")
await concatCaCerts(github, core, context)
- name: Commit changes
run: |
git config --global user.name 'github-actions[bot]'

View File

@@ -16,18 +16,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Overwrite cache
uses: actions/github-script@v7
with:
@@ -35,6 +40,7 @@ jobs:
const {overwriteCache} = await import("${{ github.workspace }}/dist/gwh_overwrite_cache.js")
await overwriteCache(github, core, context, "${{ inputs.manufacturers || '' }}")
- name: Commit changes
run: |
git config --global user.name 'github-actions[bot]'

44
.github/workflows/report_ota_pr.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Report OTA PR
on:
workflow_run:
workflows: ['Check OTA PR']
types:
- completed
permissions:
contents: read
pull-requests: write
actions: read
jobs:
report-ota-pr:
runs-on: ubuntu-latest
# should never be anything else...
if: |
github.event.workflow_run.event == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Check OTA PR
uses: actions/github-script@v7
with:
script: |
const {reportOtaPR} = await import("${{ github.workspace }}/dist/ghw_report_ota_pr.js")
await reportOtaPR(github, core, context)

View File

@@ -22,18 +22,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Create and checkout new branch
id: create_branch
run: |
@@ -42,6 +47,7 @@ jobs:
branch_name="reprocess-$(date +'%Y-%m-%d-%H-%M-%S')"
echo "branch_name=$branch_name" >> $GITHUB_OUTPUT
git checkout -b $branch_name
- name: Reprocess
uses: actions/github-script@v7
env:
@@ -51,11 +57,13 @@ jobs:
const {reProcessAllImages} = await import("${{ github.workspace }}/dist/ghw_reprocess_all_images.js")
await reProcessAllImages(github, core, context, ${{ fromJSON(inputs.remove_not_in_manifest) }}, true)
- name: Commit changes in new branch
run: |
git add .
git commit -m "Re-Processed all images" || echo 'Nothing to commit'
git push -u origin HEAD
- name: Create pull request
uses: actions/github-script@v7
with:

View File

@@ -28,18 +28,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Run Autodl
uses: actions/github-script@v7
env:
@@ -51,6 +56,7 @@ jobs:
const {runAutodl} = await import("${{ github.workspace }}/dist/ghw_run_autodl.js")
await runAutodl(github, core, context, "${{ inputs.manufacturers || '' }}")
- name: Create Autodl release
uses: actions/github-script@v7
with:
@@ -58,6 +64,7 @@ jobs:
const {createAutodlRelease} = await import("${{ github.workspace }}/dist/ghw_create_autodl_release.js")
await createAutodlRelease(github, core, context)
- name: Commit changes
run: |
git config --global user.name 'github-actions[bot]'

View File

@@ -1,50 +1,43 @@
name: Update OTA PR
name: Update manifests
on:
pull_request:
types: [opened, synchronize, reopened, edited, closed]
push:
branches: [master]
paths: ['images/**']
permissions:
contents: write
pull-requests: write
jobs:
update-pr:
update-manifests:
runs-on: ubuntu-latest
# don't run if PR was closed without merge, or explicitly disabled
if: |
!contains(github.event.pull_request.labels.*.name, 'ignore-ota-workflow') && (github.event.action != 'closed' || github.event.pull_request.merged == true)
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm run build
- name: Get changed files
run: |
files=$(gh pr view ${{ github.event.pull_request.number }} --json files -q '.files[].path' | tr '\n' ',')
echo "files=$files" >> $GITHUB_OUTPUT
id: changed_files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update PR
- name: Update manifests
uses: actions/github-script@v7
with:
script: |
const {updateOtaPR} = await import("${{ github.workspace }}/dist/ghw_update_ota_pr.js")
const {updateManifests} = await import("${{ github.workspace }}/dist/ghw_update_manifests.js")
await updateManifests(github, core, context)
await updateOtaPR(github, core, context, "${{steps.changed_files.outputs.files}}")
- name: Commit changes on push
if: github.event.pull_request.merged == true
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ dist/
temp/
tmp/
.jest-tmp/
pr/
tsconfig.tsbuildinfo
# used by tests

View File

@@ -1,6 +1,6 @@
{
"name": "zigbee-ota",
"version": "1.0.0",
"version": "1.1.0",
"repository": {
"type": "git",
"url": "git+https://github.com/Koenkk/zigbee-OTA.git"
@@ -47,12 +47,12 @@
"devDependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.0",
"@eslint/core": "^0.7.0",
"@eslint/core": "^0.8.0",
"@eslint/js": "^9.13.0",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@octokit/rest": "^21.0.2",
"@types/jest": "^29.5.14",
"@types/node": "^22.8.1",
"@types/node": "^22.8.6",
"eslint": "^9.13.0",
"eslint-config-prettier": "^9.1.0",
"jest": "^29.7.0",
@@ -60,6 +60,6 @@
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"typescript-eslint": "^8.12.0"
"typescript-eslint": "^8.12.2"
}
}

314
pnpm-lock.yaml generated
View File

@@ -19,8 +19,8 @@ importers:
specifier: ^6.0.0
version: 6.0.0
'@eslint/core':
specifier: ^0.7.0
version: 0.7.0
specifier: ^0.8.0
version: 0.8.0
'@eslint/js':
specifier: ^9.13.0
version: 9.13.0
@@ -34,8 +34,8 @@ importers:
specifier: ^29.5.14
version: 29.5.14
'@types/node':
specifier: ^22.8.1
version: 22.8.1
specifier: ^22.8.6
version: 22.8.6
eslint:
specifier: ^9.13.0
version: 9.13.0
@@ -44,22 +44,22 @@ importers:
version: 9.1.0(eslint@9.13.0)
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
version: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
prettier:
specifier: ^3.3.3
version: 3.3.3
ts-jest:
specifier: ^29.2.5
version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)))(typescript@5.6.3)
version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)))(typescript@5.6.3)
ts-node:
specifier: ^10.9.2
version: 10.9.2(@types/node@22.8.1)(typescript@5.6.3)
version: 10.9.2(@types/node@22.8.6)(typescript@5.6.3)
typescript:
specifier: ^5.6.3
version: 5.6.3
typescript-eslint:
specifier: ^8.12.0
version: 8.12.0(eslint@9.13.0)(typescript@5.6.3)
specifier: ^8.12.2
version: 8.12.2(eslint@9.13.0)(typescript@5.6.3)
packages:
@@ -82,20 +82,20 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@babel/code-frame@7.26.0':
resolution: {integrity: sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==}
'@babel/code-frame@7.26.2':
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.26.0':
resolution: {integrity: sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==}
'@babel/compat-data@7.26.2':
resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==}
engines: {node: '>=6.9.0'}
'@babel/core@7.26.0':
resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.26.0':
resolution: {integrity: sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==}
'@babel/generator@7.26.2':
resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.25.9':
@@ -132,8 +132,8 @@ packages:
resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.26.1':
resolution: {integrity: sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==}
'@babel/parser@7.26.2':
resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -265,6 +265,10 @@ packages:
resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/core@0.8.0':
resolution: {integrity: sha512-ncQZoR8YJtXIrBuJo1vDlIIR8+uoyYj2tRXE/RbZ3KHWYXNLcPeOgNKRBzXSZ/yQbVObVS8JGbhzvpifU+eQqw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/eslintrc@3.1.0':
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -577,8 +581,8 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/node@22.8.1':
resolution: {integrity: sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==}
'@types/node@22.8.6':
resolution: {integrity: sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==}
'@types/stack-utils@2.0.3':
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
@@ -589,8 +593,8 @@ packages:
'@types/yargs@17.0.33':
resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
'@typescript-eslint/eslint-plugin@8.12.0':
resolution: {integrity: sha512-uRqchEKT0/OwDePTwCjSFO2aH4zccdeQ7DgAzM/8fuXc+PAXvpdMRbuo+oCmK1lSfXssk2UUBNiWihobKxQp/g==}
'@typescript-eslint/eslint-plugin@8.12.2':
resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
@@ -600,8 +604,8 @@ packages:
typescript:
optional: true
'@typescript-eslint/parser@8.12.0':
resolution: {integrity: sha512-7U20duDQWAOhCk2VtyY41Vor/CJjiEW063Zel9aoRXq89FQ/jr+0e0m3kxh9Sk5SFW9B1AblVIBtXd+1xQ1NWQ==}
'@typescript-eslint/parser@8.12.2':
resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -610,12 +614,12 @@ packages:
typescript:
optional: true
'@typescript-eslint/scope-manager@8.12.0':
resolution: {integrity: sha512-jbuCXK18iEshRFUtlCIMAmOKA6OAsKjo41UcXPqx7ZWh2b4cmg6pV/pNcZSB7oW9mtgF95yizr7Jnwt3IUD2pA==}
'@typescript-eslint/scope-manager@8.12.2':
resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.12.0':
resolution: {integrity: sha512-cHioAZO/nLgyzTmwv7gWIjEKMHSbioKEZqLCaItTn7RvJP1QipuGVwEjPJa6Kv9u9UiUMVAESY9JH186TjKITw==}
'@typescript-eslint/type-utils@8.12.2':
resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@@ -623,12 +627,12 @@ packages:
typescript:
optional: true
'@typescript-eslint/types@8.12.0':
resolution: {integrity: sha512-Cc+iNtqBJ492f8KLEmKXe1l6683P0MlFO8Bk1NMphnzVIGH4/Wn9kvandFH+gYR1DDUjH/hgeWRGdO5Tj8gjYg==}
'@typescript-eslint/types@8.12.2':
resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.12.0':
resolution: {integrity: sha512-a4koVV7HHVOQWcGb6ZcAlunJnAdwo/CITRbleQBSjq5+2WLoAJQCAAiecvrAdSM+n/man6Ghig5YgdGVIC6xqw==}
'@typescript-eslint/typescript-estree@8.12.2':
resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@@ -636,14 +640,14 @@ packages:
typescript:
optional: true
'@typescript-eslint/utils@8.12.0':
resolution: {integrity: sha512-5i1tqLwlf0fpX1j05paNKyIzla/a4Y3Xhh6AFzi0do/LDJLvohtZYaisaTB9kq0D4uBocAxWDTGzNMOCCwIgXA==}
'@typescript-eslint/utils@8.12.2':
resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
'@typescript-eslint/visitor-keys@8.12.0':
resolution: {integrity: sha512-2rXkr+AtZZLuNY18aUjv5wtB9oUiwY1WnNi7VTsdCdy1m958ULeUKoAegldQTjqpbpNJ5cQ4egR8/bh5tbrKKQ==}
'@typescript-eslint/visitor-keys@8.12.2':
resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2:
@@ -774,8 +778,8 @@ packages:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
caniuse-lite@1.0.30001673:
resolution: {integrity: sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==}
caniuse-lite@1.0.30001676:
resolution: {integrity: sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@@ -879,8 +883,8 @@ packages:
engines: {node: '>=0.10.0'}
hasBin: true
electron-to-chromium@1.5.48:
resolution: {integrity: sha512-FXULnNK7ACNI9MTMOVAzUGiz/YrK9Kcb0s/JT4aJgsam7Eh6XYe7Y6q95lPq+VdBe1DpT2eTnfXFtnuPGCks4w==}
electron-to-chromium@1.5.50:
resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==}
emittery@0.13.1:
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
@@ -913,16 +917,16 @@ packages:
peerDependencies:
eslint: '>=7.0.0'
eslint-scope@8.1.0:
resolution: {integrity: sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==}
eslint-scope@8.2.0:
resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
eslint-visitor-keys@4.1.0:
resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==}
eslint-visitor-keys@4.2.0:
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.13.0:
@@ -935,8 +939,8 @@ packages:
jiti:
optional: true
espree@10.2.0:
resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==}
espree@10.3.0:
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
esprima@4.0.1:
@@ -1700,8 +1704,8 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
ts-api-utils@1.3.0:
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
ts-api-utils@1.4.0:
resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==}
engines: {node: '>=16'}
peerDependencies:
typescript: '>=4.2.0'
@@ -1760,8 +1764,8 @@ packages:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
typescript-eslint@8.12.0:
resolution: {integrity: sha512-m8aQM4pqc17dcD3BsQzUqVXkcclCspuCCv7GhYlwMWNYAXFV8xJkn8vUM8YxoR78BY6S+NX/J7rfNVaGNLgXgQ==}
typescript-eslint@8.12.2:
resolution: {integrity: sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
@@ -1887,23 +1891,23 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
'@babel/code-frame@7.26.0':
'@babel/code-frame@7.26.2':
dependencies:
'@babel/helper-validator-identifier': 7.25.9
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.26.0': {}
'@babel/compat-data@7.26.2': {}
'@babel/core@7.26.0':
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.26.0
'@babel/generator': 7.26.0
'@babel/code-frame': 7.26.2
'@babel/generator': 7.26.2
'@babel/helper-compilation-targets': 7.25.9
'@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0)
'@babel/helpers': 7.26.0
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@babel/template': 7.25.9
'@babel/traverse': 7.25.9
'@babel/types': 7.26.0
@@ -1915,9 +1919,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/generator@7.26.0':
'@babel/generator@7.26.2':
dependencies:
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
@@ -1925,7 +1929,7 @@ snapshots:
'@babel/helper-compilation-targets@7.25.9':
dependencies:
'@babel/compat-data': 7.26.0
'@babel/compat-data': 7.26.2
'@babel/helper-validator-option': 7.25.9
browserslist: 4.24.2
lru-cache: 5.1.1
@@ -1960,7 +1964,7 @@ snapshots:
'@babel/template': 7.25.9
'@babel/types': 7.26.0
'@babel/parser@7.26.1':
'@babel/parser@7.26.2':
dependencies:
'@babel/types': 7.26.0
@@ -2051,15 +2055,15 @@ snapshots:
'@babel/template@7.25.9':
dependencies:
'@babel/code-frame': 7.26.0
'@babel/parser': 7.26.1
'@babel/code-frame': 7.26.2
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
'@babel/traverse@7.25.9':
dependencies:
'@babel/code-frame': 7.26.0
'@babel/generator': 7.26.0
'@babel/parser': 7.26.1
'@babel/code-frame': 7.26.2
'@babel/generator': 7.26.2
'@babel/parser': 7.26.2
'@babel/template': 7.25.9
'@babel/types': 7.26.0
debug: 4.3.7
@@ -2095,11 +2099,13 @@ snapshots:
'@eslint/core@0.7.0': {}
'@eslint/core@0.8.0': {}
'@eslint/eslintrc@3.1.0':
dependencies:
ajv: 6.12.6
debug: 4.3.7
espree: 10.2.0
espree: 10.3.0
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.0
@@ -2133,8 +2139,8 @@ snapshots:
'@ianvs/prettier-plugin-sort-imports@4.3.1(prettier@3.3.3)':
dependencies:
'@babel/core': 7.26.0
'@babel/generator': 7.26.0
'@babel/parser': 7.26.1
'@babel/generator': 7.26.2
'@babel/parser': 7.26.2
'@babel/traverse': 7.25.9
'@babel/types': 7.26.0
prettier: 3.3.3
@@ -2168,27 +2174,27 @@ snapshots:
'@jest/console@29.7.0':
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
jest-message-util: 29.7.0
jest-util: 29.7.0
slash: 3.0.0
'@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))':
'@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))':
dependencies:
'@jest/console': 29.7.0
'@jest/reporters': 29.7.0
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.9.0
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
jest-config: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
jest-config: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -2213,7 +2219,7 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
jest-mock: 29.7.0
'@jest/expect-utils@29.7.0':
@@ -2231,7 +2237,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
'@types/node': 22.8.1
'@types/node': 22.8.6
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -2253,7 +2259,7 @@ snapshots:
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.25
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
collect-v8-coverage: 1.0.2
exit: 0.1.2
@@ -2323,7 +2329,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.8.1
'@types/node': 22.8.6
'@types/yargs': 17.0.33
chalk: 4.1.2
@@ -2497,7 +2503,7 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
@@ -2509,7 +2515,7 @@ snapshots:
'@types/babel__template@7.4.4':
dependencies:
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
'@types/babel__traverse@7.20.6':
@@ -2520,7 +2526,7 @@ snapshots:
'@types/graceful-fs@4.1.9':
dependencies:
'@types/node': 22.8.1
'@types/node': 22.8.6
'@types/istanbul-lib-coverage@2.0.6': {}
@@ -2539,7 +2545,7 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/node@22.8.1':
'@types/node@22.8.6':
dependencies:
undici-types: 6.19.8
@@ -2551,30 +2557,30 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@8.12.0(@typescript-eslint/parser@8.12.0(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)':
'@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/scope-manager': 8.12.0
'@typescript-eslint/type-utils': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 8.12.0
'@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/scope-manager': 8.12.2
'@typescript-eslint/type-utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 8.12.2
eslint: 9.13.0
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
ts-api-utils: 1.3.0(typescript@5.6.3)
ts-api-utils: 1.4.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.12.0(eslint@9.13.0)(typescript@5.6.3)':
'@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.12.0
'@typescript-eslint/types': 8.12.0
'@typescript-eslint/typescript-estree': 8.12.0(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 8.12.0
'@typescript-eslint/scope-manager': 8.12.2
'@typescript-eslint/types': 8.12.2
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
'@typescript-eslint/visitor-keys': 8.12.2
debug: 4.3.7
eslint: 9.13.0
optionalDependencies:
@@ -2582,54 +2588,54 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.12.0':
'@typescript-eslint/scope-manager@8.12.2':
dependencies:
'@typescript-eslint/types': 8.12.0
'@typescript-eslint/visitor-keys': 8.12.0
'@typescript-eslint/types': 8.12.2
'@typescript-eslint/visitor-keys': 8.12.2
'@typescript-eslint/type-utils@8.12.0(eslint@9.13.0)(typescript@5.6.3)':
'@typescript-eslint/type-utils@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.12.0(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
debug: 4.3.7
ts-api-utils: 1.3.0(typescript@5.6.3)
ts-api-utils: 1.4.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.3
transitivePeerDependencies:
- eslint
- supports-color
'@typescript-eslint/types@8.12.0': {}
'@typescript-eslint/types@8.12.2': {}
'@typescript-eslint/typescript-estree@8.12.0(typescript@5.6.3)':
'@typescript-eslint/typescript-estree@8.12.2(typescript@5.6.3)':
dependencies:
'@typescript-eslint/types': 8.12.0
'@typescript-eslint/visitor-keys': 8.12.0
'@typescript-eslint/types': 8.12.2
'@typescript-eslint/visitor-keys': 8.12.2
debug: 4.3.7
fast-glob: 3.3.2
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.6.3
ts-api-utils: 1.3.0(typescript@5.6.3)
ts-api-utils: 1.4.0(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.12.0(eslint@9.13.0)(typescript@5.6.3)':
'@typescript-eslint/utils@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0)
'@typescript-eslint/scope-manager': 8.12.0
'@typescript-eslint/types': 8.12.0
'@typescript-eslint/typescript-estree': 8.12.0(typescript@5.6.3)
'@typescript-eslint/scope-manager': 8.12.2
'@typescript-eslint/types': 8.12.2
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
eslint: 9.13.0
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/visitor-keys@8.12.0':
'@typescript-eslint/visitor-keys@8.12.2':
dependencies:
'@typescript-eslint/types': 8.12.0
'@typescript-eslint/types': 8.12.2
eslint-visitor-keys: 3.4.3
acorn-jsx@5.3.2(acorn@8.14.0):
@@ -2756,8 +2762,8 @@ snapshots:
browserslist@4.24.2:
dependencies:
caniuse-lite: 1.0.30001673
electron-to-chromium: 1.5.48
caniuse-lite: 1.0.30001676
electron-to-chromium: 1.5.50
node-releases: 2.0.18
update-browserslist-db: 1.1.1(browserslist@4.24.2)
@@ -2777,7 +2783,7 @@ snapshots:
camelcase@6.3.0: {}
caniuse-lite@1.0.30001673: {}
caniuse-lite@1.0.30001676: {}
chalk@4.1.2:
dependencies:
@@ -2812,13 +2818,13 @@ snapshots:
convert-source-map@2.0.0: {}
create-jest@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)):
create-jest@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)):
dependencies:
'@jest/types': 29.6.3
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
jest-config: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
jest-config: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
jest-util: 29.7.0
prompts: 2.4.2
transitivePeerDependencies:
@@ -2859,7 +2865,7 @@ snapshots:
dependencies:
jake: 10.9.2
electron-to-chromium@1.5.48: {}
electron-to-chromium@1.5.50: {}
emittery@0.13.1: {}
@@ -2881,14 +2887,14 @@ snapshots:
dependencies:
eslint: 9.13.0
eslint-scope@8.1.0:
eslint-scope@8.2.0:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
eslint-visitor-keys@3.4.3: {}
eslint-visitor-keys@4.1.0: {}
eslint-visitor-keys@4.2.0: {}
eslint@9.13.0:
dependencies:
@@ -2909,9 +2915,9 @@ snapshots:
cross-spawn: 7.0.3
debug: 4.3.7
escape-string-regexp: 4.0.0
eslint-scope: 8.1.0
eslint-visitor-keys: 4.1.0
espree: 10.2.0
eslint-scope: 8.2.0
eslint-visitor-keys: 4.2.0
espree: 10.3.0
esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
@@ -2930,11 +2936,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
espree@10.2.0:
espree@10.3.0:
dependencies:
acorn: 8.14.0
acorn-jsx: 5.3.2(acorn@8.14.0)
eslint-visitor-keys: 4.1.0
eslint-visitor-keys: 4.2.0
esprima@4.0.1: {}
@@ -3135,7 +3141,7 @@ snapshots:
istanbul-lib-instrument@5.2.1:
dependencies:
'@babel/core': 7.26.0
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 6.3.1
@@ -3145,7 +3151,7 @@ snapshots:
istanbul-lib-instrument@6.0.3:
dependencies:
'@babel/core': 7.26.0
'@babel/parser': 7.26.1
'@babel/parser': 7.26.2
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.6.3
@@ -3196,7 +3202,7 @@ snapshots:
'@jest/expect': 29.7.0
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
co: 4.6.0
dedent: 1.5.3
@@ -3216,16 +3222,16 @@ snapshots:
- babel-plugin-macros
- supports-color
jest-cli@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)):
jest-cli@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)):
dependencies:
'@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
'@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
create-jest: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
create-jest: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
exit: 0.1.2
import-local: 3.2.0
jest-config: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
jest-config: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -3235,7 +3241,7 @@ snapshots:
- supports-color
- ts-node
jest-config@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)):
jest-config@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)):
dependencies:
'@babel/core': 7.26.0
'@jest/test-sequencer': 29.7.0
@@ -3260,8 +3266,8 @@ snapshots:
slash: 3.0.0
strip-json-comments: 3.1.1
optionalDependencies:
'@types/node': 22.8.1
ts-node: 10.9.2(@types/node@22.8.1)(typescript@5.6.3)
'@types/node': 22.8.6
ts-node: 10.9.2(@types/node@22.8.6)(typescript@5.6.3)
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
@@ -3290,7 +3296,7 @@ snapshots:
'@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -3300,7 +3306,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.9
'@types/node': 22.8.1
'@types/node': 22.8.6
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11
@@ -3326,7 +3332,7 @@ snapshots:
jest-message-util@29.7.0:
dependencies:
'@babel/code-frame': 7.26.0
'@babel/code-frame': 7.26.2
'@jest/types': 29.6.3
'@types/stack-utils': 2.0.3
chalk: 4.1.2
@@ -3339,7 +3345,7 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
jest-util: 29.7.0
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@@ -3374,7 +3380,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11
@@ -3402,7 +3408,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
cjs-module-lexer: 1.4.1
collect-v8-coverage: 1.0.2
@@ -3423,7 +3429,7 @@ snapshots:
jest-snapshot@29.7.0:
dependencies:
'@babel/core': 7.26.0
'@babel/generator': 7.26.0
'@babel/generator': 7.26.2
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0)
'@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0)
'@babel/types': 7.26.0
@@ -3448,7 +3454,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -3467,7 +3473,7 @@ snapshots:
dependencies:
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.8.1
'@types/node': 22.8.6
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -3476,17 +3482,17 @@ snapshots:
jest-worker@29.7.0:
dependencies:
'@types/node': 22.8.1
'@types/node': 22.8.6
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
jest@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)):
jest@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)):
dependencies:
'@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
'@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
'@jest/types': 29.6.3
import-local: 3.2.0
jest-cli: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
jest-cli: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@@ -3648,7 +3654,7 @@ snapshots:
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.26.0
'@babel/code-frame': 7.26.2
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
@@ -3822,16 +3828,16 @@ snapshots:
dependencies:
is-number: 7.0.0
ts-api-utils@1.3.0(typescript@5.6.3):
ts-api-utils@1.4.0(typescript@5.6.3):
dependencies:
typescript: 5.6.3
ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)))(typescript@5.6.3):
ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3)))(typescript@5.6.3):
dependencies:
bs-logger: 0.2.6
ejs: 3.1.10
fast-json-stable-stringify: 2.1.0
jest: 29.7.0(@types/node@22.8.1)(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))
jest: 29.7.0(@types/node@22.8.6)(ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3))
jest-util: 29.7.0
json5: 2.2.3
lodash.memoize: 4.1.2
@@ -3845,14 +3851,14 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.26.0)
ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3):
ts-node@10.9.2(@types/node@22.8.6)(typescript@5.6.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
'@types/node': 22.8.1
'@types/node': 22.8.6
acorn: 8.14.0
acorn-walk: 8.3.4
arg: 4.1.3
@@ -3873,11 +3879,11 @@ snapshots:
type-fest@0.21.3: {}
typescript-eslint@8.12.0(eslint@9.13.0)(typescript@5.6.3):
typescript-eslint@8.12.2(eslint@9.13.0)(typescript@5.6.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.12.0(@typescript-eslint/parser@8.12.0(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/parser': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.0(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
optionalDependencies:
typescript: 5.6.3
transitivePeerDependencies:

View File

@@ -19,6 +19,13 @@ export const BASE_INDEX_MANIFEST_FILENAME = 'index.json';
export const PREV_INDEX_MANIFEST_FILENAME = 'index1.json';
export const CACHE_DIR = '.cache';
export const TMP_DIR = 'tmp';
export const PR_ARTIFACT_DIR = 'pr';
export const PR_DIFF_FILENAME = 'PR_DIFF';
export const PR_ERROR_FILENAME = 'PR_ERROR';
export const PR_NUMBER_FILENAME = 'PR_NUMBER';
export const PR_ARTIFACT_DIFF_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_DIFF_FILENAME);
export const PR_ARTIFACT_ERROR_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_ERROR_FILENAME);
export const PR_ARTIFACT_NUMBER_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_NUMBER_FILENAME);
/**
* 'ikea_new' first, to prioritize downloads from new URL
*/

68
src/ghw_check_ota_pr.ts Normal file
View File

@@ -0,0 +1,68 @@
import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import assert from 'assert';
import {existsSync, mkdirSync, writeFileSync} from 'fs';
import {
BASE_INDEX_MANIFEST_FILENAME,
execute,
PR_ARTIFACT_DIFF_FILEPATH,
PR_ARTIFACT_DIR,
PR_ARTIFACT_ERROR_FILEPATH,
PR_ARTIFACT_NUMBER_FILEPATH,
PREV_INDEX_MANIFEST_FILENAME,
readManifest,
writeManifest,
} from './common.js';
import {getChangedOtaFiles} from './ghw_get_changed_ota_files.js';
import {processOtaFiles} from './ghw_process_ota_files.js';
function throwError(comment: string): void {
writeFileSync(PR_ARTIFACT_ERROR_FILEPATH, comment);
throw new Error(comment);
}
export async function checkOtaPR(github: Octokit, core: typeof CoreApi, context: Context): Promise<void> {
assert(context.payload.pull_request, 'Not a pull request');
assert(!context.payload.pull_request.merged, 'Should not be executed on a merged pull request');
if (!existsSync(PR_ARTIFACT_DIR)) {
mkdirSync(PR_ARTIFACT_DIR, {recursive: true});
}
writeFileSync(PR_ARTIFACT_NUMBER_FILEPATH, context.issue.number.toString(10), 'utf8');
const baseManifest = readManifest(BASE_INDEX_MANIFEST_FILENAME);
const prevManifest = readManifest(PREV_INDEX_MANIFEST_FILENAME);
try {
const filePaths = await getChangedOtaFiles(
github,
core,
context,
`${context.payload.pull_request.base.sha}...${context.payload.pull_request.head.sha}`,
true,
);
await processOtaFiles(github, core, context, filePaths, baseManifest, prevManifest);
} catch (error) {
throwError((error as Error).message);
}
writeManifest(PREV_INDEX_MANIFEST_FILENAME, prevManifest);
writeManifest(BASE_INDEX_MANIFEST_FILENAME, baseManifest);
core.info(`Prev manifest has ${prevManifest.length} images.`);
core.info(`Base manifest has ${baseManifest.length} images.`);
const diff = await execute(`git diff`);
core.startGroup('diff');
core.info(diff);
core.endGroup();
writeFileSync(PR_ARTIFACT_DIFF_FILEPATH, diff);
}

View File

@@ -2,8 +2,9 @@ import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import type {RepoImageMeta} from './types.js';
import {BASE_IMAGES_DIR, BASE_INDEX_MANIFEST_FILENAME, execute, PREV_IMAGES_DIR, PREV_INDEX_MANIFEST_FILENAME, readManifest} from './common.js';
import {RepoImageMeta} from './types.js';
// about 3 lines
const MAX_RELEASE_NOTES_LENGTH = 380;

View File

@@ -0,0 +1,34 @@
import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import assert from 'assert';
import {BASE_IMAGES_DIR} from './common.js';
export async function getChangedOtaFiles(
github: Octokit,
core: typeof CoreApi,
context: Context,
basehead: string,
isPR: boolean,
): Promise<string[]> {
// NOTE: includes up to 300 files, per https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#compare-two-commits
const compare = await github.rest.repos.compareCommitsWithBasehead({
owner: context.repo.owner,
repo: context.repo.repo,
basehead,
});
assert(compare.data.files && compare.data.files.length > 0, 'No file');
core.info(`Changed files: ${compare.data.files.map((f) => f.filename).join(', ')}`);
const fileList = compare.data.files.filter((f) => f.filename.startsWith(`${BASE_IMAGES_DIR}/`));
if (isPR && fileList.length !== compare.data.files.length) {
throw new Error(`Detected changes in files outside of \`images\` directory. This is not allowed for a pull request with OTA files.`);
}
return fileList.map((f) => f.filename);
}

View File

@@ -2,9 +2,8 @@ import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import type {ExtraMetas, GHExtraMetas} from './types';
import type {ExtraMetas, GHExtraMetas, RepoImageMeta} from './types.js';
import assert from 'assert';
import {readFileSync, renameSync} from 'fs';
import path from 'path';
@@ -12,8 +11,6 @@ import {
addImageToBase,
addImageToPrev,
BASE_IMAGES_DIR,
BASE_INDEX_MANIFEST_FILENAME,
execute,
findMatchImage,
getOutDir,
getParsedImageStatus,
@@ -21,10 +18,7 @@ import {
ParsedImageStatus,
parseImageHeader,
PREV_IMAGES_DIR,
PREV_INDEX_MANIFEST_FILENAME,
readManifest,
UPGRADE_FILE_IDENTIFIER,
writeManifest,
} from './common.js';
const EXTRA_METAS_PR_BODY_START_TAG = '```json';
@@ -75,97 +69,46 @@ async function parsePRBodyExtraMetas(github: Octokit, core: typeof CoreApi, cont
}
}
} catch (error) {
const failureComment = `Invalid extra metas in pull request body: ` + (error as Error).message;
core.error(failureComment);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: failureComment,
});
throw new Error(failureComment);
throw new Error(`Invalid extra metas in pull request body: ${(error as Error).message}`);
}
}
return extraMetas;
}
export async function updateOtaPR(github: Octokit, core: typeof CoreApi, context: Context, fileParam: string): Promise<void> {
assert(fileParam, 'No file found in pull request.');
assert(context.payload.pull_request, 'Not a pull request');
const fileParamArr = fileParam.trim().split(',');
// take care of empty strings (GH workflow adds a comma at end), ignore files not stored in images dir
const fileList = fileParamArr.filter((f) => f.startsWith(`${BASE_IMAGES_DIR}/`));
assert(fileList.length > 0, 'No image found in pull request.');
core.info(`Images in pull request: ${fileList}.`);
const fileListWrongDir = fileParamArr.filter((f) => f.startsWith(`${PREV_IMAGES_DIR}/`));
if (fileListWrongDir.length > 0) {
const failureComment = `Detected files in 'images1':
\`\`\`
${fileListWrongDir.join('\n')}
\`\`\`
Please move all files to 'images' (in appropriate subfolders). The pull request will automatically determine the proper location on merge.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: failureComment,
});
throw new Error(failureComment);
}
const fileListNoIndex = fileParamArr.filter((f) => f.startsWith(BASE_INDEX_MANIFEST_FILENAME) || f.startsWith(PREV_INDEX_MANIFEST_FILENAME));
if (fileListNoIndex.length > 0) {
const failureComment = `Detected manual changes in ${fileListNoIndex.join(', ')}. Please remove these changes. The pull request will automatically determine the manifests on merge.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: failureComment,
});
throw new Error(failureComment);
}
// called at the top, fail early if invalid PR body metas
export async function processOtaFiles(
github: Octokit,
core: typeof CoreApi,
context: Context,
filePaths: string[],
baseManifest: RepoImageMeta[],
prevManifest: RepoImageMeta[],
): Promise<void> {
const extraMetas = await parsePRBodyExtraMetas(github, core, context);
const baseManifest = readManifest(BASE_INDEX_MANIFEST_FILENAME);
const prevManifest = readManifest(PREV_INDEX_MANIFEST_FILENAME);
for (const file of fileList) {
core.startGroup(file);
core.info(`Processing '${file}'...`);
for (const filePath of filePaths) {
core.startGroup(filePath);
const logPrefix = `[${filePath}]`;
let failureComment: string = '';
try {
const firmwareFileName = path.basename(file);
const manufacturer = file.replace(BASE_IMAGES_DIR, '').replace(firmwareFileName, '').replaceAll('/', '').trim();
const firmwareFileName = path.basename(filePath);
const manufacturer = filePath.replace(BASE_IMAGES_DIR, '').replace(firmwareFileName, '').replaceAll('/', '').trim();
if (!manufacturer) {
throw new Error(`\`${file}\` should be in its associated manufacturer subfolder.`);
throw new Error(`File should be in its associated manufacturer subfolder`);
}
const firmwareBuffer = Buffer.from(readFileSync(file));
const firmwareBuffer = Buffer.from(readFileSync(filePath));
const parsedImage = parseImageHeader(firmwareBuffer.subarray(firmwareBuffer.indexOf(UPGRADE_FILE_IDENTIFIER)));
core.info(`[${file}] Parsed image header:`);
core.info(`${logPrefix} Parsed image header:`);
core.info(JSON.stringify(parsedImage, undefined, 2));
const fileExtraMetas = getFileExtraMetas(extraMetas, firmwareFileName);
core.info(`[${file}] Extra metas:`);
core.info(`${logPrefix} Extra metas:`);
core.info(JSON.stringify(fileExtraMetas, undefined, 2));
const baseOutDir = getOutDir(manufacturer, BASE_IMAGES_DIR);
@@ -200,7 +143,7 @@ ${JSON.stringify(parsedImage, undefined, 2)}
case ParsedImageStatus.NEWER:
case ParsedImageStatus.NEW: {
addImageToPrev(
`[${file}]`,
logPrefix,
statusToPrev === ParsedImageStatus.NEWER,
prevManifest,
prevMatchIndex,
@@ -214,7 +157,7 @@ ${JSON.stringify(parsedImage, undefined, 2)}
fileExtraMetas,
() => {
// relocate file to prev
renameSync(file, file.replace(`${BASE_IMAGES_DIR}/`, `${PREV_IMAGES_DIR}/`));
renameSync(filePath, filePath.replace(`${BASE_IMAGES_DIR}/`, `${PREV_IMAGES_DIR}/`));
},
);
@@ -240,7 +183,7 @@ ${JSON.stringify(parsedImage, undefined, 2)}
case ParsedImageStatus.NEWER:
case ParsedImageStatus.NEW: {
addImageToBase(
`[${file}]`,
logPrefix,
statusToBase === ParsedImageStatus.NEWER,
prevManifest,
prevOutDir,
@@ -267,41 +210,10 @@ ${JSON.stringify(parsedImage, undefined, 2)}
}
if (failureComment) {
core.error(`[${file}] ` + failureComment);
await github.rest.pulls.createReviewComment({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: failureComment,
commit_id: context.payload.pull_request.head.sha,
path: file,
subject_type: 'file',
});
throw new Error(failureComment);
core.endGroup();
throw new Error(`${logPrefix} ${failureComment}`);
}
core.endGroup();
}
writeManifest(PREV_INDEX_MANIFEST_FILENAME, prevManifest);
writeManifest(BASE_INDEX_MANIFEST_FILENAME, baseManifest);
core.info(`Prev manifest has ${prevManifest.length} images.`);
core.info(`Base manifest has ${baseManifest.length} images.`);
if (!context.payload.pull_request.merged) {
const diff = await execute(`git diff`);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Merging this pull request will add these changes in a following commit:
\`\`\`diff
${diff}
\`\`\`
`,
});
}
}

82
src/ghw_report_ota_pr.ts Normal file
View File

@@ -0,0 +1,82 @@
import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import assert from 'assert';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {execute, PR_ARTIFACT_DIR, PR_DIFF_FILENAME, PR_ERROR_FILENAME, PR_NUMBER_FILENAME} from './common.js';
export async function reportOtaPR(github: Octokit, core: typeof CoreApi, context: Context): Promise<void> {
assert(context.payload.workflow_run, 'Not a workflow run');
// XXX: context.payload.workflow_run is not typed...
const workflow_run = context.payload.workflow_run as Awaited<ReturnType<typeof github.rest.actions.getWorkflowRun>>['data'];
// workflow_run.conclusion: action_required, cancelled, failure, neutral, skipped, stale, success, timed_out, startup_failure, null
if (workflow_run.conclusion !== 'success' && workflow_run.conclusion !== 'failure') {
core.info(`Ignoring workflow run ${workflow_run.html_url} with conclusion ${workflow_run.conclusion}.`);
return;
}
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: workflow_run.id,
});
const matchArtifact = artifacts.data.artifacts.find((artifact) => artifact.name == PR_ARTIFACT_DIR);
assert(matchArtifact, `No artifact found for ${workflow_run.url}`);
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
const artifactZipFileName = `${PR_ARTIFACT_DIR}.zip`;
writeFileSync(artifactZipFileName, Buffer.from(download.data as ArrayBuffer));
const unzipOutput = await execute(`unzip ${artifactZipFileName}`);
core.info(unzipOutput);
assert(existsSync(PR_NUMBER_FILENAME), `Invalid artifact for ${workflow_run.html_url}`);
const prNumber = parseInt(readFileSync(PR_NUMBER_FILENAME, 'utf8'), 10);
core.info(`Running for pr#${prNumber} for ${workflow_run.html_url}`);
if (workflow_run.conclusion === 'failure') {
assert(existsSync(PR_ERROR_FILENAME), `Workflow failed but could not find ${PR_ERROR_FILENAME} for ${workflow_run.html_url}`);
const prError = readFileSync(PR_ERROR_FILENAME, 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: prError,
});
throw new Error(prError);
} else if (workflow_run.conclusion === 'success') {
assert(existsSync(PR_DIFF_FILENAME), `Workflow succeeded but could not find ${PR_DIFF_FILENAME} for ${workflow_run.html_url}`);
const prDiff = readFileSync(PR_DIFF_FILENAME, 'utf8');
core.info(prDiff);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `Merging this pull request will add these changes in a following commit:
\`\`\`diff
${prDiff}
\`\`\`
`,
});
}
}

View File

@@ -0,0 +1,26 @@
import type CoreApi from '@actions/core';
import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
import assert from 'assert';
import {BASE_INDEX_MANIFEST_FILENAME, PREV_INDEX_MANIFEST_FILENAME, readManifest, writeManifest} from './common.js';
import {getChangedOtaFiles} from './ghw_get_changed_ota_files.js';
import {processOtaFiles} from './ghw_process_ota_files.js';
export async function updateManifests(github: Octokit, core: typeof CoreApi, context: Context): Promise<void> {
assert(context.eventName === 'push', 'Not a push');
const filePaths = await getChangedOtaFiles(github, core, context, `${context.payload.before}...${context.payload.after}`, false);
const baseManifest = readManifest(BASE_INDEX_MANIFEST_FILENAME);
const prevManifest = readManifest(PREV_INDEX_MANIFEST_FILENAME);
// will throw if anything goes wrong
await processOtaFiles(github, core, context, filePaths, baseManifest, prevManifest);
writeManifest(PREV_INDEX_MANIFEST_FILENAME, prevManifest);
writeManifest(BASE_INDEX_MANIFEST_FILENAME, baseManifest);
core.info(`Prev manifest has ${prevManifest.length} images.`);
core.info(`Base manifest has ${baseManifest.length} images.`);
}

View File

@@ -1,9 +1,13 @@
export * as common from './common.js';
export {checkOtaPR} from './ghw_check_ota_pr.js';
export {concatCaCerts} from './ghw_concat_cacerts.js';
export {createAutodlRelease} from './ghw_create_autodl_release.js';
export {createPRToDefault} from './ghw_create_pr_to_default.js';
export {getChangedOtaFiles} from './ghw_get_changed_ota_files.js';
export {overwriteCache} from './ghw_overwrite_cache.js';
export {processOtaFiles} from './ghw_process_ota_files.js';
export {reportOtaPR} from './ghw_report_ota_pr.js';
export {reProcessAllImages} from './ghw_reprocess_all_images.js';
export {runAutodl} from './ghw_run_autodl.js';
export {updateOtaPR} from './ghw_update_ota_pr.js';
export {updateManifests} from './ghw_update_manifests.js';
export {processFirmwareImage} from './process_firmware_image.js';

View File

@@ -202,7 +202,7 @@ export const getImageOriginalDirPath = (imageName: string): string => {
return path.join('tests', common.BASE_IMAGES_DIR, imageName);
};
export const useImage = (imageName: string, outDir: string = BASE_IMAGES_TEST_DIR_PATH): string => {
export const useImage = (imageName: string, outDir: string = BASE_IMAGES_TEST_DIR_PATH): {filename: string} => {
const realPath = path.join(outDir, imageName);
if (!existsSync(outDir)) {
@@ -212,7 +212,7 @@ export const useImage = (imageName: string, outDir: string = BASE_IMAGES_TEST_DI
copyFileSync(getImageOriginalDirPath(imageName), realPath);
// return as posix for github match
return path.posix.join(BASE_IMAGES_TEST_DIR_PATH.replaceAll('\\', '/'), imageName);
return {filename: path.posix.join(outDir.replaceAll('\\', '/'), imageName)};
};
export const withExtraMetas = (meta: RepoImageMeta, extraMetas: ExtraMetas): RepoImageMeta => {

View File

@@ -4,10 +4,11 @@ import type {Octokit} from '@octokit/rest';
import type {RepoImageMeta} from '../src/types';
import {rmSync} from 'fs';
import {existsSync, readFileSync, rmSync} from 'fs';
import path from 'path';
import * as common from '../src/common';
import {updateOtaPR} from '../src/ghw_update_ota_pr';
import {checkOtaPR} from '../src/ghw_check_ota_pr';
import {
BASE_IMAGES_TEST_DIR_PATH,
getAdjustedContent,
@@ -27,17 +28,10 @@ import {
const github = {
rest: {
issues: {
createComment: jest.fn<
ReturnType<Octokit['rest']['issues']['createComment']>,
Parameters<Octokit['rest']['issues']['createComment']>,
unknown
>(),
},
pulls: {
createReviewComment: jest.fn<
ReturnType<Octokit['rest']['pulls']['createReviewComment']>,
Parameters<Octokit['rest']['pulls']['createReviewComment']>,
repos: {
compareCommitsWithBasehead: jest.fn<
ReturnType<Octokit['rest']['repos']['compareCommitsWithBasehead']>,
Parameters<Octokit['rest']['repos']['compareCommitsWithBasehead']>,
unknown
>(),
},
@@ -59,6 +53,9 @@ const context: Partial<Context> = {
head: {
sha: 'abcd',
},
base: {
sha: 'zyxw',
},
},
},
issue: {
@@ -72,13 +69,14 @@ const context: Partial<Context> = {
},
};
describe('Github Workflow: Update OTA PR', () => {
describe('Github Workflow: Check OTA PR', () => {
let baseManifest: RepoImageMeta[];
let prevManifest: RepoImageMeta[];
let readManifestSpy: jest.SpyInstance;
let writeManifestSpy: jest.SpyInstance;
let addImageToBaseSpy: jest.SpyInstance;
let addImageToPrevSpy: jest.SpyInstance;
let filePaths: ReturnType<typeof useImage>[] = [];
const getManifest = (fileName: string): RepoImageMeta[] => {
if (fileName === common.BASE_INDEX_MANIFEST_FILENAME) {
@@ -141,15 +139,21 @@ describe('Github Workflow: Update OTA PR', () => {
beforeEach(() => {
resetManifests();
filePaths = [];
readManifestSpy = jest.spyOn(common, 'readManifest').mockImplementation(getManifest);
writeManifestSpy = jest.spyOn(common, 'writeManifest').mockImplementation(setManifest);
addImageToBaseSpy = jest.spyOn(common, 'addImageToBase');
addImageToPrevSpy = jest.spyOn(common, 'addImageToPrev');
github.rest.repos.compareCommitsWithBasehead.mockImplementation(
// @ts-expect-error mock
() => ({data: {files: filePaths}}),
);
});
afterEach(() => {
rmSync(BASE_IMAGES_TEST_DIR_PATH, {recursive: true, force: true});
rmSync(PREV_IMAGES_TEST_DIR_PATH, {recursive: true, force: true});
rmSync(common.PR_ARTIFACT_DIR, {recursive: true, force: true});
});
// XXX: Util
@@ -162,128 +166,125 @@ describe('Github Workflow: Update OTA PR', () => {
// })
it('hard failure from outside PR context', async () => {
const fileParam: string = `images/test.ota`;
filePaths = [useImage(IMAGE_V14_1)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, {payload: {}}, fileParam);
await checkOtaPR(github, core, {payload: {}});
}).rejects.toThrow(`Not a pull request`);
expectNoChanges(true);
});
it('hard failure without fileParam', async () => {
// NOTE: this path should always be prevented by workflow `paths` filter
const fileParam: string = '';
it('hard failure from merged PR context', async () => {
filePaths = [useImage(IMAGE_V14_1)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
}).rejects.toThrow(`No file found in pull request.`);
await checkOtaPR(github, core, {payload: {pull_request: {merged: true}}});
}).rejects.toThrow(`Should not be executed on a merged pull request`);
expectNoChanges(true);
});
it('failure with images in images1', async () => {
const fileParam: string = `images1/test2.ota,images/test.ota`;
it('hard failure with no file changed', async () => {
filePaths = [];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Detected files in 'images1'`)}));
expectNoChanges(true);
expect(github.rest.issues.createComment).toHaveBeenCalledTimes(1);
});
it('failure with edited manifest', async () => {
const fileParam: string = `index.json,images/test.ota`;
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Detected manual changes in index.json`)}));
expectNoChanges(true);
expect(github.rest.issues.createComment).toHaveBeenCalledTimes(1);
});
it('failure when no subfolder (manufacturer)', async () => {
const fileParam: string = `images/test.ota`;
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
}).rejects.toThrow(
expect.objectContaining({message: expect.stringContaining(`\`images/test.ota\` should be in its associated manufacturer subfolder.`)}),
);
await checkOtaPR(github, core, context);
}).rejects.toThrow(`No file`);
expectNoChanges(false);
expect(github.rest.pulls.createReviewComment).toHaveBeenCalledTimes(1);
expect(existsSync(common.PR_ARTIFACT_NUMBER_FILEPATH)).toStrictEqual(true);
expect(readFileSync(common.PR_ARTIFACT_NUMBER_FILEPATH, 'utf8')).toStrictEqual(`${context.payload?.pull_request?.number}`);
expect(existsSync(common.PR_ARTIFACT_DIFF_FILEPATH)).toStrictEqual(false);
expect(existsSync(common.PR_ARTIFACT_ERROR_FILEPATH)).toStrictEqual(true);
expect(readFileSync(common.PR_ARTIFACT_ERROR_FILEPATH, 'utf8')).toStrictEqual(`No file`);
});
it('failure with file outside of images directory', async () => {
filePaths = [useImage(IMAGE_V13_1, PREV_IMAGES_TEST_DIR_PATH), useImage(IMAGE_V14_1)];
await expect(async () => {
// @ts-expect-error mock
await checkOtaPR(github, core, context);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Detected changes in files outside`)}));
expectNoChanges(false);
});
it('failure when no manufacturer subfolder', async () => {
filePaths = [useImage(IMAGE_V14_1, common.BASE_IMAGES_DIR)];
await expect(async () => {
// @ts-expect-error mock
await checkOtaPR(github, core, context);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`File should be in its associated manufacturer subfolder`)}));
expectNoChanges(false);
rmSync(path.join(common.BASE_IMAGES_DIR, IMAGE_V14_1), {force: true});
});
it('failure with invalid OTA file', async () => {
const fileParam: string = useImage(IMAGE_INVALID);
filePaths = [useImage(IMAGE_INVALID)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Not a valid OTA file`)}));
expectNoChanges(false);
expect(github.rest.pulls.createReviewComment).toHaveBeenCalledTimes(1);
});
it('failure with identical OTA file', async () => {
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V14_1_METAS]);
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Conflict with image at index \`0\``)}));
expectNoChanges(false);
expect(github.rest.pulls.createReviewComment).toHaveBeenCalledTimes(1);
});
it('failure with older OTA file that has identical in prev', async () => {
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V14_1_METAS]);
setManifest(common.PREV_INDEX_MANIFEST_FILENAME, [IMAGE_V13_1_METAS]);
const fileParam: string = useImage(IMAGE_V13_1);
filePaths = [useImage(IMAGE_V13_1)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
}).rejects.toThrow(
expect.objectContaining({message: expect.stringContaining(`an equal or better match is already present in prev manifest`)}),
);
expectNoChanges(false);
expect(github.rest.pulls.createReviewComment).toHaveBeenCalledTimes(1);
});
it('failure with older OTA file that has newer in prev', async () => {
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V14_1_METAS]);
setManifest(common.PREV_INDEX_MANIFEST_FILENAME, [IMAGE_V13_1_METAS]);
const fileParam: string = useImage(IMAGE_V12_1);
filePaths = [useImage(IMAGE_V12_1)];
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
}).rejects.toThrow(
expect.objectContaining({message: expect.stringContaining(`an equal or better match is already present in prev manifest`)}),
);
expectNoChanges(false);
expect(github.rest.pulls.createReviewComment).toHaveBeenCalledTimes(1);
});
it('success into base', async () => {
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);
@@ -291,15 +292,19 @@ describe('Github Workflow: Update OTA PR', () => {
expect(addImageToPrevSpy).toHaveBeenCalledTimes(0);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V14_1_METAS]);
expect(existsSync(common.PR_ARTIFACT_NUMBER_FILEPATH)).toStrictEqual(true);
expect(readFileSync(common.PR_ARTIFACT_NUMBER_FILEPATH, 'utf8')).toStrictEqual(`${context.payload?.pull_request?.number}`);
expect(existsSync(common.PR_ARTIFACT_DIFF_FILEPATH)).toStrictEqual(true);
expect(existsSync(common.PR_ARTIFACT_ERROR_FILEPATH)).toStrictEqual(false);
});
it('success into prev', async () => {
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V14_1_METAS]);
const fileParam: string = useImage(IMAGE_V13_1);
filePaths = [useImage(IMAGE_V13_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);
@@ -310,10 +315,10 @@ describe('Github Workflow: Update OTA PR', () => {
});
it('success with newer than current without existing prev', async () => {
const fileParam: string = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(addImageToBaseSpy).toHaveBeenCalledTimes(2); // adds both, relocates first during second processing
@@ -324,10 +329,10 @@ describe('Github Workflow: Update OTA PR', () => {
});
it('success with newer than current with existing prev', async () => {
const fileParam: string = [useImage(IMAGE_V12_1), useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V12_1), useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(addImageToBaseSpy).toHaveBeenCalledTimes(3); // adds both, relocates first during second processing
@@ -339,10 +344,10 @@ describe('Github Workflow: Update OTA PR', () => {
it('success with older that is newer than prev', async () => {
setManifest(common.PREV_INDEX_MANIFEST_FILENAME, [IMAGE_V12_1_METAS]);
const fileParam: string = [useImage(IMAGE_V14_1), useImage(IMAGE_V13_1)].join(',');
filePaths = [useImage(IMAGE_V14_1), useImage(IMAGE_V13_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(addImageToBaseSpy).toHaveBeenCalledTimes(1);
@@ -354,10 +359,10 @@ describe('Github Workflow: Update OTA PR', () => {
it('success with newer with missing file', async () => {
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [IMAGE_V13_1_METAS]);
const fileParam: string = [useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V14_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(addImageToBaseSpy).toHaveBeenCalledTimes(1);
@@ -368,10 +373,10 @@ describe('Github Workflow: Update OTA PR', () => {
});
it('success with multiple different files', async () => {
const fileParam: string = [useImage(IMAGE_V14_2), useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V14_2), useImage(IMAGE_V14_1)];
// @ts-expect-error mock
await updateOtaPR(github, core, context, fileParam);
await checkOtaPR(github, core, context);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(addImageToBaseSpy).toHaveBeenCalledTimes(2); // adds both, relocates first during second processing
@@ -382,11 +387,11 @@ describe('Github Workflow: Update OTA PR', () => {
});
it('success with extra metas', async () => {
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
const newContext = withBody(`Text before start tag \`\`\`json {"manufacturerName": ["lixee"]} \`\`\` Text after end tag`);
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);
@@ -399,7 +404,7 @@ describe('Github Workflow: Update OTA PR', () => {
});
it('success with all extra metas', async () => {
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
const newContext = withBody(`Text before start tag
\`\`\`json
{
@@ -416,7 +421,7 @@ describe('Github Workflow: Update OTA PR', () => {
Text after end tag`);
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);
@@ -438,18 +443,17 @@ Text after end tag`);
});
it('failure with invalid extra metas', async () => {
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
const newContext = withBody(`Text before start tag \`\`\`json {"manufacturerName": "myManuf"} \`\`\` Text after end tag`);
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
}).rejects.toThrow(
expect.objectContaining({message: expect.stringContaining(`Invalid format for 'manufacturerName', expected 'array of string' type.`)}),
);
expectNoChanges(true);
expect(github.rest.issues.createComment).toHaveBeenCalledTimes(1);
expectNoChanges(false);
});
it.each([
@@ -464,21 +468,20 @@ Text after end tag`);
['modelId'],
['releaseNotes'],
])('failure with invalid type for extra meta %s', async (metaName) => {
const fileParam: string = useImage(IMAGE_V14_1);
filePaths = [useImage(IMAGE_V14_1)];
// use object since no value type is ever expected to be object
const newContext = withBody(`Text before start tag \`\`\`json {"${metaName}": {}} \`\`\` Text after end tag`);
await expect(async () => {
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
}).rejects.toThrow(expect.objectContaining({message: expect.stringContaining(`Invalid format for '${metaName}'`)}));
expectNoChanges(true);
expect(github.rest.issues.createComment).toHaveBeenCalledTimes(1);
expectNoChanges(false);
});
it('success with multiple files and specific extra metas', async () => {
const fileParam: string = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)];
const newContext = withBody(`Text before start tag
\`\`\`json
[
@@ -489,7 +492,7 @@ Text after end tag`);
Text after end tag`);
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);
@@ -505,7 +508,7 @@ Text after end tag`);
});
it('success with multiple files and specific extra metas, ignore without fileName', async () => {
const fileParam: string = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)].join(',');
filePaths = [useImage(IMAGE_V13_1), useImage(IMAGE_V14_1)];
const newContext = withBody(`Text before start tag
\`\`\`json
[
@@ -516,7 +519,7 @@ Text after end tag`);
Text after end tag`);
// @ts-expect-error mock
await updateOtaPR(github, core, newContext, fileParam);
await checkOtaPR(github, core, newContext);
expect(readManifestSpy).toHaveBeenCalledWith(common.BASE_INDEX_MANIFEST_FILENAME);
expect(readManifestSpy).toHaveBeenCalledWith(common.PREV_INDEX_MANIFEST_FILENAME);

View File

@@ -0,0 +1,29 @@
// import type CoreApi from '@actions/core';
// import type {Context} from '@actions/github/lib/context';
import type {Octokit} from '@octokit/rest';
const github = {
rest: {
issues: {
createComment: jest.fn<
ReturnType<Octokit['rest']['issues']['createComment']>,
Parameters<Octokit['rest']['issues']['createComment']>,
unknown
>(),
},
pulls: {
createReviewComment: jest.fn<
ReturnType<Octokit['rest']['pulls']['createReviewComment']>,
Parameters<Octokit['rest']['pulls']['createReviewComment']>,
unknown
>(),
},
},
};
describe('Github Workflow: Report OTA PR', () => {
it('passes', async () => {
console.log(github);
});
});

View File

@@ -245,7 +245,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(imagePath)).toStrictEqual(false);
expect(existsSync(imagePath.filename)).toStrictEqual(false);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expectWriteNoChange(1, common.PREV_INDEX_MANIFEST_FILENAME);
@@ -261,9 +261,9 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(image1Path)).toStrictEqual(false);
expect(existsSync(image2Path)).toStrictEqual(false);
expect(existsSync(image3Path)).toStrictEqual(false);
expect(existsSync(image1Path.filename)).toStrictEqual(false);
expect(existsSync(image2Path.filename)).toStrictEqual(false);
expect(existsSync(image3Path.filename)).toStrictEqual(false);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expectWriteNoChange(1, common.PREV_INDEX_MANIFEST_FILENAME);
@@ -281,7 +281,7 @@ describe('Github Workflow: Re-Process All Images', () => {
await reProcessAllImages(github, core, context, false, true);
const newPath = path.join(NOT_IN_BASE_MANIFEST_IMAGE_DIR_PATH, IMAGE_V12_1);
expect(existsSync(oldPath)).toStrictEqual(false);
expect(existsSync(oldPath.filename)).toStrictEqual(false);
expect(existsSync(newPath)).toStrictEqual(true);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(3);
@@ -302,11 +302,11 @@ describe('Github Workflow: Re-Process All Images', () => {
const newPath2 = path.join(NOT_IN_BASE_MANIFEST_IMAGE_DIR_PATH, IMAGE_V12_1);
const newPath3 = path.join(NOT_IN_PREV_MANIFEST_IMAGE_DIR_PATH, IMAGE_V12_1);
expect(existsSync(newPath1)).toStrictEqual(true);
expect(existsSync(oldPath1)).toStrictEqual(false);
expect(existsSync(oldPath1.filename)).toStrictEqual(false);
expect(existsSync(newPath2)).toStrictEqual(true);
expect(existsSync(oldPath2)).toStrictEqual(false);
expect(existsSync(oldPath2.filename)).toStrictEqual(false);
expect(existsSync(newPath3)).toStrictEqual(true);
expect(existsSync(oldPath3)).toStrictEqual(false);
expect(existsSync(oldPath3.filename)).toStrictEqual(false);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(4);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, NOT_IN_PREV_MANIFEST_FILEPATH, expect.any(Array));
@@ -321,7 +321,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, false, true);
expect(existsSync(oldPath)).toStrictEqual(false);
expect(existsSync(oldPath.filename)).toStrictEqual(false);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, common.PREV_INDEX_MANIFEST_FILENAME, []);
@@ -338,7 +338,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(oldPath)).toStrictEqual(false);
expect(existsSync(oldPath.filename)).toStrictEqual(false);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, common.PREV_INDEX_MANIFEST_FILENAME, []);
@@ -354,7 +354,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(imagePath)).toStrictEqual(true);
expect(existsSync(imagePath.filename)).toStrictEqual(true);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, common.PREV_INDEX_MANIFEST_FILENAME, []);
@@ -369,9 +369,9 @@ describe('Github Workflow: Re-Process All Images', () => {
oldMetas.url = baseUrl + escape(newName);
setManifest(common.BASE_INDEX_MANIFEST_FILENAME, [oldMetas]);
const imagePath = useImage(IMAGE_V14_1, BASE_IMAGES_TEST_DIR_PATH);
const baseName = path.basename(imagePath);
const renamedPath = imagePath.replace(baseName, newName);
renameSync(imagePath, renamedPath);
const baseName = path.basename(imagePath.filename);
const renamedPath = imagePath.filename.replace(baseName, newName);
renameSync(imagePath.filename, renamedPath);
console.log(newName, oldMetas.url, renamedPath);
// @ts-expect-error mocked as needed
@@ -399,7 +399,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(image1Path)).toStrictEqual(true);
expect(existsSync(image1Path.filename)).toStrictEqual(true);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, common.PREV_INDEX_MANIFEST_FILENAME, []);
@@ -418,7 +418,7 @@ describe('Github Workflow: Re-Process All Images', () => {
// @ts-expect-error mocked as needed
await reProcessAllImages(github, core, context, true, true);
expect(existsSync(image1Path)).toStrictEqual(true);
expect(existsSync(image1Path.filename)).toStrictEqual(true);
expect(readManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenCalledTimes(2);
expect(writeManifestSpy).toHaveBeenNthCalledWith(1, common.PREV_INDEX_MANIFEST_FILENAME, []);

View File

@@ -26,7 +26,13 @@ const config: JestConfigWithTsJest = {
collectCoverage: false,
// An array of glob patterns indicating a set of files for which coverage information should be collected
collectCoverageFrom: ['src/ghw_update_ota_pr.ts', 'src/process_firmware_image.ts', 'src/ghw_reprocess_all_images.ts'],
collectCoverageFrom: [
'src/ghw_check_ota_pr.ts',
'src/ghw_get_changed_ota_files.ts',
'src/ghw_process_ota_files.ts',
'src/process_firmware_image.ts',
'src/ghw_reprocess_all_images.ts',
],
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',