dependabot-nuget 0.283.0 → 0.285.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }],