• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HicServices / RDMP / 7194961165

13 Dec 2023 12:07PM UTC coverage: 56.776% (-0.2%) from 57.013%
7194961165

push

github

web-flow
Merge Latest Release into main (#1702)

* Bump YamlDotNet from 13.3.1 to 13.4.0

Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 13.3.1 to 13.4.0.
- [Release notes](https://github.com/aaubry/YamlDotNet/releases)
- [Commits](https://github.com/aaubry/YamlDotNet/compare/v13.3.1...v13.4.0)

---
updated-dependencies:
- dependency-name: YamlDotNet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump shogo82148/actions-setup-perl from 1.23.1 to 1.24.1

Bumps [shogo82148/actions-setup-perl](https://github.com/shogo82148/actions-setup-perl) from 1.23.1 to 1.24.1.
- [Release notes](https://github.com/shogo82148/actions-setup-perl/releases)
- [Commits](https://github.com/shogo82148/actions-setup-perl/compare/v1.23.1...v1.24.1)

---
updated-dependencies:
- dependency-name: shogo82148/actions-setup-perl
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix checkbox issue

* improve confirmation text (#1639)

* improve confirmation text
* Loop tidyup, use var where possible

---------

Co-authored-by: jas88 <j.a.sutherland@dundee.ac.uk>

* correct typo in create logging sql (#1640)

* Feature/ci codescan (#1641)

* Move SecurityCodescan.VS2019 to run on Github CI alone, integrate results with CodeQL
* Remove SecurityCodescan from Packages.md, no longer used via Nuget

---------

Co-authored-by: James A Sutherland <j@sutherland.pw>

* hide source control when not available

* Remove old Plugin object bits, tidy up (#1636)

* Remove old Plugin object bits, tidy up

* Purge remaining bits of AllExpiredPluginsNode

* Fix plugin display name in tree

* Update CreateNewDataExtractionProjectUI.cs

Casting fix

* Feature/rdmp42 delete plugins (#1642)

* add ui plugin delete functionality

* Warning and inherita... (continued)

10722 of 20351 branches covered (0.0%)

Branch coverage included in aggregate %.

215 of 789 new or added lines in 63 files covered. (27.25%)

39 existing lines in 16 files now uncovered.

30650 of 52518 relevant lines covered (58.36%)

7294.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.56
/Rdmp.Core/Curation/Data/CommitInProgress.cs
1
// Copyright (c) The University of Dundee 2018-2019
2
// This file is part of the Research Data Management Platform (RDMP).
3
// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4
// RDMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5
// You should have received a copy of the GNU General Public License along with RDMP. If not, see <https://www.gnu.org/licenses/>.
6

7
using System;
8
using System.Collections.Generic;
9
using System.Linq;
10
using Rdmp.Core.CommandExecution;
11
using Rdmp.Core.MapsDirectlyToDatabaseTable;
12
using Rdmp.Core.Repositories;
13
using YamlDotNet.Serialization;
14

15
namespace Rdmp.Core.Curation.Data;
16

17
/// <summary>
18
/// Tracks changes made by the user to one or more objects.  Changes are tracked from
19
/// the moment the class is constructed until <see cref="TryFinish(IBasicActivateItems)"/>
20
/// completes successfully.  This helps with cancellation
21
/// </summary>
22
public class CommitInProgress : IDisposable
23
{
24
    private Dictionary<IMapsDirectlyToDatabaseTable, MementoInProgress> originalStates = new();
4✔
25

26
    public CommitInProgressSettings Settings { get; }
12✔
27

28
    private IRDMPPlatformRepositoryServiceLocator _locator;
29
    private List<IRepository> _repositories;
30
    private ISerializer _serializer;
31

32
    /// <summary>
33
    /// True when <see cref="TryFinish(IBasicActivateItems)"/> is confirmed to definitely be happening.  Controls
34
    /// save suppression
35
    /// </summary>
36
    private bool _finishing;
37

38
    private bool _isDisposed;
39

40
    /// <summary>
41
    /// Starts progress towards creating a <see cref="Commit"/>.
42
    /// </summary>
43
    /// <param name="locator"></param>
44
    /// <param name="settings"></param>
45
    public CommitInProgress(IRDMPPlatformRepositoryServiceLocator locator, CommitInProgressSettings settings)
4✔
46
    {
47
        Settings = settings;
4✔
48

49
        _locator = locator;
4✔
50

51
        _repositories = _locator.GetAllRepositories().ToList();
4✔
52
        _serializer = YamlRepository.CreateSerializer(_repositories.SelectMany(r => r.GetCompatibleTypes()).Distinct()
12✔
53
        );
4✔
54

55
        foreach (var repo in _repositories)
24✔
56
        {
57
            repo.Deleting += Deleting;
8✔
58
            repo.Inserting += Inserting;
8✔
59

60
            if (settings.UseTransactions)
8✔
61
                // these get cleaned up in Dispose or TryFinish
62
                repo.BeginNewTransaction();
4✔
63
        }
64

65
        foreach (var t in settings.ObjectsToTrack)
16✔
66
            originalStates.Add(t, new MementoInProgress(t, _serializer.Serialize(t)));
4✔
67
    }
4✔
68

69
    private void Inserting(object sender, IMapsDirectlyToDatabaseTableEventArgs e)
70
    {
71
        if (_finishing)
8!
72
            return;
8✔
73

74
        // if we are not in global mode with transactions then this is a long term
75
        // commit (e.g. user has tab open for half an hour).  Don't hoover up all created/deleted objects
76
        if (!Settings.UseTransactions) return;
×
77

78
        // how can we be tracking an object that was not created yet?
79
        if (originalStates.TryGetValue(e.Object, out var state))
×
80
            // oh well just pretend it magicked into existence
81
            state.Type = MementoType.Add;
×
82
        else
83
            // legit new object we didn't know about before
84
            originalStates.Add(e.Object, new MementoInProgress(e.Object, null)
×
85
            {
×
86
                Type = MementoType.Add
×
87
            });
×
88
    }
×
89

90
    private void Deleting(object sender, IMapsDirectlyToDatabaseTableEventArgs e)
91
    {
92
        if (_finishing)
×
93
            return;
×
94

95
        // if we are not in global mode with transactions then this is a long term
96
        // commit (e.g. user has tab open for half an hour).  Don't hoover up all created/deleted objects
97
        if (!Settings.UseTransactions) return;
×
98

99
        // one of the objects we are tracking has been deleted
NEW
100
        if (originalStates.TryGetValue(e.Object, out var inProgress))
×
101
        {
102
            // change our understanding of this object
103

NEW
104
            if (inProgress.Type == MementoType.Add)
×
105
                // ok user created this object during the commit then deleted it again... odd but fair enough
106
                // pretend it never existed
107
                originalStates.Remove(e.Object);
×
108
            else
NEW
109
                inProgress.Type = MementoType.Delete;
×
110
        }
111
        else
112
        {
113
            // an object we are not yet tracking has been deleted
114
            originalStates.Add(e.Object, new MementoInProgress(e.Object, _serializer.Serialize(e.Object))
×
115
            {
×
116
                Type = MementoType.Delete
×
117
            });
×
118
        }
119
    }
×
120

121
    /// <summary>
122
    /// Returns a new <see cref="Commit"/> or null if nothing has changed with
123
    /// the tracked objects since construction.
124
    /// </summary>
125
    /// <returns></returns>
126
    public Commit TryFinish(IBasicActivateItems activator)
127
    {
128
        if (_finishing)
4!
129
            throw new ObjectDisposedException(
×
130
                $"{nameof(CommitInProgress)} has already been successfully finished and shutdown",
×
131
                nameof(CommitInProgress));
×
132

133
        if (_isDisposed)
4!
134
            throw new ObjectDisposedException(nameof(CommitInProgress));
×
135

136
        var changes = new Dictionary<IMapsDirectlyToDatabaseTable, Tuple<MementoInProgress, string>>();
4✔
137

138
        foreach (var t in originalStates)
16✔
139
        {
140
            // serialize the current state on finishing into yaml (or use null for deleted objects)
141
            var newYaml = t.Value.Type == MementoType.Delete ? null : _serializer.Serialize(t.Key);
4!
142

143
            //something changed
144
            if (newYaml != t.Value.OldYaml) changes.Add(t.Key, Tuple.Create(t.Value, newYaml));
6✔
145
        }
146

147
        if (!changes.Any())
4✔
148
            // no changes so no need for a Commit
149
            return null;
2✔
150
        var cataRepo = _locator.CatalogueRepository;
2✔
151

152
        var description = GetDescription(changes);
2✔
153
        var transaction = Guid.NewGuid();
2✔
154

155
        if (activator.IsInteractive)
2!
156
        {
157
            // object name or count of the number of objects
158
            var collectionDescription =
×
159
                changes.Count == 1 ? changes.Single().Key.ToString() : $"{changes.Count} object(s)";
×
160

161
            if (activator.TypeText(new DialogArgs
×
162
            {
×
163
                WindowTitle = transaction.ToString(),
×
164
                TaskDescription = $"Enter a description of what changes you have made to {collectionDescription}"
×
165
            }, int.MaxValue, description, out var newDescription, false))
×
166
                description = newDescription;
×
167
            else
168
                // user cancelled creating Commit
169
                return null;
×
170
        }
171

172
        // We couldn't describe the changes, that's bad...
173
        if (description == null)
2!
174
            return null;
×
175

176
        // Ok user has typed in a description (or system generated one) and we are
177
        // definitely going to do this
178

179
        _finishing = true;
2✔
180

181
        var c = new Commit(cataRepo, transaction, description);
2✔
182

183
        foreach (var m in changes.OrderBy(c => c.Value.Item1.Order))
10✔
184
            _ = new Memento(cataRepo, c, m.Value.Item1.Type, m.Key, m.Value.Item1.OldYaml, m.Value.Item2);
2✔
185

186
        // if we created a bunch of db transactions (one per database/server known about) for this commit
187
        // then we should be letting these changes go ahead
188
        if (Settings.UseTransactions)
2!
189
            foreach (var repo in _repositories)
×
190
                repo.EndTransaction(true);
×
191

192
        return c;
2✔
193
    }
194

195
    private string GetDescription(Dictionary<IMapsDirectlyToDatabaseTable, Tuple<MementoInProgress, string>> changes)
196
    {
197
        // no changes
198
        if (changes.Count == 0)
2!
199
            return null;
×
200

201
        if (Settings.Description != null) return Settings.Description;
2!
202

203
        // we can't summarise changes to multiple objects
204
        if (changes.Count != 1) return "TODO";
2!
205

206
        var kv = changes.Single();
2✔
207
        var props = kv.Value.Item1.GetDiffProperties(kv.Key).ToArray();
2✔
208

209
        // no visible changes... but yaml is different which is odd.
210
        // Either way abandon this commit.
211
        return !props.Any()
2!
212
            ? null
2✔
213
            : $"Update {kv.Key.GetType().Name} {string.Join(", ", props.Select(p => p.Name).ToArray())}";
6✔
214
    }
215

216
    public void Dispose()
217
    {
218
        GC.SuppressFinalize(this);
4✔
219
        foreach (var repo in _repositories)
24✔
220
        {
221
            repo.Deleting += Deleting;
8✔
222
            repo.Inserting += Inserting;
8✔
223

224

225
            if (Settings.UseTransactions && _finishing == false)
8✔
226
                try
227
                {
228
                    // Abandon transactions
229
                    repo.EndTransaction(false);
4✔
230
                }
4✔
231
                catch (NotSupportedException)
×
232
                {
233
                    // ok maybe someone else shut this down somehow... whatever
234
                }
×
235
        }
236

237
        _isDisposed = true;
4✔
238
    }
4✔
239
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc