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
25 changes: 25 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 2
updates:
# Gradle (version catalog, plugins and wrapper)
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
day: "wednesday"
open-pull-requests-limit: 10
groups:
gradle:
patterns:
- "*" # Prefer a single PR per dependency update round.

# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "wednesday"
open-pull-requests-limit: 10
groups:
github-actions:
patterns:
- "*"
269 changes: 269 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
name: CI

on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch: # Allows manual trigger of the workflow

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
JAVA_VERSION: '17'
# Robolectric needs JDK 21 to run on the latest Android SDKs
TEST_JAVA_VERSION: '21'

# Stages: Resolve Version -> Test (lowest and latest Android SDK) -> Build library & sample app -> Tag & Release
# The Test report job publishes the JUnit results of every SDK, also when the tests fail.
# Every stage must succeed for the next one to start.
jobs:
version:
name: Resolve Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.resolve.outputs.version }}
tag_exists: ${{ steps.resolve.outputs.tag_exists }}

steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Read version from gradle.properties
id: resolve
shell: bash
run: |
VERSION=$(sed -n 's/^VERSION_NAME=\(.*\)$/\1/p' gradle.properties | head -1)
if [ -z "$VERSION" ]; then
echo "::error file=gradle.properties::No VERSION_NAME found"
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

if git ls-remote --exit-code --tags origin "refs/tags/$VERSION" >/dev/null 2>&1; then
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
echo "::notice::Tag $VERSION already present - skip release"
else
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
fi

echo "### Version \`$VERSION\`" >> "$GITHUB_STEP_SUMMARY"

test:
name: Test (SDK ${{ matrix.sdk }})
runs-on: ubuntu-latest
needs: [version]
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
# Android version the Robolectric unit tests run on: the lowest one Robolectric supports
# (23, the library minSdk 21 is no longer supported by Robolectric) and the latest one.
sdk: [23, 37]

steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup JDK
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ env.TEST_JAVA_VERSION }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6

- name: Select Robolectric SDK
run: echo "sdk=${{ matrix.sdk }}" > flowlayoutmanager/src/test/resources/robolectric.properties

- name: Test
run: ./gradlew :flowlayoutmanager:testDebugUnitTest

# Read by the report job
- name: Upload JUnit results
if: always()
uses: actions/upload-artifact@v7
with:
name: junit-sdk${{ matrix.sdk }}
path: flowlayoutmanager/build/test-results/testDebugUnitTest/*.xml
if-no-files-found: warn

- name: Upload HTML report
if: failure()
uses: actions/upload-artifact@v7
with:
name: test-report-sdk${{ matrix.sdk }}
path: flowlayoutmanager/build/reports/tests/
if-no-files-found: ignore

report:
name: Test report
runs-on: ubuntu-latest
needs: [test]
if: always()
permissions:
contents: read
actions: read # download the JUnit artifacts
checks: write # publish a check run per SDK

steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

# One check run per junit-sdk<N> artifact, "Unit Tests Result (SDK <N>)"
- name: Publish Unit Tests Result
uses: dorny/test-reporter@v1
with:
name: Unit Tests Result (SDK $1)
artifact: /junit-sdk(.*)/
path: '**/*.xml'
reporter: java-junit
fail-on-error: true
# Recent v1 releases default to the job summary only: create the check runs with their state
use-actions-summary: false

build:
name: Build library & sample app
runs-on: ubuntu-latest
needs: [version, test]
timeout-minutes: 30
env:
VERSION: ${{ needs.version.outputs.version }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}

steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup JDK
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ env.JAVA_VERSION }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6

- name: Prepare signing key
if: env.ANDROID_KEYSTORE_BASE64 != '' && github.event_name != 'pull_request'
run: |
echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$RUNNER_TEMP/release.keystore"
echo "ANDROID_KEYSTORE_FILE=$RUNNER_TEMP/release.keystore" >> "$GITHUB_ENV"

- name: Build
run: |
./gradlew \
:flowlayoutmanager:assembleRelease \
:flowlayoutmanager:publishToMavenLocal \
:app:assembleDebug \
:app:assembleRelease

- name: Package
run: |
mkdir -p dist
cp flowlayoutmanager/build/outputs/aar/flowlayoutmanager-release.aar "dist/FlowLayoutManager-${VERSION}.aar"

# Signed release APK when a keystore is configured, debug APK otherwise
# (an unsigned APK cannot be installed).
APK="$(find app/build/outputs/apk/release -name '*.apk' ! -name '*unsigned*' -print -quit)"
[ -n "$APK" ] || APK="$(find app/build/outputs/apk/debug -name '*.apk' -print -quit)"
if [ -z "$APK" ]; then
echo "::error::No APK produced"
exit 1
fi
cp "$APK" "dist/FlowLayoutManager-sample-${VERSION}.apk"
ls -lh dist

- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: flowlayoutmanager-${{ env.VERSION }}
path: dist/*
if-no-files-found: error

release:
name: Tag & Release
runs-on: ubuntu-latest
needs: [version, build]
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request'
permissions:
contents: write
statuses: write
id-token: write
attestations: write
env:
VERSION: ${{ needs.version.outputs.version }}

steps:
- uses: actions/checkout@v7

- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: flowlayoutmanager-${{ env.VERSION }}
path: release

- name: Checksums
run: |
cd release
sha256sum * > SHA256SUMS
cat SHA256SUMS

- name: Attest build provenance
uses: actions/attest-build-provenance@v4
with:
subject-path: 'release/*.aar, release/*.apk'

- name: Tag release
id: tag
if: needs.version.outputs.tag_exists != 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "$VERSION"
git push origin "$VERSION"

- name: Create GitHub Release
id: gh_release
if: steps.tag.outcome == 'success'
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ env.VERSION }}
name: ${{ env.VERSION }}
generate_release_notes: true
files: release/*

- name: Report release status
if: always()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "${{ needs.version.outputs.tag_exists }}" = "true" ]; then
STATE=pending
DESCRIPTION="Version $VERSION already released - bump VERSION_NAME in gradle.properties."
elif [ "${{ steps.gh_release.outcome }}" = "success" ]; then
STATE=success
DESCRIPTION="Released $VERSION with library AAR and sample APK."
else
STATE=failure
DESCRIPTION="Release failed with an unexpected error."
fi
gh api repos/${{ github.repository }}/statuses/${{ github.sha }} \
-f state="$STATE" \
-f description="$DESCRIPTION" \
-f context="release"
85 changes: 13 additions & 72 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,82 +1,23 @@
# Built application files
*.apk
*.ap_

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
# Gradle
.gradle/
build/
.kotlin/

# Local configuration file (sdk path, etc)
local.properties

# Windows thumbnail db
Thumbs.db

# Windows thumbnail db
Thumbs.db

# OSX files
.DS_Store

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# IntelliJ
*.iml
# Android Studio / IntelliJ
.idea/
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries
.idea/*
*/.idea/*

# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
#*.jks

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# Google Services (e.g. APIs or Firebase)
google-services.json

# Freeline
freeline.py
freeline/
freeline_project_description.json

# Android Studio
*.iml
.idea
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
.gradle
build/
.navigation
captures/
output.json
.externalNativeBuild/
.cxx/

#NDK
obj/
.externalNativeBuild
# Build outputs
*.apk
*.aab
*.ap_
*.dex

# OS files
.DS_Store
Binary file removed FlowLayoutManager.zip
Binary file not shown.
Loading
Loading