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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ matrix:
- openssl aes-256-cbc -K $encrypted_1701aaafcc71_key -iv $encrypted_1701aaafcc71_iv
-in .travis/android/release.zip.enc -out release.zip -d
- "./.travis/android/before_install.bash"
script: ".travis/android/run.bash"
script:
- ".travis/android/run.bash"
- ".travis/android/release_to_alpha.bash"
# - language: objective-c
# os: osx
# osx_image: xcode10.1
Expand Down
14 changes: 14 additions & 0 deletions .travis/android/promote_to_production.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

set -eu

die() {
echo "$*" 1>&2
exit 1
}

source "$(dirname $0)/../bash.source"

source .release/bash.source

./gradlew promoteProduction -PeditId="$1"
Binary file modified .travis/android/release.zip.enc
Binary file not shown.
22 changes: 22 additions & 0 deletions .travis/android/release_to_alpha.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

set -eu

if [[ -z "${TRAVIS_TAG:-}" ]]; then
exit 0
fi

die() {
echo "$*" 1>&2
exit 1
}

source "$(dirname $0)/../bash.source"

source .release/bash.source

if [[ ! -d ".transart" ]]; then
transart -f .travis/android/to_github.transart.yml download
fi

./gradlew publishAlpha
46 changes: 46 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
import dependencies.Dep
import dependencies.Packages
import publish.DistributionTrack
import publish.EditStatus
import publish.PromoteApk
import publish.UploadApk

apply from: file('gradle/dependencyGraph.gradle')

Expand Down Expand Up @@ -190,3 +195,44 @@ task dependencyReport {
file << "}\n"
}
}

task publishAlpha {
doLast {
def uploadApk = new UploadApk(logger)

def apkFile = new File(System.getenv("UNIVERSAL_APK_PATH"))
// FIXME more flexible
def mappingFile = new File(rootProject.projectDir, ".transart/mapping.txt")

uploadApk.execute(
Packages.name,
rootProject.file(".release/service-account.json"),
apkFile,
mappingFile,
DistributionTrack.Alpha.INSTANCE,
"New Alpha Release",
EditStatus.Completed.INSTANCE,
[
"en-US": rootProject.file("publish/release-notes/en-US/default.txt"),
"ja-JP": rootProject.file("publish/release-notes/ja-JP/default.txt")
]
)
}
}

task promoteProduction {
doLast {
def promoteApk = new PromoteApk(logger)
def editId = project.property("editId")

if (!editId) {
throw new GradleScriptException("editId must be privided")
}

promoteApk.execute(
Packages.name,
rootProject.file(".release/service-account.json"),
editId
)
}
}
20 changes: 20 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("com.google.apis:google-api-services-androidpublisher:v3-rev46-1.25.0")
classpath("com.google.api-client:google-api-client:1.28.0")
}
}

plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}

dependencies {
implementation("com.google.guava:guava:26.0-jre")
implementation("com.google.apis:google-api-services-androidpublisher:v3-rev46-1.25.0") {
exclude(group = "com.google.guava", module = "guava")
}
implementation("com.google.api-client:google-api-client:1.28.0") {
exclude(group = "com.google.guava", module = "guava")
}
}
6 changes: 6 additions & 0 deletions buildSrc/src/main/java/dependencies/Packages.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dependencies

object Packages {
const val name = "io.github.droidkaigi.confsched2019"
const val debugNameSuffix = ".debug"
}
21 changes: 21 additions & 0 deletions buildSrc/src/main/java/publish/DistributionTrack.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package publish

sealed class DistributionTrack {
abstract val name: String

object Internal : DistributionTrack() {
override val name: String = "internal"
}

object Alpha : DistributionTrack() {
override val name: String = "alpha"
}

object Beta : DistributionTrack() {
override val name: String = "beta"
}

object Production : DistributionTrack() {
override val name: String = "production"
}
}
21 changes: 21 additions & 0 deletions buildSrc/src/main/java/publish/EditStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package publish

sealed class EditStatus {
abstract val status: String

object InProgress : EditStatus() {
override val status: String = "inProgress"
}

object Draft : EditStatus() {
override val status: String = "draft"
}

object Completed : EditStatus() {
override val status: String = "completed"
}

object Halted : EditStatus() {
override val status: String = "halted"
}
}
49 changes: 49 additions & 0 deletions buildSrc/src/main/java/publish/Extension.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package publish

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport
import com.google.api.client.json.jackson2.JacksonFactory
import com.google.api.services.androidpublisher.AndroidPublisher
import com.google.api.services.androidpublisher.AndroidPublisherScopes
import java.io.File

