class MavenToolsTest(unittest.TestCase):

    #
    # Fixture Framework
    #
    #       gen                     const                      gen         const                    gen
    # http://nexus.art:8081 /nexus/service/local/repositories/ snapshots /content/ uk/gov/fsa/rsd/scenariomanager/ScenarioManager-webapp/ 1.0-SNAPSHOT /ScenarioManager-webapp-1.0-20110916.103149-102.war
    # http://nexus.art:8081 /nexus/service/local/repositories/ releases  /content/ uk/gov/fsa/rsd/scenariomanager/ScenarioManager-webapp/  0.8.2.B1    /ScenarioManager-webapp-0.8.2.B1.war

    def setUp(self):
        print "\nTest Fixture setUp"
        self.C = Config()
        self.C.validate_set_options()
        self.M = MavenTools("scenariomanager-webapp")

    def tearDown(self):
        print "\nTest Fixture tearDown"
        del self.C
        del self.M

    #
    # Tests
    #

    def test_01_tmp_dir_creation_deletion(self):
        print "\n running tmp_dir_creation_deletion"
        tmpdir = self.M.get_temp_dir()
        self.failUnlessEqual(True, os.path.isdir(tmpdir))
        self.M.cleanup_temp_dir()
        self.failUnlessEqual(False, os.path.isdir(tmpdir))
 def setUp(self):
     print '\nTest Fixture setUp'
     self.S = SvnTools()
     self.C = Config()
     self.C.validate_set_options()
     self.C.set_svn_host('sd1appsdl05.fsa.gov.uk')
     #self.C.set_svn_port('80')
     self.svn_url = self.C.get_svn_baseurl()
class SvnToolsTest(unittest.TestCase):

#
# Fixture Framework
#

    def setUp(self):
        print '\nTest Fixture setUp'
        self.S = SvnTools()
        self.C = Config()
        self.C.validate_set_options()
        self.C.set_svn_host('sd1appsdl05.fsa.gov.uk')
        #self.C.set_svn_port('80')
        self.svn_url = self.C.get_svn_baseurl()


    def tearDown(self):
        print '\nTest Fixture tearDown'
        del self.S
        del self.C
        del self.svn_url

#
# Tests
#

    def test_01_findpoms(self):
        print '\n running checkout'
        base_url = self.svn_url + '/' + 'mock-project'
        print base_url
        if os.path.isdir(os.path.join(os.path.expanduser('~'), 'tmp', 'svntest', 'testcheckout')):
            shutil.rmtree(os.path.join(os.path.expanduser('~'), 'tmp', 'svntest', 'testcheckout'))
        self.S.checkout(base_url, os.path.join(os.path.expanduser('~'), 'tmp', 'svntest', 'testcheckout', 'mock-project'))
        self.failUnlessEqual(True, os.path.isfile(os.path.join(os.path.expanduser('~'), 'tmp', 'svntest', 'testcheckout', 'mock-project', 'trunk', 'text.txt')))
        base_dir = os.path.join(os.path.expanduser('~'), 'tmp', 'svntest', 'testcheckout', 'mock-project')
        walker = ReWalker(base_dir, r"*\.pom$", [".svn"]).execute()
    def __init__(self, project, branch=None, revision=None, suppress_email=False, skip_tests=False):
        self.project = project
        if branch == None:
            self.branch = 'trunk'
        else:
            self.branch = branch

        if revision == None:
            self.revision = 'HEAD'
        else:
            self.revision = revision
        self.suppress_email = suppress_email
        self.tmpdir = None
        self.skip_tests = skip_tests
        self.S = SvnTools()
        self.C = Config()
        self.C.validate_set_options()
        self.V = VersionValidator()
        self.version = None
        self.pom = None
        self.buildtime = None
        self.svn_location = None
        self.svn_revision = None
        self.data = None
