574 lines
17 KiB
Kotlin
574 lines
17 KiB
Kotlin
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
|
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
|
|
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
|
|
import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.slackConnection
|
|
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.notifications
|
|
|
|
/*
|
|
The settings script is an entry point for defining a TeamCity
|
|
project hierarchy. The script should contain a single call to the
|
|
project() function with a Project instance or an init function as
|
|
an argument.
|
|
|
|
VcsRoots, BuildTypes, Templates, and subprojects can be
|
|
registered inside the project using the vcsRoot(), buildType(),
|
|
template(), and subProject() methods respectively.
|
|
|
|
To debug settings scripts in command-line, run the
|
|
|
|
mvnDebug org.jetbrains.teamcity:teamcity-configs-maven-plugin:generate
|
|
|
|
command and attach your debugger to the port 8000.
|
|
|
|
To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
|
|
-> Tool Windows -> Maven Projects), find the generate task node
|
|
(Plugins -> teamcity-configs -> teamcity-configs:generate), the
|
|
'Debug' option is available in the context menu for the task.
|
|
*/
|
|
|
|
version = "2020.2"
|
|
|
|
project {
|
|
vcsRoot(GitProjectRepo)
|
|
|
|
cleanup {
|
|
keepRule {
|
|
id = "KEEP_RULE_1"
|
|
keepAtLeast = days(3)
|
|
dataToKeep = everything()
|
|
applyPerEachBranch = true
|
|
preserveArtifactsDependencies = true
|
|
}
|
|
}
|
|
|
|
features {
|
|
slackConnection {
|
|
id = "PROJECT_EXT_2"
|
|
displayName = "Slack"
|
|
botToken = "zxxf1ef05c471abaea287f16830919d229f61360973870b6e853ace38bf62e5ec066b2bdef118e22d099ad99fe1343aad4a9f24ef83589597df775d03cbe80d301b"
|
|
clientId = "141599046048.1771998951381"
|
|
clientSecret = "zxx87b200290c3fc5ac692d3612fdb1ab75faab4e67de5dfbd2e779f4ac295144e0775d03cbe80d301b"
|
|
}
|
|
}
|
|
|
|
sequence {
|
|
parallel {
|
|
//Android
|
|
build(BuildAndroid)
|
|
build(UploadArtifactToSlack("Build_Upload_Android", BuildAndroid))
|
|
|
|
//IOS
|
|
build(BuildIOS)
|
|
build(UploadArtifactToSlack("Build_Upload_IOS", BuildIOS))
|
|
}
|
|
}
|
|
}
|
|
|
|
object BuildAndroid : BuildAndroidType("", "prod/global_android", "+:*")
|
|
object BuildIOS : BuildIOSType("", "prod/global_ios", "+:*")
|
|
|
|
open class BuildAndroidType(proj : String, env : String, branch: String) :
|
|
BuildType({
|
|
name = "Build Android"
|
|
|
|
var artifact_rules : String = "*.apk\n*.aab"
|
|
artifactRules = artifact_rules
|
|
|
|
vcs {
|
|
root(GitProjectRepo)
|
|
branchFilter = branch
|
|
}
|
|
|
|
params {
|
|
checkbox("build.env.debug", "false", label = "Debug",
|
|
description = "Build developer version.", checked = "true")
|
|
param("build.env.buildName", "%system.teamcity.buildConfName%")
|
|
param("build.env.workDir", "%system.teamcity.build.workingDir%")
|
|
param("build.env.artifactRules", artifact_rules)
|
|
}
|
|
|
|
features {
|
|
notifications {
|
|
notifierSettings = slackNotifier {
|
|
connection = "PROJECT_EXT_2"
|
|
sendTo = "#rnd-builds"
|
|
messageFormat = verboseMessageFormat {
|
|
addBranch = true
|
|
addStatusText = true
|
|
maximumNumberOfChanges = 10
|
|
}
|
|
}
|
|
buildFailed = true
|
|
buildFinishedSuccessfully = true
|
|
}
|
|
}
|
|
|
|
|
|
var gamectl_environment = if("%build.env.debug%" == "true") env.replace("global", "dev") else env
|
|
|
|
steps {
|
|
script {
|
|
name = "Deps Update"
|
|
scriptContent = "./gamectl try_deps_update"
|
|
}
|
|
script {
|
|
name = "Clean"
|
|
scriptContent = "./gamectl clean"
|
|
}
|
|
script {
|
|
name = "Produce"
|
|
scriptContent = "./gamectl --env=" + gamectl_environment + " build_android"
|
|
}
|
|
}
|
|
|
|
requirements {
|
|
equals("teamcity.agent.name", "Default Agent")
|
|
}
|
|
}
|
|
)
|
|
{}
|
|
|
|
|
|
open class BuildIOSType(proj : String, env : String, branch : String) :
|
|
BuildType({
|
|
name = "Build IOS"
|
|
|
|
var artifact_rules : String = "*.ipa"
|
|
artifactRules = artifact_rules
|
|
|
|
vcs {
|
|
root(GitProjectRepo)
|
|
branchFilter = branch
|
|
}
|
|
|
|
params {
|
|
checkbox("build.env.debug", "false", label = "Debug",
|
|
description = "Build developer version.", checked = "true")
|
|
param("build.env.buildName", "%system.teamcity.buildConfName%")
|
|
param("build.env.workDir", "%system.teamcity.build.workingDir%")
|
|
param("build.env.artifactRules", artifact_rules)
|
|
}
|
|
|
|
features {
|
|
notifications {
|
|
notifierSettings = slackNotifier {
|
|
connection = "PROJECT_EXT_2"
|
|
sendTo = "#rnd-builds"
|
|
messageFormat = verboseMessageFormat {
|
|
addBranch = true
|
|
addStatusText = true
|
|
maximumNumberOfChanges = 10
|
|
}
|
|
}
|
|
buildFailed = true
|
|
buildFinishedSuccessfully = true
|
|
}
|
|
}
|
|
|
|
var gamectl_environment = if("%build.env.debug%" == "true") env.replace("global", "dev") else env
|
|
|
|
steps {
|
|
script {
|
|
name = "Deps Update"
|
|
scriptContent = "./gamectl try_deps_update"
|
|
}
|
|
script {
|
|
name = "Clean"
|
|
scriptContent = "./gamectl clean"
|
|
}
|
|
script {
|
|
name = "Produce"
|
|
scriptContent = "./gamectl --env=" + gamectl_environment + " build_ios"
|
|
}
|
|
}
|
|
|
|
requirements {
|
|
matches("teamcity.agent.name", "(Default Agent 2|Default Agent 3)")
|
|
}
|
|
})
|
|
{}
|
|
|
|
open class UploadArtifactToSlack(build_id : String, build_deps : BuildType) : BuildType({
|
|
id(build_id)
|
|
name = build_id.replace("_", " ")
|
|
|
|
vcs {
|
|
root(GitProjectRepo)
|
|
}
|
|
|
|
val project_name : String = "%system.teamcity.projectName%"
|
|
val deps_build_name : String = build_deps.depParamRefs["build.env.buildName"].ref
|
|
val deps_build_number : String = build_deps.depParamRefs.buildNumber.ref
|
|
val deps_build_directory : String = build_deps.depParamRefs["build.env.workDir"].ref
|
|
|
|
steps {
|
|
script {
|
|
name = "Upload"
|
|
scriptContent = """
|
|
#!/bin/bash
|
|
init_message="Artifacts For ${project_name} / ${deps_build_name} #${deps_build_number} %0A:tada:"
|
|
auth="Bearer xoxb-141599046048-1775293613715-4ipxfXXSdFZaPHuoTL3ms8TT"
|
|
main_thread=${'$'}(curl -d "text=${'$'}init_message" -d "channel=C01P5JB13SM" -H "Authorization:${'$'}auth" -X POST https://slack.com/api/chat.postMessage)\;
|
|
thread_id=${'$'}(echo ${'$'}main_thread | sed 's/.*"ts":"\([^"]*\)".*/\1/')\;
|
|
|
|
artifacts=${'$'}(find ${deps_build_directory} -maxdepth 1 \( -name "*.apk" -o -name "*.aab" \))\;
|
|
for item in ${'$'}artifacts\;
|
|
do
|
|
curl -F file=@${'$'}item -F channels=C01P5JB13SM -F thread_ts=${'$'}thread_id -H "Authorization:${'$'}auth" https://slack.com/api/files.upload
|
|
done
|
|
""".trimIndent()
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
artifacts(build_deps){
|
|
artifactRules = build_deps.depParamRefs["build.env.artifactRules"].ref
|
|
}
|
|
}
|
|
})
|
|
|
|
object PublishArifactToGoogle : BuildType({
|
|
name = "Publish Android"
|
|
|
|
vcs {
|
|
root(GitProjectRepo)
|
|
}
|
|
})
|
|
|
|
object PublishArifactToTestFlight : BuildType({
|
|
name = "Publish IOS"
|
|
|
|
vcs {
|
|
root(GitProjectRepo)
|
|
}
|
|
})
|
|
|
|
object GitProjectRepo : GitVcsRoot({
|
|
name = "git: http://git.bit5.ru/rnd/base_project.git"
|
|
url = "http://git.bit5.ru/rnd/base_project.git"
|
|
agentCleanPolicy = AgentCleanPolicy.NEVER
|
|
branch = "master"
|
|
branchSpec = "+:*"
|
|
authMethod = password {
|
|
userName = "game_ci"
|
|
password = "zxx47498c67380e2c74005e14d1ad544585"
|
|
}
|
|
})
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
typealias DependencySettings = SnapshotDependency.() -> Unit
|
|
|
|
abstract class Stage {
|
|
var dependencySettings: DependencySettings = {}
|
|
val dependencies = mutableListOf<Pair<Stage, DependencySettings>>()
|
|
}
|
|
|
|
class Single(val buildType: BuildType) : Stage()
|
|
|
|
class Parallel : Stage() {
|
|
val buildTypes = arrayListOf<BuildType>()
|
|
val sequences = arrayListOf<Sequence>()
|
|
}
|
|
|
|
class Sequence : Stage() {
|
|
val stages = arrayListOf<Stage>()
|
|
}
|
|
|
|
fun Parallel.build(bt: BuildType, block: BuildType.() -> Unit = {}): BuildType {
|
|
bt.apply(block)
|
|
buildTypes.add(bt)
|
|
return bt
|
|
}
|
|
|
|
fun Parallel.build(block: BuildType.() -> Unit): BuildType {
|
|
val bt = BuildType().apply(block)
|
|
buildTypes.add(bt)
|
|
return bt
|
|
}
|
|
|
|
fun Parallel.sequence(block: Sequence.() -> Unit): Sequence {
|
|
val sequence = Sequence().apply(block)
|
|
buildDependencies(sequence)
|
|
sequences.add(sequence)
|
|
return sequence
|
|
}
|
|
|
|
fun Sequence.sequence(block: Sequence.() -> Unit): Sequence {
|
|
val sequence = Sequence().apply(block)
|
|
buildDependencies(sequence)
|
|
stages.add(sequence)
|
|
return sequence
|
|
}
|
|
|
|
fun Sequence.parallel(block: Parallel.() -> Unit): Parallel {
|
|
val parallel = Parallel().apply(block)
|
|
stages.add(parallel)
|
|
return parallel
|
|
}
|
|
|
|
fun Sequence.build(bt: BuildType, block: BuildType.() -> Unit = {}): BuildType {
|
|
bt.apply(block)
|
|
stages.add(Single(bt))
|
|
return bt
|
|
}
|
|
|
|
fun Sequence.build(block: BuildType.() -> Unit): BuildType {
|
|
val bt = BuildType().apply(block)
|
|
stages.add(Single(bt))
|
|
return bt
|
|
}
|
|
|
|
fun Project.sequence(block: Sequence.() -> Unit): Sequence {
|
|
val sequence = Sequence().apply(block)
|
|
buildDependencies(sequence)
|
|
registerBuilds(sequence)
|
|
return sequence
|
|
}
|
|
|
|
fun buildDependencies(sequence: Sequence) {
|
|
sequence.dependencies.forEach {
|
|
stageDependsOnStage(sequence, it)
|
|
}
|
|
|
|
var previous: Pair<Stage, DependencySettings>? = null
|
|
|
|
for (stage in sequence.stages) {
|
|
if (previous != null) {
|
|
stageDependsOnStage(stage, Pair(previous.first, stage.dependencySettings))
|
|
}
|
|
stage.dependencies.forEach { dependency ->
|
|
stageDependsOnStage(stage, dependency)
|
|
}
|
|
|
|
val dependencySettings = previous?.second ?: {}
|
|
previous = Pair(stage, dependencySettings)
|
|
}
|
|
}
|
|
|
|
fun stageDependsOnStage(stage: Stage, dependency: Pair<Stage, DependencySettings>) {
|
|
val s = dependency.first
|
|
val d = dependency.second
|
|
if (s is Single) {
|
|
stageDependsOnSingle(stage, Pair(s, d))
|
|
}
|
|
if (s is Parallel) {
|
|
stageDependsOnParallel(stage, Pair(s, d))
|
|
}
|
|
if (s is Sequence) {
|
|
stageDependsOnSequence(stage, Pair(s, d))
|
|
}
|
|
}
|
|
|
|
fun stageDependsOnSingle(stage: Stage, dependency: Pair<Single, DependencySettings>) {
|
|
if (stage is Single) {
|
|
singleDependsOnSingle(stage, dependency)
|
|
}
|
|
if (stage is Parallel) {
|
|
parallelDependsOnSingle(stage, dependency)
|
|
}
|
|
if (stage is Sequence) {
|
|
sequenceDependsOnSingle(stage, dependency)
|
|
}
|
|
}
|
|
|
|
fun stageDependsOnParallel(stage: Stage, dependency: Pair<Parallel, DependencySettings>) {
|
|
if (stage is Single) {
|
|
singleDependsOnParallel(stage, dependency)
|
|
}
|
|
if (stage is Parallel) {
|
|
parallelDependsOnParallel(stage, dependency)
|
|
}
|
|
if (stage is Sequence) {
|
|
sequenceDependsOnParallel(stage, dependency)
|
|
}
|
|
}
|
|
|
|
fun stageDependsOnSequence(stage: Stage, dependency: Pair<Sequence, DependencySettings>) {
|
|
if (stage is Single) {
|
|
singleDependsOnSequence(stage, dependency)
|
|
}
|
|
if (stage is Parallel) {
|
|
parallelDependsOnSequence(stage, dependency)
|
|
}
|
|
if (stage is Sequence) {
|
|
sequenceDependsOnSequence(stage, dependency)
|
|
}
|
|
}
|
|
|
|
fun singleDependsOnSingle(stage: Single, dependency: Pair<Single, DependencySettings>) {
|
|
stage.buildType.dependencies.dependency(dependency.first.buildType) {
|
|
snapshot(dependency.second)
|
|
}
|
|
}
|
|
|
|
fun singleDependsOnParallel(stage: Single, dependency: Pair<Parallel, DependencySettings>) {
|
|
dependency.first.buildTypes.forEach { buildType ->
|
|
val dep = Pair(Single(buildType), dependency.second)
|
|
singleDependsOnSingle(stage, dep)
|
|
}
|
|
dependency.first.sequences.forEach { sequence ->
|
|
val dep = Pair(sequence, dependency.second)
|
|
singleDependsOnSequence(stage, dep)
|
|
}
|
|
}
|
|
|
|
fun singleDependsOnSequence(stage: Single, dependency: Pair<Sequence, DependencySettings>) {
|
|
dependency.first.stages.lastOrNull()?.let { lastStage ->
|
|
if (lastStage is Single) {
|
|
singleDependsOnSingle(stage, Pair(lastStage, dependency.second))
|
|
}
|
|
if (lastStage is Parallel) {
|
|
singleDependsOnParallel(stage, Pair(lastStage, dependency.second))
|
|
}
|
|
if (lastStage is Sequence) {
|
|
singleDependsOnSequence(stage, Pair(lastStage, dependency.second))
|
|
}
|
|
}
|
|
}
|
|
|
|
fun parallelDependsOnSingle(stage: Parallel, dependency: Pair<Single, DependencySettings>) {
|
|
stage.buildTypes.forEach { buildType ->
|
|
val single = Single(buildType)
|
|
singleDependsOnSingle(single, dependency)
|
|
}
|
|
stage.sequences.forEach { sequence ->
|
|
sequenceDependsOnSingle(sequence, dependency)
|
|
}
|
|
}
|
|
|
|
fun parallelDependsOnParallel(stage: Parallel, dependency: Pair<Parallel, DependencySettings>) {
|
|
stage.buildTypes.forEach { buildType ->
|
|
singleDependsOnParallel(Single(buildType), dependency)
|
|
}
|
|
stage.sequences.forEach { sequence ->
|
|
sequenceDependsOnParallel(sequence, dependency)
|
|
}
|
|
}
|
|
|
|
fun parallelDependsOnSequence(stage: Parallel, dependency: Pair<Sequence, DependencySettings>) {
|
|
stage.buildTypes.forEach { buildType ->
|
|
singleDependsOnSequence(Single(buildType), dependency)
|
|
}
|
|
stage.sequences.forEach { sequence ->
|
|
sequenceDependsOnSequence(sequence, dependency)
|
|
}
|
|
}
|
|
|
|
fun sequenceDependsOnSingle(stage: Sequence, dependency: Pair<Single, DependencySettings>) {
|
|
stage.stages.firstOrNull()?.let { firstStage ->
|
|
if (firstStage is Single) {
|
|
singleDependsOnSingle(firstStage, dependency)
|
|
}
|
|
if (firstStage is Parallel) {
|
|
parallelDependsOnSingle(firstStage, dependency)
|
|
}
|
|
if (firstStage is Sequence) {
|
|
sequenceDependsOnSingle(firstStage, dependency)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun sequenceDependsOnParallel(stage: Sequence, dependency: Pair<Parallel, DependencySettings>) {
|
|
stage.stages.firstOrNull()?.let { firstStage ->
|
|
if (firstStage is Single) {
|
|
singleDependsOnParallel(firstStage, dependency)
|
|
}
|
|
if (firstStage is Parallel) {
|
|
parallelDependsOnParallel(firstStage, dependency)
|
|
}
|
|
if (firstStage is Sequence) {
|
|
sequenceDependsOnParallel(firstStage, dependency)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun sequenceDependsOnSequence(stage: Sequence, dependency: Pair<Sequence, DependencySettings>) {
|
|
stage.stages.firstOrNull()?.let { firstStage ->
|
|
if (firstStage is Single) {
|
|
singleDependsOnSequence(firstStage, dependency)
|
|
}
|
|
if (firstStage is Parallel) {
|
|
parallelDependsOnSequence(firstStage, dependency)
|
|
}
|
|
if (firstStage is Sequence) {
|
|
sequenceDependsOnSequence(firstStage, dependency)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Project.registerBuilds(sequence: Sequence) {
|
|
sequence.stages.forEach {
|
|
if (it is Single) {
|
|
buildType(it.buildType)
|
|
}
|
|
if (it is Parallel) {
|
|
it.buildTypes.forEach { build ->
|
|
buildType(build)
|
|
}
|
|
it.sequences.forEach { seq ->
|
|
registerBuilds(seq)
|
|
}
|
|
}
|
|
if(it is Sequence) {
|
|
registerBuilds(it)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Project.build(bt: BuildType, block: BuildType.() -> Unit = {}): BuildType {
|
|
bt.apply(block)
|
|
buildType(bt)
|
|
return bt
|
|
}
|
|
|
|
fun Project.build(block: BuildType.() -> Unit): BuildType {
|
|
val bt = BuildType().apply(block)
|
|
buildType(bt)
|
|
return bt
|
|
}
|
|
|
|
fun BuildType.produces(artifacts: String) {
|
|
artifactRules = artifacts
|
|
}
|
|
|
|
fun BuildType.requires(bt: BuildType, artifacts: String, settings: ArtifactDependency.() -> Unit = {}) {
|
|
dependencies.artifacts(bt) {
|
|
artifactRules = artifacts
|
|
settings()
|
|
}
|
|
}
|
|
|
|
fun BuildType.dependsOn(bt: BuildType, settings: SnapshotDependency.() -> Unit = {}) {
|
|
dependencies.dependency(bt) {
|
|
snapshot(settings)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* !!!WARNING!!!
|
|
*
|
|
* This method works as expected only if the <code>stage</code> is already populated
|
|
*/
|
|
fun BuildType.dependsOn(stage: Stage, dependencySettings: DependencySettings = {}) {
|
|
val single = Single(this)
|
|
single.dependsOn(stage, dependencySettings) //TODO: does it really work?
|
|
}
|
|
|
|
fun Stage.dependsOn(bt: BuildType, dependencySettings: DependencySettings = {}) {
|
|
val stage = Single(bt)
|
|
dependsOn(stage, dependencySettings)
|
|
}
|
|
|
|
fun Stage.dependsOn(stage: Stage, dependencySettings: DependencySettings = {}) {
|
|
dependencies.add(Pair(stage, dependencySettings))
|
|
}
|
|
|
|
fun Stage.dependencySettings(dependencySettings: DependencySettings = {}) {
|
|
this.dependencySettings = dependencySettings
|
|
}
|
|
|
|
fun BuildType.dependencySettings(dependencySettings: DependencySettings = {}) {
|
|
throw IllegalStateException("dependencySettings can only be used with parallel {} or sequence {}. Please use dependsOn instead")
|
|
}
|