Query repo committed files order by commit date - libgit2sharp

I'd like to be able to have a collection of the files in the repo ordered by their commit date.
File Committed
abc.bat Dec 1 2013
bar.txt Jan 1 2010
baz.cmd Nov 8 2010
cru.zip Feb 9 2012
How can I do this with LibGit2Sharp so that I can order by Commit Date?
The reason I need to do this is that LibGit2Sharp doesn't allow you to .Pull(), thereby merging changes. If that were the case, I'd go about with a System.IO.DirectoryInfo and query by modified date in Windows. It seems we only have .Clone(), which doesn't maintain those dates in the file system.

Hmm. There's nothing out of the box that would fit this need.
However, by walking the revision history backwards and identifying additions and modifications, one could gather the date of the latest change of each file that exist in the commit being examined.
How about this?
public void LetUsTryThis()
{
using (var repo = new Repository(StandardTestRepoPath))
{
var referenceCommit = repo.Head.Tip;
IEnumerable<KeyValuePair<string, DateTimeOffset>> res = LatestChanges(repo, referenceCommit);
foreach (KeyValuePair<string, DateTimeOffset> kvp in res)
{
Console.WriteLine(string.Format("{0} - {1}", kvp.Key, kvp.Value));
}
}
}
private IEnumerable<KeyValuePair<string, DateTimeOffset>> LatestChanges(Repository repo, Commit referenceCommit)
{
IDictionary<string, DateTimeOffset> dic = new Dictionary<string, DateTimeOffset>();
var commitLog = repo.Commits.QueryBy(new CommitFilter { Since = referenceCommit })
.Concat(new[] { default(Commit) })
.Skip(1);
var mostRecent = referenceCommit;
foreach (Commit current in commitLog)
{
IEnumerable<KeyValuePair<string, DateTimeOffset>> res = ExtractAdditionsAndModifications(repo, mostRecent, current);
AddLatest(dic, res);
mostRecent = current;
}
return dic.OrderByDescending(kvp => kvp.Value);
}
private IEnumerable<KeyValuePair<string, DateTimeOffset>> ExtractAdditionsAndModifications(Repository repo, Commit next, Commit current)
{
IDictionary<string, DateTimeOffset> dic = new Dictionary<string, DateTimeOffset>();
var tc = repo.Diff.Compare(current == null ? null : current.Tree, next.Tree);
foreach (TreeEntryChanges treeEntryChanges in tc.Added)
{
dic.Add(treeEntryChanges.Path, next.Committer.When);
}
foreach (TreeEntryChanges treeEntryChanges in tc.Modified)
{
dic.Add(treeEntryChanges.Path, next.Committer.When);
}
return dic;
}
private void AddLatest(IDictionary<string, DateTimeOffset> main, IEnumerable<KeyValuePair<string, DateTimeOffset>> latest)
{
foreach (var kvp in latest)
{
if (main.ContainsKey(kvp.Key))
{
continue;
}
main.Add(kvp);
}
}

Related

How do I write a custom sorter to sort my springdoc swagger tags by name in the UI?

I am using springdoc-openapi with the latest version (1.3.0). Now I would like sort my tags in the UI by "name" property.
I know about the "springdoc.swagger-ui.tagsSorter" configuration and that I can use a custom sorter function. But I cannot find examples how the function should look like.
I tried the following which does not seem to work:
springdoc.swagger-ui.tagsSorter=(a, b) => a.get("name").localeCompare(b.get("name"))
By default, you can sort tags alphabetically:
https://springdoc.org/faq.html#how-can-i-sort-endpoints-alphabetically
You can have control on the tags order, using OpenApiCustomiser and define your own Comparator:
#Bean
public OpenApiCustomiser sortTagsAlphabetically() {
return openApi -> openApi.setTags(openApi.getTags()
.stream()
.sorted(Comparator.comparing(tag -> StringUtils.stripAccents(tag.getName())))
.collect(Collectors.toList()));
}
With reference from #brianbro's answer, as suggested at https://springdoc.org/faq.html#how-can-i-sort-endpoints-alphabetically
I added
#Tag(name="1. Admin endpoints")
#Tag(name = "2. Everyone's enpoints!")
and below prop to application.yml :
springdoc.swagger-ui.tagsSorter=alpha
And can see them sorted according to numbering on my swagger UI.
For sorting schemas , paths and tags in OpenApi.
#Bean
public OpenApiCustomiser openApiCustomiser() {
return openApi -> {
Map<String, Schema> schemas = openApi.getComponents().getSchemas();
openApi.getComponents().setSchemas(new TreeMap<>(schemas));
};
}
#Bean
public OpenApiCustomiser sortPathsAndTagsAlphabetically() {
return openApi -> {
Map<String, PathItem> paths = openApi.getPaths();
Paths sortedPaths = new Paths();
TreeMap<String, PathItem> sortedTree = new TreeMap<String, PathItem>(paths);
Set<Map.Entry<String, PathItem>> pathItems = sortedTree.entrySet();
Map<String, Map.Entry<String, PathItem>> distinctTagMap = new TreeMap<String, Map.Entry<String, PathItem>>();
for ( Map.Entry<String, PathItem> entry:pathItems) {
PathItem pathItem = entry.getValue();
Operation getOp = pathItem.getGet();
if(getOp != null) {
String tag = getOp.getTags().get(0);
if (!distinctTagMap.containsKey(tag)) {
distinctTagMap.put(tag, entry);
}
}
Operation postOp = pathItem.getPost();
if(postOp != null){
String tag1 = postOp.getTags().get(0);
if(!distinctTagMap.containsKey(tag1)){
distinctTagMap.put(tag1,entry);
}
}
Operation putOp = pathItem.getPut();
if(putOp != null) {
String tag2 = putOp.getTags().get(0);
if (!distinctTagMap.containsKey(tag2)) {
distinctTagMap.put(tag2, entry);
}
}
}
LinkedHashMap<String, PathItem> customOrderMap = new LinkedHashMap<String, PathItem>();
for (Map.Entry<String, PathItem> entry: distinctTagMap.values()) {
customOrderMap.put(entry.getKey(), entry.getValue());
}
for(Map.Entry<String, PathItem> entry : sortedTree.entrySet()) {
customOrderMap.putIfAbsent(entry.getKey(), entry.getValue());
}
sortedPaths.putAll(customOrderMap);
openApi.setPaths(sortedPaths);
};
}

update the TFS build definitions automated way

