@@ -97,6 +97,11 @@ func (sxm *SettingsXmlManager) loadSettings() {
9797 sxm .doc .Indent (2 )
9898}
9999
100+ // buildRepositoryURL constructs the full repository URL from base URL and repository name.
101+ func buildRepositoryURL (artifactoryUrl , repoName string ) string {
102+ return strings .TrimRight (artifactoryUrl , "/" ) + "/" + repoName
103+ }
104+
100105// ConfigureArtifactoryRepository configures Maven to use Artifactory for both downloading and deployment.
101106// It updates or creates the following in settings.xml:
102107// - Mirror configuration for downloading artifacts from Artifactory
@@ -120,7 +125,7 @@ func (sxm *SettingsXmlManager) ConfigureArtifactoryRepository(artifactoryUrl, re
120125 }
121126
122127 // Build repository URL
123- repoUrl := strings . TrimRight (artifactoryUrl , "/" ) + "/" + repoName
128+ repoUrl := buildRepositoryURL (artifactoryUrl , repoName )
124129
125130 // Ensure we have a root <settings> element
126131 root := sxm .doc .SelectElement (xmlElementSettings )
@@ -189,14 +194,40 @@ func getOrCreateElement(parent *etree.Element, name string) *etree.Element {
189194 return element
190195}
191196
192- // findOrCreateElementByID finds an element with a specific ID or creates a new one.
193- func findOrCreateElementByID (parent * etree.Element , elementName , id string ) * etree.Element {
197+ // findElementByID finds an element with a specific ID within a parent container.
198+ // Returns nil if not found.
199+ func findElementByID (parent * etree.Element , elementName , id string ) * etree.Element {
194200 for _ , elem := range parent .SelectElements (elementName ) {
195201 if idElem := elem .SelectElement (xmlElementID ); idElem != nil && idElem .Text () == id {
196202 return elem
197203 }
198204 }
199- return parent .CreateElement (elementName )
205+ return nil
206+ }
207+
208+ // findOrCreateElementByID finds an element with a specific ID or creates a new one.
209+ func findOrCreateElementByID (parent * etree.Element , elementName , id string ) * etree.Element {
210+ elem := findElementByID (parent , elementName , id )
211+ if elem == nil {
212+ elem = parent .CreateElement (elementName )
213+ }
214+ return elem
215+ }
216+
217+ // removeElementByID removes an element with a specific ID from its parent container.
218+ func removeElementByID (parent * etree.Element , elementName , id string ) {
219+ elem := findElementByID (parent , elementName , id )
220+ if elem != nil {
221+ parent .RemoveChild (elem )
222+ }
223+ }
224+
225+ // removeEmptyContainer removes a container element from its parent if it has no children.
226+ func removeEmptyContainer (root * etree.Element , containerName string ) {
227+ container := root .SelectElement (containerName )
228+ if container != nil && len (container .ChildElements ()) == 0 {
229+ root .RemoveChild (container )
230+ }
200231}
201232
202233// setOrCreateChildElement sets or creates a child element with the given name and text.
@@ -205,6 +236,175 @@ func setOrCreateChildElement(parent *etree.Element, name, text string) {
205236 child .SetText (text )
206237}
207238
239+ // ValidateArtifactoryRepository checks if Artifactory repository configuration exists in settings.xml
240+ // and optionally validates the configuration values match the expected parameters.
241+ // Returns true if all components (mirror, server, profile) are configured correctly, false otherwise.
242+ //
243+ // Parameters:
244+ // - artifactoryUrl: Base URL to validate against (optional, can be empty to skip validation)
245+ // - repoName: Repository name to validate against (optional, can be empty to skip validation)
246+ // - username: Username to validate against (optional, can be empty to skip validation)
247+ // - password: Password to validate against (optional, can be empty to skip validation)
248+ func (sxm * SettingsXmlManager ) ValidateArtifactoryRepository (artifactoryUrl , repoName , username , password string ) (bool , error ) {
249+ root := sxm .doc .SelectElement (xmlElementSettings )
250+ if root == nil {
251+ return false , fmt .Errorf ("invalid settings.xml: missing <%s> root element" , xmlElementSettings )
252+ }
253+
254+ // Build expected repository URL if parameters provided
255+ var expectedRepoUrl string
256+ if artifactoryUrl != "" && repoName != "" {
257+ expectedRepoUrl = buildRepositoryURL (artifactoryUrl , repoName )
258+ }
259+
260+ // Check mirror configuration
261+ mirrors := root .SelectElement (xmlElementMirrors )
262+ mirrorConfigured := false
263+ if mirrors != nil {
264+ mirror := findElementByID (mirrors , xmlElementMirror , ArtifactoryMirrorID )
265+ if mirror != nil {
266+ mirrorConfigured = true
267+ // Validate URL if provided
268+ if expectedRepoUrl != "" {
269+ urlElem := mirror .SelectElement (xmlElementURL )
270+ if urlElem == nil || urlElem .Text () != expectedRepoUrl {
271+ return false , nil
272+ }
273+ }
274+ }
275+ }
276+
277+ // Check server configuration
278+ servers := root .SelectElement (xmlElementServers )
279+ serverConfigured := false
280+ if servers != nil {
281+ server := findElementByID (servers , xmlElementServer , ArtifactoryMirrorID )
282+ if server != nil {
283+ serverConfigured = true
284+ // Validate credentials if provided
285+ if username != "" {
286+ usernameElem := server .SelectElement (xmlElementUsername )
287+ if usernameElem == nil || usernameElem .Text () != username {
288+ return false , nil
289+ }
290+ }
291+ if password != "" {
292+ passwordElem := server .SelectElement (xmlElementPassword )
293+ if passwordElem == nil || passwordElem .Text () != password {
294+ return false , nil
295+ }
296+ }
297+ }
298+ }
299+
300+ // Check deployment profile
301+ profiles := root .SelectElement (xmlElementProfiles )
302+ profileConfigured := false
303+ if profiles != nil {
304+ profile := findElementByID (profiles , xmlElementProfile , ArtifactoryDeployProfileID )
305+ if profile != nil {
306+ profileConfigured = true
307+ // Validate altDeploymentRepository if URL provided
308+ if expectedRepoUrl != "" {
309+ properties := profile .SelectElement (xmlElementProperties )
310+ if properties != nil {
311+ altDeployElem := properties .SelectElement (AltDeploymentRepositoryProperty )
312+ expectedAltDeploy := fmt .Sprintf ("%s::default::%s" , ArtifactoryMirrorID , expectedRepoUrl )
313+ if altDeployElem == nil || altDeployElem .Text () != expectedAltDeploy {
314+ return false , nil
315+ }
316+ }
317+ }
318+ }
319+ }
320+
321+ return mirrorConfigured && serverConfigured && profileConfigured , nil
322+ }
323+
324+ // RemoveArtifactoryRepository removes all Artifactory configuration from settings.xml.
325+ // This includes:
326+ // - Mirror configuration with ArtifactoryMirrorID
327+ // - Server credentials with ArtifactoryMirrorID
328+ // - Deployment profile with ArtifactoryDeployProfileID
329+ //
330+ // Parameters:
331+ // - artifactoryUrl: Base URL of the Artifactory instance (used for verification, optional)
332+ // - repoName: Name of the Artifactory repository (used for verification, optional)
333+ //
334+ // Returns an error if the settings.xml cannot be updated.
335+ func (sxm * SettingsXmlManager ) RemoveArtifactoryRepository (artifactoryUrl , repoName string ) error {
336+ root := sxm .doc .SelectElement (xmlElementSettings )
337+ if root == nil {
338+ return fmt .Errorf ("invalid settings.xml: missing <%s> root element" , xmlElementSettings )
339+ }
340+
341+ // Build repository URL for verification if provided
342+ var repoUrl string
343+ if artifactoryUrl != "" && repoName != "" {
344+ repoUrl = buildRepositoryURL (artifactoryUrl , repoName )
345+ }
346+
347+ // Remove mirror
348+ if err := sxm .removeMirror (root , repoUrl ); err != nil {
349+ return err
350+ }
351+
352+ // Remove server
353+ sxm .removeServer (root )
354+
355+ // Remove deployment profile
356+ sxm .removeDeploymentProfile (root )
357+
358+ // Write settings to file
359+ return sxm .writeSettingsToFile ()
360+ }
361+
362+ // removeMirror removes the Artifactory mirror entry.
363+ func (sxm * SettingsXmlManager ) removeMirror (root * etree.Element , expectedUrl string ) error {
364+ mirrors := root .SelectElement (xmlElementMirrors )
365+ if mirrors == nil {
366+ return nil
367+ }
368+
369+ // Verify URL if provided before removing
370+ if expectedUrl != "" {
371+ mirror := findElementByID (mirrors , xmlElementMirror , ArtifactoryMirrorID )
372+ if mirror != nil {
373+ urlElem := mirror .SelectElement (xmlElementURL )
374+ if urlElem != nil && urlElem .Text () != expectedUrl {
375+ return fmt .Errorf ("mirror URL mismatch: expected %s, found %s" , expectedUrl , urlElem .Text ())
376+ }
377+ }
378+ }
379+
380+ removeElementByID (mirrors , xmlElementMirror , ArtifactoryMirrorID )
381+ removeEmptyContainer (root , xmlElementMirrors )
382+
383+ return nil
384+ }
385+
386+ // removeServer removes the Artifactory server entry.
387+ func (sxm * SettingsXmlManager ) removeServer (root * etree.Element ) {
388+ servers := root .SelectElement (xmlElementServers )
389+ if servers == nil {
390+ return
391+ }
392+
393+ removeElementByID (servers , xmlElementServer , ArtifactoryMirrorID )
394+ removeEmptyContainer (root , xmlElementServers )
395+ }
396+
397+ // removeDeploymentProfile removes the Artifactory deployment profile.
398+ func (sxm * SettingsXmlManager ) removeDeploymentProfile (root * etree.Element ) {
399+ profiles := root .SelectElement (xmlElementProfiles )
400+ if profiles == nil {
401+ return
402+ }
403+
404+ removeElementByID (profiles , xmlElementProfile , ArtifactoryDeployProfileID )
405+ removeEmptyContainer (root , xmlElementProfiles )
406+ }
407+
208408// writeSettingsToFile writes the document to the settings.xml file.
209409func (sxm * SettingsXmlManager ) writeSettingsToFile () error {
210410 // Ensure directory exists
0 commit comments