Skip to content

Commit

Permalink
Add ability to add project features (#20)
Browse files Browse the repository at this point in the history
Changing the artifact storage for a project is done through project
features, add support to our Terraform provider to allow specifying
project features when creating a teamcity_project

This was based on existing code to manage build features

TEST=manual

Built a new version of the Terraform provider and used it to apply some
pipelines in a local TeamCity with some random project feature
  • Loading branch information
andrewsheng2 authored Sep 20, 2023
1 parent 9e47499 commit 3c2be26
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 6 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.19
require (
github.com/hashicorp/terraform v0.12.2
github.com/robfig/cron v1.2.0
github.com/yext/go-teamcity v0.5.3
github.com/yext/go-teamcity v0.5.4
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/yext/go-teamcity v0.5.3 h1:kO8of1jNql70g9fURGs+oM0ArMX3csjGy99FAkPecEQ=
github.com/yext/go-teamcity v0.5.3/go.mod h1:GC2xvLY4y27DU/01mveI8LsSBerjpCEtHk6eQ7ym8oc=
github.com/yext/go-teamcity v0.5.4 h1:KKA1wsNF2DGnq1tkCK5iTu4zzKvBYLcquU9DcYPPpo4=
github.com/yext/go-teamcity v0.5.4/go.mod h1:GC2xvLY4y27DU/01mveI8LsSBerjpCEtHk6eQ7ym8oc=
github.com/zclconf/go-cty v0.0.0-20181129180422-88fbe721e0f8/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v0.0.0-20190426224007-b18a157db9e2/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v0.0.0-20190516203816-4fecf87372ec/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
Expand Down
9 changes: 6 additions & 3 deletions teamcity/resource_build_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,10 @@ func resourceBuildConfigRead(d *schema.ResourceData, meta interface{}) error {

srv := client.BuildFeatureService(d.Id())
buildFeatures, err := srv.GetBuildFeatures()
buildFeaturesToSave, err := flattenBuildFeatures(buildFeatures)
if err != nil {
return err
}
buildFeaturesToSave := flattenBuildFeatures(buildFeatures)
if err := d.Set("feature", buildFeaturesToSave); err != nil {
return err
}
Expand Down Expand Up @@ -788,7 +791,7 @@ func flattenBuildStepCmdLine(s *api.StepCommandLine) map[string]interface{} {
return m
}

func flattenBuildFeatures(bfs []api.BuildFeature) ([]map[string]interface{}, error) {
func flattenBuildFeatures(bfs []api.BuildFeature) []map[string]interface{} {
var bfsToSave []map[string]interface{}
for _, bf := range bfs {
bfToSave := make(map[string]interface{})
Expand All @@ -805,7 +808,7 @@ func flattenBuildFeatures(bfs []api.BuildFeature) ([]map[string]interface{}, err
}
bfsToSave = append(bfsToSave, bfToSave)
}
return bfsToSave, nil
return bfsToSave
}

func expandBuildFeatures(list interface{}) ([]api.BuildFeature, error) {
Expand Down
102 changes: 102 additions & 0 deletions teamcity/resource_project.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package teamcity

import (
"errors"
"fmt"
"log"

Expand Down Expand Up @@ -56,6 +57,22 @@ func resourceProject() *schema.Resource {
Type: schema.TypeMap,
Optional: true,
},
"feature": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Required: true,
},
"properties": {
Type: schema.TypeMap,
Required: true,
},
},
},
},
},
}
}
Expand Down Expand Up @@ -115,6 +132,28 @@ func resourceProjectUpdate(d *schema.ResourceData, meta interface{}) error {
}
}

if d.HasChange("feature") {
srv := client.ProjectFeatureService(d.Id())
err := srv.DeleteAll()
if err != nil {
return err
}
add, err := expandProjectFeatures(d.Get("feature").([]interface{}))
if err != nil {
return err
}
if len(add) > 0 {
for i, s := range add {
_, err := srv.Create(s)
log.Printf("[INFO] Adding project feature '%v' with order = %v", s.Type(), i+1)
if err != nil {
return err
}
}
}
d.SetPartial("feature")
}

dt.Parameters, err = expandParameterCollection(d)
if err != nil {
return err
Expand Down Expand Up @@ -149,6 +188,16 @@ func resourceProjectRead(d *schema.ResourceData, meta interface{}) error {
return err
}

srv := client.ProjectFeatureService(d.Id())
projectFeatures, err := srv.GetProjectFeatures()
if err != nil {
return err
}
projectFeaturesToSave := flattenProjectFeatures(projectFeatures)
if err := d.Set("feature", projectFeaturesToSave); err != nil {
return err
}

log.Printf("[DEBUG] Project: %v", dt)
return nil
}
Expand Down Expand Up @@ -180,3 +229,56 @@ func getProject(c *api.Client, id string) (*api.Project, error) {

return dt, nil
}

func flattenProjectFeatures(pfs []api.ProjectFeature) []map[string]interface{} {
var pfsToSave []map[string]interface{}
for _, pf := range pfs {
pfToSave := make(map[string]interface{})
gpf := pf.(*api.GenericProjectFeature)
pfToSave["type"] = gpf.Type()

props := gpf.Properties()
pfToSave["properties"] = make(map[string]string)
if props != nil && props.Count > 0 {
propertyMap := pfToSave["properties"].(map[string]string)
for _, property := range props.Items {
propertyMap[property.Name] = property.Value
}
}
pfsToSave = append(pfsToSave, pfToSave)
}
return pfsToSave
}

func expandProjectFeatures(list interface{}) ([]api.ProjectFeature, error) {
var out []api.ProjectFeature
rawProjectFeatures := list.([]interface{})
for _, rawPF := range rawProjectFeatures {
expandedPF, err := expandProjectFeature(rawPF)
if err != nil {
return nil, err
}
out = append(out, expandedPF)
}

return out, nil
}

func expandProjectFeature(raw interface{}) (api.ProjectFeature, error) {
feature := raw.(map[string]interface{})
var featureType string
var properties map[string]interface{}
if v, _ := feature["type"]; len(v.(string)) > 0 {
featureType = v.(string)
} else {
return nil, errors.New("feature type cannot be empty")
}
if v, ok := feature["properties"]; ok {
properties = v.(map[string]interface{})
}
pf, err := api.NewGenericProjectFeature(featureType, properties)
if err != nil {
return nil, err
}
return pf, nil
}

0 comments on commit 3c2be26

Please sign in to comment.