Skip to content
Newer
Older
100644 154 lines (141 sloc) 5.78 KB
dc3bdaa @jettro changed the artifactory integration, now most of the code is in a sep…
authored Sep 26, 2011
1 package artifactory
2
3 import groovy.text.SimpleTemplateEngine
4 import groovyx.net.http.RESTClient
5 import net.sf.json.JSON
6
7 /**
8 * This groovy class is meant to be used to clean up your Atifactory server or get more information about it's
9 * contents. The api of artifactory is documented very well at the following location
10 * {@see http://wiki.jfrog.org/confluence/display/RTF/Artifactory%27s+REST+API}
11 *
12 * At the moment there is one major use of this class, cleaning your repository.
13 *
14 * Reading data about the repositories is done against /api/repository, if you want to remove items you need to use
15 * '/api/storage'
16 *
17 * Artifactory returns a strange Content Type in the response. We want to use a generic JSON library. Therefore we need
18 * to map the incoming type to the standard application/json. An example of the mapping is below, all the other
19 * mappings can be found in the obtainServerConnection method.
20 * 'application/vnd.org.jfrog.artifactory.storage.FolderInfo+json' => server.parser.'application/json'
21 *
22 * The class makes use of a config object. The config object is a map with a minimum of the following fields:
23 * def config = [
24 * server: 'http://localhost:8080',
25 * repository: 'libs-release-local',
26 * versionsToRemove: ['/3.2.0-build-'],
27 * dryRun: true]
28 *
29 * The versionsToRemove is an array of strings that are the strart of builds that should be removed. To give an idea of
30 * the build numbers we use: 3.2.0-build-1 or 2011.10-build-1. The -build- is important for the solution. This is how
31 * we identify an artifact instead of a group folder.
32 *
33 * The final option to notice is the dryRun option. This way you can get an overview of what will be deleted. If set
34 * to false, it will delete the selected artifacts.
35 *
36 * Usage example
37 * -------------
38 * def config = [
39 * server: 'http://localhost:8080',
40 * repository: 'libs-release-local',
41 * versionsToRemove: ['/3.2.0-build-'],
42 * dryRun: false]
43 *
44 * def artifactory = new Artifactory(config)
45 *
46 * def numberRemoved = artifactory.cleanArtifactsRecursive('nl/gridshore/toberemoved')
47 *
48 * if (config.dryRun) {* println "$numberRemoved folders would have been removed."
49 *} else {* println "$numberRemoved folders were removed."
50 *}* @author Jettro Coenradie
51 */
52 private class Artifactory {
53 def engine = new SimpleTemplateEngine()
54 def config
55
56 def Artifactory(config) {
57 this.config = config
58 }
59
60 /**
61 * Print information about all the available repositories in the configured Artifactory
62 */
63 def printRepositories() {
64 def server = obtainServerConnection()
65 def resp = server.get(path: '/artifactory/api/repositories')
66 if (resp.status != 200) {
67 println "ERROR: problem with the call: " + resp.status
68 System.exit(-1)
69 }
70 JSON json = resp.data
71 json.each {
72 println "key :" + it.key
73 println "type : " + it.type
74 println "descritpion : " + it.description
75 println "url : " + it.url
76 println ""
77 }
78 }
79
80 /**
81 * Return information about the provided path for the configured artifactory and server.
82 *
83 * @param path String representing the path to obtain information for
84 *
85 * @return JSON object containing information about the specified folder
86 */
87 def JSON folderInfo(path) {
88 def binding = [repository: config.repository, path: path]
89 def template = engine.createTemplate('''/artifactory/api/storage/$repository/$path''').make(binding)
90 def query = template.toString()
91
92 def server = obtainServerConnection()
93
94 def resp = server.get(path: query)
95 if (resp.status != 200) {
96 println "ERROR: problem obtaining folder info: " + resp.status
97 println query
98 System.exit(-1)
99 }
100 return resp.data
101 }
102
103 /**
104 * Recursively removes all folders containing builds that start with the configured paths.
105 *
106 * @param path String containing the folder to check and use the childs to recursively check as well.
107 * @return Number with the amount of folders that were removed.
108 */
109 def cleanArtifactsRecursive(path) {
110 def deleteCounter = 0
111 JSON json = folderInfo(path)
112 json.children.each {child ->
113 if (child.folder) {
114 if (isArtifactFolder(child)) {
115 config.versionsToRemove.each {toRemove ->
116 if (child.uri.startsWith(toRemove)) {
117 removeItem(path, child)
118 deleteCounter++
119 }
120 }
121 } else {
122 if (!child.uri.contains("ro-scripts")) {
123 deleteCounter += cleanArtifactsRecursive(path + child.uri)
124 }
125 }
126 }
127 }
128 return deleteCounter
129 }
130
131 private RESTClient obtainServerConnection() {
132 def server = new RESTClient(config.server)
133 server.parser.'application/vnd.org.jfrog.artifactory.storage.FolderInfo+json' = server.parser.'application/json'
134 server.parser.'application/vnd.org.jfrog.artifactory.repositories.RepositoryDetailsList+json' = server.parser.'application/json'
135
136 return server
137 }
138
139 private def isArtifactFolder(child) {
140 child.uri.contains("-build-")
141 }
142
143 private def removeItem(path, child) {
144 println "folder: " + path + child.uri + " DELETE"
145 def binding = [repository: config.repository, path: path + child.uri]
146 def template = engine.createTemplate('''/artifactory/$repository/$path''').make(binding)
147 def query = template.toString()
148 if (!config.dryRun) {
149 def server = new RESTClient(config.server)
150 server.delete(path: query)
151 }
152 }
153 }
Something went wrong with that request. Please try again.