we are migrating from TFS2010 to TFS2015 update3.
we would like to update all existing TFS2010 XAML build definitions with the new TFS2015 XAML controllers & agent names. is there an automated way this can be accomplished , as it needs to be done on all existing build definitions.
You can try using TFS API to update the XAML build definitions:
Below sample for your reference: (Reference this thread for details: Updating the build definition for many TFS projects)
Call it like BuildControllerChangeUtil http://tfsserver:8080/tfs/defaultcollection ProjectName where the projectname is a project whose builds have updated build servers.
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
using System.Collections.Generic;
using System.Linq;
namespace BuildControllerChangeUtil
{
class Program
{
static void Main(string[] args)
{
string tfsDefaultcollection = args[0];
string knownGoodProject = args[1];
var tfs = new TfsTeamProjectCollection(new Uri(tfsDefaultcollection));
var buildServer = tfs.GetService<IBuildServer>();
var knownGoodDefs = buildServer.QueryBuildDefinitions(knownGoodProject);
var testController = knownGoodDefs.First(bd => bd.Name.Equals("Test")).BuildController ;
var releaseController = knownGoodDefs.First(bd => bd.Name.Equals("Release")).BuildController ;
foreach (var teamProject in GetTfsProjects( tfsDefaultcollection ))
{
var buildDetails = buildServer.QueryBuildDefinitions(teamProject);
if (!buildDetails.Any())
{
Console.WriteLine("{0} has no build defintions. ", teamProject);
}
foreach (var thisBuild in buildDetails)
{
if (thisBuild.Name.ToUpperInvariant().Contains("TEST"))
{
SetBuildController(teamProject, thisBuild, testController);
}
else if (thisBuild.Name.ToUpperInvariant().Contains("PRODUCTION"))
{
SetBuildController(teamProject, thisBuild, releaseController);
}
else
{
Console.Error.WriteLine( "Team project {0} had an unknown build name {1}",teamProject , thisBuild.Name);
}
}
}
}
private static void SetBuildController(string teamProject, IBuildDefinition thisBuild, IBuildController bc)
{
Console.WriteLine("setting {0} build {1} build controller to {2}", teamProject , thisBuild.Name, bc.Name );
thisBuild.BuildController = bc;
thisBuild.Save();
}
private static IEnumerable<string> GetTfsProjects(string tfsAddress)
{
var tpcAddress = new Uri(tfsAddress);
var tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tpcAddress);
tpc.Authenticate();
var workItemStore = new WorkItemStore(tpc);
var projectList = (from Project pr in workItemStore.Projects select pr.Name).ToList();
return projectList;
}
}
}

EF6.1.3 Expects CreatedOn field in __MigrationHistory table when upgrading in VS2015 IDE

in program.cs I have
private static bool CheckMigrationVersionAndUpgradeIfNeeded()
{
try
{
using (var db = new jtDbContext())
{
if (db.Database.CompatibleWithModel(false))
{
return true;
}
else
{
return RunMigrations(db);
}
}
}
catch (Exception ex)
{
var s = string.Format("Problem in MigrateIfNeeded /n/p" + ex);
MessageBox.Show(s);
return false;
}
}
private static bool RunMigrations(jtDbContext db)
{
if (!AskForPassword()) { return false}
return db.RunMigrations();
}
in my context i have
public void RunMigrations()
{
var configuration = new Configuration();
var migrator = new DbMigrator(configuration);
var pendings = migrator.GetPendingMigrations();
foreach (var pending in pendings)
{
migrator.Update(pending);
}
}
I see from this question that there was an issue in EF5 relating to this field.
I am using DevExpress Xaf in the project but I cant see how this could be relevant.
I can still run the migration by typing update-database at the PM> prompt
I can work around the problem by running the following script prior to updating
ALTER TABLE dbo.__MigrationHistory ADD CreatedOn DateTime Default GETDATE()
GO
UPDATE dbo.__MigrationHistory SET CreatedOn = GETDATE()
[Update] The problem happens when running within the VS2015 Update1 IDE. It does not happen when I run the .exe

Read Process Template Version and TypeID in an ISubscriber plugin for TFS

