diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d30954d..6d9369a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,7 +127,8 @@ jobs: name: ${{ steps.vars.outputs.name }} path: ${{ steps.vars.outputs.name }}.apk - # Release branches: publish to the "latest" release and Telegram + # Release branches: publish to the "latest" release and Telegram. No release per version: + # development is continuous, Telegram keeps every build (#194) - name: Upload if: github.ref_name == 'basic' || github.ref_name == 'v2' uses: softprops/action-gh-release@v2 @@ -138,73 +139,6 @@ jobs: ${{ steps.vars.outputs.name }}.apk ${{ steps.vars.outputs.name }}-mapping.txt - # v2: every version gets a release of its own (#157), at the commit that was built, with - # the APK and the merged PRs since the previous v2.* release. A push without a version - # bump (docs, CI) only updates "latest" above. Not marked Latest: the README links - # releases/tag/latest. The R8 mapping of the same build is attached as mapping-.txt - # (#181), so stack traces of that release can be retraced - - name: Versioned release - if: github.ref_name == 'v2' - env: - GH_TOKEN: ${{ github.token }} - run: | - VER=$(sed -n 's/.*versionName "\(.*\)".*/\1/p' android/app/build.gradle) - TAG="v${VER}" - if [ -z "$VER" ]; then echo "No versionName found"; exit 1; fi - APK="decoder-v2-${VER}.apk" - cp decoder-v2.apk "$APK" - ASSETS=("$APK") - MAP="mapping-${VER}.txt" - if [ -f decoder-v2-mapping.txt ]; then - cp decoder-v2-mapping.txt "$MAP" - ASSETS+=("$MAP") - fi - # An existing release is complete only with its APK (Qodo on #158) and, when this build - # has one, its mapping (Qodo on #183). Fills MISSING with what it lacks - complete() { - local have - have=$(gh release view "$TAG" --json assets -q '.assets[].name' 2>/dev/null) || have="" - MISSING=() - for a in "${ASSETS[@]}"; do grep -qx "$a" <<< "$have" || MISSING+=("$a"); done - [ ${#MISSING[@]} -eq 0 ] - } - # Only the build of the tagged commit may add the missing files (Qodo on #158) - repair() { - TAGGED=$(gh api "repos/${{ github.repository }}/commits/$TAG" -q .sha) - if [ "$TAGGED" = "$(git rev-parse HEAD)" ]; then - gh release upload "$TAG" "${MISSING[@]}" --clobber - else - echo "::warning::$TAG has no ${MISSING[*]} and points to ${TAGGED:0:7}, not this build" - fi - } - if gh release view "$TAG" >/dev/null 2>&1; then - if complete; then - echo "Release $TAG exists: only latest was updated" - else - repair - fi - exit 0 - fi - # The previous version by number, not by date: a manual build of an older commit may - # publish after a newer one (Qodo on #158) - # A failed lookup fails the step rather than publishing first-release notes - TAGS=$(gh api --paginate "repos/${{ github.repository }}/releases?per_page=100" \ - -q '.[].tag_name') - PREV=$(printf '%s\n' "$TAGS" | grep '^v2\.' | sed 's/^v//' | { cat; echo "$VER"; } \ - | sort -V -u | grep -B1 -x "$VER" | grep -v -x "$VER" || true) - if [ -n "$PREV" ]; then - NOTES=(--generate-notes --notes-start-tag "v$PREV") - else - NOTES=(--notes "First release of the 2.xx line (v2 branch). Earlier changes: https://github.com/${{ github.repository }}/commits/v2") - fi - if ! gh release create "$TAG" "${ASSETS[@]}" --target "$(git rev-parse HEAD)" \ - --title "OpenIPC Decoder ${VER}" --latest=false "${NOTES[@]}"; then - # Another build of the same version created it meanwhile, or the upload failed: - # the release must exist and carry the APK and the mapping, else the step fails - gh release view "$TAG" >/dev/null - complete || repair - fi - - name: Telegram if: github.ref_name == 'basic' || github.ref_name == 'v2' run: | diff --git a/LABORATORY.md b/LABORATORY.md index 2b5808cd..0331e2d4 100644 --- a/LABORATORY.md +++ b/LABORATORY.md @@ -249,7 +249,7 @@ The pairing is kept with the host's adb key (`~/.android/adbkey`): later only `c ### Builds - `v2` / `basic`: `gh release download latest -R OpenIPC/decoder -p decoder-v2.apk -p decoder.apk` -- A given 2.xx version: `gh release download v2.01 -R OpenIPC/decoder` (`decoder-v2-2.01.apk`). CI creates the release `v` on the first v2 build of each version (#157). +- An older `v2` / `basic` build: from the OpenIPC Telegram channel (every build of these branches is posted there with its version and commit). There are no per-version releases (#194). - Branches: `build.yml` builds signed APKs only on **push** runs (not `pull_request`); artifact name is `decoder-`: ```sh B=feat/rtsp-multicast diff --git a/README.md b/README.md index 755e2028..9fa37924 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Ready-to-install builds are in the [**latest** release](https://github.com/OpenI | `decoder-v2.apk` | **Current version**, recommended | | `decoder.apk` | Legacy version from the `basic` branch | -Each 2.xx version also has a release of its own on the [releases page](https://github.com/OpenIPC/decoder/releases), with that version's APK and the changes since the previous one. +Every build is replaced in `latest` by the next one. Development is continuous, so there are no releases per version; every `v2` and `basic` build is also posted with its version and commit to the OpenIPC Telegram channel ([our channels](https://openipc.org/our-channels)). A beta channel is available on [Google Play](https://play.google.com/apps/internaltest/4701231141824898735). To join it, send your e-mail through the [OpenIPC Telegram channels](https://openipc.org/our-channels). @@ -113,7 +113,7 @@ Every item, the remote, sharing a URL from another app and **Reset**: [Usage](do | [Drones and Wi‑Fi toys](docs/toys.md) | how toys stream, FLOW-UFO (in testing), what to try with an unknown toy, what to send | | [Laboratory](LABORATORY.md) | the test bench: devices, cameras, access, methods | -The change history is in the release notes on the [releases page](https://github.com/OpenIPC/decoder/releases) (written by CI for every v2.xx version). +The change history is the [merged pull requests](https://github.com/OpenIPC/decoder/pulls?q=is%3Apr+is%3Amerged+base%3Av2) and the [commits of v2](https://github.com/OpenIPC/decoder/commits/v2). ## Support diff --git a/README.ru.md b/README.ru.md index 53b3363e..e4ed5954 100644 --- a/README.ru.md +++ b/README.ru.md @@ -45,7 +45,7 @@ | `decoder-v2.apk` | **Текущая версия**, рекомендуется | | `decoder.apk` | Старая версия из ветки `basic` | -У каждой версии 2.xx есть и свой релиз на [странице релизов](https://github.com/OpenIPC/decoder/releases) — с APK этой версии и списком изменений после предыдущей. +Каждая новая сборка заменяет предыдущую в `latest`. Разработка идёт непрерывно, поэтому отдельных релизов по версиям нет; каждая сборка веток `v2` и `basic` с номером версии и коммитом публикуется в Telegram-канале OpenIPC ([наши каналы](https://openipc.org/our-channels)). Есть бета-канал в [Google Play](https://play.google.com/apps/internaltest/4701231141824898735). Чтобы попасть в него, пришлите свой e-mail через [Telegram-каналы OpenIPC](https://openipc.org/our-channels). @@ -115,7 +115,7 @@ | [Drones and Wi‑Fi toys](docs/toys.md) | как передают видео игрушки, FLOW-UFO (в тестировании), что попробовать с неизвестной игрушкой, что прислать | | [Laboratory](LABORATORY.md) | тестовый стенд: устройства, камеры, доступ, методики | -История изменений — в описаниях релизов на [странице релизов](https://github.com/OpenIPC/decoder/releases) (CI пишет их для каждой версии v2.xx). +История изменений — это [принятые pull request'ы](https://github.com/OpenIPC/decoder/pulls?q=is%3Apr+is%3Amerged+base%3Av2) и [коммиты ветки v2](https://github.com/OpenIPC/decoder/commits/v2). ## Поддержка diff --git a/README.zh-CN.md b/README.zh-CN.md index 734692d5..adde3275 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -45,7 +45,7 @@ | `decoder-v2.apk` | **当前版本**,推荐使用 | | `decoder.apk` | `basic` 分支的旧版本 | -每个 2.xx 版本在[发布页面](https://github.com/OpenIPC/decoder/releases)上另有独立的发布,包含该版本的 APK 以及相对上一版本的更改。 +每次新构建都会替换 `latest` 中的上一个构建。开发是持续进行的,因此不再按版本单独发布;`v2` 和 `basic` 分支的每个构建连同版本号和提交都会发布到 OpenIPC 的 Telegram 频道([我们的频道](https://openipc.org/our-channels))。 [Google Play](https://play.google.com/apps/internaltest/4701231141824898735) 上提供测试渠道。如需加入,请通过 [OpenIPC Telegram 频道](https://openipc.org/our-channels)发送您的电子邮箱。 @@ -115,7 +115,7 @@ | [Drones and Wi‑Fi toys](docs/toys.md) | 玩具如何传输视频、FLOW-UFO(测试中)、遇到未知玩具时可以尝试什么、需要提交哪些信息 | | [Laboratory](LABORATORY.md) | 测试平台:设备、摄像机、访问方式、测试方法 | -更新历史见[发布页面](https://github.com/OpenIPC/decoder/releases)上的发布说明(CI 会为每个 v2.xx 版本自动生成)。 +更新历史即[已合并的 pull request](https://github.com/OpenIPC/decoder/pulls?q=is%3Apr+is%3Amerged+base%3Av2) 和 [v2 分支的提交](https://github.com/OpenIPC/decoder/commits/v2)。 ## 支持 diff --git a/docs/testing.md b/docs/testing.md index ca2e03f5..0954bd2a 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -31,10 +31,12 @@ What a `build` run publishes: | Branch | Output | |---|---| -| `v2` | `decoder-v2.apk` and `decoder-v2-mapping.txt` in the [`latest`](https://github.com/OpenIPC/decoder/releases/tag/latest) release; a [versioned release](#versions-and-releases) for a new version; a message with the APK to the OpenIPC Telegram channel | +| `v2` | `decoder-v2.apk` and `decoder-v2-mapping.txt` in the [`latest`](https://github.com/OpenIPC/decoder/releases/tag/latest) release (replaced by every build); a message with the APK, version and commit to the OpenIPC Telegram channel | | `basic` | `decoder.apk` and its mapping in `latest`; Telegram | | any other | workflow artifacts `decoder-` (APK) and `…-mapping` on the run page | +Every run, `v2` and `basic` included, also keeps its mapping as the artifact `…-mapping`. Artifacts expire after 90 days. + A pull request therefore gets tests and lint only; its APK comes from the push run of its branch. ## Unit tests @@ -45,15 +47,27 @@ CI is the reference: the project does not depend on local builds. ## Versions and releases -- `v2` is **2.xx** (from 2.00). Every pull request that changes the app bumps `android/app/build.gradle` as its last commit before the merge: `versionName` +0.01, `versionCode` +1. Docs-only and CI-only pull requests do not. Current: **2.10** (code 35). +- `v2` is **2.xx** (from 2.00). Every pull request that changes the app bumps `android/app/build.gradle` as its last commit before the merge: `versionName` +0.01, `versionCode` +1. Docs-only and CI-only pull requests do not. - `basic` keeps its 1.07.x line. -- The first `v2` build of a new `versionName` creates the release **`v`** at the commit it built, with `decoder-v2-.apk`, `mapping-.txt` and notes generated from the merged pull requests since the previous `v2.*` release (by version number). It is not marked *Latest*: the README links `releases/tag/latest`. -- A push without a version bump updates only `latest`. A later build of the tagged commit adds a missing APK or mapping to an existing release; a build of another commit does not touch it. +- Development is continuous, so there is **no release per version** (#194). The [`latest`](https://github.com/OpenIPC/decoder/releases/tag/latest) release always holds the newest `v2` and `basic` builds. Every `v2` and `basic` build is also posted to the OpenIPC Telegram channel with its version and commit, and that is where their older builds can be found. Builds of other branches are only workflow artifacts of their runs (90 days). +- **Test pre-releases**: to let a reporter test a branch, a pre-release named after the issue is made by hand from the branch's CI artifact, e.g. [`flowufo-187-test1`](https://github.com/OpenIPC/decoder/releases/tag/flowufo-187-test1) for #187. It is deleted when the test is over. + + ```sh + B=feat/my-branch # the branch to test + RUN=$(gh run list -R OpenIPC/decoder -b "$B" -e push -w Build -L 1 --json databaseId -q '.[0].databaseId') + gh run download "$RUN" -R OpenIPC/decoder -n "decoder-${B//\//-}" # gives decoder-feat-my-branch.apk + cp "decoder-${B//\//-}.apk" decoder-my-test1.apk # the asset name the reporter sees + gh release create my-187-test1 decoder-my-test1.apk --prerelease \ + --target "$(gh run view "$RUN" -R OpenIPC/decoder --json headSha -q .headSha)" \ + --title "… test build 1 (#187)" --notes "…" + ``` + + The tag (`my-187-test1`) and the asset name are free to choose; the artifact is always named after the branch. + +- The change history is the [merged pull requests](https://github.com/OpenIPC/decoder/pulls?q=is%3Apr+is%3Amerged+base%3Av2) and the [commits of `v2`](https://github.com/OpenIPC/decoder/commits/v2). - The installed version and build hash show in the menu (under **Exit**, `v2.10, `) and in `/stats.json` (`version`, `git`). - Every build is `com.openipc.decoder` with the release signature, so a branch build installs over a release and keeps the settings. -Release notes are the change history: [releases page](https://github.com/OpenIPC/decoder/releases). - ## Testing a branch build ```sh @@ -63,16 +77,51 @@ gh run download "$RUN" -R OpenIPC/decoder -n "decoder-${B//\//-}" adb install -r "decoder-${B//\//-}.apk" ``` -A given version: `gh release download v2.10 -R OpenIPC/decoder` (`decoder-v2-2.10.apk`). Check the hash under **Exit** after installing. +The current `v2` build: `gh release download latest -R OpenIPC/decoder -p decoder-v2.apk`. Check the hash under **Exit** after installing. ## Stack traces and mapping.txt -Release builds are obfuscated by R8. To read a stack trace from a crash screen or a log, use the mapping of the same build: `mapping-.txt` from the versioned release, `decoder-v2-mapping.txt` from `latest` (only for the build that is there now), or the `…-mapping` artifact of a branch run. Then, with the Android SDK command-line tools: +Release builds are shrunk and obfuscated by R8: classes, fields and methods get short names, and line numbers survive only through a map. A crash from a release build reads like this (an example): + +``` +java.lang.IllegalStateException: … + at a.u.a(SourceFile:12) + at com.openipc.decoder.Decoder.u(SourceFile:48) +``` + +R8 writes that map as **`mapping.txt`**, one per build: + +``` +# compiler: R8 +# compiler_version: 8.13.17 +# min_api: 21 +# pg_map_id: 8df440e8… ← ties the file to exactly one build +com.openipc.decoder.DecodePlanner -> a.u: +# {"id":"sourceFile","fileName":"DecodePlanner.java"} + long capacity -> a + long proven -> c + long failedLoad -> d + 1:5:void (long,boolean,long,long):147:147 -> +``` + +For every class, field and method it gives `original -> obfuscated`, with the line ranges that map back to the source. It also covers the library classes that went into the APK, which is why it is about 9,000 lines (700 KB). It holds no secrets (the code is open), and devices don't need it: it only matters for reading crashes. + +A mapping fits **only the build it came from**. Use the one whose build matches the hash under **Exit** or `git` in `/stats.json`: + +| Build | Mapping | +|---|---| +| the current `v2` build | `decoder-v2-mapping.txt` in [`latest`](https://github.com/OpenIPC/decoder/releases/tag/latest) | +| an older `v2` build, or any branch build | the artifact `decoder-v2-mapping` (or `decoder--mapping`) of the CI run that built it, kept 90 days. A push run is found by its commit (below). A manual run (*Run workflow* with `commit_hash`) is listed under the branch it was started on, not under the commit it built: `gh run list -R OpenIPC/decoder -w Build -e workflow_dispatch -b `, then pick the run by its time or ID | +| builds before 2.08 | none: they were made before the mapping was kept (#181) | ```sh -retrace mapping-2.10.txt stacktrace.txt +RUN=$(gh run list -R OpenIPC/decoder -c -e push -w Build -L 1 --json databaseId -q '.[0].databaseId') +gh run download "$RUN" -R OpenIPC/decoder -n decoder-v2-mapping +retrace decoder-v2-mapping.txt stacktrace.txt # Android SDK command-line tools ``` +After `retrace`, the frames read `at com.openipc.decoder.DecodePlanner.step(DecodePlanner.java:215)`. + ## Building locally Not needed for contributing (CI builds every push), but possible: JDK 17 and the Android SDK (platform 36), with `ANDROID_HOME` or `android/local.properties`.