fun androidPublisher(packageName: String, serviceAccountJson: File): AndroidPublisher {
val credential = serviceAccountJson.asCredential()

return AndroidPublisher.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
JacksonFactory.getDefaultInstance(),
credential
)
.setApplicationName(packageName)
.build()
}

fun File.asCredential(): GoogleCredential {
if (!exists()) {
error("$this does not exist")
}

return inputStream().use { credentialStream ->
GoogleCredential.fromStream(credentialStream)
.createScoped(
listOf(AndroidPublisherScopes.ANDROIDPUBLISHER)
)
}
}

fun AndroidPublisher.Edits.runInTransaction(
packageName: String,
editId: String = insert(packageName, null).execute().id,
action: (editId: String) -> Unit = {},
errorHandler: (error: Throwable) -> Unit = {}
) {
try {
action(editId)

commit(packageName, editId).execute()
} catch (th: Throwable) {
errorHandler(th)
}
}

40 changes: 40 additions & 0 deletions buildSrc/src/main/java/publish/PromoteApk.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package publish

import org.slf4j.Logger
import java.io.File

class PromoteApk(
private val logger: Logger
) {
fun execute(
packageName: String,
serviceAccountJson: File,
editId: String
) {
if (packageName.isEmpty()) {
error("packageName must not be empty")
}

val editsService = androidPublisher(packageName, serviceAccountJson).edits()

editsService.runInTransaction(packageName, editId, action = { editId ->
logger.debug("The current edit transaction id is $editId")

// Use `alpha`
val existingTrack =
editsService.tracks().get(packageName, editId, DistributionTrack.Alpha.name)
.execute()

// Use `production`
val updatedTrack =
editsService.tracks()
.update(packageName, editId, DistributionTrack.Production.name, existingTrack)
.execute()

logger.info("Update ${DistributionTrack.Alpha.name} to ${updatedTrack.track}")
}) { th ->
logger.error("while edit transaction", th)
throw th
}
}
}
99 changes: 99 additions & 0 deletions buildSrc/src/main/java/publish/UploadApk.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package publish

import com.google.api.client.http.FileContent
import com.google.api.services.androidpublisher.model.LocalizedText
import com.google.api.services.androidpublisher.model.Track
import com.google.api.services.androidpublisher.model.TrackRelease
import org.slf4j.Logger
import java.io.File

class UploadApk(
private val logger: Logger
) {
fun execute(
packageName: String,
serviceAccountJson: File,
apkFile: File,
mappingFile: File,
track: DistributionTrack,
releaseName: String,
editStatus: EditStatus,
releaseNoteMap: Map<String, File>
) {
if (packageName.isEmpty()) {
error("packageName must not be empty")
}

val notFoundReleaseNotes = releaseNoteMap.filterValues { !it.exists() }

if (notFoundReleaseNotes.isNotEmpty()) {
val message = releaseNoteMap.filterValues { !it.exists() }
.map { (lang, noteFile) ->
"$lang at $noteFile "
}
.joinToString(", ")

error("ReleaseNote not found: $message")
}

if (!apkFile.exists()) {
error("apk file not found: $apkFile")
}

if (!mappingFile.exists()) {
error("mapping file not found: $mappingFile")
}

val editsService = androidPublisher(packageName, serviceAccountJson).edits()

editsService.runInTransaction(packageName, action = { editId ->
logger.warn("New edit transaction id is $editId")

val apkContent = apkFile.asApkContent()

logger.warn("apkContent has been prepared")

val apkResult =
editsService.apks().upload(packageName, editId, apkContent).execute()
val versionCode = apkResult.versionCode.toLong()

logger.warn("$packageName (${versionCode}) has been uploaded")

val releaseContent = TrackRelease().apply {
name = releaseName
versionCodes = listOf(versionCode)
status = editStatus.status
releaseNotes = releaseNoteMap.map { (lang, noteFile) ->
LocalizedText().setLanguage(lang).setText(noteFile.readText())
}
}

val updatedTrack = editsService.tracks().update(
packageName,
editId,
track.name,
Track().setReleases(listOf(releaseContent))
).execute()


val mapping = FileContent("application/octet-stream", mappingFile)
editsService.deobfuscationfiles()
.upload(packageName, editId, versionCode.toInt(), "proguard", mapping)
.execute()

logger.warn("Update ${updatedTrack.track} and the status has been ${editStatus.status}")
logger.warn("New edit id is $editId")
}) { th ->
logger.error("while edit transaction", th)
throw th
}
}

private fun File.asApkContent(): FileContent {
if (!exists()) {
error("$this does not exist")
}

return FileContent("application/vnd.android.package-archive", this)
}
}
Loading