Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ktlint 1.3.1; initial format, pre-commit hook, and GitHub Action #2

Merged
merged 7 commits into from
Sep 6, 2024
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
40 changes: 40 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# EditorConfig is awesome: https://EditorConfig.org

# Top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# YAML files
[*.yml]
indent_style = space
indent_size = 2

# KtLint
[*.{kt,kts}]
ktlint_code_style = ktlint_official

# Disable multiline-expression wrapping. This allows complex expressions to start on the same
# line as the `=`, e.g. `= Modifier`, and `= listOf(`
# See: https://pinterest.github.io/ktlint/1.3.1/rules/standard/#multiline-expression-wrapping
ktlint_standard_multiline-expression-wrapping = disabled
# Also need to disable the related rule so string templates behave similarly, e.g. `= """`
# See: https://pinterest.github.io/ktlint/1.3.1/rules/standard/#string-template-indent
ktlint_standard_string-template-indent = disabled

# Only wrap functions when there is not enough space on the line
# See: https://pinterest.github.io/ktlint/1.3.1/rules/standard/#function-signature
ktlint_function_signature_body_expression_wrapping = default
ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 2

# Allow blank lines in lists, which can be useful to help visually break things up
# and group related function params together
# See: https://pinterest.github.io/ktlint/1.3.1/rules/standard/#no-blank-lines-in-list
ktlint_standard_no-blank-line-in-list = disabled

