Skip to content

Commit 681c7bd

Browse files
teamcity: add FEATURE-BRANCH-resource-identity subproject (#13738) (#22529)
[upstream:19ff13a7b1c35e06ec99167e23e397ad2c3fa8e8] Signed-off-by: Modular Magician <[email protected]>
1 parent e6c249a commit 681c7bd

File tree

5 files changed

+227
-6
lines changed

5 files changed

+227
-6
lines changed

.teamcity/components/builds/build_configuration_per_package.kt

+5-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import replaceCharsId
2020

2121
// BuildConfigurationsForPackages accepts a map containing details of multiple packages in a provider and returns a list of build configurations for them all.
2222
// Intended to be used in projects where we're testing all packages, e.g. the nightly test projects
23-
fun BuildConfigurationsForPackages(packages: Map<String, Map<String, String>>, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration): List<BuildType> {
23+
fun BuildConfigurationsForPackages(packages: Map<String, Map<String, String>>, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration, testPrefix: String = "TestAcc"): List<BuildType> {
2424
val list = ArrayList<BuildType>()
2525

2626
// Create build configurations for all packages, except sweeper
@@ -29,7 +29,7 @@ fun BuildConfigurationsForPackages(packages: Map<String, Map<String, String>>, p
2929
val displayName: String = info.getValue("displayName").toString()
3030

3131
val pkg = PackageDetails(packageName, displayName, providerName, parentProjectName)
32-
val buildConfig = pkg.buildConfiguration(path, vcsRoot, sharedResources, environmentVariables)
32+
val buildConfig = pkg.buildConfiguration(path, vcsRoot, sharedResources, environmentVariables, testPrefix = testPrefix)
3333
list.add(buildConfig)
3434
}
3535

@@ -38,17 +38,16 @@ fun BuildConfigurationsForPackages(packages: Map<String, Map<String, String>>, p
3838

3939
// BuildConfigurationForSinglePackage accepts details of a single package in a provider and returns a build configuration for it
4040
// Intended to be used in short-lived projects where we're testing specific packages, e.g. feature branch testing
41-
fun BuildConfigurationForSinglePackage(packageName: String, packagePath: String, packageDisplayName: String, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration): BuildType{
41+
fun BuildConfigurationForSinglePackage(packageName: String, packagePath: String, packageDisplayName: String, providerName: String, parentProjectName: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration, testPrefix: String = "TestAcc"): BuildType{
4242
val pkg = PackageDetails(packageName, packageDisplayName, providerName, parentProjectName)
43-
return pkg.buildConfiguration(packagePath, vcsRoot, sharedResources, environmentVariables)
43+
return pkg.buildConfiguration(packagePath, vcsRoot, sharedResources, environmentVariables, testPrefix = testPrefix)
4444
}
4545

4646
class PackageDetails(private val packageName: String, private val displayName: String, private val providerName: String, private val parentProjectName: String) {
4747

4848
// buildConfiguration returns a BuildType for a service package
4949
// For BuildType docs, see https://teamcity.jetbrains.com/app/dsl-documentation/root/build-type/index.html
50-
fun buildConfiguration(path: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration, buildTimeout: Int = DefaultBuildTimeoutDuration): BuildType {
51-
50+
fun buildConfiguration(path: String, vcsRoot: GitVcsRoot, sharedResources: List<String>, environmentVariables: AccTestConfiguration, buildTimeout: Int = DefaultBuildTimeoutDuration, testPrefix: String): BuildType {
5251
val testPrefix = "TestAcc"
5352
val testTimeout = "12"
5453

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
// This file is maintained in the GoogleCloudPlatform/magic-modules repository and copied into the downstream provider repositories. Any changes to this file in the downstream will be overwritten.
7+
8+
package projects.feature_branches
9+
10+
import ProviderNameBeta
11+
import ProviderNameGa
12+
import SharedResourceNameBeta
13+
import SharedResourceNameGa
14+
import SharedResourceNameVcr
15+
import builds.*
16+
import generated.ServicesListBeta
17+
import generated.ServicesListGa
18+
import jetbrains.buildServer.configs.kotlin.Project
19+
import replaceCharsId
20+
import vcs_roots.HashiCorpVCSRootBeta
21+
import vcs_roots.HashiCorpVCSRootGa
22+
import vcs_roots.ModularMagicianVCSRootBeta
23+
import vcs_roots.ModularMagicianVCSRootGa
24+
import components.projects.feature_branches.getServicesList
25+
import DefaultStartHour
26+
27+
const val featureBranchResourceIdentity = "FEATURE-BRANCH-resource-identity"
28+
const val ResourceIdentityTfCoreVersion = "1.12.0-beta2"
29+
30+
fun featureBranchResourceIdentitySubProject(allConfig: AllContextParameters): Project {
31+
32+
val trigger = NightlyTriggerConfiguration(
33+
branch = "refs/heads/$featureBranchResourceIdentity", // triggered builds must test the feature branch
34+
startHour = DefaultStartHour + 6,
35+
)
36+
val vcrConfig = getVcrAcceptanceTestConfig(allConfig) // Reused below for both MM testing build configs
37+
val servicesToTest = arrayOf("secretmanager", "resourcemanager")
38+
39+
// GA
40+
val gaConfig = getGaAcceptanceTestConfig(allConfig)
41+
// These are the packages that have resources that will use write-only attributes
42+
var ServicesListWriteOnlyGA = getServicesList(servicesToTest, "GA")
43+
44+
val buildConfigsGa = BuildConfigurationsForPackages(ServicesListWriteOnlyGA, ProviderNameGa, "ResourceIdentityGa - HC", HashiCorpVCSRootGa, listOf(SharedResourceNameGa), gaConfig, "TestAcc.*ResourceIdentity")
45+
buildConfigsGa.forEach{ builds ->
46+
builds.addTrigger(trigger)
47+
}
48+
49+
var ServicesListWriteOnlyGaMM = getServicesList(servicesToTest, "GA-MM")
50+
val buildConfigsMMGa = BuildConfigurationsForPackages(ServicesListWriteOnlyGaMM, ProviderNameGa, "ResourceIdentityGa - MM", ModularMagicianVCSRootGa, listOf(SharedResourceNameGa), vcrConfig, "TestAcc.*ResourceIdentity")
51+
52+
// Beta
53+
val betaConfig = getBetaAcceptanceTestConfig(allConfig)
54+
var ServicesListWriteOnlyBeta = getServicesList(servicesToTest, "Beta")
55+
val buildConfigsBeta = BuildConfigurationsForPackages(ServicesListWriteOnlyBeta, ProviderNameBeta, "ResourceIdentityBeta - HC", HashiCorpVCSRootBeta, listOf(SharedResourceNameBeta), betaConfig, "TestAcc.*ResourceIdentity")
56+
buildConfigsBeta.forEach{ builds ->
57+
builds.addTrigger(trigger)
58+
}
59+
60+
var ServicesListWriteOnlyBetaMM = getServicesList(servicesToTest, "Beta-MM")
61+
val buildConfigsMMBeta = BuildConfigurationsForPackages(ServicesListWriteOnlyBetaMM, ProviderNameBeta, "ResourceIdentityBeta - MM", ModularMagicianVCSRootBeta, listOf(SharedResourceNameBeta), vcrConfig, "TestAcc.*ResourceIdentity")
62+
63+
// Make all builds use a 1.12.0-ish version of TF core
64+
val allBuildConfigs = buildConfigsGa + buildConfigsBeta + buildConfigsMMGa + buildConfigsMMBeta
65+
allBuildConfigs.forEach{ builds ->
66+
builds.overrideTerraformCoreVersion(ResourceIdentityTfCoreVersion)
67+
}
68+
69+
// ------
70+
71+
return Project{
72+
id("FEATURE_BRANCH_resource_identity")
73+
name = featureBranchResourceIdentity
74+
description = "Subproject for testing feature branch $featureBranchResourceIdentity"
75+
76+
// Register all build configs in the project
77+
allBuildConfigs.forEach{ builds ->
78+
buildType(builds)
79+
}
80+
81+
params {
82+
readOnlySettings()
83+
}
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
package components.projects.feature_branches
6+
7+
import generated.ServicesListGa
8+
import generated.ServicesListBeta
9+
10+
// This file is maintained in the GoogleCloudPlatform/magic-modules repository and copied into the downstream provider repositories. Any changes to this file in the downstream will be overwritten.
11+
12+
// This function is used to get the services list for a given version. Typically used in feature branch builds for testing very specific services only.
13+
fun getServicesList(Services: Array<String>, version: String): Map<String,Map<String,String>> {
14+
if (Services.isEmpty()) {
15+
throw Exception("No services found for version $version")
16+
}
17+
18+
var servicesList = mutableMapOf<String,Map<String,String>>()
19+
for (service in Services) {
20+
if (version == "GA" || version == "GA-MM") {
21+
servicesList[service] = ServicesListGa.getOrElse(service) { throw Exception("Service $service not found") }
22+
} else if (version == "Beta" || version == "Beta-MM") {
23+
servicesList[service] = ServicesListBeta.getOrElse(service) { throw Exception("Service $service not found") }
24+
} else {
25+
throw Exception("Invalid version $version")
26+
}
27+
}
28+
29+
when (version) {
30+
"GA" -> servicesList
31+
"Beta" -> {
32+
servicesList.mapValues { (_, value) ->
33+
value + mapOf(
34+
"displayName" to "${value["displayName"]} - Beta"
35+
)
36+
}.toMutableMap()
37+
}
38+
"GA-MM" -> {
39+
servicesList.mapValues { (_, value) ->
40+
value + mapOf(
41+
"displayName" to "${value["displayName"]} - MM"
42+
)
43+
}.toMutableMap()
44+
}
45+
"Beta-MM" -> {
46+
servicesList.mapValues { (_, value) ->
47+
value + mapOf(
48+
"displayName" to "${value["displayName"]} - Beta - MM"
49+
)
50+
}.toMutableMap()
51+
}
52+
else -> throw Exception("Invalid version $version")
53+
}.also { servicesList = it as MutableMap<String, Map<String, String>> }
54+
55+
return servicesList
56+
}

.teamcity/components/projects/root_project.kt

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import generated.ServicesListBeta
1818
import generated.ServicesListGa
1919
import jetbrains.buildServer.configs.kotlin.Project
2020
import jetbrains.buildServer.configs.kotlin.sharedResource
21+
import projects.feature_branches.featureBranchResourceIdentitySubProject
2122

2223
// googleCloudRootProject returns a root project that contains a subprojects for the GA and Beta version of the
2324
// Google provider. There are also resources to help manage the test projects used for acceptance tests.
@@ -61,6 +62,7 @@ fun googleCloudRootProject(allConfig: AllContextParameters): Project {
6162
subProject(googleSubProjectGa(allConfig))
6263
subProject(googleSubProjectBeta(allConfig))
6364
subProject(projectSweeperSubProject(allConfig))
65+
subProject(featureBranchResourceIdentitySubProject(allConfig))
6466

6567
// Feature branch-testing projects - these will be added and removed as needed
6668

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
// This file is maintained in the GoogleCloudPlatform/magic-modules repository and copied into the downstream provider repositories. Any changes to this file in the downstream will be overwritten.
7+
8+
package tests
9+
10+
import jetbrains.buildServer.configs.kotlin.triggers.ScheduleTrigger
11+
import org.junit.Assert
12+
import org.junit.Test
13+
import projects.feature_branches.featureBranchResourceIdentity
14+
import projects.googleCloudRootProject
15+
16+
class FeatureBranchResourceIdentitySubProject {
17+
@Test
18+
fun buildsUsingHashiCorpReposAreOnSchedule() {
19+
val root = googleCloudRootProject(testContextParameters())
20+
21+
// Find feature branch project
22+
val project = getSubProject(root, featureBranchResourceIdentity)
23+
24+
// All builds using the HashiCorp owned GitHub repos
25+
val hashiBuilds = project.buildTypes.filter { bt ->
26+
bt.name.contains("HashiCorp downstream")
27+
}
28+
29+
hashiBuilds.forEach{bt ->
30+
Assert.assertTrue(
31+
"Build configuration `${bt.name}` should contain at least one trigger",
32+
bt.triggers.items.isNotEmpty()
33+
)
34+
// Look for at least one CRON trigger
35+
var found = false
36+
lateinit var schedulingTrigger: ScheduleTrigger
37+
for (item in bt.triggers.items){
38+
if (item.type == "schedulingTrigger") {
39+
schedulingTrigger = item as ScheduleTrigger
40+
found = true
41+
break
42+
}
43+
}
44+
45+
Assert.assertTrue(
46+
"Build configuration `${bt.name}` should contain a CRON/'schedulingTrigger' trigger",
47+
found
48+
)
49+
50+
// Check that triggered builds are being run on the feature branch
51+
val isCorrectBranch: Boolean = schedulingTrigger.branchFilter == "+:refs/heads/$featureBranchResourceIdentity"
52+
53+
Assert.assertTrue(
54+
"Build configuration `${bt.name}` is using the $featureBranchResourceIdentity branch filter",
55+
isCorrectBranch
56+
)
57+
}
58+
}
59+
60+
@Test
61+
fun buildsUsingModularMagicianReposAreNotTriggered() {
62+
val root = googleCloudRootProject(testContextParameters())
63+
64+
// Find feature branch project
65+
val project = getSubProject(root, featureBranchResourceIdentity)
66+
67+
// All builds using the HashiCorp owned GitHub repos
68+
val magicianBuilds = project.buildTypes.filter { bt ->
69+
bt.name.contains("MM upstream")
70+
}
71+
72+
magicianBuilds.forEach{bt ->
73+
Assert.assertTrue(
74+
"Build configuration `${bt.name}` should not have any triggers",
75+
bt.triggers.items.isEmpty()
76+
)
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)