diff --git a/post-processor/vagrant-cloud/post-processor.go b/post-processor/vagrant-cloud/post-processor.go index 8a7f53ebc..f6a5b2dfe 100644 --- a/post-processor/vagrant-cloud/post-processor.go +++ b/post-processor/vagrant-cloud/post-processor.go @@ -1,6 +1,7 @@ // vagrant_cloud implements the packer.PostProcessor interface and adds a // post-processor that uploads artifacts from the vagrant post-processor -// to Vagrant Cloud (vagrantcloud.com) +// to Vagrant Cloud (vagrantcloud.com) or manages self hosted boxes on the +// Vagrant Cloud package vagrantcloud import ( @@ -25,9 +26,16 @@ type Config struct { AccessToken string `mapstructure:"access_token"` VagrantCloudUrl string `mapstructure:"vagrant_cloud_url"` + BoxDownloadUrl string `mapstructure:"box_download_url"` + tpl *packer.ConfigTemplate } +type boxDownloadUrlTemplate struct { + ArtifactId string + Provider string +} + type PostProcessor struct { config Config client *VagrantCloudClient @@ -103,6 +111,14 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac // The name of the provider for vagrant cloud, and vagrant providerName := providerFromBuilderName(artifact.Id()) + boxDownloadUrl, err := p.config.tpl.Process(p.config.BoxDownloadUrl, &boxDownloadUrlTemplate { + ArtifactId: artifact.Id(), + Provider: providerName, + }) + if err != nil { + return nil, false, fmt.Errorf("Error processing box_download_url: %s", err) + } + // Set up the state state := new(multistep.BasicStateBag) state.Put("config", p.config) @@ -111,16 +127,27 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac state.Put("artifactFilePath", artifact.Files()[0]) state.Put("ui", ui) state.Put("providerName", providerName) + state.Put("boxDownloadUrl", boxDownloadUrl) // Build the steps - steps := []multistep.Step{ - new(stepVerifyBox), - new(stepCreateVersion), - new(stepCreateProvider), - new(stepPrepareUpload), - new(stepUpload), - new(stepVerifyUpload), - new(stepReleaseVersion), + steps := []multistep.Step{} + if p.config.BoxDownloadUrl == "" { + steps = []multistep.Step{ + new(stepVerifyBox), + new(stepCreateVersion), + new(stepCreateProvider), + new(stepPrepareUpload), + new(stepUpload), + new(stepVerifyUpload), + new(stepReleaseVersion), + } + } else { + steps = []multistep.Step{ + new(stepVerifyBox), + new(stepCreateVersion), + new(stepCreateProvider), + new(stepReleaseVersion), + } } // Run the steps diff --git a/post-processor/vagrant-cloud/step_create_provider.go b/post-processor/vagrant-cloud/step_create_provider.go index 887932c4f..c2d6772bd 100644 --- a/post-processor/vagrant-cloud/step_create_provider.go +++ b/post-processor/vagrant-cloud/step_create_provider.go @@ -8,6 +8,7 @@ import ( type Provider struct { Name string `json:"name"` + Url string `json:"url,omitempty"` HostedToken string `json:"hosted_token,omitempty"` UploadUrl string `json:"upload_url,omitempty"` } @@ -22,11 +23,16 @@ func (s *stepCreateProvider) Run(state multistep.StateBag) multistep.StepAction box := state.Get("box").(*Box) version := state.Get("version").(*Version) providerName := state.Get("providerName").(string) + downloadUrl := state.Get("boxDownloadUrl").(string) path := fmt.Sprintf("box/%s/version/%v/providers", box.Tag, version.Number) provider := &Provider{Name: providerName} + if downloadUrl != "" { + provider.Url = downloadUrl + } + // Wrap the provider in a provider object for the API wrapper := make(map[string]interface{}) wrapper["provider"] = provider diff --git a/post-processor/vagrant-cloud/step_release_version.go b/post-processor/vagrant-cloud/step_release_version.go index 43512bdca..d8809f9ca 100644 --- a/post-processor/vagrant-cloud/step_release_version.go +++ b/post-processor/vagrant-cloud/step_release_version.go @@ -2,6 +2,7 @@ package vagrantcloud import ( "fmt" + "strings" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" ) @@ -30,6 +31,10 @@ func (s *stepReleaseVersion) Run(state multistep.StateBag) multistep.StepAction if err != nil || (resp.StatusCode != 200) { cloudErrors := &VagrantCloudErrors{} err = decodeBody(resp, cloudErrors) + if strings.Contains(cloudErrors.FormatErrors(), "already been released") { + ui.Message("Not releasing version, already released") + return multistep.ActionContinue + } state.Put("error", fmt.Errorf("Error releasing version: %s", cloudErrors.FormatErrors())) return multistep.ActionHalt }