I'm setting up a TFS ISubscriber plugin and I want to be able to decide whether to trigger based on the installed Process Template Name (DONE), TypeID and Version.
The code to read the name is relatively straightforward:
var ics = context.GetService<ICommonStructureService>();
string ProjectName = string.Empty;
string ProjectState = String.Empty;
int templateId = 0;
CommonStructureProjectProperty[] ProjectProperties = null;
ics.GetProjectProperties(context, projectUri.ToString(), out ProjectName, out ProjectState, out ProjectProperties);
// The Projectproperties contains a property called "Process Template", holding the name.
But I can't find a way to read the other properties... I've nicked this code from looking at the TFS assemblies using Reflector, but it always returns Unknown:
private ArtifactSpec GetProcessTemplateVersionSpec(string projectUri)
{
var commonService = this.context.GetService<CommonStructureService>();
Guid guid = commonService.GetProject(this.context, projectUri).ToProjectReference().Id;
return new ArtifactSpec(ArtifactKinds.ProcessTemplate, guid.ToByteArray(), 0);
}
public ProcessTemplateVersion GetCurrentProjectProcessVersion(Uri projectUri)
{
return this.GetProjectProcessVersion(projectUri.AbsoluteUri, ProcessTemplateVersionPropertyNames.CurrentVersion);
}
public ProcessTemplateVersion GetCreationProjectProcessVersion(Uri projectUri)
{
return this.GetProjectProcessVersion(projectUri.AbsoluteUri, ProcessTemplateVersionPropertyNames.CreationVersion);
}
private ProcessTemplateVersion GetProjectProcessVersion(string projectUri, string versionPropertyName)
{
ArtifactSpec processTemplateVersionSpec = GetProcessTemplateVersionSpec(projectUri);
ProcessTemplateVersion unknown = ProcessTemplateVersion.Unknown;
using (TeamFoundationDataReader reader = context.GetService<TeamFoundationPropertyService>().GetProperties(context, processTemplateVersionSpec, new string[] { versionPropertyName }))
{
foreach (ArtifactPropertyValue value2 in reader)
{
foreach (PropertyValue value3 in value2.PropertyValues)
{
return TeamFoundationSerializationUtility.Deserialize<ProcessTemplateVersion>(value3.Value as string);
}
return unknown;
}
return unknown;
}
}
Even worse, I'd also like to be able to do this from the client Object Model, but that seems even harder.
After consulting with the Microsoft Product Team I'm sad to report that this property is currently only supported by Visual Studio Online and that the values are not even stored for on-premise instances.
There is a sort-of work around from Rene van Osnabrugge to copy these values and place them in the "standard" project properties.
Put the following in your Classification.xml of each process template:
<properties>
<property name="MSPROJ" value="Classification\FieldMapping.xml" isFile="true" />
<property name="Process Template" value="Microsoft Visual Studio Scrum 2.2" />
<property name="Create Version" value="Custom Text is allowed here" />
<property name="Current Version" value="Custom Text is allowed here" />
</properties>
And use this code to read it afterwards:
string uri = #"http://myServer:8080/tfs/defaultcollection";
string teamProjectName = "myTeamProject";
// Get the team project
var tpc = new TfsTeamProjectCollection(new Uri(uri));
tpc.Authenticate();
var ics = tpc.GetService<ICommonStructureService>();
var teamProject = ics.GetProjectFromName(teamProjectName);
// Read the properties
string projectName = string.Empty;
string projectState = string.Empty;
int templateId = 0;
ProjectProperty[] projectProperties = null;
ics.GetProjectProperties(teamProject.Uri, out projectName, out projectState, out templateId, out projectProperties);
// Return the properties
string processtemplate = projectProperties.Where(p => (p.Name == "Process Template")).Select(p => p.Value).FirstOrDefault();
string currentVersion = projectProperties.Where(p => (p.Name == "Current version")).Select(p => p.Value).FirstOrDefault();
string createVersion = projectProperties.Where(p => (p.Name == "Create version")).Select(p => p.Value).FirstOrDefault();
//Update the properties
projectProperties.Where(p => (p.Name == "Current version")).First().Value = "MS Scrum 2.2 - Custom 2.3";
ics.UpdateProjectProperties(teamProject.Uri, projectState, projectProperties);

TFS: How can I automatically close matching work items on successful build?

