Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] ClosedDate is set to Null and will revert to the current date on save! #1959

Open
MrHinsh opened this issue Feb 27, 2024 · 19 comments
Open

Comments

@MrHinsh
Copy link
Member

MrHinsh commented Feb 27, 2024

          Any update on a fix?

In both v14.4.6 and v14.4.7 I receive the additional warning logs on these "ClosedDateIsMigrationDate" work items:
2024-02-26 15:32:18.078 -06:00 [WRN] The field Microsoft.VSTS.Common.ClosedDate is set to Null and will revert to the current date on save! 2024-02-26 15:32:18.078 -06:00 [WRN] Source Closed Date [#nnnnnn][Rev4]: "2022-04-20T14:04:02.1230000-05:00"

The History tab on the source work items has the Closed revision data showing: Closed by, Closed Date, Board Column (new and old), Reason (new and old), Resolved By, and State (new and old).

Originally posted by @t-anderson in #1747 (comment)

Somehow between these two breakpoints the value is lost!

https://github.com/nkdAgility/azure-devops-migration-tools/blob/855c55cefb23b27ae62aedca45127a6430c65103/src/VstsSyncMigrator.Core/Execution/MigrationContext/WorkItemMigrationContext.cs

  • 801 - Mapps the existing Source fields to the Target fields
  • 846 - System.ClosedDate comes up Null!

image


HELP NEEDED - We are unable to replicate this! But it does happen!

Can someone with this error please run a specific work item that they find has this issue through the tool and do one of the following:

Option 1: Generate and attach Log - if you are non-technical this is your option. It might provide us with enough info to diagnose, but may only result in more asks.

  1. In the Config file change LogLevel to Debug.
  2. Find a work item ID that has this issue, and craft a query that only selects this work item.
  3. Delete any target copy of that work item.
  4. Then run the migration
  5. Comment here with the full Log attached

Option 2: Debug in Visual Studio - This option is best but requires some developer experience.

  1. Fork the Repo and Clone it to your local computer
  2. Open the Solution in Visual Studio (we use 2022) and do a Full Rebuild
  3. Edit the Launch Profile to point to your config.
    image
  4. Craft the query to only load the work item with the issue
  5. Add the breakpoints detailed above
  6. "Play" the Launch Profile that you created and

Create a comment below with the results of your investigation!

@MrHinsh MrHinsh self-assigned this Feb 27, 2024
@MrHinsh MrHinsh changed the title ClosedDate is set to Null and will revert to the current date on save! [Bug] ClosedDate is set to Null and will revert to the current date on save! Feb 27, 2024
@TomBolen
Copy link

TomBolen commented Mar 21, 2024

Hello, i can reproduced the issue.

The Problem is that the field Microsoft.VSTS.Common.ClosedDate is readonly at the target.

image

The check of the State in this Line (Current Master Branch Line No. 474 ):

if (!_ignore.Contains(f.ReferenceName) &&
(!newWorkItem.Fields[f.ReferenceName].IsChangedInRevision || newWorkItem.Fields[f.ReferenceName].IsEditable)
&& oldWorkItem.Fields[f.ReferenceName].Value != newWorkItem.Fields[f.ReferenceName].Value)

returns false and the Field in the target can't be set.

State Values:
newWorkItem.Fields[f.ReferenceName].IsChangedInRevision = true
newWorkItem.Fields[f.ReferenceName].IsEditable = false
oldWorkItem.Fields[f.ReferenceName].Value = 04/08/2019 12:05:04
newWorkItem.Fields[f.ReferenceName].Value = null

Source: DevOps Server on premise
Target: Azure DevOps Server

@MrHinsh
Copy link
Member Author

MrHinsh commented Mar 21, 2024

This is great work. If IsEditable is false, then there is no way we can update it.

What we need to figure out is what is causing the IsEditable to be false. What are the previous revisions and what is causing the work item to be in a state where its not editable. It might be something that we can check for...

@MrHinsh
Copy link
Member Author

MrHinsh commented Mar 21, 2024

Could you be clearer as to the source and target version? Which versions are TFS (on-prem) and which are ADO (cloud)...

p.s. I just call everything on-prem TFS as it avoids confusion...

@TomBolen
Copy link

On-Prem it is the latest Version of DevOps 2020.1.2 with Patch 9.
Target ist the current Version of Microsoft Azure DevOps environment. (dev.azure.com)
Both are running the default Agile Template of Microsoft with limited changes.
The biggest different is the language. Why ever i did that, but the local installation is german...
For the migration i made this translation in the json file:
"FieldMaps": [
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "",
"sourceField": "System.State",
"targetField": "System.State",
"defaultValue": "New",
"valueMapping": {
"Neu": "New",
"Aktiv": "Active",
"Gelöst": "Resolved",
"Geschlossen": "Closed",
"Entfernt": "Removed"
}
},
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "
",
"sourceField": "Microsoft.VSTS.Common.Risk",
"targetField": "Microsoft.VSTS.Common.Risk",
"defaultValue": "3 - Low",
"valueMapping": {
"1 - Hoch": "1 - High",
"2 - Mittel": "2 - Medium",
"3 - Niedrig": "3 - Low"
}
},
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "",
"sourceField": "Microsoft.VSTS.Common.Severity",
"targetField": "Microsoft.VSTS.Common.Severity",
"defaultValue": "3 - Medium",
"valueMapping": {
"1 - Kritisch": "1 - Critical",
"2 - Hoch": "2 - High",
"3 - Mittel": "3 - Medium",
"4 - Niedrig": "4 - Low"
}
},
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "
",
"sourceField": "Microsoft.VSTS.Common.ValueArea",
"targetField": "Microsoft.VSTS.Common.ValueArea",
"defaultValue": "Business",
"valueMapping": {
"Geschäft": "Business",
"Architektonisch": "Architectural"
}
},
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "",
"sourceField": "Microsoft.VSTS.Common.Activity",
"targetField": "Microsoft.VSTS.Common.Activity",
"defaultValue": "",
"valueMapping": {
"Bereitstellung": "Deployment",
"Entwurf": "Design",
"Entwicklung": "Development",
"Dokumentation": "Documentation",
"Anforderung": "Requirements",
"Test": "Testing"
}
},
{
"$type": "FieldValueMapConfig",
"WorkItemTypeName": "
",
"sourceField": "Microsoft.VSTS.Common.ResolvedReason",
"targetField": "Microsoft.VSTS.Common.ResolvedReason",
"defaultValue": "",
"valueMapping": {
"Korrigiert": "Fixed"
}
}
],

@TomBolen
Copy link

And this is the test config of my WorkItemMigrationConfig Processor:
{
"$type": "WorkItemMigrationConfig",
"Enabled": true,
"UpdateCreatedDate": true,
"UpdateCreatedBy": true,
"WIQLQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @teamproject AND [System.ID] >= 160 AND [System.ID] <= 165 AND [System.WorkItemType] NOT IN ('Codeüberprüfungsanforderung', 'Codeüberprüfungsantwort', 'Testsuite', 'Testfall', 'Testplan','Shared Steps','Shared Parameter','Feedback Request') ORDER BY [System.Id] asc",
"AttachmentMigration": true,
"AttachmentWorkingPath": "c:\devopsmigrate\WorkItemAttachmentWorkingFolder\",
"FixHtmlAttachmentLinks": false,
"SkipToFinalRevisedWorkItemType": false,
"WorkItemCreateRetryLimit": 5,
"FilterWorkItemsThatAlreadyExistInTarget": false,
"PauseAfterEachWorkItem": false,
"AttachmentMaxSize": 480000000,
"AttachRevisionHistory": false,
"LinkMigrationSaveEachAsAdded": false,
"GenerateMigrationComment": false,
"WorkItemIDs": null,
"MaxGracefulFailures": 0,
"SkipRevisionWithInvalidIterationPath": false,
"SkipRevisionWithInvalidAreaPath": false
},

@Slawisch
Copy link

Hello, I hope all is well! I wanted to check in and see if there's been any progress on the bug.
I also ran into it, couple more details from my attempts:
Not all items are affected, just some of them, and it doesn't seem to matter what type of work item it is – we can't find any pattern.
Also, when we skip migrating the work item's history, it always sets today's date, but that might just be how it's supposed to work.
I'm on version 15.0.0, by the way.

Any updates or tips would be super helpful and much appreciated.

@MrHinsh
Copy link
Member Author

MrHinsh commented Mar 27, 2024

@Slawisch thanks for getting in touch. We have not been able to identify a pattern either... I've raised it with the product team, and added additional logging to see what the issue is.

It would require some debugging in Visual Studio to really find the issue. There are some instructions above if you can!

@Slawisch
Copy link

Hello again. I think I found why it happens.
Pattern - when change to 'Closed' state is in the last revision. When WI's state is 'Closed' before it, 'Closed Date' is set in the next revision.

