167 wipe.go
@@ -2,13 +2,12 @@ package main

import (
"fmt"
"strings"
"regexp"
// "github.com/davecgh/go-spew/spew"
"encoding/xml"
"path/filepath"
"os"
"io/ioutil"
"strings"
// "github.com/davecgh/go-spew/spew"
"encoding/xml"
"io/ioutil"
"os"
"path/filepath"
)

var cmdWipe = &Command{
@@ -38,137 +37,97 @@ Examples:
// destructiveChanges
// https://developer.salesforce.com/docs/atlas.en-us.daas.meta/daas/daas_destructive_changes.htm

func runWipe(cmd *Command, args []string) {
force, _ := ActiveForce()

func metadataEnumerator(files ForceMetadataFiles, metadataName string, metadataFolderPath string, metadataFileExtension string, ignoreRegex string) MetaType {
ApexClassTypeEntry := MetaType{
Name: metadataName,
Members: make([]string, 0),
}

// now, the only way to infer the resources it determine it from the regularly-formatted
// names of metadata items that were returned to us in a the package (the Metadata API actually
// returned a ZIP file)
// compile a regex:
ApexClassNameScraper, err := regexp.Compile(fmt.Sprintf("^%s\\/(.*)\\.%s$", metadataFolderPath, metadataFileExtension))
if err != nil {
ErrorAndExit(err.Error())
}

IgnoreMatcher, err := regexp.Compile(ignoreRegex)
if err != nil {
ErrorAndExit(err.Error())
}

for name, _ := range files {
// fmt.Printf("%s\n", name)
MatchedName := ApexClassNameScraper.FindStringSubmatch(name)

//spew.Printf("shitpoop: %v\n", MatchedName)

if MatchedName != nil && len(MatchedName) == 2 {
ApexClassName := MatchedName[1]
// fmt.Printf("MATCHED AN APEX CLASS: %s\n", ApexClassName)

// now, check if it matches the ignore regex:
// fmt.Printf("TESTING IF STRING MATCHES: %s\n", ApexClassName)
if !IgnoreMatcher.MatchString(ApexClassName) {
ApexClassTypeEntry.Members = append(ApexClassTypeEntry.Members, ApexClassName)
}
}
}

return ApexClassTypeEntry
}

func runWipe(cmd *Command, args[]string) {
force, _ := ActiveForce()


// a first attempt to discover files via metadata api, but, frankly,
// we may want to not touch any Apex classes not in our local project. TODO make it switchable!
query := ForceMetadataQuery{
{Name: "ApexClass", Members: []string{"*"}},
// a first attempt to discover files via metadata api, but, frankly,
// we may want to not touch any Apex classes not in our local project. TODO make it switchable!
query := ForceMetadataQuery{
{Name: "ApexClass", Members: []string{"*"}},
//{Name: "ApexComponent", Members: []string{"*"}},
// {Name: "ApexPage", Members: []string{"*"}},
{Name: "ApexTrigger", Members: []string{"*"}},
{Name: "FlowDefinition", Members: []string{"*"}},
{Name: "Flow", Members: []string{"*"}},
}
salesforceSideFiles, err := force.Metadata.Retrieve(query)
{Name: "FlowDefinition", Members: []string{"*"}},
{Name: "Flow", Members: []string{"*"}},
}
salesforceSideFiles, err := force.Metadata.Retrieve(query)
if err != nil {
fmt.Printf("Encountered an error with retrieve...\n")
ErrorAndExit(err.Error())
}

root := DetermineProjectPath("joist/src") // lol

files := make(ForceMetadataFiles)

err = filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if f.Mode().IsRegular() {
if f.Name() != ".DS_Store" {
data, err := ioutil.ReadFile(path)
if err != nil {
ErrorAndExit(err.Error())
}
files[strings.Replace(path, fmt.Sprintf("%s%s", root, string(os.PathSeparator)), "", -1)] = data
}
}
return nil
root := DetermineProjectPath("joist/src") // lol

files := make(ForceMetadataFiles)

// TODO this was copypasta'd from elsewhere. Should be refactored.
err = filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if f.Mode().IsRegular() {
if f.Name() != ".DS_Store" {
data, err := ioutil.ReadFile(path)
if err != nil {
ErrorAndExit(err.Error())
}
files[strings.Replace(path, fmt.Sprintf("%s%s", root, string(os.PathSeparator)), "", -1)] = data
}
}
return nil
})

// now, we want to generate a destructiveChanges.xml. It's in
// the same format as package.xml, so we'll borrow the types
// from package builder. (And then, we'll actually use
// we'll actually use packagebuilder to build a deployable
// package that contains just that destructiveChanges.xml)
// now, we want to generate a destructiveChanges.xml. It's in
// the same format as package.xml, so we'll borrow the types
// from package builder. (And then, we'll actually use
// we'll actually use packagebuilder to build a deployable
// package that contains just that destructiveChanges.xml)

DestructiveChanges := Package{
DestructiveChanges := Package{
Version: strings.TrimPrefix(apiVersion, "v"),
Xmlns: "http://soap.sforce.com/2006/04/metadata",
}

DestructiveChanges.Types = make([]MetaType, 0)
DestructiveChanges.Types = make([]MetaType, 0)

// shit. looks like deletes have to be ordered by dependencies in the XML file, since it's all just processed as dumb commands.
// shit. looks like deletes have to be ordered by dependencies in the XML file, since it's all just processed as dumb commands.

// DEACTIVATE ALL FLOWS
// DELETE ALL VISUALFORCE PAGES (and put up empty ones to work around limitation of at least 1 layout must be present)
DestructiveChanges.Types = append(DestructiveChanges.Types, metadataEnumerator(salesforceSideFiles, "ApexTrigger", "triggers", "trigger", "^DS"))
DestructiveChanges.Types = append(DestructiveChanges.Types, metadataEnumerator(salesforceSideFiles, "ApexClass", "classes", "cls", "^DS|^test_DS"))
DestructiveChanges.Types = append(DestructiveChanges.Types, metadataEnumerator(salesforceSideFiles, "Flow", "flows", "flow", "bogusbogusbogusbogusbogusbogus"))
// DestructiveChanges.Types = append(DestructiveChanges.Types, metadataEnumerator(salesforceSideFiles, "FlowDefinition", "flowDefinitions", "flowDefinition"))
// DEACTIVATE ALL FLOWS
// DELETE ALL VISUALFORCE PAGES (and put up empty ones to work around limitation of at least 1 layout must be present)
filesForType := enumerateMetadataByType(salesforceSideFiles, "ApexTrigger", "triggers", "trigger", "^DS")

// OTHER DEPLOY STEPS:
DestructiveChanges.Types = append(DestructiveChanges.Types, filesForType.MetaType())
filesForType = enumerateMetadataByType(salesforceSideFiles, "ApexClass", "classes", "cls", "^DS|^test_DS")
DestructiveChanges.Types = append(DestructiveChanges.Types, filesForType.MetaType())
filesForType = enumerateMetadataByType(salesforceSideFiles, "Flow", "flows", "flow", "bogusbogusbogusbogusbogusbogus")
DestructiveChanges.Types = append(DestructiveChanges.Types, filesForType.MetaType())
// DestructiveChanges.Types = append(DestructiveChanges.Types, metadataEnumerator(salesforceSideFiles, "FlowDefinition", "flowDefinitions", "flowDefinition"))

// DELETE ALL FLOWS
//
// OTHER DEPLOY STEPS:

// DELETE ALL FLOWS
//

// TODO prompt the user with a list of all files that will be deleted!
// TODO prompt the user with a list of all files that will be deleted!

// spew.Dump(DestructiveChanges)
// spew.Dump(DestructiveChanges)

byteXML, _ := xml.MarshalIndent(DestructiveChanges, "", " ")
byteXML = append([]byte(xml.Header), byteXML...)
fmt.Printf("Generated destructiveChanges.xml: %s\n", string(byteXML))
byteXML, _ := xml.MarshalIndent(DestructiveChanges, "", " ")
byteXML = append([]byte(xml.Header), byteXML...)
fmt.Printf("Generated destructiveChanges.xml: %s\n", string(byteXML))

var DeploymentOptions ForceDeployOptions
DeploymentOptions.AllowMissingFiles = true
var DeploymentOptions ForceDeployOptions
DeploymentOptions.AllowMissingFiles = true
DeploymentOptions.AutoUpdatePackage = false
DeploymentOptions.CheckOnly = true // lol
DeploymentOptions.IgnoreWarnings = false
DeploymentOptions.PurgeOnDelete = false
DeploymentOptions.RollbackOnError = true
DeploymentOptions.TestLevel = "RunLocalTests"

packageBuilder := NewPushBuilder()
packageBuilder.AddDestructiveChangesData(byteXML)

packageBuilder := NewPushBuilder()
packageBuilder.AddDestructiveChangesData(byteXML)

fmt.Printf("Now deploying destructiveChanges.xml...")
fmt.Printf("Now deploying destructiveChanges.xml...")

_, err = force.Metadata.Deploy(packageBuilder.ForceMetadataFiles(), DeploymentOptions)
_, err = force.Metadata.Deploy(packageBuilder.ForceMetadataFiles(), DeploymentOptions)
//problems := result.Details.ComponentFailures
//successes := result.Details.ComponentSuccesses
if err != nil {