Skip to content

Commit a40af1e

Browse files
authored
Update CI/CD workflow (#42)
Update CI/CD flow
1 parent 036d2f3 commit a40af1e

File tree

15 files changed

+300
-100
lines changed

15 files changed

+300
-100
lines changed

.github/workflows/ci.yml

Lines changed: 118 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [ main, master ]
5+
branches: [main, master]
66
pull_request:
7-
branches: [ '**' ]
7+
branches: ["**"]
88

99
concurrency:
1010
group: ci-${{ github.workflow }}-${{ github.ref }}
@@ -15,16 +15,34 @@ jobs:
1515
name: Lint, Test, Coverage
1616
runs-on: ubuntu-latest
1717
timeout-minutes: 30
18+
env:
19+
ANDROID_HOME: /usr/local/lib/android/sdk
20+
ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
21+
permissions:
22+
contents: read
23+
checks: write
24+
pull-requests: write
1825

1926
steps:
2027
- name: Checkout
2128
uses: actions/checkout@v4
2229

23-
- name: Setup Java 21
30+
- name: Cache Android SDK
31+
uses: actions/cache@v4
32+
with:
33+
path: |
34+
${{ env.ANDROID_SDK_ROOT }}
35+
~/.android
36+
key: ${{ runner.os }}-android-sdk-36-buildtools-35-0-0
37+
restore-keys: |
38+
${{ runner.os }}-android-sdk-
39+
40+
- name: Setup Java 17
2441
uses: actions/setup-java@v4
2542
with:
2643
distribution: temurin
27-
java-version: '21'
44+
java-version: "17"
45+
cache: gradle
2846

2947
- name: Setup Android SDK
3048
uses: android-actions/setup-android@v3
@@ -45,14 +63,60 @@ jobs:
4563
run: ./gradlew --version
4664

4765
- name: Lint
48-
run: ./gradlew --stacktrace lint
66+
run: ./gradlew --stacktrace --build-cache lint
67+
68+
- name: Publish lint results to PR (masked-edittext)
69+
if: >-
70+
always() &&
71+
github.event_name == 'pull_request' &&
72+
github.event.pull_request.head.repo.full_name == github.repository &&
73+
hashFiles('masked-edittext/build/reports/lint-results-debug.xml') != ''
74+
uses: dvdandroid/action-android-lint@master
75+
with:
76+
github_token: ${{ secrets.GITHUB_TOKEN }}
77+
lint_xml_file: masked-edittext/build/reports/lint-results-debug.xml
78+
reporter: github-pr-check
79+
80+
- name: Publish lint results to PR (demo_app)
81+
if: >-
82+
always() &&
83+
github.event_name == 'pull_request' &&
84+
github.event.pull_request.head.repo.full_name == github.repository &&
85+
hashFiles('demo_app/build/reports/lint-results-debug.xml') != ''
86+
uses: dvdandroid/action-android-lint@master
87+
with:
88+
github_token: ${{ secrets.GITHUB_TOKEN }}
89+
lint_xml_file: demo_app/build/reports/lint-results-debug.xml
90+
reporter: github-pr-check
91+
92+
- name: Publish lint results to PR (demo_app_compose)
93+
if: >-
94+
always() &&
95+
github.event_name == 'pull_request' &&
96+
github.event.pull_request.head.repo.full_name == github.repository &&
97+
hashFiles('demo_app_compose/build/reports/lint-results-debug.xml') != ''
98+
uses: dvdandroid/action-android-lint@master
99+
with:
100+
github_token: ${{ secrets.GITHUB_TOKEN }}
101+
lint_xml_file: demo_app_compose/build/reports/lint-results-debug.xml
102+
reporter: github-pr-check
103+
104+
- name: Publish lint reports
105+
if: always()
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: lint-reports
109+
path: |
110+
**/build/reports/lint-results-*.html
111+
**/build/reports/lint-results-*.xml
112+
**/build/reports/lint-results-*.txt
49113
50114
- name: Unit tests (all modules)
51-
run: ./gradlew --stacktrace test
115+
run: ./gradlew --stacktrace --build-cache test
52116

53117
- name: Coverage (Kover) for library module
54118
run: |
55-
./gradlew --stacktrace :masked-edittext:koverXmlReport :masked-edittext:koverHtmlReport
119+
./gradlew --stacktrace --build-cache :masked-edittext:koverXmlReport :masked-edittext:koverHtmlReport
56120
57121
- name: Publish test reports
58122
if: always()
@@ -76,32 +140,50 @@ jobs:
76140
shell: bash
77141
run: |
78142
set -euo pipefail
79-
REPORT_XML="masked-edittext/build/reports/kover/xml/report.xml"
80-
if [[ -f "$REPORT_XML" ]]; then
81-
python3 - << 'PY'
82-
import xml.etree.ElementTree as ET
83-
import os
84-
path = os.environ.get('REPORT_XML', 'masked-edittext/build/reports/kover/xml/report.xml')
85-
tree = ET.parse(path)
86-
root = tree.getroot()
87-
line = next((c for c in root.findall('counter') if c.get('type')=='LINE'), None)
88-
inst = next((c for c in root.findall('counter') if c.get('type')=='INSTRUCTION'), None)
89-
def pct(counter):
90-
if counter is None: return None
91-
missed = int(counter.get('missed', '0'))
92-
covered = int(counter.get('covered', '0'))
93-
total = missed + covered
94-
return (covered * 100.0 / total) if total else 0.0
95-
lines = pct(line)
96-
instructions = pct(inst)
97-
summary = []
98-
if lines is not None:
99-
summary.append(f"Line coverage: {lines:.2f}%")
100-
if instructions is not None:
101-
summary.append(f"Instruction coverage: {instructions:.2f}%")
102-
print("\n".join(summary) or "No coverage counters found.")
103-
PY
104-
else
105-
echo "Coverage report not found at $REPORT_XML"
106-
fi >> "$GITHUB_STEP_SUMMARY"
107-
143+
SUMMARY_FILE="${GITHUB_STEP_SUMMARY:-/dev/stdout}"
144+
report_candidates=(
145+
"masked-edittext/build/reports/kover/xml/report.xml"
146+
"masked-edittext/build/reports/kover/report.xml"
147+
"masked-edittext/build/reports/kover/xmlDebug/report.xml"
148+
"masked-edittext/build/reports/kover/xmlRelease/report.xml"
149+
)
150+
REPORT_XML=""
151+
for candidate in "${report_candidates[@]}"; do
152+
if [[ -f "$candidate" ]]; then
153+
REPORT_XML="$candidate"
154+
break
155+
fi
156+
done
157+
if [[ -n "$REPORT_XML" ]]; then
158+
REPORT_XML="$REPORT_XML" python3 - << 'PY'
159+
import xml.etree.ElementTree as ET
160+
import os
161+
import sys
162+
path = os.environ["REPORT_XML"]
163+
try:
164+
tree = ET.parse(path)
165+
except Exception as exc:
166+
print(f"Failed to parse coverage report at {path}: {exc}")
167+
sys.exit(0)
168+
root = tree.getroot()
169+
line = next((c for c in root.findall('counter') if c.get('type')=='LINE'), None)
170+
inst = next((c for c in root.findall('counter') if c.get('type')=='INSTRUCTION'), None)
171+
def pct(counter):
172+
if counter is None: return None
173+
missed = int(counter.get('missed', '0'))
174+
covered = int(counter.get('covered', '0'))
175+
total = missed + covered
176+
return (covered * 100.0 / total) if total else 0.0
177+
lines = pct(line)
178+
instructions = pct(inst)
179+
summary = []
180+
if lines is not None:
181+
summary.append(f"Line coverage: {lines:.2f}%")
182+
if instructions is not None:
183+
summary.append(f"Instruction coverage: {instructions:.2f}%")
184+
print("\n".join(summary) or f"No coverage counters found in {path}.")
185+
PY
186+
else
187+
echo "Coverage report not found. Checked:"
188+
printf '%s\n' "${report_candidates[@]}"
189+
fi >> "$SUMMARY_FILE"

.github/workflows/release.yml

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,23 @@ name: Release to Maven Central
33
on:
44
push:
55
tags:
6-
- 'v*'
6+
- "v*"
77
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: "Release version (e.g., 2.2.1). Overrides tag when set."
11+
required: false
12+
type: string
813

914
jobs:
1015
publish:
1116
name: Publish artifacts
1217
runs-on: ubuntu-latest
1318
timeout-minutes: 60
14-
1519
env:
20+
ANDROID_HOME: /usr/local/lib/android/sdk
21+
ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
22+
1623
# Common envs many Gradle configs consume for Sonatype + Signing
1724
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
1825
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
@@ -32,11 +39,22 @@ jobs:
3239
- name: Checkout
3340
uses: actions/checkout@v4
3441

35-
- name: Setup Java 21
42+
- name: Cache Android SDK
43+
uses: actions/cache@v4
44+
with:
45+
path: |
46+
${{ env.ANDROID_SDK_ROOT }}
47+
~/.android
48+
key: ${{ runner.os }}-android-sdk-36-buildtools-35-0-0
49+
restore-keys: |
50+
${{ runner.os }}-android-sdk-
51+
52+
- name: Setup Java 17
3653
uses: actions/setup-java@v4
3754
with:
3855
distribution: temurin
39-
java-version: '21'
56+
java-version: "17"
57+
cache: gradle
4058

4159
- name: Setup Android SDK
4260
uses: android-actions/setup-android@v3
@@ -53,6 +71,31 @@ jobs:
5371
- name: Setup Gradle
5472
uses: gradle/actions/setup-gradle@v4
5573

74+
- name: Set release version from tag
75+
shell: bash
76+
run: |
77+
set -euo pipefail
78+
version_input="${{ inputs.version }}"
79+
if [[ -n "$version_input" ]]; then
80+
echo "Using workflow_dispatch version ${version_input}"
81+
echo "ORG_GRADLE_PROJECT_VERSION=${version_input}" >> "$GITHUB_ENV"
82+
exit 0
83+
fi
84+
85+
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
86+
echo "No version input provided for manual release; refusing to continue."
87+
exit 1
88+
fi
89+
90+
ref="${GITHUB_REF_NAME}"
91+
if [[ "$ref" == v* ]]; then
92+
version="${ref#v}"
93+
echo "Using release version ${version}"
94+
echo "ORG_GRADLE_PROJECT_VERSION=${version}" >> "$GITHUB_ENV"
95+
else
96+
echo "GITHUB_REF_NAME '${ref}' does not match a version tag; skipping override."
97+
fi
98+
5699
- name: Import GPG key (for signing)
57100
if: env.SIGNING_KEY != ''
58101
shell: bash
@@ -71,7 +114,7 @@ jobs:
71114
rm -f "$tmpkey"
72115
73116
- name: Build release AAR (sanity)
74-
run: ./gradlew --stacktrace :masked-edittext:assembleRelease
117+
run: ./gradlew --stacktrace --build-cache :masked-edittext:assembleRelease
75118

76119
- name: Publish to Sonatype or generic Maven
77120
shell: bash
@@ -80,10 +123,10 @@ jobs:
80123
echo "Checking for Nexus Publish tasks..."
81124
if ./gradlew -q tasks --all | grep -q "publishToSonatype"; then
82125
echo "Using Gradle Nexus Publish Plugin"
83-
./gradlew --stacktrace publishToSonatype closeAndReleaseSonatypeStagingRepository
126+
./gradlew --stacktrace --build-cache publishToSonatype closeAndReleaseSonatypeStagingRepository
84127
else
85128
echo "Falling back to generic 'publish'"
86-
./gradlew --stacktrace publish
129+
./gradlew --stacktrace --build-cache publish
87130
fi
88131
89132
- name: Upload built artifacts
@@ -94,4 +137,3 @@ jobs:
94137
path: |
95138
masked-edittext/build/outputs/aar/*.aar
96139
**/build/publications/**
97-

build.gradle

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@ buildscript {
44
ext.kotlin_version = '2.2.0'
55
ext.compose_version = '1.9.2'
66
ext.compose_compiler_version = '1.4.3'
7-
7+
88
repositories {
99
google()
1010
mavenCentral()
11+
gradlePluginPortal()
1112
}
1213
dependencies {
1314
classpath 'com.android.tools.build:gradle:8.11.2'
1415
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1516
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
1617
classpath 'org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.2.0'
1718
classpath 'org.jetbrains.kotlinx:kover-gradle-plugin:0.9.3'
19+
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
1820
// NOTE: Do not place your application dependencies here; they belong
1921
// in the individual module build.gradle files
2022
}
@@ -26,3 +28,14 @@ allprojects {
2628
mavenCentral()
2729
}
2830
}
31+
32+
apply plugin: 'io.github.gradle-nexus.publish-plugin'
33+
34+
nexusPublishing {
35+
repositories {
36+
sonatype {
37+
nexusUrl = uri("https://s01.oss.sonatype.org/service/local/")
38+
snapshotRepositoryUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
39+
}
40+
}
41+
}

demo_app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ android {
2424
}
2525
}
2626
compileOptions {
27-
sourceCompatibility JavaVersion.VERSION_21
28-
targetCompatibility JavaVersion.VERSION_21
27+
sourceCompatibility JavaVersion.VERSION_17
28+
targetCompatibility JavaVersion.VERSION_17
2929
}
3030
kotlinOptions {
31-
jvmTarget = '21'
31+
jvmTarget = '17'
3232
}
3333
buildFeatures {
3434
viewBinding true
@@ -39,8 +39,8 @@ dependencies {
3939
implementation project(':masked-edittext')
4040
implementation 'androidx.core:core-ktx:1.17.0'
4141
implementation 'androidx.appcompat:appcompat:1.7.1'
42-
implementation 'androidx.activity:activity-ktx:1.9.3'
43-
implementation 'com.google.android.material:material:1.12.0'
42+
implementation 'androidx.activity:activity-ktx:1.12.2'
43+
implementation 'com.google.android.material:material:1.13.0'
4444
testImplementation 'junit:junit:4.13.2'
4545
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
4646
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'

demo_app/src/main/res/values-land/dimens.xml

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
<resources xmlns:tools="http://schemas.android.com/tools">
22
<!-- Base application theme. -->
3-
<style name="Base.Theme.MaskedEdittext" parent="Theme.Material3.DayNight.NoActionBar">
3+
<style
4+
name="Base.Theme.MaskedEdittext"
5+
parent="Theme.Material3.DayNight.NoActionBar"
6+
>
47
<item name="android:statusBarColor">@android:color/transparent</item>
5-
<item name="android:navigationBarColor">@android:color/transparent</item>
6-
<item name="android:enforceStatusBarContrast">false</item>
7-
<item name="android:enforceNavigationBarContrast">false</item>
8+
<item
9+
name="android:navigationBarColor"
10+
>@android:color/transparent</item>
11+
<item
12+
name="android:enforceStatusBarContrast"
13+
tools:targetApi="29"
14+
>false</item>
15+
<item
16+
name="android:enforceNavigationBarContrast"
17+
tools:targetApi="29"
18+
>false</item>
819
</style>
920
</resources>

0 commit comments

Comments
 (0)