Skip to content

Commit

Permalink
Merge pull request #1946 from instructure/release/parent-3.7.0-45
Browse files Browse the repository at this point in the history
Release Parent 3.7.0 (45)
  • Loading branch information
hermannakos authored Apr 25, 2023
2 parents 6de6de3 + dc62abd commit 2dee9b8
Show file tree
Hide file tree
Showing 791 changed files with 12,305 additions and 7,809 deletions.
10 changes: 5 additions & 5 deletions apps/flutter_parent/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ if (keystorePropertiesFile.exists()) {
}

android {
compileSdkVersion Versions.COMPILE_SDK
buildToolsVersion Versions.BUILD_TOOLS
compileSdkVersion 31
buildToolsVersion "30.0.2"

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand All @@ -46,8 +46,8 @@ android {

defaultConfig {
applicationId "com.instructure.parentapp"
minSdkVersion Versions.MIN_SDK
targetSdkVersion Versions.TARGET_SDK
minSdkVersion 26
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -99,7 +99,7 @@ flutter {
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.KOTLIN}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30"

testImplementation 'junit:junit:4.12'

Expand Down
8 changes: 4 additions & 4 deletions apps/flutter_parent/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ buildscript {
}

dependencies {
classpath Plugins.ANDROID_GRADLE_TOOLS
classpath Plugins.FIREBASE_CRASHLYTICS
classpath Plugins.GOOGLE_SERVICES
classpath Plugins.KOTLIN
classpath "com.android.tools.build:gradle:4.1.0"
classpath "com.google.firebase:firebase-crashlytics-gradle:2.1.0"
classpath "com.google.gms:google-services:4.3.10"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30"
}
}

Expand Down
1 change: 0 additions & 1 deletion apps/flutter_parent/android/buildSrc

This file was deleted.

1 change: 1 addition & 0 deletions apps/flutter_parent/android/buildSrc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
33 changes: 33 additions & 0 deletions apps/flutter_parent/android/buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 - present Instructure, Inc.
*
* 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.
*
*/
repositories {
google()
mavenCentral()
}

val agpVersion = "4.1.0"

dependencies {
implementation("com.android.tools.build:gradle:$agpVersion")
implementation("com.android.tools.build:gradle-api:$agpVersion")
implementation("org.javassist:javassist:3.24.1-GA")
implementation("com.google.code.gson:gson:2.8.8")
}

plugins {
`kotlin-dsl`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import org.gradle.BuildListener
import org.gradle.BuildResult
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.initialization.Settings
import org.gradle.api.invocation.Gradle
import org.gradle.api.tasks.TaskState

import java.util.concurrent.TimeUnit

// A listener that will allow us to monitor task timings and, ultimately, APK size
class TimingsListener implements TaskExecutionListener, BuildListener {
private long startTime
private timings = [:]
private Project refProject
private long buildStartTime

TimingsListener(Project _refProject) {
refProject = _refProject
buildStartTime = System.nanoTime()
}


@Override
void beforeExecute(Task task) {
startTime = System.nanoTime()
}

@Override
void afterExecute(Task task, TaskState taskState) {
def ms = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS)
timings.put(task.name, ms)
}

@Override
void buildFinished(BuildResult result) {

// Compute build time
def totalBuildTimeMs = TimeUnit.MILLISECONDS.convert(System.nanoTime() - buildStartTime, TimeUnit.NANOSECONDS)

// Grab the Splunk-mobile token from Bitrise
def splunkToken = System.getenv("SPLUNK_MOBILE_TOKEN")

// Let's abort early if (1) the build failed, or (2) we're not on bitrise
if(result.failure != null) {
println("Build report logic aborting due to failed build")
return
}

if(splunkToken == null || splunkToken.isEmpty()) {
println("Build report logic aborting because we're not on bitrise")
return
}

// Grab the gradle tasks passed on the command line for the job
def startTaskNames = result.gradle.startParameter.taskNames.join(",")

// Sort the timings in descending time order, compute our top 10
timings = timings.sort { -it.value }
def top10 = timings.take(10).entrySet()

// Figure out our build type
def buildType = "debug"
if(startTaskNames.contains("Release")) {
buildType = "release"
}

// Figure out our build flavor
def buildFlavor = "qa"
if(startTaskNames.contains("Dev")) {
buildFlavor = "dev"
}
else if(startTaskNames.contains("Prod")) {
buildFlavor = "prod"
}

// Grab some data from the environment
def bitriseWorkflow = System.getenv("BITRISE_TRIGGERED_WORKFLOW_ID")
def bitriseApp = System.getenv("BITRISE_APP_TITLE")
def bitriseBranch = System.getenv("BITRISE_GIT_BRANCH")
def bitriseBuildNumber = System.getenv("BITRISE_BUILD_NUMBER")

// Determine our project name.
// It's not as simple as looking at refProject.name; since we add this listener via the
// student project, refProject.name will always be "student". Glean our actual project name
// via the bitrise app name.
def projectName = ""
if(bitriseApp.contains("Student")) {
projectName = "student"
}
else if(bitriseApp.contains("Teacher")) {
projectName = "teacher"
}
else if(bitriseApp.toLowerCase().contains("parent")) {
projectName = "parent"
}
else {
projectName = "unknown" // Punt
}
println("projectName = $projectName")

// Locate the apk
def file = null
def fileSizeInMB = 0.0
if(projectName!="parent") {
// We don't necessarily want refProject.buildDir, since it will always be the student buildDir
def buildDir = refProject.buildDir.toString().replace("student",projectName)
file = new File("$buildDir/outputs/apk/$buildFlavor/$buildType/$projectName-$buildFlavor-${buildType}.apk")
fileSizeInMB = file.length() == 0 ? 0 : (file.length() / (1024.0 * 1024.0)).round(3)
}
else {
// Different location logic for flutter parent apk file
def buildDir = refProject.buildDir.toString()
file = new File("$buildDir/outputs/apk/$buildType/app-${buildType}.apk")
fileSizeInMB = file.length() == 0 ? 0 : (file.length() / (1024.0 * 1024.0))
fileSizeInMB = (fileSizeInMB * 1000.0).toInteger() / 1000.0 // Round to three decimal places
}
println("file name=${file.path} length=${file.length()}")


// Construct the JSON payload for our "buildComplete" event
def payloadBuilder = new groovy.json.JsonBuilder()
payloadBuilder buildTime: totalBuildTimeMs,
gradleTasks: startTaskNames,
apkFilePath: file.path,
apkSize: fileSizeInMB,
bitriseWorkflow: bitriseWorkflow,
bitriseApp: bitriseApp,
bitriseBranch: bitriseBranch,
bitriseBuildNumber: bitriseBuildNumber,
topTasks: top10

// Create the event payload. Change key/value in top 10 tasks to task/ms.
def payload = payloadBuilder.toString().replaceAll("\"key\"", "\"task\"").replaceAll("\"value\"", "\"ms\"")

println("event payload: $payload")

// Let's issue our curl command to emit our data
refProject.exec {
executable "curl"
args "-k", "https://http-inputs-inst.splunkcloud.com:443/services/collector", "-H", "Authorization: Splunk $splunkToken",
"-d", "{\"sourcetype\" : \"mobile-android-build\", \"event\" : $payload}"
}

}

@Override
void buildStarted(Gradle gradle) {}

@Override
void projectsEvaluated(Gradle gradle) {}

@Override
void projectsLoaded(Gradle gradle) {}

@Override
void settingsEvaluated(Settings settings) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@file:Suppress("unused")

import org.gradle.api.Project
import org.gradle.kotlin.dsl.extra
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.security.MessageDigest
import java.util.*

object PrivateData {

private const val PRINT_PAD_SIZE = 60

@JvmStatic
@JvmOverloads
fun merge(project: Project, dataDirName: String = "") {

val baseDir = resolvePrivateDataDir(project.projectDir)
val dataDir = File(baseDir, dataDirName).canonicalFile

println("")
println("============= MERGE PRIVATE FILES: ${dataDirName.toUpperCase()} ".padEnd(PRINT_PAD_SIZE, '='))

/* Confirm dir exists */
if (!dataDir.exists() || !dataDir.isDirectory) {
failMerge("Unable to find private data source directory at ${dataDir.canonicalPath}. Please add private project files.")
}

/* Confirm files list exists */
val fileList = File(dataDir, "files.list")
if (!fileList.exists()) {
failMerge("Unable to find file list at ${fileList.canonicalPath}. Ensure private project files have been added.")
}

/* Grab list of files */
val props = Properties()
FileInputStream(fileList).use { props.load(it) }

/* Copy files and properties */
props.stringPropertyNames().forEach { srcName ->
val src = File(dataDir, srcName)
if (!src.exists() || !src.isFile) {
failMerge("Could not find source file at ${src.canonicalPath}")
}

/* Merge private.properties */
if (srcName == "private.properties") {
println("Merging private.properties:")
val privateProps = Properties()
FileInputStream(src).use { privateProps.load(it) }
privateProps.stringPropertyNames().forEach { propName ->
println(" $propName")
var value = privateProps.getProperty(propName)
if (value.startsWith("file:")) {
val fileName = value.replaceFirst("file:", "")
val file = File(dataDir, fileName)
if (!file.exists()) {
failMerge("Could not find source file ${file.canonicalPath} for '$propName' specified in private.properties")
}
value = file.readText()
}
val escaped = value.replace("\"", "\\\"").replace("[\n\r]", "")
project.extra.set(propName, escaped)
}
} else {
val dstPath = props.getProperty(srcName)
val dst = File(project.projectDir, dstPath)

/* Make parent dir if necessary */
val dstParent = dst.parentFile
if (!dstParent.exists()) dstParent.mkdirs()

if (!dst.exists()) {
println("Copying ${src.canonicalPath} to $dst")
src.copyTo(dst, true)
} else if (!src.md5.contentEquals(dst.md5)) {
println("${dst.canonicalPath} differs from $src and will be replaced")
src.copyTo(dst, true)
} else {
println("${dst.canonicalPath} exists and is UP-TO-DATE")
}
}
}

println("".padEnd(PRINT_PAD_SIZE, '='))
println("")
}

private fun failMerge(message: String): Nothing = throw Exception("Failed to merge private data. $message")

private val File.md5 get() = MessageDigest.getInstance("MD5").digest(readBytes())

private tailrec fun resolvePrivateDataDir(srcDir: File?): File {
if (srcDir == null) throw FileNotFoundException("Could not locate private data directory!")
return srcDir.resolve("private-data").takeIf { it.exists() && it.isDirectory }
?: resolvePrivateDataDir(srcDir.parentFile)
}
}
34 changes: 34 additions & 0 deletions apps/flutter_parent/assets/svg/ic_instructure_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2dee9b8

Please sign in to comment.