public static void CheckDuplicates(ProjectCreationParams pcp) { string restRoot = pcp.ServerUrl + (pcp.ServerUrl.EndsWith("/") ? String.Empty : "/") + "httpAuth/app/rest/"; // check for duplicates pcp.Log.Status = "Checking for projects with same name"; pcp.Client = new RestClient(restRoot); pcp.Client.Authenticator = new HttpBasicAuthenticator(pcp.Username, pcp.Password); var rq = new RestRequest(projectResource, Method.GET); var resp = pcp.Client.Get<Projects>(rq); if (resp.Data == null) { pcp.Log.ErrorMessage = "Failed to connect. Check server URL, username and password."; return; } var ps = resp.Data.project; foreach (var serverProject in ps) { if (serverProject.name.Equals(pcp.ProjectName)) { #if DEBUG pcp.Log.Status = "Deleting project " + serverProject.name; var drq = new RestRequest(projectResource + "/" + pcp.ProjectName, Method.DELETE); pcp.Client.Execute(drq); #else pcp.Log.ErrorMessage = "A project with this name already exists on the server."; return; #endif } } CreateProject(pcp); }
/// <summary> /// Very simple process for a dependency graph. First of all, we check that the bear hasn't /// gotten drunk on vodka and isn't trying to reassemble the nuclear generator. Then, we check /// the projects to make sure that the first layer contains only the /// </summary> /// <param name="client"></param> /// <param name="project"></param> /// <param name="solutionPath"></param> private static void BuildSolutionGraph(ProjectCreationParams pcp) { pcp.Log.Status = "Building solution graph"; List<VSProject> projects; var items = GetProjectItemsFromSolution(pcp.SolutionPath, out projects); var projectData = items.Values.ToList(); // let's build execution layers here and now var layers = new List<HashSet<ProjectData>>(); int currentLayer = 0; do { pcp.Log.Status = "Analyzing layer " + currentLayer; var thisLayer = new HashSet<ProjectData>(); if (currentLayer == 0) { foreach (var p in projectData) if (!p.Dependencies.Any()) thisLayer.Add(p); foreach (var p in thisLayer) projectData.Remove(p); } else { // all elements dependent on previous layer var existingIdx = layers.SelectMany(x => x).Select(y => y.Id).ToSortedSet(); foreach (var p in projectData) if (p.Dependencies.All(d => existingIdx.Contains(d))) thisLayer.Add(p); foreach (var p in thisLayer) projectData.Remove(p); if (thisLayer.Count == 0) { pcp.Log.ErrorMessage = "Failed to find elements for layer " + currentLayer; return; } } layers.Add(thisLayer); currentLayer++; } while (projectData.Count > 0); build: pcp.Layers = layers; CreateBuildConfigurations(pcp); }
public static void Start(ProjectCreationParams pcp) { CheckDuplicates(pcp); }
private static void CreateProject(ProjectCreationParams pcp) { pcp.Log.Status = "Creating new project"; var rq = new RestRequest(projectResource); rq.AddParameter("text/plain", pcp.ProjectName, ParameterType.RequestBody); var resp = pcp.Client.Post<Project>(rq); pcp.Project = resp.Data; if (pcp.Project == null) { pcp.Log.ErrorMessage = "Failed to create project. Check the user has appropriate rights."; return; } BuildSolutionGraph(pcp); }
private static void CreateBuildConfigurations(ProjectCreationParams pcp) { var configurationNames = new Dictionary<int,Configuration>(); //Parallel.For(0, pcp.Layers.Count, i => for (int i = 0; i < pcp.Layers.Count; ++i) { var layer = pcp.Layers[i]; // create a subproject for this layer pcp.Log.Status = "Creating subproject for layer " + i; var rq = new RestRequest("/projects"); rq.AddParameter("text/plain", "Layer " + i, ParameterType.RequestBody); var layerProject = pcp.Client.Post<Project>(rq); if (layerProject.Data == null) { pcp.Log.ErrorMessage = "Failed to create subproject."; return; } // ensure this layer is a child pcp.Log.Status = "Setting parent of layer " + i; rq = new RestRequest(projectResource + "/" + layerProject.Data.id + "/parentProject"); rq.AddParameter("application/xml", "<project-ref id=\"" + pcp.Project.id + "\"/>", ParameterType.RequestBody); layerProject = pcp.Client.Put<Project>(rq); if (layerProject.Data == null) { pcp.Log.ErrorMessage = "Failed to change layer parent project."; return; } // for each of the projects in the layer // this is *not* parallelizable foreach (var pd in layer) { // create a build configuration pcp.Log.Status = "Creating build config for " + layerProject.Data.name; rq = new RestRequest("/projects/" + layerProject.Data.id + "/buildTypes"); rq.AddParameter("text/plain", Path.GetFileNameWithoutExtension(pd.Project.FileName), ParameterType.RequestBody); var resp = pcp.Client.Post<Configuration>(rq); if (resp.Data == null) { pcp.Log.ErrorMessage = "Failed to create configuration " + layerProject.Data.id; return; } // write a configuration Configuration conf = resp.Data; configurationNames.Add(pd.Id, conf); conf.description = "This configuration builds the project " + Path.GetFileName(pd.Project.FileName) + " which resides in layer " + i + " of the parent project " + pcp.ProjectName; rq = new RestRequest("/buildTypes/id:" + conf.id); rq.AddBody(conf); resp = pcp.Client.Post<Configuration>(rq); // add artifact rules rq = new RestRequest("/buildTypes/id:" + conf.id + "/settings"); var relativeOutputFolder = "\\" + MakeRelativePath(pcp.SolutionPath, Path.GetDirectoryName(pd.Project.FileName)) + "\\" +pd.Project.OutputFolder; var e = "<properties><property name=\"artifactRules\" value=\"" + relativeOutputFolder.Replace('\\','/') + "*.*\"/></properties>"; rq.AddParameter("application/xml", e, ParameterType.RequestBody); var _ = pcp.Client.Put<object>(rq); // add build root entry string entry = @" <vcs-root-entry id=""Experimental_FooAndBar_LocalHg""> <vcs-root id=""Experimental_FooAndBar_LocalHg"" name=""Local HG"" href=""/httpAuth/app/rest/vcs-roots/id:Experimental_FooAndBar_LocalHg""/> <checkout-rules/> </vcs-root-entry>"; rq = new RestRequest("/buildTypes/id:" + conf.id + "/vcs-root-entries"); rq.AddParameter("application/xml", entry, ParameterType.RequestBody); resp = pcp.Client.Post<Configuration>(rq); // add a build step var template = @"<step name="""" type=""MSBuild""> <properties> <property name=""build-file-path"" value=""{0}""/> <property name=""msbuild_version"" value=""4.5""/> <property name=""run-platform"" value=""x64""/> <property name=""runnerArgs"" value=""/p:BuildProjectReferences=false""/> <property name=""targets"" value=""{1}""/> <property name=""teamcity.step.mode"" value=""default""/> <property name=""toolsVersion"" value=""4.0""/> </properties> </step>"; string step = string.Format(template, Path.GetFileName(pcp.SolutionPath), Path.GetFileNameWithoutExtension(pd.Project.FileName).Replace('.','_')); rq = new RestRequest("/buildTypes/id:" + conf.id + "/steps"); rq.AddParameter("application/xml", step, ParameterType.RequestBody); var __ = pcp.Client.Post<object>(rq); // create dependencies const string sd = @"<snapshot-dependency type=""snapshot_dependency""> <properties> <property name=""run-build-if-dependency-failed"" value=""false""/> <property name=""run-build-on-the-same-agent"" value=""false""/> <property name=""take-started-build-with-same-revisions"" value=""true""/> <property name=""take-successful-builds-only"" value=""true""/> </properties> {0} </snapshot-dependency>"; const string ad = @"<artifact-dependency type=""artifact_dependency""> <properties> <property name=""cleanDestinationDirectory"" value=""false""/> <property name=""pathRules"" value=""*.*=>{1}""/> <property name=""revisionName"" value=""sameChainOrLastFinished""/> <property name=""revisionValue"" value=""latest.sameChainOrLastFinished""/> </properties> {0} </artifact-dependency>"; foreach (var dependencyId in pd.Dependencies) { // snapshot dependency string sdep = string.Format(sd, configurationNames[dependencyId].SourceBuildTypeXML); rq = new RestRequest("/buildTypes/id:" + conf.id + "/snapshot-dependencies"); rq.AddParameter("application/xml", sdep, ParameterType.RequestBody); pcp.Client.Post<SnapshotDependency>(rq); // artifact dependency // we need the relative output folder of _dependency_, not this item // find project in previous layers var p = pcp.Layers.SelectMany(x => x).First(z => z.Id == dependencyId); var relativeOutputFolderOfDependency = "\\" + MakeRelativePath(pcp.SolutionPath, Path.GetDirectoryName( p.Project.FileName )) + "\\" + pd.Project.OutputFolder; string adep = string.Format(ad, configurationNames[dependencyId].SourceBuildTypeXML, relativeOutputFolderOfDependency); rq = new RestRequest("/buildTypes/id:" + conf.id + "/artifact-dependencies"); rq.AddParameter("application/xml", adep, ParameterType.RequestBody); pcp.Client.Post<ArtifactDependency>(rq); } } }; }
private void BtnCreateProject_Click(object sender, RoutedEventArgs e) { Available = false; var pcp = new ProjectCreationParams { ServerUrl = ServerUrl, Username = Username, Password = TbPassword.Password, ProjectName = ProjectName, SolutionPath = SolutionPath, SolutionRelativePath = SolutionRelativePath, Log = this }; Action a = () => ProjectCreator.Start(pcp); a.BeginInvoke(ar => Dispatcher.Invoke(() => { Available = true; TbSubmit.Text = "Done creating project '" + ProjectName + "'. Enjoy!"; }), null); }