dependabot-nuget 0.283.0 → 0.285.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/CloneCommand.cs +40 -0
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +1 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/CloneWorker.cs +144 -0
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/IGitCommandHandler.cs +6 -0
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/ShellGitCommandHandler.cs +37 -0
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotFound.cs +5 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +1 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +9 -2
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobRepoNotFound.cs +13 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobSource.cs +2 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/MarkAsProcessed.cs +6 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PrivateSourceAuthenticationFailure.cs +5 -1
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UnknownError.cs +5 -1
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdateNotPossible.cs +5 -1
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/HttpApiHandler.cs +8 -2
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +73 -31
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +30 -9
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +3 -3
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +2 -0
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/CloneWorkerTests.cs +183 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/TestGitCommandHandler.cs +16 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +640 -17
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +10 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatedDependencyListTests.cs +53 -6
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/BindingRedirectsTests.cs +225 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +106 -0
  29. metadata +13 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a3154a8f2ecd254dc3463bcca6f6e188e033bcf1d6aea863090f348035a9fe8
4
- data.tar.gz: 480467b2e57d224ed646f81cd6614fbad2af03154ba07fc0dc4dde36d2ab3440
3
+ metadata.gz: d8dd6e625e132b28270ffbff6c1af11b0173e3a786a1f6518080c20adc028ac2
4
+ data.tar.gz: 7afe9afdd9b8ab5ae40372ac51fb292efce75ed4d4b5ba7fee96468e00e835bc
5
5
  SHA512:
6
- metadata.gz: 8b56eff2a40277413354577fe830f472bf0c46e72ba22cd948f207de01e2c3e0990ba84f60af648ba5e833fe209f8a7cc46b1172aa44987da2a3a6669cab9df5
7
- data.tar.gz: 3f0bec73a56ac9e6eeed3e61eee12b0dcac72875325b6e543797b893a7dcbc4e2099f318c8822c115e9db810560df61179f0df68c6008d2474d9b0569a116fb7
6
+ metadata.gz: 0d9b4fdc7ba52be531cb199699324e7be1a68ae6a698619e961535f0cdb993833cc06e6e4f0df7a88f5b12e3a8bb06627a5ba2233e24bcafa4ade1badcf6a2bf
7
+ data.tar.gz: e9619a91fc865a8aa45a812a923f089a10e67f0be0c8588908206726e4e2b6d95ee1626cc0897d3dad5c5aca1a2e89f1c657e25a9137d4f186e05a7813b3e34c
@@ -0,0 +1,40 @@
1
+ using System.CommandLine;
2
+
3
+ using NuGetUpdater.Core;
4
+ using NuGetUpdater.Core.Clone;
5
+ using NuGetUpdater.Core.Run;
6
+
7
+ namespace NuGetUpdater.Cli.Commands;
8
+
9
+ internal static class CloneCommand
10
+ {
11
+ internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
12
+ internal static readonly Option<DirectoryInfo> RepoContentsPathOption = new("--repo-contents-path") { IsRequired = true };
13
+ internal static readonly Option<Uri> ApiUrlOption = new("--api-url") { IsRequired = true };
14
+ internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
15
+
16
+ internal static Command GetCommand(Action<int> setExitCode)
17
+ {
18
+ var command = new Command("clone", "Clones a repository in preparation for a dependabot job.")
19
+ {
20
+ JobPathOption,
21
+ RepoContentsPathOption,
22
+ ApiUrlOption,
23
+ JobIdOption,
24
+ };
25
+
26
+ command.TreatUnmatchedTokensAsErrors = true;
27
+
28
+ command.SetHandler(async (jobPath, repoContentsPath, apiUrl, jobId) =>
29
+ {
30
+ var apiHandler = new HttpApiHandler(apiUrl.ToString(), jobId);
31
+ var logger = new ConsoleLogger();
32
+ var gitCommandHandler = new ShellGitCommandHandler(logger);
33
+ var worker = new CloneWorker(apiHandler, gitCommandHandler, logger);
34
+ var exitCode = await worker.RunAsync(jobPath, repoContentsPath);
35
+ setExitCode(exitCode);
36
+ }, JobPathOption, RepoContentsPathOption, ApiUrlOption, JobIdOption);
37
+
38
+ return command;
39
+ }
40
+ }
@@ -13,6 +13,7 @@ internal sealed class Program
13
13
 
