Merge pull request #3025 from element-hq/feature/bma/elementEnterprise

Element enterprise (EE) foundations
This commit is contained in:
Benoit Marty
2024-07-01 17:08:40 +02:00
committed by GitHub
36 changed files with 602 additions and 37 deletions

View File

@@ -16,8 +16,6 @@ jobs:
debug:
name: Build APKs
runs-on: ubuntu-latest
# Skip for `main`
if: github.ref != 'refs/heads/main'
strategy:
matrix:
variant: [debug, release, nightly, samples]

69
.github/workflows/build_enterprise.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: Enterprise APK Build
on:
workflow_dispatch:
pull_request:
merge_group:
push:
branches: [ develop ]
# Enrich gradle.properties for CI/CD
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx7g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseG1GC
CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true
jobs:
build:
name: Build Enterprise APKs
runs-on: ubuntu-latest
# Skip in forks
if: github.repository == 'element-hq/element-x-android'
strategy:
matrix:
variant: [debug, release, nightly]
fail-fast: false
# Allow all jobs on develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-enterprise-{0}-{1}', matrix.variant, github.sha) || format('build-enterprise-{0}-{1}', matrix.variant, github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Assemble debug Gplay Enterprise APK
if: ${{ matrix.variant == 'debug' }}
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew :app:assembleGplayDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Upload debug Enterprise APKs
if: ${{ matrix.variant == 'debug' }}
uses: actions/upload-artifact@v4
with:
name: elementx-enterprise-debug
path: |
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
- name: Compile release sources
if: ${{ matrix.variant == 'release' }}
run: ./gradlew compileReleaseSources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Compile nightly sources
if: ${{ matrix.variant == 'nightly' }}
run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES

View File

@@ -8,6 +8,13 @@ jobs:
name: Danger main check
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger

View File

@@ -0,0 +1,57 @@
name: Build and release Enterprise nightly application
on:
workflow_dispatch:
schedule:
# Every nights at 4
- cron: "0 4 * * *"
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseG1GC
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true
jobs:
nightly:
name: Build and publish Enterprise nightly bundle to Firebase
runs-on: ubuntu-latest
if: ${{ github.repository == 'element-hq/element-x-android' }}
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Install towncrier
run: |
python3 -m pip install towncrier
- name: Prepare changelog file
run: |
mv towncrier.toml towncrier.toml.bak
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
rm towncrier.toml.bak
yes n | towncrier build --version nightly
- name: Build and upload Nightly application
run: |
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}
FIREBASE_TOKEN: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_FIREBASE_TOKEN }}
- name: Additionally upload Nightly APK to browserstack for testing
continue-on-error: true # don't block anything by this upload failing (for now)
run: |
curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" -F "custom_id=element-x-android-nightly"
env:
BROWSERSTACK_USERNAME: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_USERNAME }}
BROWSERSTACK_PASSWORD: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_ACCESS_KEY }}

View File

@@ -18,6 +18,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Run code quality check suite
run: ./tools/check/check_code_quality.sh
@@ -68,6 +75,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@@ -100,6 +114,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@@ -136,6 +157,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@@ -168,6 +196,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
@@ -200,6 +235,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:

View File

@@ -39,6 +39,40 @@ jobs:
path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
enterprise:
name: Create App Bundle Enterprise
runs-on: ubuntu-latest
concurrency:
group: ${{ format('build-release-main-gplay-{0}', github.sha) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
run: git submodule update --init --recursive
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
- name: Create Enterprise app bundle
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload bundle as artifact
uses: actions/upload-artifact@v4
with:
name: elementx-enterprise-app-gplay-bundle-unsigned
path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
fdroid:
name: Create APKs (FDroid)
runs-on: ubuntu-latest

View File

@@ -38,6 +38,13 @@ jobs:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Add SSH private keys for submodule repositories
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
- name: Clone submodules
if: github.repository == 'element-hq/element-x-android'
run: git submodule update --init --recursive
- name: ☕️ Use JDK 17
uses: actions/setup-java@v4
with:

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "enterprise"]
path = enterprise
url = git@github.com:element-hq/element-android-enterprise.git

6
.idea/copyright/Element_FOSS.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) &amp;#36;today.year New Vector Ltd&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; https://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="Element FOSS" />
</copyright>
</component>

