taskman_teamcity/teamcity/settings.kts.in

567 lines
17 KiB
Plaintext

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(BuildAndroidDev)
build(UploadArtifactToSlack("Build_Upload_Android", BuildAndroid))
//IOS
build(BuildIOS)
build(BuildIOSDev)
build(UploadArtifactToSlack("Build_Upload_IOS", BuildIOS))
}
}
}
object BuildAndroid : BuildAndroidType("", "prod/global_android")
object BuildAndroidDev : BuildAndroidType("Dev", "dev/global_android")
object BuildAndroidCh : BuildAndroidType("Ch", "prod/china_android")
object BuildIOS : BuildIOSType("", "prod/global_ios")
object BuildIOSDev : BuildIOSType("Dev", "dev/global_ios")
object BuildIOSCh : BuildIOSType("Ch", "prod/china_ios")
open class BuildAndroidType(name_suffix : String, environment : String) :
BuildType({
name = "Build Android " + name_suffix
artifactRules = "%build.env.artifactRules%"
vcs {
root(GitProjectRepo)
branchFilter = "+:*"
}
params {
param("build.env.buildName", "%system.teamcity.buildConfName%")
param("build.env.workDir", "%system.teamcity.build.workingDir%")
param("build.env.artifactRules", "artifacts/android/*.apk\nartifacts/android/*.aab")
}
features {
notifications {
notifierSettings = slackNotifier {
connection = "PROJECT_EXT_2"
sendTo = "#rnd-builds"
messageFormat = verboseMessageFormat {
addBranch = true
addStatusText = true
maximumNumberOfChanges = 10
}
}
buildFailed = true
buildFinishedSuccessfully = true
}
}
steps {
script {
name = "Deps Update"
scriptContent = "./gamectl deps_update"
}
script {
name = "Clean"
scriptContent = "./gamectl clean"
}
script {
name = "Produce"
scriptContent = "./gamectl --env=" + environment + " build_android"
}
}
requirements {
matches("teamcity.agent.name", "(Default Agent|Default Agent 2)")
}
}
)
{}
open class BuildIOSType(name_suffix : String, environment : String) :
BuildType({
name = "Build IOS " + name_suffix
artifactRules = "%build.env.artifactRules%"
vcs {
root(GitProjectRepo)
branchFilter = "+:*"
}
params {
param("build.env.buildName", "%system.teamcity.buildConfName%")
param("build.env.workDir", "%system.teamcity.build.workingDir%")
param("build.env.artifactRules", "artifacts/ios/*.ipa")
}
features {
notifications {
notifierSettings = slackNotifier {
connection = "PROJECT_EXT_2"
sendTo = "#rnd-builds"
messageFormat = verboseMessageFormat {
addBranch = true
addStatusText = true
maximumNumberOfChanges = 10
}
}
buildFailed = true
buildFinishedSuccessfully = true
}
}
steps {
script {
name = "Deps Update"
scriptContent = "./gamectl deps_update"
}
script {
name = "Clean"
scriptContent = "./gamectl clean"
}
script {
name = "Produce"
scriptContent = "./gamectl --env=" + environment + " build_ios"
}
}
requirements {
equals("teamcity.agent.name", "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 = %(TEAM_CITY_SETTINGS_NAME_HERE)%
url = %(TEAM_CITY_SETTINGS_URL_HERE)%
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")
}