14
14
  var command = new RootCommand
15
15
  {
16
+ CloneCommand.GetCommand(setExitCode),
16
17
  FrameworkCheckCommand.GetCommand(setExitCode),
17
18
  DiscoverCommand.GetCommand(setExitCode),
18
19
  AnalyzeCommand.GetCommand(setExitCode),
@@ -41,7 +41,6 @@ public partial class EntryPointTests
41
41
  ],
42
42
  job: new Job()
43
43
  {
44
- PackageManager = "nuget",
45
44
  AllowedUpdates = [
46
45
  new()
47
46
  {
@@ -0,0 +1,144 @@
1
+ using System.Net;
2
+
3
+ using NuGetUpdater.Core.Run;
4
+ using NuGetUpdater.Core.Run.ApiModel;
5
+
6
+ using CommandArguments = (string[] Args, string? WorkingDirectory);
7
+
8
+ namespace NuGetUpdater.Core.Clone;
9
+
10
+ public class CloneWorker
11
+ {
12
+ private readonly IApiHandler _apiHandler;
13
+ private readonly IGitCommandHandler _gitCommandHandler;
14
+ private readonly ILogger _logger;
15
+
16
+ public CloneWorker(IApiHandler apiHandler, IGitCommandHandler gitCommandHandler, ILogger logger)
17
+ {
18
+ _apiHandler = apiHandler;
19
+ _gitCommandHandler = gitCommandHandler;
20
+ _logger = logger;
21
+ }
22
+
23
+ // entrypoint for cli
24
+ public async Task<int> RunAsync(FileInfo jobFilePath, DirectoryInfo repoContentsPath)
25
+ {
26
+ var jobFileContent = await File.ReadAllTextAsync(jobFilePath.FullName);
27
+ var jobWrapper = RunWorker.Deserialize(jobFileContent);
28
+ var result = await RunAsync(jobWrapper.Job, repoContentsPath.FullName);
29
+ return result;
30
+ }
31
+
32
+ // object model entry point
33
+ public async Task<int> RunAsync(Job job, string repoContentsPath)
34
+ {
35
+ JobErrorBase? error = null;
36
+ try
37
+ {
38
+ var commandArgs = GetAllCommandArgs(job, repoContentsPath);
39
+ foreach (var (args, workingDirectory) in commandArgs)
40
+ {
41
+ await _gitCommandHandler.RunGitCommandAsync(args, workingDirectory);
42
+ }
43
+ }
44
+ catch (HttpRequestException ex)
45
+ when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
46
+ {
47
+ error = new JobRepoNotFound(ex.Message);
48
+ }
49
+ catch (Exception ex)
50
+ {
51
+ error = new UnknownError(ex.ToString());
52
+ }
53
+
54
+ if (error is not null)
55
+ {
56
+ await _apiHandler.RecordUpdateJobError(error);
57
+ await _apiHandler.MarkAsProcessed(new("unknown"));
58
+ return 1;
59
+ }
60
+
61
+ return 0;
62
+ }
63
+
64
+ internal static CommandArguments[] GetAllCommandArgs(Job job, string repoContentsPath)
65
+ {
66
+ var commandArgs = new List<CommandArguments>()
67
+ {
68
+ GetCloneArgs(job, repoContentsPath)
69
+ };
70
+
71
+ if (job.Source.Commit is { } commit)
72
+ {
73
+ commandArgs.Add(GetFetchArgs(commit, repoContentsPath));
74
+ commandArgs.Add(GetResetArgs(commit, repoContentsPath));
75
+ }
76
+
77
+ return commandArgs.ToArray();
78
+ }
79
+
80
+ internal static CommandArguments GetCloneArgs(Job job, string repoContentsPath)
81
+ {
82
+ var url = GetRepoUrl(job);
83
+ var args = new List<string>()
84
+ {
85
+ "clone",
86
+ "--no-tags",
87
+ "--depth",
88
+ "1",
89
+ "--recurse-submodules",
90
+ "--shallow-submodules",
91
+ };
92
+
93
+ if (job.Source.Branch is { } branch)
94
+ {
95
+ args.Add("--branch");
96
+ args.Add(branch);
97
+ args.Add("--single-branch");
98
+ }
99
+
100
+ args.Add(url);
101
+ args.Add(repoContentsPath);
102
+ return (args.ToArray(), null);
103
+ }
104
+
105
+ internal static CommandArguments GetFetchArgs(string commit, string repoContentsPath)
106
+ {
107
+ return
108
+ (
109
+ [
110
+ "fetch",
111
+ "--depth",
112
+ "1",
113
+ "--recurse-submodules=on-demand",
114
+ "origin",
115
+ commit
116
+ ],
117
+ repoContentsPath
118
+ );
119
+ }
120
+
121
+ internal static CommandArguments GetResetArgs(string commit, string repoContentsPath)
122
+ {
123
+ return
124
+ (
125
+ [
126
+ "reset",
127
+ "--hard",
128
+ "--recurse-submodules",
129
+ commit
130
+ ],
131
+ repoContentsPath
132
+ );
133
+ }
134
+
135
+ private static string GetRepoUrl(Job job)
136
+ {
137
+ return job.Source.Provider switch
138
+ {
139
+ "azure" => $"https://dev.azure.com/{job.Source.Repo}",
140
+ "github" => $"https://github.com/{job.Source.Repo}",
141
+ _ => throw new ArgumentException($"Unknown provider: {job.Source.Provider}")
142
+ };
143
+ }
144
+ }
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core.Clone;
2
+
3
+ public interface IGitCommandHandler
4
+ {
5
+ Task RunGitCommandAsync(IReadOnlyCollection<string> args, string? workingDirectory = null);
6
+ }
@@ -0,0 +1,37 @@
1
+ using System.Net;
2
+
3
+ namespace NuGetUpdater.Core.Clone;
4
+
5
+ public class ShellGitCommandHandler : IGitCommandHandler
6
+ {
7
+ private readonly ILogger _logger;
8
+
9
+ public ShellGitCommandHandler(ILogger logger)
10
+ {
11
+ _logger = logger;
12
+ }
13
+
14
+ public async Task RunGitCommandAsync(IReadOnlyCollection<string> args, string? workingDirectory = null)
15
+ {
16
+ _logger.Log($"Running command: git {string.Join(" ", args)}{(workingDirectory is null ? "" : $" in directory {workingDirectory}")}");
17
+ var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("git", args, workingDirectory);
18
+ HandleErrorsFromOutput(stdout, stderr);
19
+ }
20
+
21
+ internal static void HandleErrorsFromOutput(string stdout, string stderr)
22
+ {
23
+ foreach (var output in new[] { stdout, stderr })
24
+ {
25
+ ThrowOnUnauthenticated(output);
26
+ }
27
+ }
28
+
29
+ private static void ThrowOnUnauthenticated(string output)
30
+ {
31
+ if (output.Contains("Authentication failed for") ||
32
+ output.Contains("could not read Username for"))
33
+ {
34
+ throw new HttpRequestException(output, inner: null, statusCode: HttpStatusCode.Unauthorized);
35
+ }
36
+ }
37
+ }
@@ -2,5 +2,9 @@ namespace NuGetUpdater.Core.Run.ApiModel;
2
2
 
3
3
  public record DependencyFileNotFound : JobErrorBase
4
4
  {
5
- public override string Type => "dependency_file_not_found";
5
+ public DependencyFileNotFound(string filePath)
6
+ : base("dependency_file_not_found")
7
+ {
8
+ Details = filePath;
9
+ }
6
10
  }
@@ -2,7 +2,7 @@ namespace NuGetUpdater.Core.Run.ApiModel;
2
2
 
3
3
  public sealed record Job
4
4
  {
5
- public required string PackageManager { get; init; }
5
+ public string PackageManager { get; init; } = "nuget";
6
6
  public AllowedUpdate[]? AllowedUpdates { get; init; } = null;
7
7
  public bool Debug { get; init; } = false;
8
8
  public object[]? DependencyGroups { get; init; } = null;
@@ -4,8 +4,15 @@ namespace NuGetUpdater.Core.Run.ApiModel;
4
4
 
5
5
  public abstract record JobErrorBase
6
6
  {
7
+ public JobErrorBase(string type)
8
+ {
9
+ Type = type;
10
+ }
11
+
7
12
  [JsonPropertyName("error-type")]
8
- public abstract string Type { get; }
13
+ public string Type { get; }
14
+
9
15
  [JsonPropertyName("error-details")]
10
- public required object Details { get; init; }
16
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
17
+ public object? Details { get; init; } = null;
11
18
  }
@@ -0,0 +1,13 @@
1
+ namespace NuGetUpdater.Core.Run.ApiModel;
2
+
3
+ public record JobRepoNotFound : JobErrorBase
4
+ {
5
+ public JobRepoNotFound(string message)
6
+ : base("job_repo_not_found")
7
+ {
8
+ Details = new Dictionary<string, string>()
9
+ {
10
+ ["message"] = message
11
+ };
12
+ }
13
+ }
@@ -4,6 +4,8 @@ public sealed class JobSource
4
4
  {
5
5
  public required string Provider { get; init; }
6
6
  public required string Repo { get; init; }
7
+ public string? Branch { get; init; } = null;
8
+ public string? Commit { get; init; } = null;
7
9
  public string? Directory { get; init; } = null;
8
10
  public string[]? Directories { get; init; } = null;
9
11
  public string? Hostname { get; init; } = null;
@@ -4,6 +4,11 @@ namespace NuGetUpdater.Core.Run.ApiModel;
4
4
 
5
5
  public sealed record MarkAsProcessed
6
6
  {
7
+ public MarkAsProcessed(string baseCommitSha)
8
+ {
9
+ BaseCommitSha = baseCommitSha;
10
+ }
11
+
7
12
  [JsonPropertyName("base-commit-sha")]
8
- public required string BaseCommitSha { get; init; }
13
+ public string BaseCommitSha { get; }
9
14
  }
@@ -2,5 +2,9 @@ namespace NuGetUpdater.Core.Run.ApiModel;
2
2
 
3
3
  public record PrivateSourceAuthenticationFailure : JobErrorBase
4
4
  {
5
- public override string Type => "private_source_authentication_failure";
5
+ public PrivateSourceAuthenticationFailure(string[] urls)
6
+ : base("private_source_authentication_failure")
7
+ {
8
+ Details = $"({string.Join("|", urls)})";
9
+ }
6
10
  }
@@ -2,5 +2,9 @@ namespace NuGetUpdater.Core.Run.ApiModel;
2
2
 
3
3
  public record UnknownError : JobErrorBase
4
4
  {
5
- public override string Type => "unknown_error";
5
+ public UnknownError(string details)
6
+ : base("unknown_error")
7
+ {
8
+ Details = details;
9
+ }
6
10
  }
@@ -2,5 +2,9 @@ namespace NuGetUpdater.Core.Run.ApiModel;
2
2
 
3
3
  public record UpdateNotPossible : JobErrorBase
4
4
  {
5
- public override string Type => "update_not_possible";
5
+ public UpdateNotPossible(string[] dependencies)
6
+ : base("update_not_possible")
7
+ {
8
+ Details = dependencies;
9
+ }
6
10
  }
@@ -50,13 +50,19 @@ public class HttpApiHandler : IApiHandler
50
50
  await PostAsJson("mark_as_processed", markAsProcessed);
51
51
  }
52
52
 
53
- private async Task PostAsJson(string endpoint, object body)
53
+ internal static string Serialize(object body)
54
54
  {
55
55
  var wrappedBody = new
56
56
  {
57
- Data = body,
57
+ Data = body
58
58
  };
59
59
  var payload = JsonSerializer.Serialize(wrappedBody, SerializerOptions);
60
+ return payload;
61
+ }
62
+
63
+ private async Task PostAsJson(string endpoint, object body)
64
+ {
65
+ var payload = Serialize(body);
60
66
  var content = new StringContent(payload, Encoding.UTF8, "application/json");
61
67
  var response = await HttpClient.PostAsync($"{_apiUrl}/update_jobs/{_jobId}/{endpoint}", content);
62
68
  var _ = response.EnsureSuccessStatusCode();
@@ -63,7 +63,8 @@ public class RunWorker
63
63
  var result = await RunForDirectory(job, repoContentsPath, directory, baseCommitSha);
64
64
  foreach (var dependencyFile in result.Base64DependencyFiles)
65
65
  {
66
- allDependencyFiles[dependencyFile.Name] = dependencyFile;
66
+ var uniqueKey = Path.GetFullPath(Path.Join(dependencyFile.Directory, dependencyFile.Name)).NormalizePathToUnix().EnsurePrefix("/");
67
+ allDependencyFiles[uniqueKey] = dependencyFile;
67
68
  }
68
69
  }
69
70
 
@@ -76,31 +77,19 @@ public class RunWorker
76
77
  catch (HttpRequestException ex)
77
78
  when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
78
79
  {
79
- error = new PrivateSourceAuthenticationFailure()
80
- {
81
- Details = $"({string.Join("|", lastUsedPackageSourceUrls)})",
82
- };
80
+ error = new PrivateSourceAuthenticationFailure(lastUsedPackageSourceUrls);
83
81
  }
84
82
  catch (MissingFileException ex)
85
83
  {
86
- error = new DependencyFileNotFound()
87
- {
88
- Details = ex.FilePath,
89
- };
84
+ error = new DependencyFileNotFound(ex.FilePath);
90
85
  }
91
86
  catch (UpdateNotPossibleException ex)
92
87
  {
93
- error = new UpdateNotPossible()
94
- {
95
- Details = ex.Dependencies,
96
- };
88
+ error = new UpdateNotPossible(ex.Dependencies);
97
89
  }
98
90
  catch (Exception ex)
99
91
  {
100
- error = new UnknownError()
101
- {
102
- Details = ex.ToString(),
103
- };
92
+ error = new UnknownError(ex.ToString());
104
93
  }
105
94
 
106
95
  if (error is not null)
@@ -108,7 +97,7 @@ public class RunWorker
108
97
  await _apiHandler.RecordUpdateJobError(error);
109
98
  }
110
99
 
111
- await _apiHandler.MarkAsProcessed(new() { BaseCommitSha = baseCommitSha });
100
+ await _apiHandler.MarkAsProcessed(new(baseCommitSha));
112
101
 
113
102
  return runResult;
114
103
  }
@@ -122,7 +111,7 @@ public class RunWorker
122
111
  _logger.Log(JsonSerializer.Serialize(discoveryResult, DiscoveryWorker.SerializerOptions));
123
112
 
124
113
  // report dependencies
125
- var discoveredUpdatedDependencies = GetUpdatedDependencyListFromDiscovery(discoveryResult);
114
+ var discoveredUpdatedDependencies = GetUpdatedDependencyListFromDiscovery(discoveryResult, repoContentsPath.FullName);
126
115
  await _apiHandler.UpdateDependencyList(discoveredUpdatedDependencies);
127
116
 
128
117
  // TODO: pull out relevant dependencies, then check each for updates and track the changes
@@ -146,6 +135,16 @@ public class RunWorker
146
135
  var localPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, project.FilePath);
147
136
  var content = await File.ReadAllTextAsync(localPath);
148
137
  originalDependencyFileContents[path] = content;
138
+
139
+ // track packages.config if it exists
140
+ var projectDirectory = Path.GetDirectoryName(project.FilePath);
141
+ var packagesConfigPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, projectDirectory, "packages.config");
142
+ var normalizedPackagesConfigPath = Path.Join(discoveryResult.Path, projectDirectory, "packages.config").NormalizePathToUnix().EnsurePrefix("/");
143
+ if (File.Exists(packagesConfigPath))
144
+ {
145
+ var packagesConfigContent = await File.ReadAllTextAsync(packagesConfigPath);
146
+ originalDependencyFileContents[normalizedPackagesConfigPath] = packagesConfigContent;
147
+ }
149
148
  }
