Validate the default.xml with XML DTD schema

Change-Id: I7563cc1e3fab6583e839011c85cdcab46d327018
diff --git a/Jenkinsfile b/Jenkinsfile
index d0c41c6..5732b3f 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,4 +1,4 @@
-import groovy.json.JsonSlurperClassic 
+import groovy.json.JsonSlurperClassic
 
 env.IGNORE_LIST = ["All-Users"]
 
@@ -24,7 +24,11 @@
 
 def createBranch(def proj, def branch, def parent) {
     cmd = 'ssh -p 29418 gerrit.opencord.org gerrit create-branch ' + proj + " " + branch + " " + parent
-    sh returnStdout: true, script: cmd 
+    sh returnStdout: true, script: cmd
+}
+
+def validateXMLwithDTD() {
+    sh returnStdout: true, script 'validate_manifest.sh'
 }
 
 int checkBranchExists(def proj) {
@@ -42,6 +46,9 @@
 
 node ('master') {
 
+    stage 'Validate default.xml with DTD'
+    validateXMLwithDTD()
+
     stage 'Check and create support branches'
     def url = 'https://gerrit.opencord.org/projects/?type=CODE'
     def response = httpRequest url: url, validResponseCodes: '200'
@@ -64,7 +71,7 @@
                 body: "Please go to ${BUILD_URL}input and promote or abort the release. It will timeout after 12 hours."
             metadata = input id: 'release-build', message: 'Should I perform a release?',
                 parameters: [booleanParam(defaultValue: true,
-                description: 'Release onos applications (assumes versions have been updated)', name: 'build_onos_apps'), 
+                description: 'Release onos applications (assumes versions have been updated)', name: 'build_onos_apps'),
                 string(defaultValue: branch, description: 'Release version', name: 'release_version')], submitter: 'ash,llp,acb'
         }
 
@@ -77,16 +84,16 @@
         checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: metadata['release_version'] ]], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'WipeWorkspace'], [$class: 'CleanBeforeCheckout']], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'dd9d4677-2415-4f82-8e79-99dcd530f023', url: 'ssh://jenkins@gerrit.opencord.org:29418/manifest']]]
         sh returnStdout: true, script: 'git checkout ' + metadata['release_version']
         sh returnStdout: true, script: 'git pull origin ' + metadata['release_version']
-        sh returnStdout: true, script: 'cp ' + env.JENKINS_HOME + '/tmp/manifest-' + env.BRANCH_NAME + '.xml default.xml' 
-    
+        sh returnStdout: true, script: 'cp ' + env.JENKINS_HOME + '/tmp/manifest-' + env.BRANCH_NAME + '.xml default.xml'
+
         sh returnStdout: true, script: 'git commit -a -m "JENKINS: Updating manifest"'
         sh returnStdout: true, script: 'git push origin ' + metadata['release_version']
 
         stage 'Build and Release ONOS applications'