[**/build/generated/**]
# Ignore generated code
ktlint_standard = disabled
3 changes: 3 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Initial ktlint 1.3.1 installation and formatting
2bb8d42a74ea6d3f7f7dd3e45cf6b58bd04cf63e
29900055f992d0c84ecb4c0e880a25e994308fa0
10 changes: 10 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

echo "Running ktlint..."

ktlint
status=$?

# return 1 exit code if running checks fails
[ $status -ne 0 ] && exit 1
exit 0
30 changes: 30 additions & 0 deletions .github/workflows/ktlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Lint - Kotlin

on:
pull_request:
paths-ignore:
- "**.md"
push:
branches:
- main
workflow_dispatch:

jobs:
ktlint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: install ktlint 1.3.1
# https://pinterest.github.io/ktlint/1.3.1/install/cli/#download-using-curl
run: |
curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.3.1/ktlint
chmod a+x ktlint
mv ktlint /usr/local/bin/

- name: ktlint version
run: ktlint --version

- name: ktlint
run: ktlint
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![ktlint](https://img.shields.io/badge/ktlint%20code--style-%E2%9D%A4-FF4081)](https://pinterest.github.io/ktlint/)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add Github Actions badge?


# OAuth PKCE Flow for Kotlin Multiplatform (Android/iOS)

A Kotlin Multiplatform library for Android and iOS that provides an [OAuth PKCE flow](https://oauth.net/2/pkce/) implementation.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
//trick: for the same plugin versions in all sub-modules
// trick: for the same plugin versions in all sub-modules
alias(libs.plugins.androidLibrary).apply(false)
alias(libs.plugins.kotlinMultiplatform).apply(false)
alias(libs.plugins.kotlinSerialization).apply(false)
Expand All @@ -24,7 +24,7 @@ val sonatypeUsername = gradlePropertyOrEnvironmentVariable("SONATYPE_USERNAME")
val sonatypePassword = gradlePropertyOrEnvironmentVariable("SONATYPE_PASSWORD")
if (sonatypeUsername != null) {
subprojects {
plugins.withType<MavenPublishPlugin>() {
plugins.withType<MavenPublishPlugin> {
configure<PublishingExtension> {
repositories {
maven {
Expand Down
4 changes: 2 additions & 2 deletions oauth-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ kotlin {
androidTarget {
publishAllLibraryVariants()
}

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
iosSimulatorArm64(),
).forEach {
it.binaries.framework {
baseName = "OAuthKMP"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent

public class AndroidPKCEFlow(private val context: Context): PlatformPKCEFlow {
override fun startSignIn(signInUrl: String, redirectUrl: String, completionHandler: (String?, String?) -> Unit) {
public class AndroidPKCEFlow(
private val context: Context,
) : PlatformPKCEFlow {
override fun startSignIn(
signInUrl: String,
redirectUrl: String,
completionHandler: (String?, String?) -> Unit,
) {
// NOTE: Android is unable to directly invoke the completionHandler to process the
// callback URL when the external web browser transfers control back to the app.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ public interface OAuthService {
* @param redirectUrl The original `redirect_uri` that was included as a sign-in URL query parameter.
*/
@Throws(OAuthException::class, CancellationException::class)
public suspend fun exchangeAuthorizationCode(code: String, verifier: String, redirectUrl: String): TokenResponse
public suspend fun exchangeAuthorizationCode(
code: String,
verifier: String,
redirectUrl: String,
): TokenResponse

/**
* Meant to be called when an access_token is no longer value, to get new access/refresh tokens.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ public class OAuthServiceImpl(
private val httpClient: HttpClient,
override val clientId: String,
) : OAuthService {
override suspend fun exchangeAuthorizationCode(code: String, verifier: String, redirectUrl: String): TokenResponse {
override suspend fun exchangeAuthorizationCode(
code: String,
verifier: String,
redirectUrl: String,
): TokenResponse {
val response: HttpResponse = httpClient.post("oauth/token") {
setBody(
AuthorizationCodeRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class PKCEFlowTest {
fun `flow reports error message when server rejects authorization code`() = runTest {
val pkceFlow = PKCEFlow(
TestPlatformPKCEFlow(
automaticallyInvokeCompletionCallback = true
automaticallyInvokeCompletionCallback = true,
),
createOAuthService(
MockEngine {
Expand Down Expand Up @@ -309,6 +309,7 @@ class PKCEFlowTest {
)

assertEquals(
@Suppress("ktlint:standard:max-line-length")
PKCEFlow.PKCEAuthState(
state = PKCEFlow.PKCEAuthState.State.FINISHED,
tokenResponse = null,
Expand All @@ -325,7 +326,7 @@ class PKCEFlowTest {
fun `flow reports error message when authorization code fails`() = runTest {
val pkceFlow = PKCEFlow(
TestPlatformPKCEFlow(
automaticallyInvokeCompletionCallback = true
automaticallyInvokeCompletionCallback = true,
),
createOAuthService(
MockEngine {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,35 @@ import platform.Foundation.NSURL
import platform.UIKit.UIApplication
import platform.darwin.NSObject

public class IosPKCEFlow: PlatformPKCEFlow {
override fun startSignIn(signInUrl: String, redirectUrl: String, completionHandler: (String?, String?) -> Unit) {
public class IosPKCEFlow : PlatformPKCEFlow {
override fun startSignIn(
signInUrl: String,
redirectUrl: String,
completionHandler: (String?, String?) -> Unit,
) {
val authSession = ASWebAuthenticationSession(
uRL = NSURL.URLWithString(signInUrl)!!,
callbackURLScheme = NSURL.URLWithString(redirectUrl)!!.scheme,
completionHandler = object : ASWebAuthenticationSessionCompletionHandler {
override fun invoke(callbackUrl: NSURL?, error: NSError?) {
override fun invoke(
callbackUrl: NSURL?,
error: NSError?,
) {
completionHandler(
callbackUrl?.absoluteString,
error?.localizedDescription
error?.localizedDescription,
)
}
}
},
)

authSession.presentationContextProvider = object : NSObject(), ASWebAuthenticationPresentationContextProvidingProtocol {
// https://developer.apple.com/documentation/authenticationservices/aswebauthenticationpresentationcontextproviding/presentationanchor(for:)?language=objc
override fun presentationAnchorForWebAuthenticationSession(session: ASWebAuthenticationSession): ASPresentationAnchor {
return UIApplication.sharedApplication.keyWindow ?: ASPresentationAnchor()
}
override fun presentationAnchorForWebAuthenticationSession(session: ASWebAuthenticationSession): ASPresentationAnchor =
UIApplication.sharedApplication.keyWindow ?: ASPresentationAnchor()
}

authSession.prefersEphemeralWebBrowserSession = true
authSession.start()
}


}