150
149
 
151
150
  // do update
@@ -180,9 +179,15 @@ public class RunWorker
180
179
  // TODO: log analysisResult
181
180
  if (analysisResult.CanUpdate)
182
181
  {
182
+ var dependencyLocation = Path.GetFullPath(Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix().EnsurePrefix("/"));
183
+ if (dependency.Type == DependencyType.PackagesConfig)
184
+ {
185
+ dependencyLocation = Path.Combine(Path.GetDirectoryName(dependencyLocation)!, "packages.config");
186
+ }
187
+
183
188
  // TODO: this is inefficient, but not likely causing a bottleneck
184
189
  var previousDependency = discoveredUpdatedDependencies.Dependencies
185
- .Single(d => d.Name == dependency.Name && d.Requirements.Single().File == Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix().EnsurePrefix("/"));
190
+ .Single(d => d.Name == dependency.Name && d.Requirements.Single().File == dependencyLocation);
186
191
  var updatedDependency = new ReportedDependency()
187
192
  {
188
193
  Name = dependency.Name,
@@ -191,7 +196,7 @@ public class RunWorker
191
196
  [
192
197
  new ReportedRequirement()
193
198
  {
194
- File = Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix().EnsurePrefix("/"),
199
+ File = dependencyLocation,
195
200
  Requirement = analysisResult.UpdatedVersion,
196
201
  Groups = previousDependency.Requirements.Single().Groups,
197
202
  Source = new RequirementSource()
@@ -210,6 +215,11 @@ public class RunWorker
210
215
  // TODO: need to report if anything was actually updated
211
216
  if (updateResult.ErrorType is null || updateResult.ErrorType == ErrorType.None)
212
217
  {
218
+ if (dependencyLocation != dependencyFilePath)
219
+ {
220
+ updatedDependency.Requirements.All(r => r.File == dependencyFilePath);
221
+ }
222
+
213
223
  actualUpdatedDependencies.Add(updatedDependency);
214
224
  }
215
225
  }
@@ -220,19 +230,40 @@ public class RunWorker
220
230
  var updatedDependencyFiles = new List<DependencyFile>();
221
231
  foreach (var project in discoveryResult.Projects)
222
232
  {
223
- var path = Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix().EnsurePrefix("/");
224
- var localPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, project.FilePath);
225
- var updatedContent = await File.ReadAllTextAsync(localPath);
226
- var originalContent = originalDependencyFileContents[path];
227
- if (updatedContent != originalContent)
233
+ var projectPath = Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix().EnsurePrefix("/");
234
+ var localProjectPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, project.FilePath);
235
+ var updatedProjectContent = await File.ReadAllTextAsync(localProjectPath);
236
+ var originalProjectContent = originalDependencyFileContents[projectPath];
237
+
238
+ if (updatedProjectContent != originalProjectContent)
228
239
  {
229
240
  updatedDependencyFiles.Add(new DependencyFile()
230
241
  {
231
242
  Name = project.FilePath,
232
- Content = updatedContent,
233
- Directory = discoveryResult.Path,
243
+ Content = updatedProjectContent,
244
+ Directory = Path.GetDirectoryName(projectPath)!.NormalizeUnixPathParts(),
234
245
  });
235
246
  }
247
+
248
+ var projectDirectory = Path.GetDirectoryName(project.FilePath);
249
+ var packagesConfigPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, projectDirectory, "packages.config");
250
+ var normalizedPackagesConfigPath = Path.Join(discoveryResult.Path, projectDirectory, "packages.config").NormalizePathToUnix().EnsurePrefix("/");
251
+
252
+ if (File.Exists(packagesConfigPath))
253
+ {
254
+ var updatedPackagesConfigContent = await File.ReadAllTextAsync(packagesConfigPath);
255
+ var originalPackagesConfigContent = originalDependencyFileContents[normalizedPackagesConfigPath];
256
+
257
+ if (updatedPackagesConfigContent != originalPackagesConfigContent)
258
+ {
259
+ updatedDependencyFiles.Add(new DependencyFile()
260
+ {
261
+ Name = Path.Join(projectDirectory!, "packages.config"),
262
+ Content = updatedPackagesConfigContent,
263
+ Directory = Path.GetDirectoryName(normalizedPackagesConfigPath)!.NormalizeUnixPathParts(),
264
+ });
265
+ }
266
+ }
236
267
  }
