Skip to content

Commit 117d56e

Browse files
committed
ci: add release workflows
1 parent 7116e00 commit 117d56e

13 files changed

Lines changed: 710 additions & 10 deletions

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ jobs:
3535
uses: gradle/actions/setup-gradle@v5
3636

3737
- name: Decode google-services.json
38-
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
38+
run: |
39+
mkdir -p app/src/debug
40+
echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/src/debug/google-services.json
3941
env:
4042
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
4143

.github/workflows/e2e.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ jobs:
5757
uses: gradle/actions/setup-gradle@v5
5858

5959
- name: Decode google-services.json
60-
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
60+
run: |
61+
mkdir -p app/src/debug
62+
echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/src/debug/google-services.json
6163
env:
6264
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
6365

@@ -100,7 +102,9 @@ jobs:
100102
uses: gradle/actions/setup-gradle@v5
101103

102104
- name: Decode google-services.json
103-
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
105+
run: |
106+
mkdir -p app/src/debug
107+
echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/src/debug/google-services.json
104108
env:
105109
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
106110

.github/workflows/e2e_migration.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ jobs:
3737
uses: gradle/actions/setup-gradle@v5
3838

3939
- name: Decode google-services.json
40-
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
40+
run: |
41+
mkdir -p app/src/debug
42+
echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/src/debug/google-services.json
4143
env:
4244
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
4345

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Release Internal
2+
3+
on:
4+
workflow_dispatch:
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: false
9+
10+
env:
11+
TERM: xterm-256color
12+
FORCE_COLOR: 1
13+
14+
jobs:
15+
build-internal:
16+
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release-') || startsWith(github.ref, 'refs/tags/v')
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 45
19+
environment: release-internal
20+
21+
permissions:
22+
contents: read
23+
packages: read
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v6
28+
29+
- name: Setup Java
30+
uses: actions/setup-java@v5
31+
with:
32+
java-version: '17'
33+
distribution: 'adopt'
34+
35+
- name: Setup Gradle
36+
uses: gradle/actions/setup-gradle@v5
37+
38+
- name: Decode mainnet release google-services.json
39+
env:
40+
MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64 }}
41+
run: |
42+
set -euo pipefail
43+
test -n "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64"
44+
mkdir -p app/src/mainnetRelease
45+
printf '%s' "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64" | base64 --decode > app/src/mainnetRelease/google-services.json
46+
47+
- name: Decode internal keystore
48+
env:
49+
INTERNAL_KEYSTORE_BASE64: ${{ secrets.INTERNAL_KEYSTORE_BASE64 }}
50+
run: |
51+
set -euo pipefail
52+
test -n "$INTERNAL_KEYSTORE_BASE64"
53+
umask 077
54+
keystore_path="$RUNNER_TEMP/internal.keystore"
55+
printf '%s' "$INTERNAL_KEYSTORE_BASE64" | base64 --decode > "$keystore_path"
56+
echo "KEYSTORE_FILE=$keystore_path" >> "$GITHUB_ENV"
57+
58+
- name: Build internal release APK
59+
env:
60+
GPR_USER: ${{ secrets.GPR_USER || github.actor }}
61+
GPR_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
62+
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
63+
KEYSTORE_PASSWORD: ${{ secrets.INTERNAL_KEYSTORE_PASSWORD }}
64+
KEY_ALIAS: ${{ secrets.INTERNAL_KEY_ALIAS }}
65+
KEY_PASSWORD: ${{ secrets.INTERNAL_KEY_PASSWORD }}
66+
run: ./gradlew assembleMainnetRelease --no-daemon --stacktrace
67+
68+
- name: Verify internal release signature
69+
run: |
70+
set -euo pipefail
71+
android_sdk_root="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
72+
test -n "$android_sdk_root"
73+
apksigner_path="$(find "$android_sdk_root/build-tools" -name apksigner -type f | sort -V | tail -n 1)"
74+
test -n "$apksigner_path"
75+
76+
apk_count=0
77+
while IFS= read -r -d '' apk_path; do
78+
apk_count=$((apk_count + 1))
79+
"$apksigner_path" verify --verbose --print-certs "$apk_path"
80+
done < <(find app/build/outputs/apk/mainnet/release -name 'bitkit-mainnet-release-*.apk' -print0)
81+
test "$apk_count" -gt 0
82+
83+
- name: Collect internal artifacts
84+
id: artifacts
85+
run: |
86+
set -euo pipefail
87+
artifact_dir="$RUNNER_TEMP/internal-release"
88+
mkdir -p "$artifact_dir"
89+
find app/build/outputs/apk/mainnet/release -name 'bitkit-mainnet-release-*.apk' -print0 |
90+
xargs -0 -I {} cp {} "$artifact_dir/"
91+
(cd "$artifact_dir" && sha256sum *.apk > SHA256SUMS.txt)
92+
echo "artifact_dir=$artifact_dir" >> "$GITHUB_OUTPUT"
93+
94+
- name: Upload internal artifacts
95+
uses: actions/upload-artifact@v6
96+
with:
97+
name: bitkit-internal-release-${{ github.run_number }}
98+
path: ${{ steps.artifacts.outputs.artifact_dir }}
99+
retention-days: 30