6
.idea/copyright/Enterprise.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="© &amp;#36;today.year New Vector Limited, Element Software SARL, Element Software Inc.,&#10;and Element Software GmbH (the &quot;Element Group&quot;) only make this file available&#10;under a proprietary license model.&#10;&#10;Without a proprietary license with us, you cannot use this file. The terms of&#10;the proprietary license agreement between you and any member of the Element Group&#10;shall always apply to your use of this file. Unauthorised use, copying, distribution,&#10;or modification of this file, via any medium, is strictly prohibited.&#10;&#10;For details about the licensing terms, you must either visit our website or contact&#10;a member of our sales team." />
<option name="myName" value="Enterprise" />
</copyright>
</component>

View File

@@ -1,6 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) &amp;#36;today.year New Vector Ltd&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="NewVector" />
</copyright>
</component>

View File

@@ -1,3 +1,7 @@
<component name="CopyrightManager">
<settings default="NewVector" />
<settings default="Element FOSS">
<module2copyright>
<element module="Enterprise" copyright="Enterprise" />
</module2copyright>
</settings>
</component>

3
.idea/scopes/Enterprise.xml generated Normal file
View File

@@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Enterprise" pattern="file://*||file[ElementX.enterprise*]:*//*" />
</component>

View File

@@ -17,6 +17,7 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
import extension.allEnterpriseImpl
import extension.allFeaturesImpl
import extension.allLibrariesImpl
import extension.allServicesImpl
@@ -46,7 +47,11 @@ android {
namespace = "io.element.android.x"
defaultConfig {
applicationId = "io.element.android.x"
applicationId = if (isEnterpriseBuild) {
"io.element.enterprise"
} else {
"io.element.android.x"
}
targetSdk = Versions.targetSdk
versionCode = Versions.versionCode
versionName = Versions.versionName
@@ -99,15 +104,22 @@ android {
}
}
val baseAppName = if (isEnterpriseBuild) {
"Element Enterprise"
} else {
"Element X"
}
logger.warnInBox("Building $baseAppName")
buildTypes {
getByName("debug") {
resValue("string", "app_name", "Element X dbg")
resValue("string", "app_name", "$baseAppName dbg")
applicationIdSuffix = ".debug"
signingConfig = signingConfigs.getByName("debug")
}
getByName("release") {
resValue("string", "app_name", "Element X")
resValue("string", "app_name", baseAppName)
signingConfig = signingConfigs.getByName("debug")
postprocessing {
@@ -124,7 +136,7 @@ android {
initWith(release)
applicationIdSuffix = ".nightly"
versionNameSuffix = "-nightly"
resValue("string", "app_name", "Element X nightly")
resValue("string", "app_name", "$baseAppName nightly")
matchingFallbacks += listOf("release")
signingConfig = signingConfigs.getByName("nightly")
@@ -220,6 +232,9 @@ knit {
dependencies {
allLibrariesImpl()
allServicesImpl()
if (isEnterpriseBuild) {
allEnterpriseImpl(rootDir, logger)
}
allFeaturesImpl(rootDir, logger)
implementation(projects.features.migration.api)
implementation(projects.anvilannotations)

View File

@@ -24,6 +24,7 @@ import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.appconfig.ApplicationConfig
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider
import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
@@ -77,13 +78,18 @@ object AppModule {
@Provides
@SingleIn(AppScope::class)
fun providesBuildMeta(@ApplicationContext context: Context, buildType: BuildType) = BuildMeta(
fun providesBuildMeta(
@ApplicationContext context: Context,
buildType: BuildType,
enterpriseService: EnterpriseService,
) = BuildMeta(
isDebuggable = BuildConfig.DEBUG,
buildType = buildType,
applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name),
productionApplicationName = ApplicationConfig.PRODUCTION_APPLICATION_NAME,
desktopApplicationName = ApplicationConfig.DESKTOP_APPLICATION_NAME,
applicationId = BuildConfig.APPLICATION_ID,
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
lowPrivacyLoggingEnabled = false,
versionName = BuildConfig.VERSION_NAME,

1
enterprise Submodule

Submodule enterprise added at ceb65e32d9

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.features.enterprise.api"
}
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.enterprise.api
import io.element.android.libraries.matrix.api.core.SessionId
interface EnterpriseService {
val isEnterpriseBuild: Boolean
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-library")
alias(libs.plugins.anvil)
}
android {
namespace = "io.element.android.features.enterprise.impl"
}
dependencies {
implementation(projects.anvilannotations)
api(projects.features.enterprise.api)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
testImplementation(libs.coroutines.test)
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
testImplementation(projects.libraries.matrix.test)
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.enterprise.impl
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.core.SessionId
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultEnterpriseService @Inject constructor() : EnterpriseService {
override val isEnterpriseBuild = false
override suspend fun isEnterpriseUser(sessionId: SessionId) = false
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.enterprise.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.A_SESSION_ID
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultEnterpriseServiceTest {
@Test
fun `isEnterpriseBuild is false`() {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.isEnterpriseBuild).isFalse()
}
@Test
fun `isEnterpriseUser always return false`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.isEnterpriseUser(A_SESSION_ID)).isFalse()
}
}

View File

@@ -169,6 +169,9 @@ class DefaultBugReporter @Inject constructor(
currentTracingFilter?.let {
builder.addFormDataPart("tracing_filter", it)
}
if (buildMeta.isEnterpriseBuild) {
builder.addFormDataPart("label", "Enterprise")
}
// add the gzipped files, don't cancel the whole upload if only some file failed to upload
var totalUploadedSize = 0L
var uploadedSomeLogs = false

View File

@@ -26,16 +26,12 @@ import android.os.Build
import android.provider.Settings
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.RequiresApi
import androidx.core.content.pm.PackageInfoCompat
import io.element.android.libraries.androidutils.R
import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat
import io.element.android.libraries.core.mimetype.MimeTypes
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
fun supportNotificationChannels() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
/**
* Return the application label of the provided package. If not found, the package is returned.
*/

View File

@@ -23,6 +23,7 @@ data class BuildMeta(
val productionApplicationName: String,
val desktopApplicationName: String,
val applicationId: String,
val isEnterpriseBuild: Boolean,
val lowPrivacyLoggingEnabled: Boolean,
val versionName: String,
val versionCode: Long,

View File

@@ -26,6 +26,7 @@ fun aBuildMeta(
productionApplicationName: String = applicationName,
desktopApplicationName: String = applicationName,
applicationId: String = "",
isEnterpriseBuild: Boolean = false,
lowPrivacyLoggingEnabled: Boolean = true,
versionName: String = "",
versionCode: Long = 0,
@@ -40,6 +41,7 @@ fun aBuildMeta(
productionApplicationName = productionApplicationName,
desktopApplicationName = desktopApplicationName,
applicationId = applicationId,
isEnterpriseBuild = isEnterpriseBuild,
lowPrivacyLoggingEnabled = lowPrivacyLoggingEnabled,
versionName = versionName,
versionCode = versionCode,

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File
/**
* Are we building with the enterprise sources?
*/
val isEnterpriseBuild = File("enterprise/README.md").exists()

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.gradle.api.logging.Logger
import kotlin.math.max
fun Logger.warnInBox(
text: String,
minBoxWidth: Int = 80,
padding: Int = 4,
) {
val textLength = text.length
val boxWidth = max(textLength + 2, minBoxWidth)
val textPadding = max((boxWidth - textLength) / 2, 1)
warn(
buildString {
append(" ".repeat(padding))
append("")
append("".repeat(boxWidth))
append("")
}
)
warn(
buildString {
append(" ".repeat(padding))
append("")
append(" ".repeat(textPadding))
append(text)
append(" ".repeat(textPadding))
if (textLength % 2 == 1 && boxWidth == minBoxWidth) append(" ")
append("")
}
)
warn(
buildString {
append(" ".repeat(padding))
append("")
append("".repeat(boxWidth))
append("")
}
)
}

View File

@@ -64,7 +64,7 @@ object Versions {
const val compileSdk = 34
const val targetSdk = 33
// When updating the `minSdk`, make sure to update the value of `minSdkVersion` in the file `tools/release/release.sh`
const val minSdk = 24
val minSdk = if (isEnterpriseBuild) 26 else 24
val javaCompileVersion = JavaVersion.VERSION_17
val javaLanguageVersion: JavaLanguageVersion = JavaLanguageVersion.of(11)
}

View File

@@ -18,6 +18,7 @@ package extension
import Versions
import com.android.build.api.dsl.CommonExtension
import isEnterpriseBuild
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.JavaVersion
import org.gradle.api.Project
@@ -46,6 +47,11 @@ fun CommonExtension<*, *, *, *, *, *>.androidConfig(project: Project) {
lint {
lintConfig = File("${project.rootDir}/tools/lint/lint.xml")
if (isEnterpriseBuild) {
// Disable check on ObsoleteSdkInt for Enterprise builds
// since the min sdk is higher for Enterprise builds
disable.add("ObsoleteSdkInt")
}
checkDependencies = false
abortOnError = true
ignoreTestFixturesSources = true

View File

@@ -130,6 +130,11 @@ fun DependencyHandlerScope.allServicesImpl() {
implementation(project(":services:toolbox:impl"))
}
fun DependencyHandlerScope.allEnterpriseImpl(rootDir: File, logger: Logger) {
val enterpriseDir = File(rootDir, "enterprise")
addImplementationProjects(enterpriseDir, ":enterprise", "impl", logger)
}
fun DependencyHandlerScope.allFeaturesApi(rootDir: File, logger: Logger) {
val featuresDir = File(rootDir, "features")
addImplementationProjects(featuresDir, ":features", "api", logger)

View File

@@ -36,6 +36,7 @@ object Singleton {
productionApplicationName = "EAX-Minimal",
desktopApplicationName = "EAX-Minimal-Desktop",
applicationId = "io.element.android.samples.minimal",
isEnterpriseBuild = false,
lowPrivacyLoggingEnabled = false,
versionName = "0.1.0",
versionCode = 1,

View File

@@ -87,6 +87,7 @@ fun includeProjects(directory: File, path: String, maxDepth: Int = 1) {
}
}
includeProjects(File(rootDir, "enterprise"), ":enterprise", maxDepth = 2)
includeProjects(File(rootDir, "features"), ":features")
includeProjects(File(rootDir, "libraries"), ":libraries")
includeProjects(File(rootDir, "services"), ":services")

View File

@@ -112,6 +112,7 @@ class KonsistClassNameTest {
"DBov",
"Default",
"DataStore",
"Enterprise",
"FileExtensionExtractor",
"KeyStore",
"Matrix",

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.tests.konsist
import com.lemonappdev.konsist.api.Konsist
import com.lemonappdev.konsist.api.verify.assertTrue
import org.junit.Test
class KonsistLicenseTest {
private val publicLicense = """
/\*
(?:.*\n)* \* Copyright \(c\) 20\d\d New Vector Ltd
(?:.*\n)* \*
\* Licensed under the Apache License, Version 2\.0 \(the "License"\);
\* you may not use this file except in compliance with the License\.
\* You may obtain a copy of the License at
\*
\* {5}https?://www\.apache\.org/licenses/LICENSE-2\.0
\*
\* Unless required by applicable law or agreed to in writing, software
\* distributed under the License is distributed on an "AS IS" BASIS,
\* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.
\* See the License for the specific language governing permissions and
\* limitations under the License\.
\*/
""".trimIndent().toRegex()
private val enterpriseLicense = """
/\*
\* © 20\d\d New Vector Limited, Element Software SARL, Element Software Inc\.,
\* and Element Software GmbH \(the "Element Group"\) only make this file available
\* under a proprietary license model\.
\*
\* Without a proprietary license with us, you cannot use this file\. The terms of
\* the proprietary license agreement between you and any member of the Element Group
\* shall always apply to your use of this file\. Unauthorised use, copying, distribution,
\* or modification of this file, via any medium, is strictly prohibited\.
\*
\* For details about the licensing terms, you must either visit our website or contact
\* a member of our sales team\.
\*/
""".trimIndent().toRegex()
@Test
fun `assert that FOSS files have the correct license header`() {
Konsist
.scopeFromProject()
.files
.filter {
it.path.contains("/enterprise/features").not() &&
it.nameWithExtension != "locales.kt" &&
it.name.startsWith("Template ").not()
}
.assertTrue {
publicLicense.containsMatchIn(it.text)
}
}
@Test
fun `assert that Enterprise files have the correct license header`() {
Konsist
.scopeFromProject()
.files
.filter {
it.path.contains("/enterprise/features")
}
.assertTrue {
enterpriseLicense.containsMatchIn(it.text)
}
}
}

View File

@@ -197,9 +197,7 @@ performance:
# Note: all rules for `comments` are disabled by default, but I put them here to be aware of their existence
comments:
AbsentOrWrongFileLicense:
active: true
licenseTemplateFile: 'license.template'
licenseTemplateIsRegex: true
active: false
CommentOverPrivateFunction:
active: false
CommentOverPrivateProperty:

View File

@@ -1,15 +0,0 @@
\/\*
(?:.*\n)* \* Copyright \(c\) 20\d\d New Vector Ltd
(?:.*\n)* \*
\* Licensed under the Apache License, Version 2\.0 \(the "License"\);
\* you may not use this file except in compliance with the License\.
\* You may obtain a copy of the License at
\*
\* http(?:s)?:\/\/www\.apache\.org\/licenses\/LICENSE-2\.0
\*
\* Unless required by applicable law or agreed to in writing, software
\* distributed under the License is distributed on an "AS IS" BASIS,
\* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.
\* See the License for the specific language governing permissions and
\* limitations under the License\.
\*\/