237
268
 
238
269
  if (updatedDependencyFiles.Count > 0)
@@ -265,14 +296,14 @@ public class RunWorker
265
296
  {
266
297
  Name = Path.GetFileName(kvp.Key),
267
298
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes(kvp.Value)),
268
- Directory = Path.GetDirectoryName(kvp.Key)!.NormalizePathToUnix(),
299
+ Directory = Path.GetFullPath(Path.GetDirectoryName(kvp.Key)!).NormalizePathToUnix(),
269
300
  }).ToArray(),
270
301
  BaseCommitSha = baseCommitSha,
271
302
  };
272
303
  return result;
273
304
  }
274
305
 
275
- internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult)
306
+ internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult, string pathToContents)
276
307
  {
277
308
  string GetFullRepoPath(string path)
278
309
  {
@@ -294,6 +325,17 @@ public class RunWorker
294
325
  auxiliaryFiles.Add(GetFullRepoPath(discoveryResult.DirectoryPackagesProps.FilePath));
295
326
  }
296
327
 
328
+ foreach (var project in discoveryResult.Projects)
329
+ {
330
+ var projectDirectory = Path.GetDirectoryName(project.FilePath);
331
+ var pathToPackagesConfig = Path.Join(pathToContents, discoveryResult.Path, projectDirectory, "packages.config").NormalizePathToUnix().EnsurePrefix("/");
332
+
333
+ if (File.Exists(pathToPackagesConfig))
334
+ {
335
+ auxiliaryFiles.Add(GetFullRepoPath(Path.Join(projectDirectory, "packages.config")));
336
+ }
337
+ }
338
+
297
339
  var updatedDependencyList = new UpdatedDependencyList()
298
340
  {
299
341
  Dependencies = discoveryResult.Projects.SelectMany(p =>
@@ -304,7 +346,7 @@ public class RunWorker
304
346
  Name = d.Name,
305
347
  Requirements = d.IsTransitive ? [] : [new ReportedRequirement()
306
348
  {
307
- File = GetFullRepoPath(p.FilePath),
349
+ File = d.Type == DependencyType.PackagesConfig ? Path.Combine(Path.GetDirectoryName(GetFullRepoPath(p.FilePath))!, "packages.config"): GetFullRepoPath(p.FilePath),
308
350
  Requirement = d.Version!,
309
351
  Groups = ["dependencies"],
310
352
  }],