Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 2 additions & 68 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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-<version>.txt
# (#181), so stack traces of that release can be retraced
- name: Versioned release
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
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: |
Expand Down
2 changes: 1 addition & 1 deletion LABORATORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<versionName>` 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-<branch with / → ->`:
```sh
B=feat/rtsp-multicast
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down Expand Up @@ -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).

## Поддержка

Expand Down
4 changes: 2 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)发送您的电子邮箱。

Expand Down Expand Up @@ -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)。

## 支持

Expand Down
67 changes: 58 additions & 9 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-<branch, / → ->` (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
Expand All @@ -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<version>`** at the commit it built, with `decoder-v2-<version>.apk`, `mapping-<version>.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, <hash>`) 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
Expand All @@ -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-<version>.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 <init>(long,boolean,long,long):147:147 -> <init>
```

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-<branch>-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 <branch>`, 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 <full commit hash> -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`.
Expand Down
Loading