Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9208416fa4
|
||
|
|
778ac58612
|
||
|
|
e8b6be00e8
|
||
|
|
089f57f759
|
||
|
|
1d3847d070 | ||
|
|
dc43a6a747
|
||
|
|
21c952ea81 | ||
|
|
3bfafa5bac | ||
|
|
8e64d9a83c | ||
|
|
af38def2d2 | ||
|
|
f739a96f7a
|
||
|
|
a2f8f2b5fd
|
||
|
|
5ddd5a3317
|
||
|
|
cf9d53d786
|
No files matched your search
@@ -1,14 +0,0 @@
|
||||
version: 2.1
|
||||
setup: true
|
||||
orbs:
|
||||
qqq-orb: kingsrook/qqq-orb@0.8
|
||||
workflows:
|
||||
setup:
|
||||
jobs:
|
||||
- qqq-orb/generate_pipeline:
|
||||
orb_version: '0.8'
|
||||
filters:
|
||||
branches:
|
||||
ignore: automation/qbit-rc-pending
|
||||
tags:
|
||||
only: /.*/
|
||||
@@ -0,0 +1,19 @@
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
branches: ['**']
|
||||
tags: ['v*']
|
||||
jobs:
|
||||
android:
|
||||
uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/android.yaml@v1
|
||||
secrets: inherit
|
||||
with:
|
||||
node-version: '24.11.1'
|
||||
commands: |
|
||||
node scripts/ci/check-source-standards.mjs
|
||||
node --test scripts/ci/scanner-echo-guards.test.mjs
|
||||
tasks: |
|
||||
testDebugUnitTest :scanner-host:lintDebug :scanner-host:assembleDebug
|
||||
-PscannerTestBuildType=qa :scanner-host:assembleQa :scanner-host:assembleQaAndroidTest
|
||||
emulator-tasks: connectedDebugAndroidTest
|
||||
publish-tasks: :qqq:android:core:publishAllPublicationsToGiteaRepository :qqq:android:mobileapp:publishAllPublicationsToGiteaRepository
|
||||
@@ -1,13 +0,0 @@
|
||||
name: QRun Android lifecycle
|
||||
'on':
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
jobs:
|
||||
release:
|
||||
uses: self:KofTwentyTwo/platform-ci/.gitea/workflows/android.yaml@qrun-release-v1
|
||||
with:
|
||||
runner: android-build
|
||||
@@ -1,138 +0,0 @@
|
||||
name: Release scanner APK
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['scanner-v*']
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: scanner-release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
uses: ./.github/workflows/scanner.yml
|
||||
|
||||
package:
|
||||
needs: verify
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
environment: scanner-release
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Require main ancestry and a strictly newer Android version
|
||||
id: release-version
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
SCANNER_VERSION_CODE: ${{ vars.SCANNER_VERSION_CODE }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git merge-base --is-ancestor "$GITHUB_SHA" refs/remotes/origin/main
|
||||
[[ "$SCANNER_VERSION_CODE" =~ ^[1-9][0-9]{0,9}$ ]] || exit 1
|
||||
(( SCANNER_VERSION_CODE <= 2100000000 )) || exit 1
|
||||
gh api --paginate "repos/$GH_REPO/releases?per_page=100" \
|
||||
--jq '.[] | select(.draft == false) | select(.tag_name | startswith("scanner-v")) | .tag_name' > "$RUNNER_TEMP/scanner-prior-tags.txt"
|
||||
while IFS= read -r tag; do
|
||||
[[ "$tag" =~ ^scanner-v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?$ ]] || exit 1
|
||||
prior_directory=$(mktemp -d "$RUNNER_TEMP/scanner-prior.XXXXXX")
|
||||
gh release download "$tag" --pattern BUILD.txt --dir "$prior_directory"
|
||||
previous=$(sed -n 's/^Version code: //p' "$prior_directory/BUILD.txt")
|
||||
[[ "$previous" =~ ^[1-9][0-9]{0,9}$ ]] || exit 1
|
||||
(( SCANNER_VERSION_CODE > previous )) || { echo 'Version code must exceed every published scanner release'; exit 1; }
|
||||
done < "$RUNNER_TEMP/scanner-prior-tags.txt"
|
||||
printf 'code=%s\n' "$SCANNER_VERSION_CODE" >> "$GITHUB_OUTPUT"
|
||||
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4
|
||||
- name: Install Android SDK packages
|
||||
run: |
|
||||
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "platforms;android-35" "build-tools;34.0.0" "build-tools;35.0.0" "platform-tools"
|
||||
- name: Build and verify signed release
|
||||
env:
|
||||
SCANNER_KEYSTORE_BASE64: ${{ secrets.SCANNER_KEYSTORE_BASE64 }}
|
||||
SCANNER_STORE_PASSWORD: ${{ secrets.SCANNER_STORE_PASSWORD }}
|
||||
SCANNER_KEY_ALIAS: ${{ secrets.SCANNER_KEY_ALIAS }}
|
||||
SCANNER_KEY_PASSWORD: ${{ secrets.SCANNER_KEY_PASSWORD }}
|
||||
SCANNER_CERTIFICATE_SHA256: ${{ vars.SCANNER_CERTIFICATE_SHA256 }}
|
||||
SCANNER_VERSION_CODE: ${{ steps.release-version.outputs.code }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
version="${GITHUB_REF_NAME#scanner-v}"
|
||||
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?$ ]] || exit 1
|
||||
[[ "$SCANNER_VERSION_CODE" =~ ^[1-9][0-9]{0,9}$ ]] || exit 1
|
||||
(( SCANNER_VERSION_CODE <= 2100000000 )) || exit 1
|
||||
[[ "$SCANNER_CERTIFICATE_SHA256" =~ ^[A-Fa-f0-9]{64}$ ]] || exit 1
|
||||
for name in SCANNER_KEYSTORE_BASE64 SCANNER_STORE_PASSWORD SCANNER_KEY_ALIAS SCANNER_KEY_PASSWORD; do
|
||||
[[ -n "${!name}" ]] || { echo "Missing release signing configuration: $name"; exit 1; }
|
||||
done
|
||||
export SCANNER_KEYSTORE="$RUNNER_TEMP/scanner-release.jks"
|
||||
trap 'rm -f -- "$SCANNER_KEYSTORE"' EXIT
|
||||
printf '%s' "$SCANNER_KEYSTORE_BASE64" | base64 --decode > "$SCANNER_KEYSTORE"
|
||||
unset SCANNER_KEYSTORE_BASE64
|
||||
./gradlew --no-daemon --console=plain :scanner-host:lintRelease :scanner-host:assembleRelease \
|
||||
"-PscannerVersionName=$version" "-PscannerVersionCode=$SCANNER_VERSION_CODE"
|
||||
mkdir -p release
|
||||
cp scanner-host/build/outputs/apk/release/scanner-host-release.apk "release/qqq-mobile-$version.apk"
|
||||
cp scanner-host/build/reports/third-party/release/{aboutlibraries.json,LICENSE,NOTICE} release/
|
||||
"$ANDROID_HOME/build-tools/35.0.0/apksigner" verify --verbose --print-certs "release/qqq-mobile-$version.apk" > release/signature.txt
|
||||
certificate=$(sed -n 's/^Signer #1 certificate SHA-256 digest: //p' release/signature.txt)
|
||||
[[ "${certificate,,}" == "${SCANNER_CERTIFICATE_SHA256,,}" ]] || { echo 'Unexpected signing certificate'; exit 1; }
|
||||
"$ANDROID_HOME/build-tools/35.0.0/aapt" dump badging "release/qqq-mobile-$version.apk" > "$RUNNER_TEMP/scanner-manifest.txt"
|
||||
grep -F "package: name='io.qrun.mobile.scanner' versionCode='$SCANNER_VERSION_CODE' versionName='$version'" "$RUNNER_TEMP/scanner-manifest.txt"
|
||||
if grep -q 'application-debuggable' "$RUNNER_TEMP/scanner-manifest.txt"; then
|
||||
echo 'Refusing a debuggable release'; exit 1
|
||||
fi
|
||||
printf 'Source: %s\nVersion: %s\nVersion code: %s\n' "$GITHUB_SHA" "$version" "$SCANNER_VERSION_CODE" > release/BUILD.txt
|
||||
(cd release && sha256sum -- *.apk signature.txt BUILD.txt aboutlibraries.json LICENSE NOTICE > SHA256SUMS)
|
||||
- name: Retain signed deliverable
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: scanner-release-${{ github.sha }}
|
||||
path: release/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
publish:
|
||||
needs: package
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: scanner-release-${{ github.sha }}
|
||||
path: release
|
||||
- name: Publish immutable-tag APK assets
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
(cd release && sha256sum --check SHA256SUMS)
|
||||
prerelease=()
|
||||
version="${GITHUB_REF_NAME#scanner-v}"
|
||||
tag_object=$(gh api "repos/$GH_REPO/git/ref/tags/$GITHUB_REF_NAME" --jq '.object.sha')
|
||||
tag_type=$(gh api "repos/$GH_REPO/git/ref/tags/$GITHUB_REF_NAME" --jq '.object.type')
|
||||
for ((attempt=0; attempt<5; attempt++)); do
|
||||
if [[ "$tag_type" == commit ]]; then break; fi
|
||||
[[ "$tag_type" == tag ]] || exit 1
|
||||
tag_json=$(gh api "repos/$GH_REPO/git/tags/$tag_object")
|
||||
tag_object=$(jq -r '.object.sha' <<< "$tag_json")
|
||||
tag_type=$(jq -r '.object.type' <<< "$tag_json")
|
||||
done
|
||||
[[ "$tag_type" == commit && "$tag_object" == "$GITHUB_SHA" ]] || { echo 'Release tag no longer identifies the verified source'; exit 1; }
|
||||
if [[ "$version" == *-* ]]; then prerelease=(--prerelease); fi
|
||||
gh release create "$GITHUB_REF_NAME" --verify-tag --title "QQQ Mobile $version" \
|
||||
--generate-notes "${prerelease[@]}" release/*
|
||||
@@ -1,163 +0,0 @@
|
||||
name: Scanner Android
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, 'feature/**', 'fix/**', 'release/**', 'hotfix/**']
|
||||
pull_request:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
emulator:
|
||||
description: Run native UI and real-server scanner end-to-end tests
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: scanner-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
name: Tests, lint, and debug APK
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4
|
||||
with:
|
||||
cache-read-only: ${{ github.event_name == 'pull_request' }}
|
||||
- name: Verify source headers, whitespace, imports and JavaScript syntax
|
||||
run: node scripts/ci/check-source-standards.mjs
|
||||
- name: Run no-device Echo fixture guard tests
|
||||
run: node --test scripts/ci/scanner-echo-guards.test.mjs
|
||||
- name: Install required Android SDK packages
|
||||
run: |
|
||||
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "platforms;android-35" "build-tools;34.0.0" "build-tools;35.0.0" "platform-tools"
|
||||
- name: Verify shared libraries and scanner host
|
||||
run: >-
|
||||
./gradlew --no-daemon --console=plain
|
||||
:qqq:android:core:testDebugUnitTest
|
||||
:qqq:android:mobileapp:testDebugUnitTest
|
||||
:scanner-host:testDebugUnitTest
|
||||
:scanner-host:lintDebug
|
||||
:scanner-host:assembleDebug
|
||||
- name: Compile opt-in physical QA acceptance
|
||||
run: >-
|
||||
./gradlew --no-daemon --console=plain -PscannerTestBuildType=qa
|
||||
:scanner-host:assembleQa :scanner-host:assembleQaAndroidTest
|
||||
- name: Hash debug APK
|
||||
run: |
|
||||
mkdir -p scanner-host/build/outputs/apk/debug/notices
|
||||
cp scanner-host/build/reports/third-party/debug/{aboutlibraries.json,LICENSE,NOTICE} scanner-host/build/outputs/apk/debug/notices/
|
||||
(cd scanner-host/build/outputs/apk/debug && sha256sum scanner-host-debug.apk notices/* > SHA256SUMS)
|
||||
- name: Upload installable development APK
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: scanner-debug-${{ github.sha }}
|
||||
path: scanner-host/build/outputs/apk/debug/
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
- name: Upload test and lint evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: scanner-checks-${{ github.sha }}
|
||||
path: |
|
||||
qqq/android/core/build/test-results/
|
||||
qqq/android/mobileapp/build/test-results/
|
||||
scanner-host/build/test-results/
|
||||
scanner-host/build/reports/
|
||||
retention-days: 14
|
||||
|
||||
emulator:
|
||||
name: Native UI and real-server scanner E2E
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.emulator
|
||||
needs: verify
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 40
|
||||
env:
|
||||
QQQ_CORE_SHA: ecf0f550a0357cec6387c2b54efca128a405a629
|
||||
SCANNER_SERVER_SHA: 10416938724c9663d66f7848ff2b1a63fe635794
|
||||
MAVEN_OPTS: -XX:ActiveProcessorCount=2 -Xmx768m
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4
|
||||
- name: Check out the pinned QQQ core source
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
repository: QRun-IO/qqq
|
||||
ref: ${{ env.QQQ_CORE_SHA }}
|
||||
path: .e2e-core
|
||||
persist-credentials: false
|
||||
- name: Check out the pinned real QQQ demo
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
repository: QRun-IO/qbit-mobile-scanners
|
||||
ref: ${{ env.SCANNER_SERVER_SHA }}
|
||||
path: .e2e-server
|
||||
persist-credentials: false
|
||||
- name: Verify and build the isolated source-pinned server fixture
|
||||
env:
|
||||
JAVA_TOOL_OPTIONS: -XX:ActiveProcessorCount=2 -Xmx768m
|
||||
run: |
|
||||
test "$(git -C .e2e-core rev-parse HEAD)" = "$QQQ_CORE_SHA"
|
||||
test "$(git -C .e2e-server rev-parse HEAD)" = "$SCANNER_SERVER_SHA"
|
||||
fixture_m2=$(mktemp -d "$RUNNER_TEMP/scanner-fixture-m2.XXXXXX")
|
||||
core_revision="4.1.0-ci.$QQQ_CORE_SHA"
|
||||
(cd .e2e-core && ./mvnw --batch-mode --no-transfer-progress \
|
||||
-Dmaven.repo.local="$fixture_m2" -Drevision="$core_revision" \
|
||||
-pl qqq-bom,qqq-middleware-api -am clean install)
|
||||
(cd .e2e-server && ./mvnw --batch-mode --no-transfer-progress \
|
||||
-Dmaven.repo.local="$fixture_m2" -Dqqq.version="$core_revision" clean install)
|
||||
(cd .e2e-server && ./mvnw --batch-mode --no-transfer-progress -f demo/pom.xml \
|
||||
-Dmaven.repo.local="$fixture_m2" -Dqqq.version="$core_revision" clean verify \
|
||||
dependency:build-classpath -DincludeScope=runtime -Dmdep.outputFile=target/e2e-classpath.txt \
|
||||
dependency:tree -Dscope=runtime -DoutputFile=target/fixture-dependencies.txt \
|
||||
help:effective-pom -Doutput=target/fixture-effective-pom.xml)
|
||||
node scripts/ci/verify-fixture-provenance.mjs .e2e-server "$fixture_m2" "$QQQ_CORE_SHA" "$SCANNER_SERVER_SHA"
|
||||
- name: Enable hosted-runner hardware acceleration
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
- name: Run emulator checks
|
||||
uses: ReactiveCircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2
|
||||
with:
|
||||
api-level: 35
|
||||
target: google_apis
|
||||
arch: x86_64
|
||||
disable-animations: true
|
||||
script: |
|
||||
./gradlew --no-daemon --console=plain :qqqsampleandroidmobileapp:connectedDebugAndroidTest :scanner-host:assembleE2e :scanner-host:assembleE2eAndroidTest
|
||||
node scripts/ci/scanner-e2e.mjs .e2e-server
|
||||
- name: Upload emulator evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: scanner-emulator-${{ github.sha }}
|
||||
include-hidden-files: true
|
||||
path: |
|
||||
qqqsampleandroidmobileapp/build/reports/androidTests/
|
||||
qqqsampleandroidmobileapp/build/outputs/androidTest-results/
|
||||
scanner-host/build/native-e2e/
|
||||
.e2e-server/demo/target/fixture-provenance.json
|
||||
.e2e-server/demo/target/fixture-dependencies.txt
|
||||
.e2e-server/demo/target/fixture-effective-pom.xml
|
||||
.e2e-core/**/target/surefire-reports/TEST-*.xml
|
||||
.e2e-server/**/target/surefire-reports/TEST-*.xml
|
||||
retention-days: 14
|
||||
@@ -1,3 +0,0 @@
|
||||
profile: android
|
||||
orb_version: '0.8'
|
||||
default_branch: main
|
||||
@@ -24,4 +24,4 @@ Never log or place passwords, session cookies, or device tokens in process value
|
||||
|
||||
## Repository automation
|
||||
|
||||
The primary forge is Gitea (`git.kof22.com/QRun-IO`); GitHub is a shadow/archive, so make no ordinary GitHub writes. Protected `main` on Gitea has `.gitea/workflows/qrun-android-release.yaml` calling the shared `KofTwentyTwo/platform-ci` `android.yaml@qrun-release-v1`; pull-request checks come from central Gitea policy, not from that release workflow. It is not a scanner-APK signing pipeline, and no automatic signing CI is configured. CircleCI is managed by `kingsrook/qqq-orb` using `.qqq-ci.yml`; preserve that lane and its main-only library publication. The legacy `.github` `Scanner Android` workflow builds a debug APK artifact and never publishes libraries or production releases; it and the scanner release workflow are not a selected release path. The owner has authorized production signing with the QRun-owned key `qqq-mobile-release` (details and fingerprint in `docs/RELEASING.md`) for signed-APK/MDM distribution. Do not create replacement or additional signing keys, put key material, passwords or vault item details in the repository, or use the legacy GitHub release workflows; create no tags or releases without current authorization. Do not replace managed CI with a stale local template.
|
||||
The primary forge is Gitea (`git.kof22.com/QRun-IO`); GitHub is a shadow/archive, so make no ordinary GitHub writes. `.gitea/workflows/build.yaml` calls the shared `KofTwentyTwo/ci-workflows` Android workflow (`android.yaml@v1`) on every push: source checks, JVM unit tests, scanner lint, debug and QA APK assembly, and connected tests on an emulator (android-build runners). A `vX.Y.Z` tag also publishes the SDK AARs (`qqq-android-core`, `qqq-android-mobileapp`) to the QRun-IO Gitea Maven registry. It is not a scanner-APK signing pipeline, and no automatic signing CI is configured. The owner has authorized production signing with the QRun-owned key `qqq-mobile-release` (details and fingerprint in `docs/RELEASING.md`) for signed-APK/MDM distribution. Do not create replacement or additional signing keys, or put key material, passwords or vault item details in the repository; create no tags or releases without current authorization.
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.2 (versionCode 4), candidate
|
||||
|
||||
Not yet built, signed, tagged or published (prepared 2026-11-06). Supersedes the unpublished signed 1.0.1 (versionCode 3) candidate and updates it in place with the same permanent signer.
|
||||
|
||||
- Company sign-out now completes: the provider logout request runs before the scanner host ends its device session, so the browser end-session page opens. Previously the device-session end ran first, removed the QQQ session server-side, and `nativeLogoutData` was never returned; observed on the MC9400 with the production APK against the real Authentik server. (PR 17)
|
||||
- The signed-in user's name is shown after browser (OAuth) sign-in instead of a blank current user. (PR 17)
|
||||
- The scanner host reports the installed app and OS version on every session heartbeat, so scan receipts show the new version after an in-place update. Effective with mobile-scanners server 1.6.0; older servers ignore the keys. (PR 18)
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Add the QQQ Mobile scanner host for metadata-defined native apps and processes.
|
||||
|
||||
+2
-2
@@ -23,9 +23,9 @@ The smoke script clears application data only after verifying the target is an e
|
||||
|
||||
## CI and delivery
|
||||
|
||||
Managed CircleCI remains the shared-library test and Maven publication lane. Its Android profile publishes libraries only from `main`, after its checks. Feature branches do not publish.
|
||||
`.gitea/workflows/build.yaml` calls the shared `KofTwentyTwo/ci-workflows` Android workflow (`android.yaml@v1`) on every push: source checks, JVM unit tests, scanner lint, debug and QA APK assembly, and connected tests on an emulator (android-build runners). A `vX.Y.Z` tag also publishes the SDK AARs (`qqq-android-core`, `qqq-android-mobileapp`) to the QRun-IO Gitea Maven registry. Feature branches never publish.
|
||||
|
||||
The GitHub **Scanner Android** workflow runs shared-library/scanner JVM tests, scanner lint, and debug APK assembly for pull requests and supported branches. It uploads the development APK with SHA256 and verification reports. **Run workflow** optionally adds native emulator tests and a scanner launch screenshot. This workflow never publishes Maven artifacts, signs a production APK, or deploys to a device/store.
|
||||
The emulator scanner end-to-end suite against a real QQQ server (`scripts/ci/scanner-e2e.mjs`) is not part of CI; run it locally as described in [emulator testing](docs/EMULATOR.md).
|
||||
|
||||
Production signing and distribution require a separately configured release procedure. Do not treat the development APK as a production release.
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ See [emulator testing](docs/EMULATOR.md) for an emulator demo, synthetic scans a
|
||||
|
||||
### Signed APK (direct install / MDM)
|
||||
|
||||
Requires an **HTTPS** server URL and the production-signed APK built with the QRun-owned key. Follow the [installation guide](docs/INSTALLATION.md) and [release readiness](docs/RELEASING.md). The published download remains the [signed 1.0.0 preview](https://git.kof22.com/QRun-IO/qqq-android/releases/tag/scanner-v1.0.0) (prerelease, forge sign-in required). The signed 1.0.1 candidate has passed trusted-HTTPS enrollment, physical scanning, navigation and an in-place update on the MC9400, preserving login and enrollment. Its publication, native Authentik qualification and final dependency-cohort checks remain open. Development-signed installations require an explicit migration to the production signer.
|
||||
Requires an **HTTPS** server URL and the production-signed APK built with the QRun-owned key. Follow the [installation guide](docs/INSTALLATION.md) and [release readiness](docs/RELEASING.md). The published download remains the [signed 1.0.0 preview](https://git.kof22.com/QRun-IO/qqq-android/releases/tag/scanner-v1.0.0) (prerelease, forge sign-in required). The signed 1.0.1 candidate has passed trusted-HTTPS enrollment, physical scanning, navigation and an in-place update on the MC9400, preserving login and enrollment. Its publication, native Authentik qualification and final dependency-cohort checks remain open; a 1.0.2 (versionCode 4) candidate with company sign-out, user-name and heartbeat-version fixes is prepared but not yet built (see [CHANGELOG](CHANGELOG.md)). Development-signed installations require an explicit migration to the production signer.
|
||||
|
||||
## Build and test
|
||||
|
||||
@@ -73,7 +73,7 @@ Limits: JVM, emulator and synthetic-scan tests do not prove physical trigger, li
|
||||
|
||||
## CI and automation
|
||||
|
||||
The primary forge is Gitea (`git.kof22.com/QRun-IO`); GitHub is a shadow/archive and receives no ordinary writes. Protected `main` runs [`.gitea/workflows/qrun-android-release.yaml`](.gitea/workflows/qrun-android-release.yaml) on push and manual dispatch; it calls the shared `KofTwentyTwo/platform-ci` Android workflow (`android.yaml@qrun-release-v1`). That workflow builds, verifies and publishes the SDK libraries; it is not a scanner-APK signing or release pipeline. Pull-request checks come from central Gitea policy. The managed CircleCI profile (`.qqq-ci.yml`) and its main-only library publication are retained. The `.github` workflows are legacy and not a release path. Shared CI design is out of scope for this repository's local use: the demo above needs none of it.
|
||||
The primary forge is Gitea (`git.kof22.com/QRun-IO`); GitHub is a shadow/archive and receives no ordinary writes. `.gitea/workflows/build.yaml` calls the shared `KofTwentyTwo/ci-workflows` Android workflow (`android.yaml@v1`) on every push: source checks, JVM unit tests, scanner lint, debug and QA APK assembly, and connected tests on an emulator (android-build runners). A `vX.Y.Z` tag also publishes the SDK AARs (`qqq-android-core`, `qqq-android-mobileapp`) to the QRun-IO Gitea Maven registry. It is not a scanner-APK signing or release pipeline. Shared CI design is out of scope for this repository's local use: the demo above needs none of it.
|
||||
|
||||
## Extension points
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Use this for the **production-signed** APK on a small number of devices. Move to
|
||||
|
||||
This guide is not the local demo. The demo uses the development-signed debug APK, plain HTTP and `adb reverse` port forwarding to a workstation server; see [README](../README.md#installing-on-a-device). The two builds have different signers and cannot update each other.
|
||||
|
||||
**Current release status (November 5, 2026):** the only published release is the signed preview 1.0.0 below. A signed **1.0.1 (versionCode 3) candidate** exists but is **not published and has no download link**; this guide does not point to one. Use the table below for what is actually hosted. When 1.0.1 is published, use the file, checksum and link given by the release owner, and verify the same signer.
|
||||
**Current release status (November 5, 2026):** the only published release is the signed preview 1.0.0 below. A signed **1.0.1 (versionCode 3) candidate** exists but is **not published and has no download link**; this guide does not point to one. Use the table below for what is actually hosted. It is superseded by the planned **1.0.2 (versionCode 4)** candidate (not yet built; see [RELEASING](RELEASING.md#next-candidate-102-versioncode-4)). When a newer version is published, use the file, checksum and link given by the release owner, and verify the same signer.
|
||||
|
||||
| Candidate (not published) | Value |
|
||||
| --- | --- |
|
||||
|
||||
+18
-3
@@ -8,8 +8,23 @@
|
||||
- **Candidate APK:** SHA-256 `5124716B59CAD303717E7834FE64DDC1537E33A25C9AB75A6EA1ACF03AC2717F`, 15015419 bytes.
|
||||
- **Source:** Android PR 15 `ab6e44c`, merged as `c782aaaaba3f62422232436a9000af9d4b38fc82` with the same app-source tree. Installed APK bytes, signature, non-debuggable flag and 16 KiB alignment were verified. `lintRelease` reported 0 errors, 0 warnings and 5 informational findings; the release build passed.
|
||||
- **Distribution:** maintainers use the existing manual signing path for direct APK/MDM distribution. Automated signing CI is optional.
|
||||
- **Next candidate:** **1.0.2 (versionCode 4)** is prepared but not built; see [Next candidate](#next-candidate-102-versioncode-4).
|
||||
- **Open:** see [Qualification status](#qualification-status) and [TODO](TODO.md).
|
||||
|
||||
## Next candidate: 1.0.2 (versionCode 4)
|
||||
|
||||
Prepared on 2026-11-06 on branch `release/scanner-1.0.2` (Android PRs 17 and 18 merged locally plus these notes). **Nothing is built, signed, tagged, installed or published for 1.0.2.** The signed 1.0.1 candidate stays unpublished and is superseded; 1.0.2 updates it in place with the same signer and a higher `versionCode`.
|
||||
|
||||
Changes since 1.0.1 (details in [CHANGELOG](../CHANGELOG.md#102-versioncode-4-candidate)): company sign-out now completes (the device-session end ran before the provider logout, so no `nativeLogoutData` came back and the browser never opened on the MC9400); the user name is shown after browser sign-in; app/OS version are reported on every heartbeat (effective with mobile-scanners server 1.6.0).
|
||||
|
||||
Build only after PRs 17 and 18 are merged to `main` and this branch has been rebased onto that `main`, from the exact merged commit, with no `SCANNER_*` signing variables set:
|
||||
|
||||
```
|
||||
./gradlew --no-daemon --console=plain :scanner-host:lintRelease :scanner-host:assembleRelease -PscannerVersionName=1.0.2 -PscannerVersionCode=4
|
||||
```
|
||||
|
||||
Then sign `scanner-host/build/outputs/apk/release/scanner-host-release-unsigned.apk` in isolation with `apksigner` using the existing permanent key (certificate SHA-256 `BDDB2D2F...5B17A9FF`), verify v2+v3 with exactly one signer, 16 KiB alignment, `versionCode='4' versionName='1.0.2'` and non-debuggable, and write `QQQ-Mobile-1.0.2.apk`, `SHA256SUMS`, `signature-verification.txt`, `apk-metadata.txt` and `release-receipt.json` next to each other as for 1.0.1. Record the resulting hashes here, in [INSTALLATION](INSTALLATION.md) and in [SESSION-STATE](SESSION-STATE.md) before any tag or release.
|
||||
|
||||
## Historical status (November 4, 2026, superseded where noted)
|
||||
|
||||
Dated evidence below is preserved. As of November 4: a QRun-owned production signing key existed with a verified backup, and the signed 1.0.0 (versionCode 2) APK was published as a signed preview: [scanner-v1.0.0](https://git.kof22.com/QRun-IO/qqq-android/releases/tag/scanner-v1.0.0), release ID 1361, tag on protected `main` `3eef6431ca39b6450cf764424d921a02b2afb9ab`. It had been installed and launched once on a fresh MC9400; at that time enrollment, scanning and update were unqualified. *(Superseded November 5: the MC9400 was migrated to the signed build; see below. The statement that the MC9400 ran the development-signed debug APK is no longer current. The TC22 still runs its original development-signed installation.)* Manual TC22 acceptance was reported all-pass by the operator on November 4 (operator report, no per-case artifacts) for the development-signed build; it does not qualify the production signer and is not rerun.
|
||||
@@ -26,7 +41,7 @@ Dated evidence below is preserved. As of November 4: a QRun-owned production sig
|
||||
|
||||
## What exists today
|
||||
|
||||
- **Gitea CI (actual).** `.gitea/workflows/qrun-android-release.yaml` is in the repository, runs on push to `main` (and manual dispatch) and calls the central `KofTwentyTwo/platform-ci` Android workflow at `qrun-release-v1`. A central main run (3634) passed and published the SDK AARs. It is **not** a scanner-APK signing or release pipeline: it uses no scanner signing secrets and produces no production-signed scanner APK.
|
||||
- **Gitea CI (actual).** `.gitea/workflows/build.yaml` calls the shared `KofTwentyTwo/ci-workflows` Android workflow (`android.yaml@v1`) on every push: source checks, JVM unit tests, scanner lint, debug and QA APK assembly, and connected tests on an emulator (android-build runners). A `vX.Y.Z` tag also publishes the SDK AARs (`qqq-android-core`, `qqq-android-mobileapp`) to the QRun-IO Gitea Maven registry. It is **not** a scanner-APK signing or release pipeline: it uses no scanner signing secrets and produces no production-signed scanner APK.
|
||||
- **Gradle signing (supported, not selected).** `scanner-host/build.gradle.kts` reads four environment variables: `SCANNER_KEYSTORE`, `SCANNER_STORE_PASSWORD`, `SCANNER_KEY_ALIAS`, `SCANNER_KEY_PASSWORD`.
|
||||
- All four set: the `release` build type is signed with them.
|
||||
- None set: `assembleRelease` produces an **unsigned** APK, which is what the isolated signing step consumes.
|
||||
@@ -34,7 +49,7 @@ Dated evidence below is preserved. As of November 4: a QRun-owned production sig
|
||||
- Debug, `e2e` and `qa` builds keep the development debug signing.
|
||||
- Version comes from `-PscannerVersionName` (semantic version, default `0.1.0`) and `-PscannerVersionCode` (1 to 2100000000, default `1`).
|
||||
- **Identity.** One APK serves all customers; branding is applied at runtime from the selected server's metadata, so no per-customer key or build is needed.
|
||||
- **Legacy GitHub workflows (historical only).** `.github/workflows/release-scanner.yml` and `scanner.yml` predate Gitea as primary forge. They are not a release path; do not run or follow them. The [November 1 review](RELEASE-AUTOMATION-REVIEW.md) covered those files only.
|
||||
- **Legacy GitHub workflows (removed).** `.github/workflows/release-scanner.yml` and `scanner.yml` predated Gitea as primary forge and were removed with the CircleCI configuration. The [November 1 review](RELEASE-AUTOMATION-REVIEW.md) covered those files only.
|
||||
|
||||
## First release: 1.0.0 (versionCode 2)
|
||||
|
||||
@@ -65,7 +80,7 @@ Open:
|
||||
2. **Printing:** the print nonce fix (PR 11, merged `abc3d0d`, 532 hosted tests passed) postdates the published print 1.1.1; the next installer remains with the active printing owner.
|
||||
3. Public compatible Core/Collab/document/files/scripting/bridges, the final public cohort gate, GS1 physical print/rescan, and full release-asset publication and distribution.
|
||||
4. Company profiles and wallpaper are tracked separately.
|
||||
5. Publish the 1.0.1 tag, release, APK, checksum and installation instructions after its remaining qualification. The published download remains the 1.0.0 signed preview; automated signing CI is optional.
|
||||
5. Build, sign and publish 1.0.2 (versionCode 4) in place of the unpublished 1.0.1 candidate after PRs 17 and 18 merge (see [Next candidate](#next-candidate-102-versioncode-4)), with its checksum and installation instructions after remaining qualification. The published download remains the 1.0.0 signed preview; automated signing CI is optional.
|
||||
|
||||
## Release requirements
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# Current status
|
||||
|
||||
As of **2026-11-05**. Scope: scanner host and maintained local Echo workflow. [TODO](TODO.md) tracks remaining work; [history](history/README.md) preserves earlier evidence. This is not a final-release or full-qualification claim. See [Release facts](#release-facts-2026-11-05) below.
|
||||
As of **2026-11-06**. Scope: scanner host and maintained local Echo workflow. [TODO](TODO.md) tracks remaining work; [history](history/README.md) preserves earlier evidence. This is not a final-release or full-qualification claim. See [Release facts](#release-facts-2026-11-05) below.
|
||||
|
||||
## Open fix (2026-11-06, uncommitted branch `fix/refresh-device-versions`)
|
||||
## Release candidate 1.0.2 (versionCode 4), 2026-11-06
|
||||
|
||||
- After the MC9400 in-place 1.0.0 to 1.0.1 update, scan receipts still reported `appVersion` 1.0.0: the host only sent `osVersion`/`appVersion` at enrollment and the server never refreshed them. `MobileSessionApi` now sends both on every heartbeat (`MobileSessionTest.networkPayloadUsesSemanticRoutesAndCarriesOnlyScreenMetadata` covers the payload); the matching server change is mobile-scanners 1.6 on the same-named server branch. Older servers ignore the keys; the installed 1.0.1 APK does not include this change.
|
||||
- Branch `release/scanner-1.0.2` carries Android PR 17 (company sign-out ordering, OAuth user name) and PR 18 (heartbeat app/OS version) plus the [1.0.2 changelog](../CHANGELOG.md#102-versioncode-4-candidate) and build instructions in [RELEASING](RELEASING.md#next-candidate-102-versioncode-4). It depends on both PRs merging first and must be rebased onto the resulting `main`. **Nothing is built, signed, tagged, installed or published for 1.0.2**; the signed 1.0.1 candidate stays unpublished.
|
||||
|
||||
## Heartbeat version fix (2026-11-06, Android PR 18)
|
||||
|
||||
- After the MC9400 in-place 1.0.0 to 1.0.1 update, scan receipts still reported `appVersion` 1.0.0: the host only sent `osVersion`/`appVersion` at enrollment and the server never refreshed them. `MobileSessionApi` now sends both on every heartbeat (`MobileSessionTest.networkPayloadUsesSemanticRoutesAndCarriesOnlyScreenMetadata` covers the payload); the matching server change is mobile-scanners 1.6.0 on the same-named server branch. Older servers ignore the keys; the installed 1.0.1 APK does not include this change (planned for 1.0.2).
|
||||
|
||||
## Release facts (2026-11-05)
|
||||
|
||||
@@ -14,7 +18,7 @@ As of **2026-11-05**. Scope: scanner host and maintained local Echo workflow. [T
|
||||
- **Network:** the local QQQ server stays on a PC, reached over trusted HTTPS temporarily through a user-approved private Tailscale network. This is not a customer production deployment; customer instructions require a customer HTTPS URL with a trusted certificate. TLS is not weakened; no hostnames, IPs, ports, device/vault IDs, private paths or passwords are published.
|
||||
- **Server/Authentik:** real shared Authentik server discovery verified (UI API 1.10, strict nonce, scanner and printing channels/extensions/callbacks). Production-APK native login/logout/account switching is **open**, awaiting the MC wireless-debug endpoint; no native-Authentik PASS is claimed. Print nonce fix PR 11 (merged `abc3d0d`, 532 hosted tests passed) postdates published print 1.1.1; the next installer remains with the active printing owner.
|
||||
- **Photo policy:** live. A signed MC9400 gallery synthetic PNG became a Saved photo, `AVAILABLE`, with exact parent/type/size/hash; the previous three photos were released normally. The app has no admission policy; the server receipt controls the message. The root is running the updated disposable TC22 E2E; no full new-preview or native PASS is claimed until it completes.
|
||||
- **Company sign-out bug (2026-11-05):** on the physical MC9400 with the production APK against the real Authentik fixture, **Sign out of company** never opened the browser and reported "Company sign-out did not complete". Cause: `QViewModel.performLogout` ran the host `beforeLogout` hook (scanner device-session end, which runs the core logout server-side) before the provider logout request, so `nativeLogoutData` was never returned. A fix reordering provider logout before the host hook, plus adoption of the server-reported user name after browser login (Account showed a blank "Current User"), is prepared on branch `fix/company-signout-before-session-end` with unit tests; it is **not released** and no new APK is built. See [AUTHENTICATION](AUTHENTICATION.md#optional-company-sign-out-implementation-awaiting-qualification).
|
||||
- **Company sign-out bug (2026-11-05):** on the physical MC9400 with the production APK against the real Authentik fixture, **Sign out of company** never opened the browser and reported "Company sign-out did not complete". Cause: `QViewModel.performLogout` ran the host `beforeLogout` hook (scanner device-session end, which runs the core logout server-side) before the provider logout request, so `nativeLogoutData` was never returned. A fix reordering provider logout before the host hook, plus adoption of the server-reported user name after browser login (Account showed a blank "Current User"), is Android PR 17 (`cf82dd5`) with unit tests; it is **not released** and no new APK is built (planned for 1.0.2, versionCode 4). See [AUTHENTICATION](AUTHENTICATION.md#optional-company-sign-out-implementation-awaiting-qualification).
|
||||
- **Open:** public compatible Core/Collab/document/files/scripting/bridges, final public cohort gate, GS1 physical print/rescan, full release-asset publication/distribution. Company profiles/wallpaper are tracked separately; signing CI is optional and not blocking a direct APK release. Release authorizations already exist.
|
||||
|
||||
Statements below were written before these facts and are historical where they conflict (for example "debug update", MC9400 trigger check "outstanding", signed-build HTTPS qualification "open").
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ Open work only, as of **2026-11-05**. Current evidence: [SESSION-STATE](SESSION-
|
||||
|
||||
- [ ] Qualify actual GS1 label media and physical printed-label rescan. Synthetic capture/render evidence does not close this check.
|
||||
- [ ] Verify actual production-APK native Authentik login, logout and account switching; awaiting the MC wireless-debug endpoint. Real-server discovery (UI API 1.10, strict nonce, scanner and printing channels) is already verified; no native-Authentik PASS is claimed.
|
||||
- [ ] Publish signed candidate 1.0.1 (versionCode 3, APK SHA-256 `5124716B...AC2717F`, same permanent signer), checksum and installation instructions after remaining qualification. The published release is still the 1.0.0 signed preview.
|
||||
- [ ] After Android PRs 17 and 18 merge, rebase `release/scanner-1.0.2`, then build, sign (same permanent signer) and publish 1.0.2 (versionCode 4) with checksum and installation instructions after remaining qualification; see [RELEASING](RELEASING.md#next-candidate-102-versioncode-4). The signed 1.0.1 (versionCode 3) candidate is superseded and stays unpublished. The published release is still the 1.0.0 signed preview.
|
||||
- [ ] Publish and distribute full release assets to remaining devices; validate MDM/company profile and wallpaper separately. A customer deployment needs a customer HTTPS URL with a trusted certificate.
|
||||
- [ ] Printing: the next installer remains with the active printing owner (print nonce fix PR 11 postdates published print 1.1.1).
|
||||
- [ ] Optional, non-blocking: automatic APK signing CI. Direct APK release does not depend on it.
|
||||
|
||||
@@ -30,10 +30,10 @@ plugins {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "githubQqqMavenRegistry"
|
||||
url = uri("https://maven.pkg.github.com/QRun-IO/qqq-maven-registry")
|
||||
// username and password (a personal Github access token) should be specified as
|
||||
// `githubPackagesUsername` and `githubPackagesPassword` Gradle properties
|
||||
// Gitea Maven registry of the repository owner. CI sets giteaMavenUrl, giteaUsername
|
||||
// and giteaPassword (ci-workflows android.yaml, publish-tasks on vX.Y.Z tags).
|
||||
name = "gitea"
|
||||
url = uri(providers.gradleProperty("giteaMavenUrl").getOrElse("https://git.kof22.com/api/packages/QRun-IO/maven"))
|
||||
credentials(PasswordCredentials::class)
|
||||
}
|
||||
}
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2004-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.frontend.android.core.model.metadata
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
/*******************************************************************************
|
||||
** Current QQQ core serializes widget icons as plain strings and sends
|
||||
** summary-only help entries; the decoder must accept those shapes and the
|
||||
** older object/content shapes.
|
||||
*******************************************************************************/
|
||||
class MetadataDecodingTest {
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
fun widgetIconAsStringDecodes() {
|
||||
val widget = json.decodeFromString<QWidgetMetaData>("""{"name":"w","type":"table","icon":"troubleshoot"}""")
|
||||
assertEquals(JsonPrimitive("troubleshoot"), widget.icon)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
fun widgetIconAsObjectStillDecodes() {
|
||||
val widget = json.decodeFromString<QWidgetMetaData>("""{"name":"w","type":"table","icon":{"name":"troubleshoot"}}""")
|
||||
assertTrue(widget.icon is JsonObject)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
fun widgetWithoutIconDecodes() {
|
||||
assertNull(json.decodeFromString<QWidgetMetaData>("""{"name":"w","type":"table"}""").icon)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
fun summaryOnlyHelpDecodes() {
|
||||
val help = json.decodeFromString<QHelpContent>("""{"summary":"short help","roles":["ALL_SCREENS"]}""")
|
||||
assertEquals("short help", help.summary)
|
||||
assertNull(help.content)
|
||||
assertNull(help.format)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
fun contentHelpStillDecodes() {
|
||||
val help = json.decodeFromString<QHelpContent>("""{"content":"body","format":"TEXT"}""")
|
||||
assertEquals("body", help.content)
|
||||
assertEquals("TEXT", help.format)
|
||||
assertNull(help.summary)
|
||||
}
|
||||
}
|
||||
@@ -30,10 +30,10 @@ plugins {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "githubQqqMavenRegistry"
|
||||
url = uri("https://maven.pkg.github.com/QRun-IO/qqq-maven-registry")
|
||||
// username and password (a personal Github access token) should be specified as
|
||||
// `githubPackagesUsername` and `githubPackagesPassword` Gradle properties
|
||||
// Gitea Maven registry of the repository owner. CI sets giteaMavenUrl, giteaUsername
|
||||
// and giteaPassword (ci-workflows android.yaml, publish-tasks on vX.Y.Z tags).
|
||||
name = "gitea"
|
||||
url = uri(providers.gradleProperty("giteaMavenUrl").getOrElse("https://git.kof22.com/api/packages/QRun-IO/maven"))
|
||||
credentials(PasswordCredentials::class)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ const args = process.argv.slice(2);
|
||||
if (args.length !== 4 || args[0] !== '--serial' || args[2] !== '--fixture' || !args[1] || !args[3]) {
|
||||
throw new Error('Usage: node scripts/ci/scanner-device-record-photo-e2e.mjs --serial DEVICE_SERIAL --fixture PRIVATE_RECORD_FILES_FIXTURE.json');
|
||||
}
|
||||
await runScannerE2e({ physical: true, serial: args[1], scenario: 'record-photos', fixture: args[3] });
|
||||
await runScannerE2e({ physical: true, serial: args[1], scenario: 'record-photos', fixture: args[3] });
|
||||
Reference in new issue
Block a user