class MavenTools(object):

    def __init__(self, project, branch=None, revision=None, suppress_email=False, skip_tests=False):
        self.project = project
        if branch == None:
            self.branch = 'trunk'
        else:
            self.branch = branch

        if revision == None:
            self.revision = 'HEAD'
        else:
            self.revision = revision
        self.suppress_email = suppress_email
        self.tmpdir = None
        self.skip_tests = skip_tests
        self.S = SvnTools()
        self.C = Config()
        self.C.validate_set_options()
        self.V = VersionValidator()
        self.version = None
        self.pom = None
        self.buildtime = None
        self.svn_location = None
        self.svn_revision = None
        self.data = None

    def get_temp_dir(self):
        if self.tmpdir == None:
            try:
                tmpdir = tempfile.mkdtemp(prefix='releasetools-')
                self.tmpdir = tmpdir
                return tmpdir
            except Exception as e:
                print "Error Detected: {0}".format(e)
        else:
            try:
                os.path.isdir(self.tmpdir)
                return self.tmpdir
            except Exception as e:
                print "Error Detected: {0}".format(e)

    def cleanup_temp_dir(self):
        if self.tmpdir != '':
            try:
                shutil.rmtree(self.tmpdir)
            except Exception as e:
                print "Error Detected: {0}".format(e)

    def checkout_project(self, url, dest):
        try:
            self.S.checkout(url, dest, self.revision)
        except Exception as e:
            print "Error Detected: {0}".format(e)
            print """check your password, try resetting the .subversion password file if
            your password has changed
            """
            sys.exit(1)

    def build(self, project_dir):
        if os.path.curdir != project_dir:
            os.chdir(project_dir)
        if self.skip_tests == True:
            command_list = [mvn, '-e', 'clean', 'package', '-DskipTests', self.get_property_file()]
        else:
            command_list = [mvn, '-e', 'clean', 'package', self.get_property_file()]
        executePoll(command_list)
        self.update_build_info()

    def deploy(self, project_dir):
        if os.path.curdir != project_dir:
            os.chdir(project_dir)
        if self.skip_tests == True:
            command_list = [mvn, '-e', 'clean', 'deploy', '-DskipTests', self.get_property_file()]
        else:
            command_list = [mvn, '-e', 'clean', 'deploy', self.get_property_file()]
        executePoll(command_list)
        self.update_build_info()
    
    def cleanup_build(self, project_dir):
        if os.path.curdir != project_dir:
            os.chdir(project_dir)
        command_list = [mvn, '-e', 'clean']
        executePoll(command_list)    

    def release(self, version=None, drop=None):
        if version != None:
            assert self.V.is_valid_version(version)
            self.version = version
        
        self.get_temp_dir()
        base_url = self.C.get_svn_baseurl()
        url = '/'.join([base_url, self.project, self.branch])
        dest = os.path.join(self.get_temp_dir(), self.branch)
        self.checkout_project(url, dest)
        
        #must sort this out and make it smarter in order to use drops as branches.
        if drop == None:
            this_drop = 0
        
        if version == None:
            version = self.get_generated_version_number(drop=this_drop)
            self.version = version
            
        if self.is_mvn_project(dest):
            self.set_pom_version(self.version)
            self.deploy(dest)
            self.cleanup_build(dest)
            print "Attempting to Tag release", self.version
            tag_url = '/'.join([base_url, self.project, 'tags', 'a', '-'.join([self.project, self.version])])
            print tag_url
            ticket = '#1646'
            self.S.tag(dest, tag_url, 'refs {0} : {1} Release {2}'.format(ticket, self.project, self.version))
        self.email_release_notification()

    def package(self, version=None, drop=None):
        if version != None:
            assert self.V.is_valid_version(version)
            self.version = version
            
        self.get_temp_dir()
        base_url = self.C.get_svn_baseurl()
        url = '/'.join([base_url, self.project, self.branch])
        print "Checking out: {0} to {1}".format(url, self.get_temp_dir())
        dest = os.path.join(self.get_temp_dir(), self.branch)
        self.checkout_project(url, dest)
        
        #must sort this out and make it smarter in order to use drops as branches.
        if drop == None:
            this_drop = 0
        
        if version == None:
            version = self.get_generated_version_number(drop=this_drop)
            self.version = version        
        
        if self.is_mvn_project(dest):
            self.set_pom_version(self.version)
            self.build(dest)

    def is_mvn_project(self, dest):
        if os.path.exists(os.path.join(dest, 'pom.xml')):
            return True
        else:
            print "Error: Maven pom.xml file not found, possible problem with checkout"
            sys.exit(1)

    def get_poms(self):
        return fileFinder(os.path.join(self.get_temp_dir(), self.branch), "pom.xml")

    def update_build_info(self):
        if self.buildtime == None:
            self.buildtime = gmtime()
        if self.svn_location == None:
            self.svn_location = self.branch
        if self.svn_revision == None:
            self.svn_revision = self.S.get_wcopy_revision(os.path.join(self.get_temp_dir(), self.branch))

    def get_buildtime(self):
        return self.buildtime

    def get_svn_location(self):
        return self.svn_location

    def get_svn_revision(self):
        return self.svn_revision

    def get_version_built(self):
        return self.version

    def get_property_file(self):
        return '-D{0}_ENV_PROPERTIES=file:src/test/resources/{1}-unittest.properties'.format(self.project.upper(), self.project.lower())

    def read_pom(self, pom_file):
        if os.path.isfile(pom_file):
            f = open(pom_file, 'r')
            raw_pom = f.read()
            f.close()
            self.pom = parseString(raw_pom)
        return self.pom

    def write_pom(self, dom, pom_file):
        if os.path.isfile(pom_file):
            f = open(pom_file, 'w')
            f.write(dom.toxml())
            f.close()
        self.pom = dom

    def get_pom_groupid(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        return dom.getElementsByTagName('groupId')[0].childNodes[0].nodeValue

    def get_package_name(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        return dom.getElementsByTagName('name')[0].childNodes[0].nodeValue

    def get_pom_artifactid(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        return dom.getElementsByTagName('artifactId')[0].childNodes[0].nodeValue

    def get_pom_version(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        return dom.getElementsByTagName('version')[0].childNodes[0].nodeValue

    def get_module_packaging(self, module):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, module, "pom.xml"))
        try:
            packaging = dom.getElementsByTagName('packaging')[0].childNodes[0].nodeValue
        except Exception as e:
            packaging = 'zip'
        return packaging

    def is_multimodule_project(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        if dom.getElementsByTagName('modules').length != 0 :
            return True
        else:
            return False

    def get_multimodule_children(self):
        dom = self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        try:    
            total_modules = dom.getElementsByTagName('modules').length
        except Exception as e:
            print "Error Detected: {0}".format(e)
        if total_modules == 0 :
            return dom.getElementsByTagName('artifactId')[0].childNodes[0].nodeValue
        else:
            counter = 0
            module_list = []
            while counter <= total_modules:
                module_list.append(dom.getElementsByTagName('modules')[0].getElementsByTagName('module')[counter].childNodes[0].nodeValue)
                counter += 1
        return module_list

    def get_module_nexus_url(self, module):
        nexus_host_url = 'http://{0}:{1}'.format(self.C.get_nexus_host(), self.C.get_nexus_port())
        nexus_service_base = 'nexus/service/local/repositories/releases/content'
        groupid = self.get_pom_groupid()
        version = self.version
        packaging = self.get_module_packaging(module)
        artifact = '{0}-{1}.{2}'.format(module, version, packaging)
        return '{0}/{1}/{2}/{3}'.format(nexus_host_url, nexus_service_base, groupid, artifact)

    def get_module_url_dict(self):
        module_dict = {}
        modules = self.get_multimodule_children()
        for module in modules:
            module_dict[module] = self.get_module_nexus_url(module)
        return module_dict

    def set_pom_version(self, version):
        pom_files = self.get_poms()
        for pom_file in pom_files:
            dom = self.read_pom(pom_file)
            dom.getElementsByTagName('version')[0].childNodes[0].nodeValue = version
            self.write_pom(dom, pom_file)

    def read_releases_url(self):
        groupid = '/'.join(self.get_pom_groupid().split('.'))
        artifactid = self.get_pom_artifactid()
        url = 'http://{0}:{1}/nexus/content/repositories/releases/{2}/{3}/maven-metadata.xml'.format(self.C.get_nexus_host(),
                                                                                                     self.C.get_nexus_port(),
                                                                                                     groupid,
                                                                                                     artifactid)
        try:
            raw_releases_list = urllib2.urlopen(url)
            release_lines = ''
            for line in raw_releases_list.readlines():
                release_lines = release_lines + ' ' + line
            return release_lines.lstrip()
        except Exception as e:
            print "Error Detected: {0}".format(e)
            return False

    def get_previous_releases(self):
        """
        This mess is due to how the Scenario Manager modules are named, and must be reorganised at some point.
        This code will cleanly handle new multimodule projects that have been created with lessons learned from
        having to relese scenariomanager.
        MUST FIX ScenarioManager modules and merge all non Webapp modules into a single module.
        """
        version_list = []
        modules_list = []
        artifactid = self.get_pom_artifactid()
        if self.is_multimodule_project():    
            if artifactid == 'ScenarioManager':
                for module in self.get_multimodule_children():
                    if module != 'ScenarioManager-webapp':
                        if module == 'sql':
                            modules_list.append('-'.join([artifactid, 'ddl']))
                        else:
                            modules_list.append('-'.join([artifactid, module]))
            else:
                modules_list = self.get_multimodule_children()
            modules_list.append(artifactid)
        else:
            modules_list = [artifactid]
        for module in modules_list:
            url = 'http://{0}:{1}/nexus/content/repositories/releases/{2}/{3}/maven-metadata.xml'.format(self.C.get_nexus_host(),
                                                                                               self.C.get_nexus_port(),
                                                                                               '/'.join(self.get_pom_groupid().split('.')),
                                                                                               module)
            print url
            try:
                raw_releases_list = urllib2.urlopen(url)
                release_lines = ''
                for line in raw_releases_list.readlines():
                    release_lines = release_lines + ' ' + line
                xml = release_lines.lstrip()
            except Exception as e:
                print "Error Detected: {0}".format(e)          
            
            dom = parseString(xml)
            length = dom.getElementsByTagName('version').length
            count = 0
            while count != (length):
                version = dom.getElementsByTagName('version')[count].childNodes[0].nodeValue
                if self.V.is_valid_version(version):
                    if isinstance(version, unicode):
                        version_list.append(version)
                    elif isinstance(version, str):
                        version_list.append(version)
                count += 1
        print set(version_list)
        #sys.exit(1)
        return list(set(version_list))

    def get_releases_dict(self):
        release_alphas = []
        release_betas = []
        release_candidates = []
        release_dict = {}
        for version in self.get_previous_releases():
            if isinstance(version, unicode):
                if self.V.is_valid_version(version.encode('utf-8')):
                    if version.encode('utf-8').find('A') != -1:
                        release_alphas.append(version.encode('utf-8'))
                    elif version.encode('utf-8').find('B') != -1:
                        release_betas.append(version.encode('utf-8'))
                    elif version.encode('utf-8').find('R') != -1:
                        release_candidates.append(version.encode('utf-8'))
            elif isinstance(version, str):
                if self.V.is_valid_version(version):
                    if version.find('A') != -1:
                        release_alphas.append(version)
                    elif version.find('B') != -1:
                        release_betas.append(version)
                    elif version.find('R') != -1:
                        release_candidates.append(version)
        release_dict['release_alphas'] = self.V.validate_version_list(release_alphas)[-5:]
        release_dict['release_betas'] = self.V.validate_version_list(release_betas)[-5:]
        release_dict['release_candidates'] = self.V.validate_version_list(release_candidates)[-5:]
        return release_dict

    def get_email_addresses(self, version):
        return self.C.get_mail_string(version)

    def get_year(self):
        return int(strftime("%Y", gmtime()))

    def get_week_of_the_year(self):
        return int(date.today().strftime("%W"))
    
    def get_end_digit(self, version):
        regex = re.compile("(?P<RELEASE>[A,B,RC,GA]?)(?P<NUMBER>[0-9]{0,3})")
        m = regex.match(version)
        version_dict = m.groupdict()
        return version_dict['NUMBER']    

    def get_next_unique_number(self):
        numbers = []
        version_list = self.get_previous_releases()
        for version in version_list:
            if version.split('.')[1] == str(self.get_week_of_the_year()):
                end_digit = self.get_end_digit(version.split('.')[3])
                if len(end_digit) == 1:
                    numbers.append(''.join(['0', end_digit]))
                else:
                    numbers.append(end_digit)
        numbers.sort()
        print numbers
        if len(numbers) == 0:
            return int(1)
        elif len(numbers) == None:
            return int(1)
        elif len(numbers) >= 1:
            nextversion = int(numbers[-1]) + 1
            return nextversion 
        else:
            nextversion = int(numbers[0]) + 1
            return nextversion 
    
    def get_generated_version_number(self, drop):
        release_state = 'A'
        return '{0}.{1}.{2}.{3}{4}'.format(self.get_year(), self.get_week_of_the_year(), drop, release_state, self.get_next_unique_number())

    # Beware dog vommit below, should be using renderengine but has issues when imported.
    def serve_template(self, template_name, **kwargs):
        from mako.template import Template
        from mako.lookup import TemplateLookup
        from mako import exceptions
        try:
            render_template = Template(filename=os.path.join(os.path.join(os.path.expanduser('~'), 'versions/canvas/release-tools/trunk/src/fsa/releasetools/classes'), 'templates', template_name))
            return render_template.render(**kwargs)
        except:
            print exceptions.text_error_template().render()
    # End of dog vommit
    
    def email_release_notification(self):
        self.read_pom(os.path.join(self.get_temp_dir(), self.branch, "pom.xml"))
        self.data = self.get_releases_dict()
        self.data['author'] = self.C.get_release_author()
        self.data['email_recipients'] = self.get_email_addresses(self.version)
        self.data['title'] = self.get_package_name()
        self.data['version'] = self.get_version_built()
        self.data['release_time'] = strftime("%H:%M", self.get_buildtime())
        self.data['release_date'] = strftime("%d/%b/%Y", self.get_buildtime())
        self.data['release_day'] = strftime("%a", self.get_buildtime())
        self.data['svn_location'] = self.get_svn_location()
        self.data['svn_revision'] = self.get_svn_revision()
        self.data['modules'] = self.get_module_url_dict()
        pprint.pprint(self.data)
        print self.serve_template('release-email.html', C=self.data)
        print
        print self.serve_template('release-email.txt', C=self.data)
        if self.suppress_email == False:
            self.notify_release(self.serve_template('release-email.html', C=self.data), self.serve_template('release-email.txt', C=self.data))

    def notify_release(self, message_html, message_text):
        print "Sending notification emails to the following: "
        for recipient in self.data['email_recipients']:
            print "\t{0}".format(recipient)
        print
        message = Message()
        message.From = '*****@*****.**'
        message.To = self.data['email_recipients']
        message.Subject = "{0} version {1} released".format(self.data['title'], self.data['version'])
        message.Body = message_text
        message.Html = message_html
        print self.C.get_smtp_host()
        mailer = Mailer(self.C.get_smtp_host())
        mailer.send(message)
 def setUp(self):
     print "\nTest Fixture setUp"
     self.C = Config()
     self.C.validate_set_options()
     self.M = MavenTools("scenariomanager-webapp")
class ConfigurationTest(unittest.TestCase):

#
# Fixture Framework
#

    def setUp(self):
        print '\nTest Fixture setUp'
        if os.path.isfile(test_config_file):
            os.remove(test_config_file)
        self.C = Config()
        self.C.validate_set_options()
        

    def tearDown(self):
        print '\nTest Fixture tearDown'
        if os.path.isfile(test_config_file):
            os.remove(test_config_file)
        del self.C

#
# Tests
#

    def test_01_get_username(self):
        print '\n running get_username'
        self.failUnlessEqual('releasetools', self.C.get_username())
        self.failIfEqual('donnald', self.C.get_username())

    def test_02_set_username(self):
        print '\n running set_username'
        self.C.set_username('mickey')
        self.failUnlessEqual('mickey', self.C.get_username())
        self.failIfEqual('donnald', self.C.get_username())
        
    def test_03_get_password(self):
        print '\n running get_password'
        self.failUnlessEqual('releasetools', self.C.get_password())
        self.failIfEqual('donnald', self.C.get_password())

    def test_04_set_password(self):
        print '\n running set_password'
        self.C.set_password('mouse')
        self.failUnlessEqual('mouse', self.C.get_password())
        self.failIfEqual('duck', self.C.get_password())

    def test_05_svn_host(self):
        print '\n running get_svn_host'
        self.failUnlessEqual('localhost', self.C.get_svn_host())
        self.failIfEqual('notarealhost.co.uk', self.C.get_svn_host())

    def test_06_set_svn_host(self):
        print '\n running set_svn_host'
        self.C.set_svn_host('sd1appsdl05.fsa.gov.uk')
        self.failUnlessEqual('sd1appsdl05.fsa.gov.uk', self.C.get_svn_host())
        self.failIfEqual('notarealhost.co.uk', self.C.get_svn_host())

    def test_07_svn_port(self):
        print '\n running get_svn_port'
        self.failUnlessEqual('80', self.C.get_svn_port())
        self.failIfEqual('5555', self.C.get_svn_port())

    def test_08_set_svn_port(self):
        print '\n running set_svn_port'
        self.C.set_svn_port('443')
        self.failUnlessEqual('443', self.C.get_svn_port())
        self.failIfEqual('555', self.C.get_svn_port())
        
    def test_09_nexus_host(self):
        print '\n running get_nexus_host'
        self.failUnlessEqual('localhost', self.C.get_nexus_host())
        self.failIfEqual('notarealhost.co.uk', self.C.get_nexus_host())

    def test_10_set_nexus_host(self):
        print '\n running set_nexus_host'
        self.C.set_nexus_host('sd1appsdl05.fsa.gov.uk')
        self.failUnlessEqual('sd1appsdl05.fsa.gov.uk', self.C.get_nexus_host())
        self.failIfEqual('notarealhost.co.uk', self.C.get_nexus_host())

    def test_11_nexus_port(self):
        print '\n running get_nexus_port'
        self.failUnlessEqual('8081', self.C.get_nexus_port())
        self.failIfEqual('5555', self.C.get_nexus_port())

    def test_12_set_nexus_port(self):
        print '\n running set_nexus_port'
        self.C.set_nexus_port('443')
        self.failUnlessEqual('443', self.C.get_nexus_port())
        self.failIfEqual('555', self.C.get_nexus_port())
 def setUp(self):
     print '\nTest Fixture setUp'
     if os.path.isfile(test_config_file):
         os.remove(test_config_file)
     self.C = Config()
     self.C.validate_set_options()