.github/workflows/release.yml

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: false
9+
10+
env:
11+
TERM: xterm-256color
12+
FORCE_COLOR: 1
13+
14+
jobs:
15+
build-release:
16+
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release-') || startsWith(github.ref, 'refs/tags/v')
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 45
19+
environment: release
20+
21+
permissions:
22+
contents: read
23+
packages: read
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v6
28+
29+
- name: Setup Java
30+
uses: actions/setup-java@v5
31+
with:
32+
java-version: '17'
33+
distribution: 'adopt'
34+
35+
- name: Setup Gradle
36+
uses: gradle/actions/setup-gradle@v5
37+
38+
- name: Decode mainnet release google-services.json
39+
env:
40+
MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64 }}
41+
run: |
42+
set -euo pipefail
43+
test -n "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64"
44+
mkdir -p app/src/mainnetRelease
45+
printf '%s' "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64" | base64 --decode > app/src/mainnetRelease/google-services.json
46+
47+
- name: Decode release keystore
48+
env:
49+
BITKIT_KEYSTORE_BASE64: ${{ secrets.BITKIT_KEYSTORE_BASE64 }}
50+
run: |
51+
set -euo pipefail
52+
test -n "$BITKIT_KEYSTORE_BASE64"
53+
umask 077
54+
keystore_path="$RUNNER_TEMP/bitkit.keystore"
55+
printf '%s' "$BITKIT_KEYSTORE_BASE64" | base64 --decode > "$keystore_path"
56+
echo "KEYSTORE_FILE=$keystore_path" >> "$GITHUB_ENV"
57+
58+
- name: Build release artifacts
59+
env:
60+
GPR_USER: ${{ secrets.GPR_USER || github.actor }}
61+
GPR_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
62+
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
63+
KEYSTORE_PASSWORD: ${{ secrets.BITKIT_KEYSTORE_PASSWORD }}
64+
KEY_ALIAS: ${{ secrets.BITKIT_KEY_ALIAS }}
65+
KEY_PASSWORD: ${{ secrets.BITKIT_KEY_PASSWORD }}
66+
run: ./gradlew assembleMainnetRelease bundleMainnetRelease --no-daemon --stacktrace
67+
68+
- name: Verify release signatures
69+
run: |
70+
set -euo pipefail
71+
android_sdk_root="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
72+
test -n "$android_sdk_root"
73+
apksigner_path="$(find "$android_sdk_root/build-tools" -name apksigner -type f | sort -V | tail -n 1)"
74+
test -n "$apksigner_path"
75+
76+
apk_count=0
77+
while IFS= read -r -d '' apk_path; do
78+
apk_count=$((apk_count + 1))
79+
"$apksigner_path" verify --verbose --print-certs "$apk_path"
80+
done < <(find app/build/outputs/apk/mainnet/release -name 'bitkit-mainnet-release-*.apk' -print0)
81+
test "$apk_count" -gt 0
82+
83+
bundle_count=0
84+
while IFS= read -r -d '' bundle_path; do
85+
bundle_count=$((bundle_count + 1))
86+
verify_output="$(mktemp)"
87+
if ! jarsigner -verify -verbose -certs "$bundle_path" 2>&1 | tee "$verify_output"; then
88+
rm -f "$verify_output"
89+
exit 1
90+
fi
91+
if grep -qi "jar is unsigned" "$verify_output"; then
92+
echo "Unsigned bundle: $bundle_path"
93+
rm -f "$verify_output"
94+
exit 1
95+
fi
96+
if ! grep -qi "jar verified" "$verify_output"; then
97+
echo "Bundle signature verification did not report success: $bundle_path"
98+
rm -f "$verify_output"
99+
exit 1
100+
fi
101+
rm -f "$verify_output"
102+
done < <(find app/build/outputs/bundle/mainnetRelease -name 'bitkit-mainnet-release-*.aab' -print0)
103+
test "$bundle_count" -gt 0
104+
105+
- name: Collect release artifacts
106+
id: artifacts
107+
run: |
108+
set -euo pipefail
109+
artifact_dir="$RUNNER_TEMP/release"
110+
mkdir -p "$artifact_dir"
111+
find app/build/outputs/bundle/mainnetRelease -name 'bitkit-mainnet-release-*.aab' -print0 |
112+
xargs -0 -I {} cp {} "$artifact_dir/"
113+
find app/build/outputs/apk/mainnet/release -name 'bitkit-mainnet-release-*.apk' -print0 |
114+
xargs -0 -I {} cp {} "$artifact_dir/"
115+
(cd "$artifact_dir" && sha256sum *.aab *.apk > SHA256SUMS.txt)
116+
echo "artifact_dir=$artifact_dir" >> "$GITHUB_OUTPUT"
117+
118+
- name: Upload release artifacts
119+
uses: actions/upload-artifact@v6
120+
with:
121+
name: bitkit-release-${{ github.run_number }}
122+
path: ${{ steps.artifacts.outputs.artifact_dir }}
123+
retention-days: 30
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Reproducible Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
comparison_artifact_name:
7+
description: Optional artifact name to compare against with diffoscope
8+
required: false
9+
default: ''
10+
comparison_run_id:
11+
description: Workflow run id that produced the comparison artifact
12+
required: false
13+
default: ''
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: false
18+
19+
env:
20+
TERM: xterm-256color
21+
FORCE_COLOR: 1
22+
23+
jobs:
24+
reproduce-mainnet:
25+
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release-') || startsWith(github.ref, 'refs/tags/v')
26+
runs-on: ubuntu-latest
27+
timeout-minutes: 60
28+
environment: release
29+
30+
permissions:
31+
actions: read
32+
contents: read
33+
packages: read
34+
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@v6
38+
39+
- name: Setup Java
40+
uses: actions/setup-java@v5
41+
with:
42+
java-version: '17'
43+
distribution: 'adopt'
44+
45+
- name: Setup Gradle
46+
uses: gradle/actions/setup-gradle@v5
47+
48+
- name: Decode mainnet release google-services.json
49+
env:
50+
MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64 }}
51+
run: |
52+
set -euo pipefail
53+
test -n "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64"
54+
mkdir -p app/src/mainnetRelease
55+
printf '%s' "$MAINNET_RELEASE_GOOGLE_SERVICES_JSON_BASE64" | base64 --decode > app/src/mainnetRelease/google-services.json
56+
57+
- name: Decode release keystore
58+
env:
59+
BITKIT_KEYSTORE_BASE64: ${{ secrets.BITKIT_KEYSTORE_BASE64 }}
60+
run: |
61+
set -euo pipefail
62+
test -n "$BITKIT_KEYSTORE_BASE64"
63+
umask 077
64+
keystore_path="$RUNNER_TEMP/bitkit.keystore"
65+
printf '%s' "$BITKIT_KEYSTORE_BASE64" | base64 --decode > "$keystore_path"
66+
echo "KEYSTORE_FILE=$keystore_path" >> "$GITHUB_ENV"
67+
68+
- name: Validate comparison inputs
69+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.comparison_artifact_name != '' }}
70+
env:
71+
COMPARISON_RUN_ID: ${{ inputs.comparison_run_id }}
72+
run: |
73+
set -euo pipefail
74+
test -n "$COMPARISON_RUN_ID"
75+
76+
- name: Download comparison artifact
77+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.comparison_artifact_name != '' }}
78+
uses: actions/download-artifact@v6
79+
with:
80+
name: ${{ inputs.comparison_artifact_name }}
81+
path: ${{ runner.temp }}/comparison
82+
github-token: ${{ github.token }}
83+
repository: ${{ github.repository }}
84+
run-id: ${{ inputs.comparison_run_id }}
85+
86+
- name: Install diffoscope
87+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.comparison_artifact_name != '' }}
88+
run: |
89+
set -euo pipefail
90+
sudo apt-get update
91+
sudo apt-get install -y diffoscope
92+
93+
- name: Build reproducibility artifacts
94+
env:
95+
GPR_USER: ${{ secrets.GPR_USER || github.actor }}
96+
GPR_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
97+
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN || github.token }}
98+
KEYSTORE_PASSWORD: ${{ secrets.BITKIT_KEYSTORE_PASSWORD }}
99+
KEY_ALIAS: ${{ secrets.BITKIT_KEY_ALIAS }}
100+
KEY_PASSWORD: ${{ secrets.BITKIT_KEY_PASSWORD }}
101+
OUTPUT_DIR: ${{ runner.temp }}/reproducible-release
102+
run: |
103+
set -euo pipefail
104+
if [ -d "$RUNNER_TEMP/comparison/extracted-apks" ]; then
105+
export DIFFOSCOPE_COMPARE_DIR="$RUNNER_TEMP/comparison/extracted-apks"
106+
elif [ -d "$RUNNER_TEMP/comparison" ]; then
107+
export DIFFOSCOPE_COMPARE_DIR="$RUNNER_TEMP/comparison"
108+
fi
109+
scripts/reproduce-release.sh
110+
111+
- name: Upload reproducibility artifacts
112+
if: ${{ always() }}
113+
uses: actions/upload-artifact@v6
114+
with:
115+
name: bitkit-reproducible-release-${{ github.run_number }}
116+
path: ${{ runner.temp }}/reproducible-release
117+
retention-days: 30

.github/workflows/ui-tests.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ jobs:
4141
gradle-${{ runner.os }}-
4242
4343
- name: Decode google-services.json
44-
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
44+
run: |
45+
mkdir -p app/src/debug
46+
echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/src/debug/google-services.json
4547
env:
4648
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
4749

0 commit comments

Comments
 (0)