We are using continuous integration as part of our build automation. For every check in, the tfs build server builds the project and deploys to our web servers on success.
When the build fails, it automatically creates a new Bug with the details of the build failure.
Due to CI and the activity on the server, this might result in 10 or 20 failure work items before the build starts succeeding again.
So, I have two options. I'd like to either have the build process see if an open work item already exists for a build failure and just add details to that; OR, I'd like the build server to close all of the build failure items automatically when it starts working again.
Any ideas?
You can create a MSBuild Task to do either of these options. Here is a similar piece of code I use to get you started but since I don't know the details of your work item or process you will have to change it.
This code takes all of the work items associated with a build and updates their status.
If you select your first option you can just change the UpdateWorkItemStatus method and update any existing WIs. For the Second method you will need to do a bit more work as you need to look up the prior build rather than take it as a input.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.Build.Framework;
using Microsoft.TeamFoundation.Build;
using Microsoft.TeamFoundation.Build.Client;
namespace Nowcom.TeamBuild.Tasks
{
public class UpdateWorkItemState: Task
{
private IBuildDetail _Build;
private void test()
{
TeamFoundationServerUrl = "Teamserver";
BuildUri = "vstfs:///Build/Build/1741";
Execute();
}
public override bool Execute()
{
bool result = true;
try
{
TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(TeamFoundationServerUrl, new UICredentialsProvider());
tfs.EnsureAuthenticated();
WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
IBuildServer buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
_Build = buildServer.GetAllBuildDetails(new Uri(BuildUri));
//add build step
IBuildStep buildStep = InformationNodeConverters.AddBuildStep(_Build, "UpdateWorkItemStatus", "Updating Work Item Status");
try
{
Log.LogMessageFromText(string.Format("Build Number: {0}", _Build.BuildNumber), MessageImportance.Normal);
List<IWorkItemSummary> assocWorkItems = InformationNodeConverters.GetAssociatedWorkItems(_Build);
// update work item status
UpdateWorkItemStatus(store, assocWorkItems, "Open", "Resolved");
SaveWorkItems(store, assocWorkItems);
}
catch (Exception)
{
UpdateBuildStep(buildStep, false);
throw;
}
UpdateBuildStep(buildStep, result);
}
catch (Exception e)
{
result = false;
BuildErrorEventArgs eventArgs;
eventArgs = new BuildErrorEventArgs("", "", BuildEngine.ProjectFileOfTaskNode, BuildEngine.LineNumberOfTaskNode, BuildEngine.ColumnNumberOfTaskNode, 0, 0, string.Format("UpdateWorkItemState failed: {0}", e.Message), "", "");
BuildEngine.LogErrorEvent(eventArgs);
throw;
}
return result;
}
private static void SaveWorkItems(WorkItemStore store, List<IWorkItemSummary> assocWorkItems)
{
foreach (IWorkItemSummary w in assocWorkItems)
{
WorkItem wi = store.GetWorkItem(w.WorkItemId);
if (wi.IsDirty)
{
wi.Save();
}
}
}
// check in this routine if the workitem is a bug created by your CI process. Check by title or assigned to or description depending on your process.
private void UpdateWorkItemStatus(WorkItemStore store, List<IWorkItemSummary> assocWorkItems, string oldState, string newState)
{
foreach (IWorkItemSummary w in assocWorkItems)
{
Log.LogMessageFromText(string.Format("Updating Workitem Id {0}", w.WorkItemId), MessageImportance.Normal);
WorkItem wi = store.GetWorkItem(w.WorkItemId);
if (wi.Fields.Contains("Microsoft.VSTS.Build.IntegrationBuild") && wi.State != "Resolved")
{
wi.Fields["Microsoft.VSTS.Build.IntegrationBuild"].Value =_Build.BuildNumber;
}
if (wi.State == oldState)
{
wi.State = newState;
foreach (Field field in wi.Fields)
{
if (!field.IsValid)
{
break;
}
}
}
if (wi.IsDirty)
{
wi.Save();
}
}
}
private void UpdateBuildStep(IBuildStep step, bool result)
{
step.Status = result ? BuildStepStatus.Succeeded : BuildStepStatus.Failed;
step.FinishTime = DateTime.Now;
step.Save();
}
[Required]
public string BuildUri { get; set; }
[Required]
public string TeamFoundationServerUrl {get; set;}
}
}
< UpdateWorkItemState
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
ContinueOnError="false"/>

Resources