Why it happens:
On the line 470: newWorkItem.State = oldWorkItem.State; it changes the state of target item. And if isEditable = true - it gets reset to false (I think that's some inner logic of WorkItem type).
So, if, for example, it is the last revision, we set State to 'Closed', isEditable becomes false and it's impossible to update Closed Date.
But, if it is the last revision, and we already have State set to Closed, then state isn't updated on that line and isEditable remains true. And date is changed successfully.

@MrHinsh
Copy link
Member Author

MrHinsh commented Mar 31, 2024

Im not sure I 100% follow your workflow there... could you update it to make it clearer? It will help me understand if I can 1) make a code change to fix it, or 2) replicate it locally.

Can you specify exactly what the order of revisions is on the source?

if I can replicate it here, I can try some cod-itzu (code+jujitzu) to get this resolved.

@Slawisch
Copy link

Slawisch commented Apr 1, 2024

_n - number of revisions, so that Rev.: n, for example, is the last one.

Scenario when bug happens:

Rev.: n-2
State: Active
Closed Date: not set

Rev.: n-1
State: Active
Closed Date: not set

Rev.: n
State: Closed
Closed Date: any date on source

Result: closed date not set on target

Scenario when bug does not happen:

Rev.: n-2
State: Active
Closed Date: not set

Rev.: n-1
State: Closed
Closed Date: any date on source

Rev.: n
State: Closed
Closed Date: any date on source

Result: closed date set on target only on last revision

@MrHinsh
Copy link
Member Author

MrHinsh commented Apr 1, 2024

OK, so based on @Slawisch's awesome work here it looks like we could work around this by injecting a new revision in the Bug Senario to turn it into No-Bug Senario!

@MrHinsh
Copy link
Member Author

MrHinsh commented Apr 1, 2024

For that we need to detect the scenario when building the revisions in the TfsRevisionManager and add the extra one.

@Slawisch
Copy link

Slawisch commented Apr 2, 2024

I made some changes locally just to make it work already. Sure it could be done better, but I just needed it to be done somehow, so here what I did so far:

Created new function to copy last revision and push it with some minor changes:

public SortedDictionary<int, RevisionItem> PushLastRevisionCopy(SortedDictionary<int, RevisionItem> sourceRevisions)
        {
            if (sourceRevisions.Any())
            {
                var revisionToPushJson = JsonConvert.SerializeObject(sourceRevisions.Last().Value);
                var revisionToPush = JsonConvert.DeserializeObject<RevisionItem>(revisionToPushJson);

                revisionToPush.Number += 1;
                revisionToPush.Index += 1;
                revisionToPush.Fields["System.Rev"].Value = revisionToPush.Number;

                // Date updates
                var dateFieldsToUpdate = new List<string>
                {
                    "Microsoft.VSTS.Common.StateChangeDate",
                    "Microsoft.VSTS.Common.ClosedDate",
                    "System.ChangedDate"
                };

                foreach (var fieldName in dateFieldsToUpdate)
                {
                    if (revisionToPush.Fields.TryGetValue(fieldName, out var fieldValue) && fieldValue.Value is DateTime dateTime)
                    {
                        revisionToPush.Fields[fieldName].Value = dateTime.AddMinutes(1);
                    }
                }

                // Clear history field if it exists
                if (revisionToPush.Fields.ContainsKey("System.History"))
                {
                    revisionToPush.Fields["System.History"].Value = string.Empty;
                }

                sourceRevisions.Add(revisionToPush.Number, revisionToPush);
            }

            return sourceRevisions;
        }

And calling it in WorkItemMigrationContext.cs on line 219 just in the beginning of foreach

sourceWorkItemData.Revisions = _revisionManager.PushLastRevisionCopy(sourceWorkItemData.Revisions);

@Slawisch
Copy link

Slawisch commented Apr 5, 2024

I also have some offtopic question, @MrHinsh, we may get The work item type cannot be found. It may have been renamed or destroyed. error in case some type on source has been destroyed but still remains in revisions. So, is there any way to successfully migrate WI with deleted WI Type on Source (and migrate WI's history as well along with WI)?

@MrHinsh
Copy link
Member Author

MrHinsh commented Apr 5, 2024

The error is comming from ADO and not from our code. We can only migrate work items that we can open. 🤷‍♂️

@Slawisch
Copy link

Hi again, is there any news on a fix?

@MrHinsh
Copy link
Member Author

MrHinsh commented Apr 12, 2024

There is no fix on my end for this. It's an Azure DevOps OM issue...

@Slawisch
Copy link

Sorry, I mean ClosedDate fix, with pushing one extra revision

@Slawisch
Copy link

Hey👋 Just wonder, if you meant ClosedDate bug or "work item cannot be found" error in your latest comment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

3 participants