-   
+
         if (metadata['build_onos_apps']) {
-            checkout changelog: false, poll: false, scm: [$class: 'RepoScm', currentBranch: true, 
-                manifestBranch: env.BRANCH_NAME, manifestGroup: 'onos', 
+            checkout changelog: false, poll: false, scm: [$class: 'RepoScm', currentBranch: true,
+                manifestBranch: env.BRANCH_NAME, manifestGroup: 'onos',
                 manifestRepositoryUrl: 'https://gerrit.opencord.org/manifest', quiet: true]
             if (env.BRANCH_NAME == 'master') {
                 sh returnStdout: true, script: 'cd onos-apps/apps && mvn clean deploy'
@@ -100,7 +107,7 @@
             replyTo: 'cord-dev@opencord.org',
             body: '''Hi CORD Community,
 
-                        |A new bleeding edge version of cord is available, feel free to test it. 
+                        |A new bleeding edge version of cord is available, feel free to test it.
                         |You can obtain it using the following commands:
 
                         |repo init -u https://gerrit.opencord.org/manifest -b '''.stripMargin() + metadata['release_version'] + '''
diff --git a/manifest.dtd b/manifest.dtd
new file mode 100644
index 0000000..7b2c66c
--- /dev/null
+++ b/manifest.dtd
@@ -0,0 +1,61 @@
+<!ELEMENT manifest (notice?,
+                    remote*,
+                    default?,
+                    manifest-server?,
+                    remove-project*,
+                    project*,
+                    extend-project*,
+                    repo-hooks?)>
+<!ELEMENT notice (#PCDATA)>
+<!ELEMENT remote EMPTY>
+<!ATTLIST remote name         ID    #REQUIRED>
+<!ATTLIST remote alias        CDATA #IMPLIED>
+<!ATTLIST remote fetch        CDATA #REQUIRED>
+<!ATTLIST remote pushurl      CDATA #IMPLIED>
+<!ATTLIST remote review       CDATA #IMPLIED>
+<!ATTLIST remote revision     CDATA #IMPLIED>
+<!ELEMENT default EMPTY>
+<!ATTLIST default remote      IDREF #IMPLIED>
+<!ATTLIST default revision    CDATA #IMPLIED>
+<!ATTLIST default dest-branch CDATA #IMPLIED>
+<!ATTLIST default sync-j      CDATA #IMPLIED>
+<!ATTLIST default sync-c      CDATA #IMPLIED>
+<!ATTLIST default sync-s      CDATA #IMPLIED>
+<!ELEMENT manifest-server EMPTY>
+<!ATTLIST manifest-server url CDATA #REQUIRED>
+<!ELEMENT project (annotation*,
+                   project*,
+                   copyfile*,
+                   linkfile*)>
+<!ATTLIST project name        CDATA #REQUIRED>
+<!ATTLIST project path        CDATA #IMPLIED>
+<!ATTLIST project remote      IDREF #IMPLIED>
+<!ATTLIST project revision    CDATA #IMPLIED>
+<!ATTLIST project dest-branch CDATA #IMPLIED>
+<!ATTLIST project groups      CDATA #IMPLIED>
+<!ATTLIST project sync-c      CDATA #IMPLIED>
+<!ATTLIST project sync-s      CDATA #IMPLIED>
+<!ATTLIST project upstream CDATA #IMPLIED>
+<!ATTLIST project clone-depth CDATA #IMPLIED>
+<!ATTLIST project force-path CDATA #IMPLIED>
+<!ELEMENT annotation EMPTY>
+<!ATTLIST annotation name  CDATA #REQUIRED>
+<!ATTLIST annotation value CDATA #REQUIRED>
+<!ATTLIST annotation keep  CDATA "true">
+<!ELEMENT copyfile EMPTY>
+<!ATTLIST copyfile src  CDATA #REQUIRED>
+<!ATTLIST copyfile dest CDATA #REQUIRED>
+<!ELEMENT linkfile EMPTY>
+<!ATTLIST linkfile src CDATA #REQUIRED>
+<!ATTLIST linkfile dest CDATA #REQUIRED>
+<!ELEMENT extend-project EMPTY>
+<!ATTLIST extend-project name CDATA #REQUIRED>
+<!ATTLIST extend-project path CDATA #IMPLIED>
+<!ATTLIST extend-project groups CDATA #IMPLIED>
+<!ELEMENT remove-project EMPTY>
+<!ATTLIST remove-project name  CDATA #REQUIRED>
+<!ELEMENT repo-hooks EMPTY>
+<!ATTLIST repo-hooks in-project CDATA #REQUIRED>
+<!ATTLIST repo-hooks enabled-list CDATA #REQUIRED>
+<!ELEMENT include EMPTY>
+<!ATTLIST include name CDATA #REQUIRED>
diff --git a/validate_manifest.sh b/validate_manifest.sh
new file mode 100755
index 0000000..a582322
--- /dev/null
+++ b/validate_manifest.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# validate_manifest.sh
+#
+# Validates the repo manifest, per the DTD format given here:
+# https://gerrit.googlesource.com/git-repo/+/master/docs/manifest-format.txt
+
+echo "Verifying default.xml using manifest.dtd"
+
+# check that xmllint is available
+if ! [ -x "$(command -v xmllint)" ]
+then
+  echo "Please install 'xmllint' to use this script"
+  exit 1
+fi
+
+# run the verification
+xmllint --noout --dtdvalid manifest.dtd default.xml
+status=$?
+
+if [ $status -ne 0 ]
+then
+  echo "FAILURE: default.xml isn't valid - exit status: $status"
+  exit $status
+else
+  echo "SUCCESS: default.xml validated correctly"
+  exit 0
+fi