mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
address review: guard the release pipeline and harden the metadata test
- fail the release before uploading to Play when the versionCode has no changelog - rely on supply's defaults for release_status and metadata_path - enforce 8-bit PNGs and reject tRNS chunks in MetadataConstraintsTest - name the nightly artifact's APKs distinctly - fix doc drift and the stale libraries uniqueId
This commit is contained in:
@@ -20,9 +20,15 @@ jobs:
|
||||
- uses: ./.github/actions/build
|
||||
with:
|
||||
gradle-args: ":app:assembleDebug :app:assembleNightly --no-daemon"
|
||||
- name: Collect
|
||||
run: |
|
||||
cp app/build/outputs/apk/debug/app-debug.apk subtracks-nightly-debug.apk
|
||||
cp app/build/outputs/apk/nightly/app-nightly.apk subtracks-nightly.apk
|
||||
- name: Checksums
|
||||
run: sha256sum app/build/outputs/apk/debug/app-debug.apk app/build/outputs/apk/nightly/app-nightly.apk
|
||||
run: sha256sum subtracks-nightly.apk subtracks-nightly-debug.apk
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: subtracks-nightly
|
||||
path: app/build/outputs/apk
|
||||
path: |
|
||||
subtracks-nightly.apk
|
||||
subtracks-nightly-debug.apk
|
||||
|
||||
@@ -68,6 +68,8 @@ jobs:
|
||||
else
|
||||
echo "value=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Check release notes exist
|
||||
run: test -f "metadata/en-US/changelogs/${{ needs.build.outputs.version-code }}.txt"
|
||||
- name: Upload to Google Play
|
||||
if: steps.stable.outputs.value == 'true'
|
||||
env:
|
||||
@@ -79,9 +81,7 @@ jobs:
|
||||
--aab dist/bundle/release/app-release.aab \
|
||||
--package_name com.subtracks \
|
||||
--track "${{ vars.PLAY_TRACK || 'internal' }}" \
|
||||
--release_status completed \
|
||||
--json_key "$RUNNER_TEMP/play.json" \
|
||||
--metadata_path metadata \
|
||||
--mapping dist/mapping/release/mapping.txt
|
||||
- name: Remove Play service account
|
||||
if: always()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"uniqueId": "com.subtracks:next",
|
||||
"uniqueId": "com.subtracks",
|
||||
"name": "Subtracks",
|
||||
"description": "Subtracks itself, a client for Subsonic-compatible servers.",
|
||||
"website": "https://github.com/austinried/subtracks",
|
||||
|
||||
@@ -66,6 +66,7 @@ class MetadataConstraintsTest {
|
||||
RGBA_COLOR_TYPE,
|
||||
image.colorType,
|
||||
)
|
||||
assertTrue("${file.path} must be an 8-bit PNG; bitDepth ${image.bitDepth}", image.bitDepth == 8)
|
||||
assertTrue("${file.path} must be at most 1 MiB", file.length() <= 1024 * 1024)
|
||||
}
|
||||
}
|
||||
@@ -119,6 +120,8 @@ class MetadataConstraintsTest {
|
||||
RGB_COLOR_TYPE,
|
||||
image.colorType,
|
||||
)
|
||||
assertTrue("${file.path} must be an 8-bit PNG; bitDepth ${image.bitDepth}", image.bitDepth == 8)
|
||||
assertTrue("${file.path} must not carry a tRNS (transparency) chunk", !image.hasTrns)
|
||||
}
|
||||
|
||||
ImageFormat.JPEG -> {
|
||||
@@ -156,6 +159,8 @@ class MetadataConstraintsTest {
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val colorType: Int?,
|
||||
val bitDepth: Int?,
|
||||
val hasTrns: Boolean,
|
||||
val format: ImageFormat,
|
||||
)
|
||||
|
||||
@@ -166,12 +171,33 @@ class MetadataConstraintsTest {
|
||||
width = bytes.beInt(PNG_WIDTH_OFFSET),
|
||||
height = bytes.beInt(PNG_HEIGHT_OFFSET),
|
||||
colorType = bytes[PNG_COLOR_TYPE_OFFSET].toInt() and 0xFF,
|
||||
bitDepth = bytes[PNG_BIT_DEPTH_OFFSET].toInt() and 0xFF,
|
||||
hasTrns = bytes.hasTrnsChunk(),
|
||||
format = ImageFormat.PNG,
|
||||
)
|
||||
}
|
||||
val image = ImageIO.read(file)
|
||||
assertTrue("unreadable image ${file.path}", image != null)
|
||||
return ImageInfo(image.width, image.height, colorType = null, format = if (bytes.isJpeg()) ImageFormat.JPEG else ImageFormat.OTHER)
|
||||
return ImageInfo(
|
||||
image.width,
|
||||
image.height,
|
||||
null,
|
||||
null,
|
||||
hasTrns = false,
|
||||
format = if (bytes.isJpeg()) ImageFormat.JPEG else ImageFormat.OTHER,
|
||||
)
|
||||
}
|
||||
|
||||
private fun ByteArray.hasTrnsChunk(): Boolean {
|
||||
var offset = PNG_SIGNATURE_SIZE
|
||||
while (offset + 8 <= size) {
|
||||
val length = beInt(offset)
|
||||
val type = String(this, offset + 4, 4, Charsets.US_ASCII)
|
||||
if (type == "tRNS") return true
|
||||
if (type == "IEND" || length < 0) return false
|
||||
offset += PNG_CHUNK_OVERHEAD + length
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun ByteArray.isPng(): Boolean =
|
||||
@@ -208,6 +234,9 @@ class MetadataConstraintsTest {
|
||||
|
||||
const val PNG_WIDTH_OFFSET = 16
|
||||
const val PNG_HEIGHT_OFFSET = 20
|
||||
const val PNG_BIT_DEPTH_OFFSET = 24
|
||||
const val PNG_COLOR_TYPE_OFFSET = 25
|
||||
const val PNG_SIGNATURE_SIZE = 8
|
||||
const val PNG_CHUNK_OVERHEAD = 12
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ keytool -printcert -jarfile app-release.aab
|
||||
|
||||
## `nightly` builds
|
||||
|
||||
The signing key is the committed [`app/debug.keystore`](../app/debug.keystore) (a public key: alias `androiddebugkey`, password `android`). Certificate SHA-256:
|
||||
The signing key is the committed [`app/debug.keystore`](../app/debug.keystore) (a public key: alias `androiddebugkey`, password `android`). The `subtracks-nightly` artifact contains `subtracks-nightly.apk` (minified) and `subtracks-nightly-debug.apk` (debuggable), both `com.subtracks.nightly`. Certificate SHA-256:
|
||||
|
||||
```
|
||||
# keytool format
|
||||
|
||||
Reference in New Issue
Block a user