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

DYN-5709: Pm publish version patch request #15395

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/DynamoCoreWpf/ViewModels/PackageManager/PackageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public PackageViewModel(DynamoViewModel dynamoViewModel, Package model)
Model = model;

PublishNewPackageVersionCommand = new DelegateCommand(() => ExecuteWithTou(PublishNewPackageVersion), IsOwner);
PublishNewPackageCommand = new DelegateCommand(() => ExecuteWithTou(PublishNewPackage), IsOwner);
PublishNewPackageCommand = new DelegateCommand(() => ExecuteWithTou(PublishNewPackage), CanPublishNewPackage);
UninstallCommand = new DelegateCommand(Uninstall, CanUninstall);
UnmarkForUninstallationCommand = new DelegateCommand(UnmarkForUninstallation, CanUnmarkForUninstallation);
LoadCommand = new DelegateCommand(Load, CanLoad);
Expand Down Expand Up @@ -410,6 +410,25 @@ private bool IsOwner()
return packageManagerClient.DoesCurrentUserOwnPackage(Model, dynamoModel.AuthenticationManager.Username);
}

private bool CanPublishNewPackage()
{
if (!CanPublish) return false;

return packageManagerClient.DoesCurrentUserOwnPackage(Model, dynamoModel.AuthenticationManager.Username) ||
Copy link
Contributor

@aparajit-pratap aparajit-pratap Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the DoesCurrentUserOwnPackage check mean that the package cannot be republished by someone who hasn't published it before?

Copy link
Contributor

@aparajit-pratap aparajit-pratap Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like only an existing package maintainer or package copyright holder can republish (publish a new version) the package? The code would be clearer if you said something like:

bool isUserOwnerOrHolder = packageManagerClient.DoesCurrentUserOwnPackage(Model, dynamoModel.AuthenticationManager.Username) || PackageNotPublishedAndUserIsHolder(Model, dynamoModel.AuthenticationManager.Username);
return isUserOwnerOrHolder;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait..Copyright Holder should not be able to publish a version or a package, we do not validate copyright holder on server side, any actions related to package publishing either republishing from local copy or publishing a version should be limited to its current maintainers only.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood.

PackageNotPublishedAndUserIsHolder(Model, dynamoModel.AuthenticationManager.Username);
}


// Utility function to assert if a local package can be published
// If the current user is the package holder and a package with that name has not been published yet, return true
private bool PackageNotPublishedAndUserIsHolder(Package package, string username)
{
bool userIsHolder = package.CopyrightHolder != null && package.CopyrightHolder.Equals(username);
Copy link
Contributor

@aparajit-pratap aparajit-pratap Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the copyright information coming from the pkg.json file? What if it's missing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming this function as IsPackageUnpublishedAndUserHolder?

bool packageHasNotBeenPublished = !this.dynamoViewModel.PackageManagerClientViewModel.CachedPackageList.Any(x => x.Name == package.Name);

return userIsHolder && packageHasNotBeenPublished;
}

private bool CanDeprecate()
{
var isDeprecated = IsPackageDeprecated(Model.Name);
Expand Down Expand Up @@ -438,15 +457,17 @@ private void PublishNewPackageVersion()
Model.RefreshCustomNodesFromDirectory(dynamoModel.CustomNodeManager, DynamoModel.IsTestMode);
var vm = PublishPackageViewModel.FromLocalPackage(dynamoViewModel, Model, true);
vm.IsNewVersion = true;
vm.IsPackageInstalled = true;

dynamoViewModel.OnRequestPackagePublishDialog(vm);
}

private void PublishNewPackage()
{
Model.RefreshCustomNodesFromDirectory(dynamoModel.CustomNodeManager, DynamoModel.IsTestMode);
var vm = PublishPackageViewModel.FromLocalPackage(dynamoViewModel, Model, false);
var vm = PublishPackageViewModel.FromLocalPackage(dynamoViewModel, Model, true);
vm.IsNewVersion = false;
vm.IsPackageInstalled = true;
Copy link
Contributor

@aparajit-pratap aparajit-pratap Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this always be true? In the case of publishing a new package, the new package doesn't need to always be loaded, does it?


dynamoViewModel.OnRequestPackagePublishDialog(vm);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,25 @@
}
}
}


