diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 940454d34..c724b0cfd 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - task: [ detekt, ktlint ] + task: [ detekt, ktlintCheck ] steps: - uses: actions/checkout@v3 - name: Set up JDK 8 diff --git a/app/build.gradle b/app/build.gradle index 4c088be09..11960f120 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,10 +31,7 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' apply plugin: 'com.github.spotbugs' apply plugin: 'io.gitlab.arturbosch.detekt' - -configurations { - ktlint -} +apply plugin: "org.jlleitschuh.gradle.ktlint" def urlFile = { url, fileName -> File file = new File("$buildDir/download/${fileName}") @@ -149,7 +146,7 @@ android { } } - check.dependsOn 'spotbugsGplayDebugReport', 'lint', 'ktlint', 'detekt' + check.dependsOn 'spotbugsGplayDebug', 'lint', 'ktlintCheck', 'detekt' lint.dependsOn 'preBuild' compileOptions { @@ -206,7 +203,6 @@ dependencies { implementation ('com.gitlab.bitfireAT:dav4jvm:2.1.3', { exclude group: 'org.ogce', module: 'xpp3' // Android comes with its own XmlPullParser }) - ktlint "com.pinterest:ktlint:0.44.0" implementation 'org.conscrypt:conscrypt-android:2.5.2' implementation 'androidx.camera:camera-core:1.0.2' @@ -338,20 +334,6 @@ dependencies { gplayImplementation "com.google.firebase:firebase-messaging:23.0.0" } -task ktlint(type: JavaExec, group: "verification") { - description = "Check Kotlin code style." - main = "com.pinterest.ktlint.Main" - classpath = configurations.ktlint - args "--reporter=plain", "--reporter=plain,output=${buildDir}/ktlint.txt,src/**/*.kt" -} - -task ktlintFormat(type: JavaExec, group: "formatting") { - description = "Fix Kotlin code style deviations." - main = "com.pinterest.ktlint.Main" - classpath = configurations.ktlint - args "-F", "src/**/*.kt" -} - detekt { reports { xml { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt index 13bf6c5b0..5025361a1 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt @@ -59,11 +59,10 @@ import java.security.cert.CertificateException import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class ServerSelectionController : NewBaseController(R.layout.controller_server_selection) { - private val binding: ControllerServerSelectionBinding by viewBinding(ControllerServerSelectionBinding::bind) +class ServerSelectionController : + NewBaseController(R.layout.controller_server_selection) { - override val appBarLayoutType: AppBarLayoutType - get() = AppBarLayoutType.EMPTY + private val binding: ControllerServerSelectionBinding by viewBinding(ControllerServerSelectionBinding::bind) @Inject lateinit var ncApi: NcApi @@ -75,14 +74,18 @@ class ServerSelectionController : NewBaseController(R.layout.controller_server_s fun onCertClick() { if (activity != null) { - KeyChain.choosePrivateKeyAlias(activity!!, { alias: String? -> - if (alias != null) { - appPreferences!!.temporaryClientCertAlias = alias - } else { - appPreferences!!.removeTemporaryClientCertAlias() - } - setCertTextView() - }, arrayOf("RSA", "EC"), null, null, -1, null) + KeyChain.choosePrivateKeyAlias( + activity!!, + { alias: String? -> + if (alias != null) { + appPreferences!!.temporaryClientCertAlias = alias + } else { + appPreferences!!.removeTemporaryClientCertAlias() + } + setCertTextView() + }, + arrayOf("RSA", "EC"), null, null, -1, null + ) } } @@ -367,6 +370,9 @@ class ServerSelectionController : NewBaseController(R.layout.controller_server_s statusQueryDisposable = null } + override val appBarLayoutType: AppBarLayoutType + get() = AppBarLayoutType.EMPTY + companion object { const val TAG = "ServerSelectionController" const val MIN_SERVER_MAJOR_VERSION = 13 diff --git a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt index a1fdb5db7..70869d0f3 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt @@ -241,31 +241,39 @@ class WebViewLoginController(args: Bundle? = null) : NewBaseController( } }.start() } else { - KeyChain.choosePrivateKeyAlias(activity!!, { chosenAlias: String? -> - if (chosenAlias != null) { - appPreferences!!.temporaryClientCertAlias = chosenAlias - Thread { - var privateKey: PrivateKey? = null - try { - privateKey = KeyChain.getPrivateKey(activity!!, chosenAlias) - val certificates = KeyChain.getCertificateChain( - activity!!, chosenAlias - ) - if (privateKey != null && certificates != null) { - request.proceed(privateKey, certificates) - } else { + KeyChain.choosePrivateKeyAlias( + activity!!, + { chosenAlias: String? -> + if (chosenAlias != null) { + appPreferences!!.temporaryClientCertAlias = chosenAlias + Thread { + var privateKey: PrivateKey? = null + try { + privateKey = KeyChain.getPrivateKey(activity!!, chosenAlias) + val certificates = KeyChain.getCertificateChain( + activity!!, chosenAlias + ) + if (privateKey != null && certificates != null) { + request.proceed(privateKey, certificates) + } else { + request.cancel() + } + } catch (e: KeyChainException) { + request.cancel() + } catch (e: InterruptedException) { request.cancel() } - } catch (e: KeyChainException) { - request.cancel() - } catch (e: InterruptedException) { - request.cancel() - } - }.start() - } else { - request.cancel() - } - }, arrayOf("RSA", "EC"), null, request.host, request.port, null) + }.start() + } else { + request.cancel() + } + }, + arrayOf("RSA", "EC"), + null, + request.host, + request.port, + null + ) } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt index 30271b244..57584222a 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SetStatusDialogFragment.kt @@ -212,17 +212,8 @@ class SetStatusDialogFragment : binding.emoji.disableKeyboardInput(popup) binding.emoji.forceSingleEmoji() - val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - adapter.add(getString(R.string.dontClear)) - adapter.add(getString(R.string.thirtyMinutes)) - adapter.add(getString(R.string.oneHour)) - adapter.add(getString(R.string.fourHours)) - adapter.add(getString(R.string.today)) - adapter.add(getString(R.string.thisWeek)) - binding.clearStatusAfterSpinner.apply { - this.adapter = adapter + this.adapter = createClearTimesArrayAdapter() onItemSelectedListener = object : OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { setClearStatusAfterValue(position) @@ -244,6 +235,18 @@ class SetStatusDialogFragment : } } + private fun createClearTimesArrayAdapter(): ArrayAdapter { + val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + adapter.add(getString(R.string.dontClear)) + adapter.add(getString(R.string.thirtyMinutes)) + adapter.add(getString(R.string.oneHour)) + adapter.add(getString(R.string.fourHours)) + adapter.add(getString(R.string.today)) + adapter.add(getString(R.string.thisWeek)) + return adapter + } + @Suppress("ComplexMethod") private fun setClearStatusAfterValue(item: Int) { diff --git a/build.gradle b/build.gradle index 60772b102..76534f9d3 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.5' classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" + classpath "org.jlleitschuh.gradle:ktlint-gradle:10.2.1" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit new file mode 100644 index 000000000..dad2ed4b7 --- /dev/null +++ b/scripts/hooks/pre-commit @@ -0,0 +1,14 @@ +#!/bin/bash +# Pre-commit hook: don't allow commits if detekt or ktlint fail. Skip with "git commit --no-verify". +echo "Running pre-commit checks..." + +if ! ./gradlew --daemon ktlintCheck &>/dev/null; then + echo >&2 "ktlint failed! Run ./gradlew ktlintCheck for details" + echo >&2 "Hint: fix most lint errors with ./gradlew ktlintFormat" + exit 1 +fi + +if ! ./gradlew --daemon detekt &>/dev/null; then + echo >&2 "Detekt failed! See report at file://$(pwd)/app/build/reports/detekt/detekt.html" + exit 1 +fi diff --git a/scripts/hooks/pre-push b/scripts/hooks/pre-push new file mode 100644 index 000000000..628975cb2 --- /dev/null +++ b/scripts/hooks/pre-push @@ -0,0 +1,27 @@ +#!/bin/bash +# Pre-push: Don't allow commits without Signed-off-by. Skip with "git push --no-verify". +set -euo pipefail + +z40=0000000000000000000000000000000000000000 # magic deleted ref + +while read local_ref local_sha remote_ref remote_sha; do + if [ "$local_sha" != $z40 ]; then + if [ "$remote_sha" = $z40 ]; then + # New branch, examine all commits + range="$(git merge-base master $local_sha)..$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for commits without sign-off + commit=$(git rev-list --no-merges --grep 'Signed-off-by' --invert-grep "$range") + if [ -n "$commit" ]; then + echo >&2 "Found commits without sign-off in $local_ref. Aborting push. Offending commits:" + echo >&2 "$commit" + exit 1 + fi + fi +done + +exit 0