5
votes

How to step up TFS 2015 Update 2 to delete artifacts when build is deleted?

Is this possible?

enter image description here

EDIT: Add retention screen shot

I am using the default retention policy but it is NOT deleting artifacts from the drive.

enter image description here

EDIT: Add Copy and Publish Build Artifacts

enter image description here

EDIT: Add Working Folder

I added a powershell to display all environment variables and it said my workingFolder = E:TfsBuilds\Agent1_WorkPlace\5\s

Do you a powershell to set workingFolder to default?

Here is the file structure i have:

enter image description here

2

2 Answers

2
votes

If you specify build retention policies, retention policies will delete the items below:

  • The build record
  • Logs
  • Published artifacts
  • Automated test results
  • Published artifacts
  • Published symbols

More details you can refer a similar question in SO: Should artifacts associated with a build record be deleted when the build record is deleted?

Moreover, if you manually delete the build, everything of the build will be deleted.

Update


For now, server drops are deleted when a build is deleted but drops to UNC shares are not. It's also a known issue: Build.Preview - Drop Folder not deleted when build is deleted

If so, you may have to delete them manually.

Update2


I was wondering did you missed up the working folder with the drop folder. The default work folder location is a _work folder directly under the agent installation directory. The files in this folder will always keep or deleted until next build triggered. You can find the directory in your build log to double check this. More details please refer the definition from MSDN.

enter image description here


Update3

Each agent will have their own work folder. Such as XXX\Agent1, XXX\Agent2,...XXX\Agent6. I think the issue is that you are confusing the file structure.

With your file structure, the files which deployed to the server is copying to the folder called XXX\builds. However, these files are not the published Artifacts. There are something like temporary files. If you want to auto delete the files under the builds, you can add a Delete files task. at the last step. Even if these files are deleted during the build. You can still download the artifacts from server after build finished. enter image description here

0
votes

I am making an assumption here that we know that TFS2015 Update2 does not support this out of the box and that MS claims to have resolved this in TFS15.

I am going to paste the whole program for everyone's benefit. This code works and I am using it. I run this utility to clean the build artifactdrop location for builds that have been wiped out of TFS. The assumption we are making is that we are going to call the exe with two parameters that are folder paths:

DeleteBuild.exe "D:\TFSDropLocation" "D:\DumpFolderBeforeIDeleteThis"

where TFSDropLocation is where TFS is dropping the build artifacts and DumpFolderBeforeIDeleteThis is a folder where I collect all builds before I delete them forever. We could have deleted them right from TFSDropLocation but I like this additional step where we remove them to a separate location so that just in case, we happen to need them, they are their or alternately delete them from this location after one more round of verification -if that makes you comfortable.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Client;
using System.IO;
using System.Configuration;

namespace DeleteBuild
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length!=2)
            {
                Console.WriteLine("Correct usage is: DeleteBuild.exe 'Absolute Folderpath Path to TFS drop location' 'Absolute Dump Location'");
                Console.WriteLine("for e.g. something with quotes around the paths: DeleteBuild.exe D:\\TFSDropLocation D:\\Dumplocation");
                return;
            }

            string BuildDropLocation = args[0];
            string BuildDumpLocation = args[1];
            #region TFSConnection
            string accountUrl = ConfigurationManager.AppSettings["accountUrl"];
            VssConnection connection = new VssConnection(new Uri(accountUrl), new VssAadCredential());
            ProjectHttpClient projectClient = connection.GetClient<ProjectHttpClient>();
            TeamProject project = projectClient.GetProject(ConfigurationManager.AppSettings["TeamProject"]).Result;
            BuildHttpClient buildClient = connection.GetClient<BuildHttpClient>();
            var builds = buildClient.GetBuildsAsync(project.Id, resultFilter: BuildResult.Succeeded).Result;
            #endregion

            //the parent directory that is the build definition name
            DirectoryInfo directory = new DirectoryInfo(BuildDropLocation);
            // list of subdirectories which are the actual buildnumber folders
            DirectoryInfo[] ParentFolders = directory.GetDirectories();

            foreach (DirectoryInfo ParentFolder in ParentFolders)
            {
                Console.WriteLine(Environment.NewLine + "Build Definition name: " + ParentFolder.Name + " contains the below mentioned builds");
                //list of all folders inside the build definition folder which are buildnumber folders
                DirectoryInfo[] ChildFolders = ParentFolder.GetDirectories();
                //We evaluate each build number folder one by one
                foreach (DirectoryInfo ChildFolder in ChildFolders)
                {
                    Console.WriteLine(Environment.NewLine + "Evaluating folder: " + ChildFolder.Name);
                    //Create an array of builds where the definition name matches the parent foldername
                    Build[] RelevantBuilds = builds.Where(b => b.Definition.Name == ParentFolder.Name).Reverse().ToArray();
                    //set flag to false to 
                    Boolean flag = false;
                    // traverse through each build in tfs
                    foreach (Build build in RelevantBuilds)
                    {
                        {
                            //compare build number with child folder name to see if it matches
                            if (string.Compare(build.BuildNumber, ChildFolder.Name) == 0)
                            {
                                Console.WriteLine("Found build existing, hence leaving here " + build.BuildNumber);
                                //this build has yet not been deleted from tfs so set flag to true and traverse to the next build
                                flag = true;
                            }

                        }
                    }
                    // if after travering the builds, we did not find any build that matches the foldername, flag will be set to initial value of false and this folder will be deleted
                    if (flag == false)
                    {
                        DirectoryInfo DropLocation = new DirectoryInfo(BuildDumpLocation);
                        string intermediatPath = Path.Combine(BuildDumpLocation, ParentFolder.Name);
                        DirectoryInfo IntermediateDirectory = new DirectoryInfo(intermediatPath);
                        if (!IntermediateDirectory.Exists)
                        {
                            DropLocation.CreateSubdirectory(ParentFolder.Name);
                        }
                        string sourcePath = ChildFolder.Name;
                        string targetPath = Path.Combine(DropLocation.FullName, ParentFolder.Name, ChildFolder.Name);
                        System.IO.Directory.Move(ChildFolder.FullName, targetPath);
                        Console.WriteLine("Did not find build in TFS hence moving: " + ChildFolder.Name + " to a separate dump location.");
                    }
                }
                Console.WriteLine("******************************************************");
            }
            Console.WriteLine("end of directory" + Environment.NewLine);
        }
    }
}