/// <summary>
/// IsPackageInstalled property </summary>
/// <value>
/// Shows if the package is already installed </value>
private bool _isPackageInstalled = false;
public bool IsPackageInstalled
{
get { return _isPackageInstalled; }

Check failure on line 222 in src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs

View workflow job for this annotation

GitHub Actions / analyze

Symbol 'IsPackageInstalled.get' is not part of the declared public API (https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
set

Check failure on line 223 in src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs

View workflow job for this annotation

GitHub Actions / analyze

Symbol 'IsPackageInstalled.set' is not part of the declared public API (https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
{
if (_isPackageInstalled != value)
{
_isPackageInstalled = value;
RaisePropertyChanged(nameof(IsPackageInstalled));
}
}
}

/// <summary>
/// CanEditName property </summary>
/// <value>
Expand Down Expand Up @@ -956,8 +974,8 @@
customNodeDefinitions = new List<CustomNodeDefinition>();
SubmitCommand = new DelegateCommand(Submit, CanSubmit);
PublishLocallyCommand = new DelegateCommand(PublishLocally, CanPublishLocally);
ShowAddFileDialogAndAddCommand = new DelegateCommand(ShowAddFileDialogAndAdd, CanShowAddFileDialogAndAdd);
SelectDirectoryAndAddFilesRecursivelyCommand = new DelegateCommand(SelectDirectoryAndAddFilesRecursively);
ShowAddFileDialogAndAddCommand = new DelegateCommand(ShowAddFileDialogAndAdd, CanAddFiles);
SelectDirectoryAndAddFilesRecursivelyCommand = new DelegateCommand(SelectDirectoryAndAddFilesRecursively, CanAddFiles);
SelectMarkdownDirectoryCommand = new DelegateCommand(SelectMarkdownDirectory);
ClearMarkdownDirectoryCommand = new DelegateCommand(ClearMarkdownDirectory);
CancelCommand = new DelegateCommand(Cancel);
Expand Down Expand Up @@ -1364,7 +1382,7 @@
{
if (e.PropertyName == "PackageContents")
{
CanSubmit();
CanSubmit();
SubmitCommand.RaiseCanExecuteChanged();
PublishLocallyCommand.RaiseCanExecuteChanged();
}
Expand Down Expand Up @@ -1493,6 +1511,7 @@
/// <summary>
/// The method is used to create a PublishPackageViewModel from a Package object.
/// If retainFolderStructure is set to true, the folder structure of the package will be retained. Else, the default folder structure will be imposed.
/// Investigating if both options (publish and publish new version) should not use 'retainFolderStructure' with disabled package files and folders editing
/// </summary>
/// <param name="dynamoViewModel"></param>
/// <param name="pkg">The package to be loaded</param>
Expand Down Expand Up @@ -2117,9 +2136,9 @@
}
}

private bool CanShowAddFileDialogAndAdd()
private bool CanAddFiles()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this redundant property (it's just the inverse of IsPackageInstalled) and use IsPackageInstalled directly?

{
return true;
return !IsPackageInstalled;
}

internal void AddFile(string filename)
Expand Down Expand Up @@ -2267,7 +2286,15 @@
{
// begin submission
var pmExtension = dynamoViewModel.Model.GetPackageManagerExtension();
var handle = pmExtension.PackageManagerClient.PublishAsync(Package, RetainFolderStructureOverride ? updatedFiles : contentFiles, MarkdownFiles, IsNewVersion, CurrentPackageRootDirectories, RetainFolderStructureOverride);
PackageUploadHandle handle;
if (IsPackageInstalled)
{
handle = pmExtension.PackageManagerClient.PublishInstalledPackageAsync(Package, IsNewVersion);
}
else
{
handle = pmExtension.PackageManagerClient.PublishAsync(Package, RetainFolderStructureOverride ? updatedFiles : contentFiles, MarkdownFiles, IsNewVersion, CurrentPackageRootDirectories, RetainFolderStructureOverride);
}

// start upload
Uploading = true;
Expand Down Expand Up @@ -2601,10 +2628,12 @@
}

/// <summary>
/// Delegate used to publish the element locally </summary>
/// Delegate used to publish the element locally
/// If the package is already installed (and therefore loaded), we shouldn't be able to publish it locally again?
/// </summary>
private bool CanPublishLocally()
{
return CheckPackageValidity();
return !IsPackageInstalled && CheckPackageValidity();
}

private bool CheckPackageValidity()
Expand Down
2 changes: 1 addition & 1 deletion src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ private void DynamoViewModelRequestPackageManager(PublishPackageViewModel model)
WindowStartupLocation = WindowStartupLocation.CenterOwner
};

// setting the owner to the packageManagerWindow will centralize promts originating from the Package Manager
// setting the owner to the packageManagerWindow will centralize prompts originating from the Package Manager
dynamoViewModel.Owner = packageManagerWindow;

packageManagerWindow.Closed += HandlePackageManagerWindowClosed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@
Property="Fill"
Value="#6AC0E7" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Folder"
Property="Fill"
Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
Expand Down Expand Up @@ -465,6 +470,11 @@
Property="Fill"
Value="#6AC0E7" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Folder"
Property="Fill"
Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
Expand All @@ -475,6 +485,7 @@
<local:CustomBrowserControl x:Name="customBrowserControl"
Grid.Column="0" Grid.Row="1"
Loaded="customBrowserControl_Loaded"
DisableRemove="{Binding IsPackageInstalled}"
Root="{Binding PackageContents, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />

<!--Files-->
Expand All @@ -487,6 +498,7 @@
CanUserSortColumns="True"
VerticalScrollBarVisibility="Disabled"
ItemsSource="{Binding RootContents, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
IsEnabled="{Binding IsPackageInstalled, Converter={StaticResource BooleanNegationConverter}}"
Style="{StaticResource DataGrid}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowStyle}">
Expand Down Expand Up @@ -599,9 +611,9 @@
Height="15"
VerticalAlignment="Center"
Margin="0 5"
IsEnabled="True"
IsChecked="{Binding Path=RetainFolderStructureOverride, Mode=TwoWay}"
IsTabStop="False"
IsEnabled="{Binding IsPackageInstalled, Converter={StaticResource BooleanNegationConverter}}"
Style="{StaticResource EllipseToggleButton1}" />
<TextBlock Text="{x:Static p:Resources.PublishPackageRetainFolderStructureToggleButtonText}"
Style="{StaticResource LabelStyle}"
Expand Down
19 changes: 18 additions & 1 deletion src/DynamoPackages/PackageDirectoryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public interface IPackageDirectoryBuilder
{
IDirectoryInfo BuildDirectory(Package packages, string packagesDirectory, IEnumerable<string> files, IEnumerable<string> markdownfiles);
IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable<string> roots, IEnumerable<IEnumerable<string>> contentFiles, IEnumerable<string> markdownFiles);
IDirectoryInfo BuildPackageHeader(Package package, string packagesDirectory);

[Obsolete]
IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable<IEnumerable<string>> contentFiles, IEnumerable<string> markdownFiles);

}

/// <summary>
Expand Down Expand Up @@ -125,6 +125,23 @@ public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirec
return rootDir;
}

/// <summary>
/// Builds package header in the provided package directory
/// </summary>
/// <param name="package">The already installed package</param>
/// <param name="packagesDirectory">The package installation folder</param>
/// <returns></returns>
public IDirectoryInfo BuildPackageHeader(Package package, string packagesDirectory)
{
var rootPath = Path.Combine(packagesDirectory, package.Name);
var rootDir = fileSystem.TryCreateDirectory(rootPath);
package.RootDirectory = rootDir.FullName;

WritePackageHeader(package, rootDir);

return rootDir;
}

public static void PreBuildDirectory(string packageName, string packagesDirectory,
out string rootDir, out string dyfDir, out string binDir, out string extraDir, out string docDir)
{
Expand Down
56 changes: 56 additions & 0 deletions src/DynamoPackages/PackageManagerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,62 @@ internal PackageUploadHandle PublishAsync(Package package, object files, IEnumer
return packageUploadHandle;
}


internal PackageUploadHandle PublishInstalledPackageAsync(Package package, bool isNewVersion)
{
var packageUploadHandle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(package));

Task.Factory.StartNew(() =>
{
Publish(package, isNewVersion, packageUploadHandle);
});

return packageUploadHandle;
}

internal void Publish(Package package, bool isNewVersion, PackageUploadHandle packageUploadHandle)
{
try
{
ResponseBody ret = null;
if (isNewVersion)
{
var pkg = uploadBuilder.InstalledPackageVersionUpload(package, packageUploadDirectory, packageUploadHandle);
packageUploadHandle.UploadState = PackageUploadHandle.State.Uploading;
ret = this.client.ExecuteAndDeserialize(pkg);
}
else
{
var pkg = uploadBuilder.InstalledPackageUpload(package, packageUploadDirectory, packageUploadHandle);
packageUploadHandle.UploadState = PackageUploadHandle.State.Uploading;
ret = this.client.ExecuteAndDeserialize(pkg);
}
if (ret == null)
{
packageUploadHandle.Error("Failed to submit. Try again later.");
return;
}

if (ret != null && !ret.success)
{
packageUploadHandle.Error(ret.message);
return;
}
packageUploadHandle.Done(null);
}
catch (Exception ex)
{
if (ex is IOException || ex is UnauthorizedAccessException)
{
packageUploadHandle.Error(DynamoPackages.Properties.Resources.CannotRemovePackageAssemblyTitle + ": " + DynamoPackages.Properties.Resources.CannotRemovePackageAssemblyMessage + "(" + ex.Message + ")");
}
else
{
packageUploadHandle.Error(ex.GetType() + ": " + ex.Message);
}
}
}

