diff --git a/README.md b/README.md index c2e9243..6ef6b29 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,8 @@ $ terraform import bitbucketserver_project.test TEST ```hcl resource "bitbucketserver_project_permissions_group" "test" { - project = "TEST" - group = "stash-users" + project = "TEST" + group = "stash-users" permission = "PROJECT_WRITE" } ``` @@ -97,8 +97,8 @@ $ terraform import bitbucketserver_project_permissions_group.test TEST/stash-use ```hcl resource "bitbucketserver_project_permissions_user" "test" { - project = "TEST" - user = "admin" + project = "TEST" + user = "admin" permission = "PROJECT_WRITE" } ``` @@ -220,7 +220,7 @@ $ terraform import bitbucketserver_user.test mreynolds ```hcl resource "bitbucketserver_group" "browncoats" { - name = "browncoats" + name = "browncoats" } ``` @@ -256,8 +256,8 @@ $ terraform import bitbucketserver_user_group.browncoat mreynolds/browncoats ```hcl resource "bitbucketserver_global_permissions_group" "test" { - project = "TEST" - group = "stash-users" + project = "TEST" + group = "stash-users" permission = "ADMIN" } ``` @@ -276,7 +276,7 @@ $ terraform import bitbucketserver_global_permissions_group.test my-group ```hcl resource "bitbucketserver_project_permissions_user" "test" { - user = "admin" + user = "admin" permission = "ADMIN" } ``` @@ -291,6 +291,63 @@ $ terraform import bitbucketserver_global_permissions_user.test my-user ``` +### Install and License Plugins + +Install plugins, manage enabled state and set license details. + +```hcl +resource "bitbucketserver_plugin" "myplugin" { + key = "com.example-my-plugin" + version = "1.2.3" + license = "ABCDEF" +} +``` + +* `key` - Required. Unique key of the plugin. +* `version` - Required. Version to install. +* `license` - Optional. License to apply to the plugin. +* `enabled` - Optional, default `true`. Flag to enable/disable the plugin. + +#### Attributes + +Additional to the above, the following attributes are emitted: + +* `enabled_by_default` - Set to `true` if the plugin is enabled by default (for system plugins). +* `version` - Installed version of the plugin. +* `name` - Name of the plugin. +* `description` - Plugin description. +* `user_installed` - Set to `true` if this is a user installed plugin vs a system bundled plugin. +* `optional` - Set to `true` if this is an optional plugin. +* `vendor.name` - Name of the vendor. +* `vendor.link` - Vendor homepage. +* `vendor.marketplace_link` - Plugin marketplace link. +* `applied_license.0.valid` - Is the license valid. true/false. +* `applied_license.0.evaluation` - Is the license an evaluation. true/false. +* `applied_license.0.nearly_expired` - Is the license nearly expired. true/false. +* `applied_license.0.maintenance_expiry_date` - Date of maintenance expiry. +* `applied_license.0.maintenance_expired` - Is the maintenance expired. true/false. +* `applied_license.0.license_type` - Type of license. +* `applied_license.0.expiry_date` - Expiry date of the license. +* `applied_license.0.raw_license` - The raw license information. +* `applied_license.0.renewable` - Is the license renewabl. true/false. +* `applied_license.0.organization_name` - Name of the organization the license is for. +* `applied_license.0.enterprise` - Is the license for enterprise. true/false. +* `applied_license.0.data_center` - Is the license for data center. true/false. +* `applied_license.0.subscription` - Is the license a subscription. true/false. +* `applied_license.0.active` - Is the license active. true/false. +* `applied_license.0.auto_renewal` - Is the license renewed automatically. true/false. +* `applied_license.0.upgradable` - Is the license able to be upgraded. true/false. +* `applied_license.0.crossgradeable` - Can the license be crossgraded. true/false. +* `applied_license.0.purchase_past_server_cutoff_date` - The purchase date past the server cutoff date. true/false. + +#### Import Plugin + +```bash +$ terraform import bitbucketserver_plugin.test com.example-my-plugin +``` + + + ### Set Server License ```hcl @@ -520,9 +577,10 @@ data "bitbucketserver_plugin" "myplugin" { } ``` +* `key` - Unique key of the plugin. + #### Attributes -* `key` - Unique key of the plugin. * `enabled` - Set to `true` if the plugin is enabled. * `enabled_by_default` - Set to `true` if the plugin is enabled by default (for system plugins). * `version` - Installed version of the plugin. @@ -533,24 +591,24 @@ data "bitbucketserver_plugin" "myplugin" { * `vendor.name` - Name of the vendor. * `vendor.link` - Vendor homepage. * `vendor.marketplace_link` - Plugin marketplace link. -* `license.0.valid` - Is the license valid. true/false. -* `license.0.evaluation` - Is the license an evaluation. true/false. -* `license.0.nearly_expired` - Is the license nearly expired. true/false. -* `license.0.maintenance_expiry_date` - Date of maintenance expiry. -* `license.0.maintenance_expired` - Is the maintenance expired. true/false. -* `license.0.license_type` - Type of license. -* `license.0.expiry_date` - Expiry date of the license. -* `license.0.raw_license` - The raw license information. -* `license.0.renewable` - Is the license renewabl. true/false. -* `license.0.organization_name` - Name of the organization the license is for. -* `license.0.enterprise` - Is the license for enterprise. true/false. -* `license.0.data_center` - Is the license for data center. true/false. -* `license.0.subscription` - Is the license a subscription. true/false. -* `license.0.active` - Is the license active. true/false. -* `license.0.auto_renewal` - Is the license renewed automatically. true/false. -* `license.0.upgradable` - Is the license able to be upgraded. true/false. -* `license.0.crossgradeable` - Can the license be crossgraded. true/false. -* `license.0.purchase_past_server_cutoff_date` - The purchase date past the server cutoff date. true/false. +* `applied_license.0.valid` - Is the license valid. true/false. +* `applied_license.0.evaluation` - Is the license an evaluation. true/false. +* `applied_license.0.nearly_expired` - Is the license nearly expired. true/false. +* `applied_license.0.maintenance_expiry_date` - Date of maintenance expiry. +* `applied_license.0.maintenance_expired` - Is the maintenance expired. true/false. +* `applied_license.0.license_type` - Type of license. +* `applied_license.0.expiry_date` - Expiry date of the license. +* `applied_license.0.raw_license` - The raw license information. +* `applied_license.0.renewable` - Is the license renewabl. true/false. +* `applied_license.0.organization_name` - Name of the organization the license is for. +* `applied_license.0.enterprise` - Is the license for enterprise. true/false. +* `applied_license.0.data_center` - Is the license for data center. true/false. +* `applied_license.0.subscription` - Is the license a subscription. true/false. +* `applied_license.0.active` - Is the license active. true/false. +* `applied_license.0.auto_renewal` - Is the license renewed automatically. true/false. +* `applied_license.0.upgradable` - Is the license able to be upgraded. true/false. +* `applied_license.0.crossgradeable` - Can the license be crossgraded. true/false. +* `applied_license.0.purchase_past_server_cutoff_date` - The purchase date past the server cutoff date. true/false. --- diff --git a/bitbucket/client.go b/bitbucket/client.go index 5d713c8..e4a7050 100644 --- a/bitbucket/client.go +++ b/bitbucket/client.go @@ -7,7 +7,10 @@ import ( "io" "io/ioutil" "log" + "mime/multipart" "net/http" + "os" + "path/filepath" ) // Error represents a error from the bitbucket api. @@ -40,7 +43,7 @@ type BitbucketClient struct { HTTPClient *http.Client } -func (c *BitbucketClient) Do(method, endpoint string, payload *bytes.Buffer) (*http.Response, error) { +func (c *BitbucketClient) Do(method, endpoint string, payload *bytes.Buffer, contentType string) (*http.Response, error) { absoluteendpoint := c.Server + endpoint log.Printf("[DEBUG] Sending request to %s %s", method, absoluteendpoint) @@ -61,8 +64,11 @@ func (c *BitbucketClient) Do(method, endpoint string, payload *bytes.Buffer) (*h req.Header.Add("X-Atlassian-Token", "no-check") if payload != nil { - // Can cause bad request when putting default reviews if set. - req.Header.Add("Content-Type", "application/json") + if contentType != "" { + req.Header.Add("Content-Type", contentType) + } else { + req.Header.Add("Content-Type", "application/json") + } } req.Close = true @@ -89,22 +95,83 @@ func (c *BitbucketClient) Do(method, endpoint string, payload *bytes.Buffer) (*h return resp, err } +// Creates a new file upload http request with optional extra params +func (c *BitbucketClient) PostFileUpload(endpoint string, params map[string]string, paramName, path string) (*http.Response, error) { + absoluteendpoint := c.Server + endpoint + log.Printf("[DEBUG] Sending request to POST %s", absoluteendpoint) + + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile(paramName, filepath.Base(path)) + if err != nil { + return nil, err + } + _, err = io.Copy(part, file) + + for key, val := range params { + _ = writer.WriteField(key, val) + } + err = writer.Close() + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", absoluteendpoint, body) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", writer.FormDataContentType()) + + req.SetBasicAuth(c.Username, c.Password) + req.Header.Add("X-Atlassian-Token", "no-check") + req.Close = true + + resp, err := c.HTTPClient.Do(req) + log.Printf("[DEBUG] Resp: %v Err: %v", resp, err) + if resp != nil && (resp.StatusCode >= 400 || resp.StatusCode < 200) { + apiError := Error{ + StatusCode: resp.StatusCode, + Endpoint: endpoint, + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Resp Body: %s", string(body)) + + _ = json.Unmarshal(body, &apiError) + return resp, error(apiError) + + } + + return resp, err +} + func (c *BitbucketClient) Get(endpoint string) (*http.Response, error) { - return c.Do("GET", endpoint, nil) + return c.Do("GET", endpoint, nil, "application/json") } func (c *BitbucketClient) Post(endpoint string, jsonpayload *bytes.Buffer) (*http.Response, error) { - return c.Do("POST", endpoint, jsonpayload) + return c.Do("POST", endpoint, jsonpayload, "application/json") } func (c *BitbucketClient) Put(endpoint string, jsonpayload *bytes.Buffer) (*http.Response, error) { - return c.Do("PUT", endpoint, jsonpayload) + return c.Do("PUT", endpoint, jsonpayload, "application/json") } func (c *BitbucketClient) PutOnly(endpoint string) (*http.Response, error) { - return c.Do("PUT", endpoint, nil) + return c.Do("PUT", endpoint, nil, "application/json") } func (c *BitbucketClient) Delete(endpoint string) (*http.Response, error) { - return c.Do("DELETE", endpoint, nil) + return c.Do("DELETE", endpoint, nil, "application/json") } diff --git a/bitbucket/data_application_properties.go b/bitbucket/data_application_properties.go index 0190197..8b660ea 100644 --- a/bitbucket/data_application_properties.go +++ b/bitbucket/data_application_properties.go @@ -39,7 +39,7 @@ func dataSourceApplicationProperties() *schema.Resource { } func dataSourceApplicationPropertiesRead(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient req, err := client.Get("/rest/api/1.0/application-properties") if err != nil { diff --git a/bitbucket/data_global_permissions_groups.go b/bitbucket/data_global_permissions_groups.go index 3269d84..8f3d1c2 100644 --- a/bitbucket/data_global_permissions_groups.go +++ b/bitbucket/data_global_permissions_groups.go @@ -78,7 +78,7 @@ func dataSourceGlobalPermissionsGroupsRead(d *schema.ResourceData, m interface{} } func readGlobalPermissionsGroups(m interface{}, filter string) ([]GlobalPermissionsGroup, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := "/rest/api/1.0/admin/permissions/groups" diff --git a/bitbucket/data_global_permissions_users.go b/bitbucket/data_global_permissions_users.go index 95ad08a..3ab0407 100644 --- a/bitbucket/data_global_permissions_users.go +++ b/bitbucket/data_global_permissions_users.go @@ -99,7 +99,7 @@ func dataSourceGlobalPermissionsUsersRead(d *schema.ResourceData, m interface{}) } func readGlobalPermissionsUsers(m interface{}, filter string) ([]GlobalPermissionsUser, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := "/rest/api/1.0/admin/permissions/users" diff --git a/bitbucket/data_group_users.go b/bitbucket/data_group_users.go index 29fdd7c..98b9829 100644 --- a/bitbucket/data_group_users.go +++ b/bitbucket/data_group_users.go @@ -94,7 +94,7 @@ func dataSourceGroupUsersRead(d *schema.ResourceData, m interface{}) error { } func readGroupUsers(m interface{}, group string, filter string) ([]GroupUser, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := fmt.Sprintf("/rest/api/1.0/admin/groups/more-members?context=%s", url.QueryEscape(group), diff --git a/bitbucket/data_groups.go b/bitbucket/data_groups.go index 5759eaf..9d61c1b 100644 --- a/bitbucket/data_groups.go +++ b/bitbucket/data_groups.go @@ -65,7 +65,7 @@ func dataSourceGroupsRead(d *schema.ResourceData, m interface{}) error { } func readGroups(m interface{}, filter string) ([]string, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := "/rest/api/1.0/admin/groups" if filter != "" { diff --git a/bitbucket/data_plugin.go b/bitbucket/data_plugin.go index c65edd7..b492721 100644 --- a/bitbucket/data_plugin.go +++ b/bitbucket/data_plugin.go @@ -1,51 +1,9 @@ package bitbucket import ( - "encoding/json" - "fmt" "github.com/hashicorp/terraform/helper/schema" - "io/ioutil" ) -type Plugin struct { - Key string `json:"key,omitempty"` - Enabled bool `json:"enabled,omitempty"` - EnabledByDefault bool `json:"enabledByDefault,omitempty"` - Version string `json:"version,omitempty"` - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - UserInstalled bool `json:"userInstalled,omitempty"` - Optional bool `json:"optional,omitempty"` - Vendor struct { - Name string `json:"name,omitempty"` - MarketplaceLink string `json:"marketplaceLink,omitempty"` - Link string `json:"link,omitempty"` - } `json:"vendor,omitempty"` -} - -type PluginLicense struct { - Valid bool `json:"valid,omitempty"` - Evaluation bool `json:"evaluation,omitempty"` - NearlyExpired bool `json:"nearlyExpired,omitempty"` - MaintenanceExpiryDate jsonTime `json:"maintenanceExpiryDate,omitempty"` - MaintenanceExpired bool `json:"maintenanceExpired,omitempty"` - LicenseType string `json:"licenseType,omitempty"` - ExpiryDate jsonTime `json:"expiryDate,omitempty"` - RawLicense string `json:"rawLicense,omitempty"` - Renewable bool `json:"renewable,omitempty"` - OrganizationName string `json:"organizationName,omitempty"` - ContactEmail string `json:"contactEmail,omitempty"` - Enterprise bool `json:"enterprise,omitempty"` - DataCenter bool `json:"dataCenter,omitempty"` - Subscription bool `json:"subscription,omitempty"` - Active bool `json:"active,omitempty"` - AutoRenewal bool `json:"autoRenewal,omitempty"` - Upgradable bool `json:"upgradable,omitempty"` - Crossgradeable bool `json:"crossgradeable,omitempty"` - PurchasePastServerCutoffDate bool `json:"purchasePastServerCutoffDate,omitempty"` - SupportEntitlementNumber string `json:"supportEntitlementNumber,omitempty"` -} - func dataSourcePlugin() *schema.Resource { return &schema.Resource{ Read: dataSourcePluginRead, @@ -103,7 +61,7 @@ func dataSourcePlugin() *schema.Resource { }, }, }, - "license": { + "applied_license": { Type: schema.TypeList, Computed: true, MaxItems: 1, @@ -198,82 +156,6 @@ func dataSourcePlugin() *schema.Resource { } func dataSourcePluginRead(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) - req, err := client.Get(fmt.Sprintf("/rest/plugins/1.0/%s-key", d.Get("key").(string))) - if err != nil { - return err - } - - var plugin Plugin - - body, readErr := ioutil.ReadAll(req.Body) - if readErr != nil { - return readErr - } - - decodeErr := json.Unmarshal(body, &plugin) - if decodeErr != nil { - return decodeErr - } - - d.SetId(plugin.Key) - _ = d.Set("enabled", plugin.Enabled) - _ = d.Set("enabled_by_default", plugin.EnabledByDefault) - _ = d.Set("version", plugin.Version) - _ = d.Set("description", plugin.Description) - _ = d.Set("name", plugin.Name) - _ = d.Set("user_installed", plugin.UserInstalled) - _ = d.Set("optional", plugin.Optional) - - vendor := map[string]string{ - "name": plugin.Vendor.Name, - "link": plugin.Vendor.Link, - "marketplace_link": plugin.Vendor.MarketplaceLink, - } - _ = d.Set("vendor", vendor) - - // Hit the license API to get license details - - req, err = client.Get(fmt.Sprintf("/rest/plugins/1.0/%s-key/license", d.Get("key").(string))) - if err != nil { - return err - } - - var pluginLicense PluginLicense - - body, readErr = ioutil.ReadAll(req.Body) - if readErr != nil { - return readErr - } - - decodeErr = json.Unmarshal(body, &pluginLicense) - if decodeErr != nil { - return decodeErr - } - - license := [1]map[string]interface{}{{ - "valid": pluginLicense.Valid, - "evaluation": pluginLicense.Evaluation, - "nearly_expired": pluginLicense.NearlyExpired, - "maintenance_expiry_date": pluginLicense.MaintenanceExpiryDate.String(), - "maintenance_expired": pluginLicense.MaintenanceExpired, - "license_type": pluginLicense.LicenseType, - "expiry_date": pluginLicense.ExpiryDate.String(), - "raw_license": pluginLicense.RawLicense, - "renewable": pluginLicense.Renewable, - "organization_name": pluginLicense.OrganizationName, - "contact_email": pluginLicense.ContactEmail, - "enterprise": pluginLicense.Enterprise, - "data_center": pluginLicense.DataCenter, - "subscription": pluginLicense.Subscription, - "active": pluginLicense.Active, - "auto_renewal": pluginLicense.AutoRenewal, - "upgradable": pluginLicense.Upgradable, - "crossgradeable": pluginLicense.Crossgradeable, - "purchase_past_server_cutoff_date": pluginLicense.PurchasePastServerCutoffDate, - "support_entitlement_number": pluginLicense.SupportEntitlementNumber, - }} - _ = d.Set("license", license) - - return nil + d.SetId(d.Get("key").(string)) + return resourcePluginRead(d, m) } diff --git a/bitbucket/data_plugin_test.go b/bitbucket/data_plugin_test.go index ecf5cb4..cc22d08 100644 --- a/bitbucket/data_plugin_test.go +++ b/bitbucket/data_plugin_test.go @@ -8,8 +8,14 @@ import ( func TestAccBitbucketDataPlugin_notifyer(t *testing.T) { config := ` - data "bitbucketserver_plugin" "test" { + resource "bitbucketserver_plugin" "test" { key = "nl.stefankohler.stash.stash-notification-plugin" + version = "4.5.1" + license = "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh" + } + + data "bitbucketserver_plugin" "test" { + key = bitbucketserver_plugin.test.key } ` @@ -31,24 +37,24 @@ func TestAccBitbucketDataPlugin_notifyer(t *testing.T) { resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "vendor.name", "ASK Software"), resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "vendor.link", "http://www.stefankohler.nl/"), resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "vendor.marketplace_link", "http://www.stefankohler.nl/"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.valid", "true"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.evaluation", "true"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.nearly_expired", "true"), - resource.TestCheckResourceAttrSet("data.bitbucketserver_plugin.test", "license.0.maintenance_expiry_date"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.maintenance_expired", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.license_type", "DEVELOPER"), - resource.TestCheckResourceAttrSet("data.bitbucketserver_plugin.test", "license.0.expiry_date"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.raw_license", "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.renewable", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.organization_name", "Atlassian"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.enterprise", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.data_center", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.subscription", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.active", "true"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.auto_renewal", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.upgradable", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.crossgradeable", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "license.0.purchase_past_server_cutoff_date", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.valid", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.evaluation", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.nearly_expired", "true"), + resource.TestCheckResourceAttrSet("data.bitbucketserver_plugin.test", "applied_license.0.maintenance_expiry_date"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.maintenance_expired", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.license_type", "DEVELOPER"), + resource.TestCheckResourceAttrSet("data.bitbucketserver_plugin.test", "applied_license.0.expiry_date"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.raw_license", "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.renewable", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.organization_name", "Atlassian"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.enterprise", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.data_center", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.subscription", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.active", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.auto_renewal", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.upgradable", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.crossgradeable", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.test", "applied_license.0.purchase_past_server_cutoff_date", "true"), ), }, }, @@ -80,8 +86,8 @@ func TestAccBitbucketDataPlugin_upm(t *testing.T) { resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "vendor.name", "Atlassian"), resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "vendor.link", "http://www.atlassian.com"), resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "vendor.marketplace_link", "http://www.atlassian.com"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "license.0.valid", "false"), - resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "license.0.active", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "applied_license.0.valid", "false"), + resource.TestCheckResourceAttr("data.bitbucketserver_plugin.upm", "applied_license.0.active", "false"), ), }, }, diff --git a/bitbucket/data_project_permissions_groups.go b/bitbucket/data_project_permissions_groups.go index 308b5e0..1064dcb 100644 --- a/bitbucket/data_project_permissions_groups.go +++ b/bitbucket/data_project_permissions_groups.go @@ -82,7 +82,7 @@ func dataSourceProjectPermissionsGroupsRead(d *schema.ResourceData, m interface{ } func readProjectPermissionsGroups(m interface{}, project string, filter string) ([]ProjectPermissionsGroup, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/groups", project, diff --git a/bitbucket/data_project_permissions_users.go b/bitbucket/data_project_permissions_users.go index ef0b000..07bf9cd 100644 --- a/bitbucket/data_project_permissions_users.go +++ b/bitbucket/data_project_permissions_users.go @@ -103,7 +103,7 @@ func dataSourceProjectPermissionsUsersRead(d *schema.ResourceData, m interface{} } func readProjectPermissionsUsers(m interface{}, project string, filter string) ([]ProjectPermissionsUser, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/users", project, diff --git a/bitbucket/data_repository_permissions_groups.go b/bitbucket/data_repository_permissions_groups.go index 3728d7e..9ca819f 100644 --- a/bitbucket/data_repository_permissions_groups.go +++ b/bitbucket/data_repository_permissions_groups.go @@ -86,7 +86,7 @@ func dataSourceRepositoryPermissionsGroupsRead(d *schema.ResourceData, m interfa } func readRepositoryPermissionsGroups(m interface{}, project string, repository string, filter string) ([]RepositoryPermissionsGroup, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/groups", url.QueryEscape(project), diff --git a/bitbucket/data_repository_permissions_users.go b/bitbucket/data_repository_permissions_users.go index ed10a71..515c10b 100644 --- a/bitbucket/data_repository_permissions_users.go +++ b/bitbucket/data_repository_permissions_users.go @@ -107,7 +107,7 @@ func dataSourceRepositoryPermissionsUsersRead(d *schema.ResourceData, m interfac } func readRepositoryPermissionsUsers(m interface{}, project string, repository string, filter string) ([]RepositoryPermissionsUser, error) { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient resourceURL := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/users", url.QueryEscape(project), diff --git a/bitbucket/marketplace/client.go b/bitbucket/marketplace/client.go new file mode 100644 index 0000000..35467f4 --- /dev/null +++ b/bitbucket/marketplace/client.go @@ -0,0 +1,130 @@ +package marketplace + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "os" +) + +// Error represents a error from the marketplace api. +type Error struct { + StatusCode int + Endpoint string +} + +func (e Error) Error() string { + var errorMessages = "" + return fmt.Sprintf("Marketplace Error: %d %s %s", e.StatusCode, e.Endpoint, errorMessages) +} + +const marketplaceServer = "https://marketplace.atlassian.com" + +type Client struct { + HTTPClient *http.Client +} + +func (c *Client) Do(method, endpoint string, payload *bytes.Buffer) (*http.Response, error) { + + absoluteendpoint := marketplaceServer + endpoint + log.Printf("[DEBUG] Sending request to %s %s", method, absoluteendpoint) + + var bodyreader io.Reader + + if payload != nil { + log.Printf("[DEBUG] With payload %s", payload.String()) + bodyreader = payload + } + + req, err := http.NewRequest(method, absoluteendpoint, bodyreader) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", "application/json") + req.Close = true + + resp, err := c.HTTPClient.Do(req) + log.Printf("[DEBUG] Resp: %v Err: %v", resp, err) + if resp != nil && (resp.StatusCode >= 400 || resp.StatusCode < 200) { + apiError := Error{ + StatusCode: resp.StatusCode, + Endpoint: endpoint, + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + log.Printf("[DEBUG] Resp Body: %s", string(body)) + + _ = json.Unmarshal(body, &apiError) + return resp, error(apiError) + + } + return resp, err +} + +func (c *Client) DownloadArtifact(url string, dest *os.File) error { + + log.Printf("[DEBUG] Downloading file from %s", url) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return err + } + + req.Close = true + + resp, err := c.HTTPClient.Do(req) + log.Printf("[DEBUG] Resp: %v Err: %v", resp, err) + if resp != nil && (resp.StatusCode >= 400 || resp.StatusCode < 200) { + apiError := Error{ + StatusCode: resp.StatusCode, + Endpoint: url, + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + log.Printf("[DEBUG] Resp Body: %s", string(body)) + + _ = json.Unmarshal(body, &apiError) + return error(apiError) + + } + + _, err = io.Copy(dest, resp.Body) + if err != nil { + return err + } + + return nil +} + +func (c *Client) Get(endpoint string) (*http.Response, error) { + return c.Do("GET", endpoint, nil) +} + +func (c *Client) Post(endpoint string, jsonpayload *bytes.Buffer) (*http.Response, error) { + return c.Do("POST", endpoint, jsonpayload) +} + +func (c *Client) Put(endpoint string, jsonpayload *bytes.Buffer) (*http.Response, error) { + return c.Do("PUT", endpoint, jsonpayload) +} + +func (c *Client) PutOnly(endpoint string) (*http.Response, error) { + return c.Do("PUT", endpoint, nil) +} + +func (c *Client) Delete(endpoint string) (*http.Response, error) { + return c.Do("DELETE", endpoint, nil) +} diff --git a/bitbucket/provider.go b/bitbucket/provider.go index c0c67d1..e89a930 100644 --- a/bitbucket/provider.go +++ b/bitbucket/provider.go @@ -1,6 +1,7 @@ package bitbucket import ( + "github.com/gavinbunney/terraform-provider-bitbucketserver/bitbucket/marketplace" "net/http" "strings" @@ -46,6 +47,7 @@ func Provider() terraform.ResourceProvider { "bitbucketserver_group": resourceGroup(), "bitbucketserver_license": resourceLicense(), "bitbucketserver_mail_server": resourceMailServer(), + "bitbucketserver_plugin": resourcePlugin(), "bitbucketserver_project": resourceProject(), "bitbucketserver_project_permissions_group": resourceProjectPermissionsGroup(), "bitbucketserver_project_permissions_user": resourceProjectPermissionsUser(), @@ -58,6 +60,11 @@ func Provider() terraform.ResourceProvider { } } +type BitbucketServerProvider struct { + BitbucketClient *BitbucketClient + MarketplaceClient *marketplace.Client +} + func providerConfigure(d *schema.ResourceData) (interface{}, error) { serverSanitized := d.Get("server").(string) @@ -65,12 +72,19 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { serverSanitized = serverSanitized[0 : len(serverSanitized)-1] } - client := &BitbucketClient{ + b := &BitbucketClient{ Server: serverSanitized, Username: d.Get("username").(string), Password: d.Get("password").(string), HTTPClient: &http.Client{}, } - return client, nil + m := &marketplace.Client{ + HTTPClient: &http.Client{}, + } + + return &BitbucketServerProvider{ + BitbucketClient: b, + MarketplaceClient: m, + }, nil } diff --git a/bitbucket/resource_global_permissions_group.go b/bitbucket/resource_global_permissions_group.go index bcf0ffd..0c80779 100644 --- a/bitbucket/resource_global_permissions_group.go +++ b/bitbucket/resource_global_permissions_group.go @@ -33,7 +33,7 @@ func resourceGlobalPermissionsGroup() *schema.Resource { } func resourceGlobalPermissionsGroupUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/admin/permissions/groups?permission=%s&name=%s", url.QueryEscape(d.Get("permission").(string)), url.QueryEscape(d.Get("group").(string)), @@ -80,7 +80,7 @@ func resourceGlobalPermissionsGroupRead(d *schema.ResourceData, m interface{}) e } func resourceGlobalPermissionsGroupDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/admin/permissions/groups?name=%s", url.QueryEscape(d.Get("group").(string)), )) diff --git a/bitbucket/resource_global_permissions_user.go b/bitbucket/resource_global_permissions_user.go index 70ce761..3adaba2 100644 --- a/bitbucket/resource_global_permissions_user.go +++ b/bitbucket/resource_global_permissions_user.go @@ -33,7 +33,7 @@ func resourceGlobalPermissionsUser() *schema.Resource { } func resourceGlobalPermissionsUserUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/admin/permissions/users?permission=%s&name=%s", url.QueryEscape(d.Get("permission").(string)), url.QueryEscape(d.Get("user").(string)), @@ -80,7 +80,7 @@ func resourceGlobalPermissionsUserRead(d *schema.ResourceData, m interface{}) er } func resourceGlobalPermissionsUserDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/admin/permissions/users?name=%s", url.QueryEscape(d.Get("user").(string)), )) diff --git a/bitbucket/resource_group.go b/bitbucket/resource_group.go index e455403..c9a9d31 100644 --- a/bitbucket/resource_group.go +++ b/bitbucket/resource_group.go @@ -26,7 +26,7 @@ func resourceGroup() *schema.Resource { } func resourceGroupCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient groupName := d.Get("name").(string) _, err := client.Post(fmt.Sprintf("/rest/api/1.0/admin/groups?name=%s", url.QueryEscape(groupName)), nil) @@ -63,7 +63,7 @@ func resourceGroupRead(d *schema.ResourceData, m interface{}) error { func resourceGroupDelete(d *schema.ResourceData, m interface{}) error { groupName := d.Get("name").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/admin/groups?name=%s", url.QueryEscape(groupName), )) diff --git a/bitbucket/resource_license.go b/bitbucket/resource_license.go index 871c840..033be92 100644 --- a/bitbucket/resource_license.go +++ b/bitbucket/resource_license.go @@ -91,7 +91,7 @@ func newLicenseFromResource(d *schema.ResourceData) *License { } func resourceLicenseUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient license := newLicenseFromResource(d) bytedata, err := json.Marshal(license) @@ -115,7 +115,7 @@ func resourceLicenseCreate(d *schema.ResourceData, m interface{}) error { func resourceLicenseRead(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient req, err := client.Get("/rest/api/1.0/admin/license") if err != nil { @@ -152,7 +152,7 @@ func resourceLicenseRead(d *schema.ResourceData, m interface{}) error { } func resourceLicenseDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete("/rest/api/1.0/admin/mail-server") return err } diff --git a/bitbucket/resource_mail_server.go b/bitbucket/resource_mail_server.go index f14c5d3..eb7407b 100644 --- a/bitbucket/resource_mail_server.go +++ b/bitbucket/resource_mail_server.go @@ -86,7 +86,7 @@ func newMailConfigurationFromResource(d *schema.ResourceData) *MailConfiguration } func resourceMailServerUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient mailConfiguration := newMailConfigurationFromResource(d) bytedata, err := json.Marshal(mailConfiguration) @@ -111,7 +111,7 @@ func resourceMailServerCreate(d *schema.ResourceData, m interface{}) error { func resourceMailServerRead(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient req, err := client.Get("/rest/api/1.0/admin/mail-server") if err != nil { @@ -146,7 +146,7 @@ func resourceMailServerRead(d *schema.ResourceData, m interface{}) error { } func resourceMailServerDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete("/rest/api/1.0/admin/mail-server") return err } diff --git a/bitbucket/resource_mail_server_test.go b/bitbucket/resource_mail_server_test.go index 3ea277f..05a695f 100644 --- a/bitbucket/resource_mail_server_test.go +++ b/bitbucket/resource_mail_server_test.go @@ -36,7 +36,7 @@ func TestAccBitbucketMailServer(t *testing.T) { } func testAccCheckBitbucketMailServerDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*BitbucketClient) + client := testAccProvider.Meta().(*BitbucketServerProvider).BitbucketClient _, ok := s.RootModule().Resources["bitbucketserver_mail_server.test"] if !ok { return fmt.Errorf("not found %s", "bitbucketserver_mail_server.test") diff --git a/bitbucket/resource_plugin.go b/bitbucket/resource_plugin.go new file mode 100644 index 0000000..a8fa002 --- /dev/null +++ b/bitbucket/resource_plugin.go @@ -0,0 +1,522 @@ +package bitbucket + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "io/ioutil" + "os" + "path/filepath" + "regexp" +) + +type Plugin struct { + Key string `json:"key,omitempty"` + Enabled bool `json:"enabled,omitempty"` + EnabledByDefault bool `json:"enabledByDefault,omitempty"` + Version string `json:"version,omitempty"` + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + UserInstalled bool `json:"userInstalled,omitempty"` + Optional bool `json:"optional,omitempty"` + Vendor struct { + Name string `json:"name,omitempty"` + MarketplaceLink string `json:"marketplaceLink,omitempty"` + Link string `json:"link,omitempty"` + } `json:"vendor,omitempty"` +} + +type PluginLicense struct { + Valid bool `json:"valid,omitempty"` + Evaluation bool `json:"evaluation,omitempty"` + NearlyExpired bool `json:"nearlyExpired,omitempty"` + MaintenanceExpiryDate jsonTime `json:"maintenanceExpiryDate,omitempty"` + MaintenanceExpired bool `json:"maintenanceExpired,omitempty"` + LicenseType string `json:"licenseType,omitempty"` + ExpiryDate jsonTime `json:"expiryDate,omitempty"` + RawLicense string `json:"rawLicense,omitempty"` + Renewable bool `json:"renewable,omitempty"` + OrganizationName string `json:"organizationName,omitempty"` + ContactEmail string `json:"contactEmail,omitempty"` + Enterprise bool `json:"enterprise,omitempty"` + DataCenter bool `json:"dataCenter,omitempty"` + Subscription bool `json:"subscription,omitempty"` + Active bool `json:"active,omitempty"` + AutoRenewal bool `json:"autoRenewal,omitempty"` + Upgradable bool `json:"upgradable,omitempty"` + Crossgradeable bool `json:"crossgradeable,omitempty"` + PurchasePastServerCutoffDate bool `json:"purchasePastServerCutoffDate,omitempty"` + SupportEntitlementNumber string `json:"supportEntitlementNumber,omitempty"` +} + +type PluginMarketplaceVersion struct { + Version string `json:"name,omitempty"` + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + } `json:"_links,omitempty"` + Embedded struct { + Artifact struct { + Links struct { + Self struct { + Href string `json:"href,omitempty"` + } `json:"self,omitempty"` + Binary struct { + Href string `json:"href,omitempty"` + } `json:"binary,omitempty"` + } `json:"_links,omitempty"` + } `json:"artifact,omitempty"` + } `json:"_embedded,omitempty"` +} + +func (p *PluginMarketplaceVersion) Key() string { + re, _ := regexp.Compile("/rest/2/addons/([a-zA-Z0-9.-]*)/versions/build/.*") + values := re.FindStringSubmatch(p.Links.Self.Href) + if len(values) > 0 { + return values[1] + } + return "" +} + +func (p *PluginMarketplaceVersion) Filename() string { + ext := filepath.Ext(p.Embedded.Artifact.Links.Self.Href) + return fmt.Sprintf("%s-%s%s", p.Key(), p.Version, ext) +} + +func resourcePlugin() *schema.Resource { + return &schema.Resource{ + Create: resourcePluginCreate, + Update: resourcePluginUpdate, + Read: resourcePluginRead, + Exists: resourcePluginExists, + Delete: resourcePluginDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "license": { + Type: schema.TypeString, + Optional: true, + }, + "enabled_by_default": { + Type: schema.TypeBool, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "user_installed": { + Type: schema.TypeBool, + Computed: true, + }, + "optional": { + Type: schema.TypeBool, + Computed: true, + }, + "vendor": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "link": { + Type: schema.TypeString, + Computed: true, + }, + "marketplace_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "applied_license": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "valid": { + Type: schema.TypeBool, + Computed: true, + }, + "evaluation": { + Type: schema.TypeBool, + Computed: true, + }, + "nearly_expired": { + Type: schema.TypeBool, + Computed: true, + }, + "maintenance_expiry_date": { + Type: schema.TypeString, + Computed: true, + }, + "maintenance_expired": { + Type: schema.TypeBool, + Computed: true, + }, + "license_type": { + Type: schema.TypeString, + Computed: true, + }, + "expiry_date": { + Type: schema.TypeString, + Computed: true, + }, + "raw_license": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "renewable": { + Type: schema.TypeBool, + Computed: true, + }, + "organization_name": { + Type: schema.TypeString, + Computed: true, + }, + "contact_email": { + Type: schema.TypeString, + Computed: true, + }, + "enterprise": { + Type: schema.TypeBool, + Computed: true, + }, + "data_center": { + Type: schema.TypeBool, + Computed: true, + }, + "subscription": { + Type: schema.TypeBool, + Computed: true, + }, + "active": { + Type: schema.TypeBool, + Computed: true, + }, + "auto_renewal": { + Type: schema.TypeBool, + Computed: true, + }, + "upgradable": { + Type: schema.TypeBool, + Computed: true, + }, + "crossgradeable": { + Type: schema.TypeBool, + Computed: true, + }, + "purchase_past_server_cutoff_date": { + Type: schema.TypeBool, + Computed: true, + }, + "support_entitlement_number": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourcePluginCreate(d *schema.ResourceData, m interface{}) error { + provider := m.(*BitbucketServerProvider) + + key := d.Get("key").(string) + version := d.Get("version").(string) + + marketplacePluginVersion, err := readMarketplacePluginVersion(key, version, provider) + if err != nil { + return err + } + + file, err := ioutil.TempFile(os.TempDir(), "*"+marketplacePluginVersion.Filename()) + if err != nil { + return err + } + + defer os.Remove(file.Name()) + + // download the plugin artifact for uploading to the API + err = provider.MarketplaceClient.DownloadArtifact(marketplacePluginVersion.Embedded.Artifact.Links.Binary.Href, file) + if err != nil { + return err + } + + err = file.Close() + if err != nil { + return err + } + + // first get a token for interacting with the UPM + resp, err := provider.BitbucketClient.Get("/rest/plugins/1.0/?os_authType=basic") + if err != nil { + return err + } + upmToken := resp.Header.Get("upm-token") + + // now we can use the token to upload the downloaded marketplace file to bitbucket + _, err = provider.BitbucketClient.PostFileUpload("/rest/plugins/1.0/?token="+upmToken, nil, "plugin", file.Name()) + if err != nil { + return err + } + + d.SetId(key) + + err = resource.Retry(d.Timeout(schema.TimeoutCreate), + func() *resource.RetryError { + exists, err := resourcePluginExists(d, m) + if exists == false || err != nil { + return resource.RetryableError(fmt.Errorf("Waiting for plugin installation to finish...")) + } else { + return nil + } + }) + if err != nil { + return err + } + + // need to also run an update loop to set enabled flags and license details + err = resource.Retry(d.Timeout(schema.TimeoutCreate), + func() *resource.RetryError { + err := resourcePluginUpdate(d, m) + if err != nil { + return resource.RetryableError(fmt.Errorf("Waiting for plugin updates to finish...")) + } else { + return nil + } + }) + if err != nil { + return err + } + + return nil +} + +func resourcePluginUpdate(d *schema.ResourceData, m interface{}) error { + client := m.(*BitbucketServerProvider).BitbucketClient + + key := d.Get("key").(string) + + if d.IsNewResource() || d.HasChange("enabled") { + var plugin Plugin + req, err := client.Do("GET", fmt.Sprintf("/rest/plugins/1.0/%s-key?os_authType=basic", key), nil, "application/vnd.atl.plugins.plugin+json") + if err != nil { + return nil + } + + body, readErr := ioutil.ReadAll(req.Body) + if readErr != nil { + return readErr + } + + decodeErr := json.Unmarshal(body, &plugin) + if decodeErr != nil { + return decodeErr + } + + plugin.Enabled = d.Get("enabled").(bool) + bytedata, err := json.Marshal(plugin) + _, err = client.Do("PUT", fmt.Sprintf("/rest/plugins/1.0/%s-key?os_authType=basic", key), bytes.NewBuffer(bytedata), "application/vnd.atl.plugins.plugin+json") + if err != nil { + return err + } + } + + if d.IsNewResource() || d.HasChange("license") { + license := d.Get("license").(string) + if license != "" { + licenseJson := map[string]string{"rawLicense": license} + bytedata, err := json.Marshal(licenseJson) + if err != nil { + return err + } + + req, err := client.Do("PUT", fmt.Sprintf("/rest/plugins/1.0/%s-key/license?os_authType=basic", key), bytes.NewBuffer(bytedata), "application/vnd.atl.plugins+json") + + // ignore 400 errors as this happens if the license is already applied + if req == nil || (err != nil && req != nil && req.StatusCode != 400) { + return err + } + } else { + _, err := client.Do("DELETE", fmt.Sprintf("/rest/plugins/1.0/%s-key/license?os_authType=basic", key), nil, "application/vnd.atl.plugins+json") + if err != nil { + return err + } + } + } + + return resourcePluginRead(d, m) +} + +func resourcePluginRead(d *schema.ResourceData, m interface{}) error { + id := d.Id() + if id != "" { + _ = d.Set("key", id) + } + + client := m.(*BitbucketServerProvider).BitbucketClient + req, err := client.Get(fmt.Sprintf("/rest/plugins/1.0/%s-key", d.Get("key").(string))) + if err != nil { + return err + } + + var plugin Plugin + + body, readErr := ioutil.ReadAll(req.Body) + if readErr != nil { + return readErr + } + + decodeErr := json.Unmarshal(body, &plugin) + if decodeErr != nil { + return decodeErr + } + + _ = d.Set("enabled", plugin.Enabled) + _ = d.Set("enabled_by_default", plugin.EnabledByDefault) + _ = d.Set("version", plugin.Version) + _ = d.Set("description", plugin.Description) + _ = d.Set("name", plugin.Name) + _ = d.Set("user_installed", plugin.UserInstalled) + _ = d.Set("optional", plugin.Optional) + + vendor := map[string]string{ + "name": plugin.Vendor.Name, + "link": plugin.Vendor.Link, + "marketplace_link": plugin.Vendor.MarketplaceLink, + } + _ = d.Set("vendor", vendor) + + // Hit the license API to get license details + + req, err = client.Get(fmt.Sprintf("/rest/plugins/1.0/%s-key/license", d.Get("key").(string))) + if err != nil { + return err + } + + var pluginLicense PluginLicense + + body, readErr = ioutil.ReadAll(req.Body) + if readErr != nil { + return readErr + } + + decodeErr = json.Unmarshal(body, &pluginLicense) + if decodeErr != nil { + return decodeErr + } + + license := [1]map[string]interface{}{{ + "valid": pluginLicense.Valid, + "evaluation": pluginLicense.Evaluation, + "nearly_expired": pluginLicense.NearlyExpired, + "maintenance_expiry_date": pluginLicense.MaintenanceExpiryDate.String(), + "maintenance_expired": pluginLicense.MaintenanceExpired, + "license_type": pluginLicense.LicenseType, + "expiry_date": pluginLicense.ExpiryDate.String(), + "raw_license": pluginLicense.RawLicense, + "renewable": pluginLicense.Renewable, + "organization_name": pluginLicense.OrganizationName, + "contact_email": pluginLicense.ContactEmail, + "enterprise": pluginLicense.Enterprise, + "data_center": pluginLicense.DataCenter, + "subscription": pluginLicense.Subscription, + "active": pluginLicense.Active, + "auto_renewal": pluginLicense.AutoRenewal, + "upgradable": pluginLicense.Upgradable, + "crossgradeable": pluginLicense.Crossgradeable, + "purchase_past_server_cutoff_date": pluginLicense.PurchasePastServerCutoffDate, + "support_entitlement_number": pluginLicense.SupportEntitlementNumber, + }} + _ = d.Set("applied_license", license) + + return nil +} + +func resourcePluginExists(d *schema.ResourceData, m interface{}) (bool, error) { + var key = "" + id := d.Id() + if id != "" { + key = id + } else { + key = d.Get("key").(string) + } + + client := m.(*BitbucketServerProvider).BitbucketClient + req, err := client.Get(fmt.Sprintf("/rest/plugins/1.0/%s-key", + key, + )) + + if err != nil { + return false, fmt.Errorf("failed to get plugin %s from bitbucket: %+v", key, err) + } + + if req.StatusCode == 200 { + return true, nil + } else { + return false, nil + } +} + +func resourcePluginDelete(d *schema.ResourceData, m interface{}) error { + client := m.(*BitbucketServerProvider).BitbucketClient + _, err := client.Delete(fmt.Sprintf("/rest/plugins/1.0/%s-key", + d.Get("key").(string), + )) + + return err +} + +func readMarketplacePluginVersion(key string, version string, provider *BitbucketServerProvider) (*PluginMarketplaceVersion, error) { + marketplaceRequest, err := provider.MarketplaceClient.Get(fmt.Sprintf("/rest/2/addons/%s/versions/name/%s", key, version)) + if err != nil { + return nil, err + } + + var marketplaceVersion PluginMarketplaceVersion + + body, readerr := ioutil.ReadAll(marketplaceRequest.Body) + if readerr != nil { + return nil, readerr + } + + decodeerr := json.Unmarshal(body, &marketplaceVersion) + if decodeerr != nil { + return nil, decodeerr + } + + return &marketplaceVersion, nil +} diff --git a/bitbucket/resource_plugin_test.go b/bitbucket/resource_plugin_test.go new file mode 100644 index 0000000..17c9512 --- /dev/null +++ b/bitbucket/resource_plugin_test.go @@ -0,0 +1,59 @@ +package bitbucket + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccBitbucketPlugin_install(t *testing.T) { + config := ` + resource "bitbucketserver_plugin" "test" { + key = "com.plugin.commitgraph.commitgraph" + version = "5.3.3" + license = "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "key", "com.plugin.commitgraph.commitgraph"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "enabled", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "version", "5.3.3"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "license", "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "enabled_by_default", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "name", "Charts and Graphs for Bitbucket Server"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "description", "Gain insight into Bitbucket with charts and graphs that help you visualize user contributions, commits, and team activity."), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "user_installed", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "optional", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "vendor.name", "Mohami"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "vendor.link", "https://mohami.io"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "vendor.marketplace_link", "https://mohami.io"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.valid", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.evaluation", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.nearly_expired", "true"), + resource.TestCheckResourceAttrSet("bitbucketserver_plugin.test", "applied_license.0.maintenance_expiry_date"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.maintenance_expired", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.license_type", "DEVELOPER"), + resource.TestCheckResourceAttrSet("bitbucketserver_plugin.test", "applied_license.0.expiry_date"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.raw_license", "AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.renewable", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.organization_name", "Atlassian"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.enterprise", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.data_center", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.subscription", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.active", "true"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.auto_renewal", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.upgradable", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.crossgradeable", "false"), + resource.TestCheckResourceAttr("bitbucketserver_plugin.test", "applied_license.0.purchase_past_server_cutoff_date", "true"), + ), + }, + }, + }) +} diff --git a/bitbucket/resource_project.go b/bitbucket/resource_project.go index 9046af3..09b4931 100644 --- a/bitbucket/resource_project.go +++ b/bitbucket/resource_project.go @@ -67,7 +67,7 @@ func newProjectFromResource(d *schema.ResourceData) *Project { } func resourceProjectUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient project := newProjectFromResource(d) bytedata, err := json.Marshal(project) @@ -88,7 +88,7 @@ func resourceProjectUpdate(d *schema.ResourceData, m interface{}) error { } func resourceProjectCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient project := newProjectFromResource(d) bytedata, err := json.Marshal(project) @@ -116,7 +116,7 @@ func resourceProjectRead(d *schema.ResourceData, m interface{}) error { project := d.Get("key").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient project_req, err := client.Get(fmt.Sprintf("/rest/api/1.0/projects/%s", project, )) @@ -158,7 +158,7 @@ func resourceProjectExists(d *schema.ResourceData, m interface{}) (bool, error) project = d.Get("key").(string) } - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient repo_req, err := client.Get(fmt.Sprintf("/rest/api/1.0/projects/%s", project, )) @@ -176,7 +176,7 @@ func resourceProjectExists(d *schema.ResourceData, m interface{}) (bool, error) func resourceProjectDelete(d *schema.ResourceData, m interface{}) error { project := d.Get("key").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s", project, )) diff --git a/bitbucket/resource_project_permissions_group.go b/bitbucket/resource_project_permissions_group.go index 9c5e414..61b601c 100644 --- a/bitbucket/resource_project_permissions_group.go +++ b/bitbucket/resource_project_permissions_group.go @@ -39,7 +39,7 @@ func resourceProjectPermissionsGroup() *schema.Resource { } func resourceProjectPermissionsGroupUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/groups?permission=%s&name=%s", d.Get("project").(string), url.QueryEscape(d.Get("permission").(string)), @@ -93,7 +93,7 @@ func resourceProjectPermissionsGroupRead(d *schema.ResourceData, m interface{}) } func resourceProjectPermissionsGroupDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/groups?name=%s", d.Get("project").(string), url.QueryEscape(d.Get("group").(string)), diff --git a/bitbucket/resource_project_permissions_user.go b/bitbucket/resource_project_permissions_user.go index e07d625..ae37883 100644 --- a/bitbucket/resource_project_permissions_user.go +++ b/bitbucket/resource_project_permissions_user.go @@ -39,7 +39,7 @@ func resourceProjectPermissionsUser() *schema.Resource { } func resourceProjectPermissionsUserUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/users?permission=%s&name=%s", d.Get("project").(string), url.QueryEscape(d.Get("permission").(string)), @@ -93,7 +93,7 @@ func resourceProjectPermissionsUserRead(d *schema.ResourceData, m interface{}) e } func resourceProjectPermissionsUserDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s/permissions/users?name=%s", d.Get("project").(string), url.QueryEscape(d.Get("user").(string)), diff --git a/bitbucket/resource_project_test.go b/bitbucket/resource_project_test.go index 3bf5cbc..4f40039 100644 --- a/bitbucket/resource_project_test.go +++ b/bitbucket/resource_project_test.go @@ -34,7 +34,7 @@ func TestAccBitbucketProject(t *testing.T) { } func testAccCheckBitbucketProjectDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*BitbucketClient) + client := testAccProvider.Meta().(*BitbucketServerProvider).BitbucketClient rs, ok := s.RootModule().Resources["bitbucketserver_project.test"] if !ok { return fmt.Errorf("not found %s", "bitbucketserver_project.test") diff --git a/bitbucket/resource_repository.go b/bitbucket/resource_repository.go index 8de5e19..b2f9a9e 100644 --- a/bitbucket/resource_repository.go +++ b/bitbucket/resource_repository.go @@ -92,7 +92,7 @@ func newRepositoryFromResource(d *schema.ResourceData) (Repo *Repository, Projec } func resourceRepositoryUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient repo, project := newRepositoryFromResource(d) bytedata, err := json.Marshal(repo) @@ -116,7 +116,7 @@ func resourceRepositoryUpdate(d *schema.ResourceData, m interface{}) error { } func resourceRepositoryCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient repo, project := newRepositoryFromResource(d) bytedata, err := json.Marshal(repo) @@ -153,7 +153,7 @@ func resourceRepositoryRead(d *schema.ResourceData, m interface{}) error { repoSlug := determineSlug(d) project := d.Get("project").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient repo_req, err := client.Get(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s", project, repoSlug, @@ -212,7 +212,7 @@ func resourceRepositoryExists(d *schema.ResourceData, m interface{}) (bool, erro } } - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient repo_req, err := client.Get(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s", project, repoSlug, @@ -232,7 +232,7 @@ func resourceRepositoryExists(d *schema.ResourceData, m interface{}) (bool, erro func resourceRepositoryDelete(d *schema.ResourceData, m interface{}) error { repoSlug := determineSlug(d) project := d.Get("project").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s", project, repoSlug, diff --git a/bitbucket/resource_repository_permissions_group.go b/bitbucket/resource_repository_permissions_group.go index cd7bc1b..ce44289 100644 --- a/bitbucket/resource_repository_permissions_group.go +++ b/bitbucket/resource_repository_permissions_group.go @@ -44,7 +44,7 @@ func resourceRepositoryPermissionsGroup() *schema.Resource { } func resourceRepositoryPermissionsGroupUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/groups?permission=%s&name=%s", url.QueryEscape(d.Get("project").(string)), url.QueryEscape(d.Get("repository").(string)), @@ -100,7 +100,7 @@ func resourceRepositoryPermissionsGroupRead(d *schema.ResourceData, m interface{ } func resourceRepositoryPermissionsGroupDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/groups?name=%s", url.QueryEscape(d.Get("project").(string)), url.QueryEscape(d.Get("repository").(string)), diff --git a/bitbucket/resource_repository_permissions_user.go b/bitbucket/resource_repository_permissions_user.go index 0cf9bdd..d2432b5 100644 --- a/bitbucket/resource_repository_permissions_user.go +++ b/bitbucket/resource_repository_permissions_user.go @@ -44,7 +44,7 @@ func resourceRepositoryPermissionsUser() *schema.Resource { } func resourceRepositoryPermissionsUserUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Put(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/users?permission=%s&name=%s", url.QueryEscape(d.Get("project").(string)), url.QueryEscape(d.Get("repository").(string)), @@ -100,7 +100,7 @@ func resourceRepositoryPermissionsUserRead(d *schema.ResourceData, m interface{} } func resourceRepositoryPermissionsUserDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/permissions/users?name=%s", url.QueryEscape(d.Get("project").(string)), url.QueryEscape(d.Get("repository").(string)), diff --git a/bitbucket/resource_repository_test.go b/bitbucket/resource_repository_test.go index cda324b..0a421ed 100644 --- a/bitbucket/resource_repository_test.go +++ b/bitbucket/resource_repository_test.go @@ -72,7 +72,7 @@ func TestAccBitbucketRepository_namewithspaces(t *testing.T) { } func testAccCheckBitbucketRepositoryDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*BitbucketClient) + client := testAccProvider.Meta().(*BitbucketServerProvider).BitbucketClient rs, ok := s.RootModule().Resources["bitbucketserver_repository.test_repo"] if !ok { return fmt.Errorf("not found %s", "bitbucketserver_repository.test_repo") diff --git a/bitbucket/resource_user.go b/bitbucket/resource_user.go index a34e0de..7ceb12b 100644 --- a/bitbucket/resource_user.go +++ b/bitbucket/resource_user.go @@ -84,7 +84,7 @@ func newUserFromResource(d *schema.ResourceData) *User { } func resourceUserUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient user := newUserFromResource(d) bytedata, err := json.Marshal(user) @@ -105,7 +105,7 @@ func resourceUserUpdate(d *schema.ResourceData, m interface{}) error { } func resourceUserCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient user := newUserFromResource(d) passwordLength := d.Get("password_length").(int) @@ -136,7 +136,7 @@ func resourceUserRead(d *schema.ResourceData, m interface{}) error { name := d.Get("name").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient req, err := client.Get(fmt.Sprintf("/rest/api/1.0/users/%s", url.QueryEscape(name), )) @@ -176,7 +176,7 @@ func resourceUserExists(d *schema.ResourceData, m interface{}) (bool, error) { name = d.Get("name").(string) } - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient req, err := client.Get(fmt.Sprintf("/rest/api/1.0/users/%s", url.QueryEscape(name), )) @@ -194,7 +194,7 @@ func resourceUserExists(d *schema.ResourceData, m interface{}) (bool, error) { func resourceUserDelete(d *schema.ResourceData, m interface{}) error { name := d.Get("name").(string) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient _, err := client.Delete(fmt.Sprintf("/rest/api/1.0/admin/users?name=%s", url.QueryEscape(name), )) diff --git a/bitbucket/resource_user_group.go b/bitbucket/resource_user_group.go index 964157a..56849e1 100644 --- a/bitbucket/resource_user_group.go +++ b/bitbucket/resource_user_group.go @@ -47,7 +47,7 @@ func newUserGroupFromResource(d *schema.ResourceData) *UserGroup { } func resourceUserGroupCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient type UserGroupRequest struct { User string `json:"user,omitempty"` @@ -110,7 +110,7 @@ func resourceUserGroupDelete(d *schema.ResourceData, m interface{}) error { userGroup := newUserGroupFromResource(d) - client := m.(*BitbucketClient) + client := m.(*BitbucketServerProvider).BitbucketClient type RemoveRequest struct { User string `json:"context,omitempty"` diff --git a/bitbucket/resource_user_test.go b/bitbucket/resource_user_test.go index f667821..53e6b4a 100644 --- a/bitbucket/resource_user_test.go +++ b/bitbucket/resource_user_test.go @@ -39,7 +39,7 @@ func TestAccBitbucketUser(t *testing.T) { } func testAccCheckBitbucketUserDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*BitbucketClient) + client := testAccProvider.Meta().(*BitbucketServerProvider).BitbucketClient rs, ok := s.RootModule().Resources["bitbucketserver_user.test"] if !ok { return fmt.Errorf("not found %s", "bitbucketserver_user.test") diff --git a/scripts/start-docker-compose.sh b/scripts/start-docker-compose.sh index e227bf2..5b3a910 100755 --- a/scripts/start-docker-compose.sh +++ b/scripts/start-docker-compose.sh @@ -15,20 +15,3 @@ ${DIR}/docker-compose up -d --build echo "--> Wait for bitbucket to be ready" bash ${DIR}/wait-for-url.sh --url http://localhost:7990/status --timeout 600 - -echo "--> Install a plugin for tests to reference licensing etc" -if [ ! -f ${DIR}/docker-compose-test-plugin.jar ]; then - curl -L -o ${DIR}/docker-compose-test-plugin.jar https://marketplace.atlassian.com/download/apps/1211185/version/400500101 -fi - -url="http://admin:admin@localhost:7990/rest/plugins/1.0/"; \ -token=$(curl -H 'X-Atlassian-Token: no-check' -sI "$url?os_authType=basic" | grep upm-token | cut -d: -f2- | tr -d '[[:space:]]'); \ -curl -H 'X-Atlassian-Token: no-check' -XPOST "$url?token=$token" -F plugin=@${DIR}/docker-compose-test-plugin.jar -sleep 10 - -echo "--> Apply a timebomb license for the plugin" -PLUGIN_LICENSE="AAABCA0ODAoPeNpdj01PwkAURffzKyZxZ1IyUzARkllQ24gRaQMtGnaP8VEmtjPNfFT59yJVFyzfubkn796Ux0Bz6SmbUM5nbDzj97RISxozHpMUnbSq88poUaLztFEStUN6MJZ2TaiVpu/YY2M6tI6sQrtHmx8qd74EZ+TBIvyUU/AoYs7jiE0jzknWQxMuifA2IBlUbnQ7AulVjwN9AaU9atASs69O2dNFU4wXJLc1aOUGw9w34JwCTTZoe7RPqUgep2X0Vm0n0fNut4gSxl/Jcnj9nFb6Q5tP/Ueu3L+0PHW4ghZFmm2zZV5k6/95CbR7Y9bYGo/zGrV3Ir4jRbDyCA6vt34DO8p3SDAsAhQnJjLD5k9Fr3uaIzkXKf83o5vDdQIUe4XequNCC3D+9ht9ZYhNZFKmnhc=X02dh" -PLUGIN_LICENSE_ENDPOINT="http://admin:admin@localhost:7990/rest/plugins/1.0/nl.stefankohler.stash.stash-notification-plugin-key/license?os_authType=basic" - -curl -H 'X-Atlassian-Token: no-check' -H 'Content-Type: application/vnd.atl.plugins+json' \ - -X PUT -d "{\"rawLicense\": \"${PLUGIN_LICENSE}\"}" ${PLUGIN_LICENSE_ENDPOINT}