internal void Publish(Package package, object files, IEnumerable<string> markdownFiles, bool isNewVersion, PackageUploadHandle packageUploadHandle, IEnumerable<string> roots, bool retainFolderStructure = false)
{
try
Expand Down
57 changes: 53 additions & 4 deletions src/DynamoPackages/PackageUploadBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ PackageUpload NewPackageUpload(Package package, string packagesDirectory, IEnume
PackageUpload NewPackageRetainUpload(Package package, string packagesDirectory, IEnumerable<string> roots, IEnumerable<IEnumerable<string>> files, IEnumerable<string> markdownFiles,
PackageUploadHandle handle);

PackageVersionUpload NewPackageVersionUpload(Package package, string packagesDirectory,
IEnumerable<string> files, IEnumerable<string> markdownFiles, PackageUploadHandle handle);
PackageVersionUpload NewPackageVersionUpload(Package package, string packagesDirectory, IEnumerable<string> files, IEnumerable<string> markdownFiles,
PackageUploadHandle handle);

PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, IEnumerable<string> roots, IEnumerable<IEnumerable<string>> files, IEnumerable<string> markdownFiles,
PackageUploadHandle handle);

PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, IEnumerable<string> roots,
IEnumerable<IEnumerable<string>> files, IEnumerable<string> markdownFiles, PackageUploadHandle handle);
PackageUpload InstalledPackageUpload(Package package, string packagesDirectory, PackageUploadHandle handle);

PackageVersionUpload InstalledPackageVersionUpload(Package package, string packagesDirectory, PackageUploadHandle handle);
}

internal class PackageUploadBuilder : IPackageUploadBuilder
Expand Down Expand Up @@ -188,6 +192,40 @@ public PackageVersionUpload NewPackageVersionRetainUpload(Package package, strin
return new PackageVersionUpload(NewRequestBody(package), BuildAndZip(package, packagesDirectory, files, markdownFiles, handle).Name);
}

/// <summary>
/// Publishes an installed package
/// </summary>
/// <param name="package"></param>
/// <param name="packagesDirectory"></param>
/// <param name="handle"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public PackageUpload InstalledPackageUpload(Package package, string packagesDirectory, PackageUploadHandle handle)
{
if (package == null) throw new ArgumentNullException("package");
if (packagesDirectory == null) throw new ArgumentNullException("packagesDirectory");
if (handle == null) throw new ArgumentNullException("handle");

return new PackageUpload(NewRequestBody(package), BuildAndZip(package, packagesDirectory, handle).Name);
}


/// <summary>
/// Publishes a new version of an installed package
/// </summary>
/// <param name="package"></param>
/// <param name="packagesDirectory"></param>
/// <param name="handle"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public PackageVersionUpload InstalledPackageVersionUpload(Package package, string packagesDirectory, PackageUploadHandle handle)
{
if (package == null) throw new ArgumentNullException("package");
if (packagesDirectory == null) throw new ArgumentNullException("packagesDirectory");
if (handle == null) throw new ArgumentNullException("handle");

return new PackageVersionUpload(NewRequestBody(package), BuildAndZip(package, packagesDirectory, handle).Name);
}
#endregion

#region Private Class Methods
Expand Down Expand Up @@ -226,6 +264,17 @@ private IFileInfo BuildAndZip(Package package, string packagesDirectory, IEnumer
return Zip(dir);
}

private IFileInfo BuildAndZip(Package package, string packagesDirectory, PackageUploadHandle handle)
{
handle.UploadState = PackageUploadHandle.State.Copying;

var dir = builder.BuildPackageHeader(package, packagesDirectory);

handle.UploadState = PackageUploadHandle.State.Compressing;

return Zip(dir);
}


private IFileInfo Zip(IDirectoryInfo directory)
{
Expand Down
Loading