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

adding functionality to porter create in a specified directory #2778

Conversation

sbdtu5498
Copy link
Contributor

@sbdtu5498 sbdtu5498 commented Jun 9, 2023

What does this change

Appropriate feature has been added and locally tested as well.

What issue does it fix

Closes #2772

If there is not an existing issue, please make sure we have context on why this change is needed. See our Contributing Guide for examples of when an existing issue isn't necessary.

Checklist

  • Did you write tests?
  • Did you write documentation?
  • Did you change porter.yaml or a storage document record? Update the corresponding schema file.
  • If this is your first pull request, please add your name to the bottom of our Contributors list. Thank you for making Porter better! 🙇‍♀️

Reviewer Checklist

  • Comment with /azp run test-porter-release if a magefile or build script was modified
  • Comment with /azp run porter-integration if it's a non-trivial PR

Copy link
Member

@troy0820 troy0820 left a comment

Choose a reason for hiding this comment

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

Some nits and a question/suggestion about the create command.

RunE: func(cmd *cobra.Command, args []string) error {
return p.Create()
bundleName := "mybundle" // Default value
Copy link
Member

Choose a reason for hiding this comment

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

Is this necessary? This command will error if bundle name is not passed which I believe is what we want.

porter create // will error out
porter create mybundle //will not fail 

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
bundleName := "mybundle" // Default value
var bundleName string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@troy0820 currently it will not throw any error. It instead will create a bundle with the default name "mybundle". But if we want to throw an error if the argument isn't passed, then sure, I will fix it.

Copy link
Member

Choose a reason for hiding this comment

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

@schristoff @phillipgibson Do we want the behavior to error (error being a word used to describe not executing the command but show the usage) when the argument for the create bundle isn't given to make the user do this?

porter create [bundle]

Or do we want to create the bundle with the default mybundle in the directory if the argument isn't given?

Copy link
Member

Choose a reason for hiding this comment

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

But if we want to throw an error if the argument isn't passed, then sure, I will fix it.

@sbdtu5498
I'm not quite sure but I want to see what is the desired behavior that we want and asking the community. From the issue I believe we want to emulate the same behavior as the below clis.

helm create requires 1 argument
cargo new requires 1 argument

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@troy0820 sure thing! Once we get more reviews on how it should be handled, I will add the required changes.

Copy link
Member

@schristoff schristoff Jun 11, 2023

Choose a reason for hiding this comment

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

My bias is towards helm, and feeling that most users of our product are familiar with helm.
In that case, let's force the user to do the hard thing, and pick a name. Error if they don't pass in an argument, because making assumptions can cause issues down the line. :)
On second thought, this is user facing.
There could be users who have scripts that rely on Porter to do stuff in the current directory.
For now, if they don't pass in an argument, we do it in the current directory. If they pass in an argument, then we create the directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure thing, this seems feasible.

// Create a directory with the given bundle name
err := os.Mkdir(bundleName, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory for bundle: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("failed to create directory for bundle: %w", err)
return fmt.Errorf("failed to create directory for bundle %s: %w", bundleName, err)

@sbdtu5498 sbdtu5498 force-pushed the adding-new-feature-in-porter-create branch 2 times, most recently from ddceee7 to 2d4c508 Compare June 20, 2023 16:33
@sbdtu5498 sbdtu5498 requested review from schristoff and troy0820 June 20, 2023 16:33
Copy link
Member

@troy0820 troy0820 left a comment

Choose a reason for hiding this comment

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

Just a couple of comments and changes requested.

bundleName = "."
}

fmt.Fprintf(p.Out, "creating porter configuration for %s\n", bundleName)
Copy link
Member

Choose a reason for hiding this comment

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

If bundle name is an empty string this will say creating porter configuration for ..

Could getting the cwd os.Getwd() p.FileSystem.Getwd() be a better way to do this?

Setting bundle name to os.Getwd() p.FileSystem.Getwd() can do two things:

  1. It can default to the current working directory and allow this to print what it needs to be.
  2. It will still work with what you have for the writing of the files to the filepath below.

Copy link
Member

Choose a reason for hiding this comment

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

You can get the basePath with porter.FileSystem.Getwd() and use that for the bundleName if it is blank.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure this one is done


err := p.CopyTemplate(p.Templates.GetManifest, config.Name)
// Create a directory with the given bundle name
err := os.MkdirAll(bundleName, os.ModePerm)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
err := os.MkdirAll(bundleName, os.ModePerm)
err := os.MkdirAll(bundleName, pkg.FileModeDirectory)

// Create a directory with the given bundle name
err := os.MkdirAll(bundleName, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory for bundle: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("failed to create directory for bundle: %w", err)
return fmt.Errorf("failed to create directory for bundle %s: %w", bundleName, err)

p := NewTestPorter(t)
defer p.Close()

err := p.Create("mybundle")
Copy link
Member

Choose a reason for hiding this comment

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

If we pass in mybundle/yourbundle/superbundle will this work?

Helm has a thing where it will create the directory (base directory) if the others exists. So it os.Stat's the previous directories before making a helm create in the last (superbundle) "directory" assuming the last isn't a file.

We are creating the whole path regardless if it's a file at that path to include a directory of that and the bundle name will be mybundle/yourbundle/superbundle.

We may need to Stat the filepath of the directories if they are passed like this to ensure we do not have a bundle name with slashes, etc.

Helm has an example of this in their create flow.

Copy link
Contributor Author

@sbdtu5498 sbdtu5498 Jun 20, 2023

Choose a reason for hiding this comment

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

Oh I am sorry I was a bit busy at the moment to answer. Let me get back on to this

If we pass in mybundle/yourbundle/superbundle will this work?

Yes this will work. But there's a catch. It would update the directory if it exists. Now I want to ask should we block the user from running porter create or porter create mybundle if any of the related files exist or should we stick with the behavior that it is in.

Copy link
Member

Choose a reason for hiding this comment

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

Yes this will work.

I'm curious as what the name will be. Will it be mybundle/yourbundle/superbundle

But there's a catch. It would update the directory if it exists.

I don't think that's a problem. Helm does the same thing. If there exists a directory, it will overwrite what's in there if the target exists.

Now I want to ask should we block the user from running porter create or porter create mybundle if any of the related files exist or should we stick with the behavior that it is in.

The existing functionality will allow you to create a bundle in the current directory if anything exits there and overwrite what is laid down on disks as an overwritten file. This behavior should stay and expect that to be the case with the target directory (if new created, if old overwrite)

Copy link
Contributor Author

@sbdtu5498 sbdtu5498 Jun 22, 2023

Choose a reason for hiding this comment

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

I'm curious as what the name will be. Will it be mybundle/yourbundle/superbundle

it will be named superbundle. And will be inside youbundle folder which will be inside, superbundle. It would work exactly like how helm create works

The existing functionality will allow you to create a bundle in the current directory if anything exits there and overwrite what is laid down on disks as an overwritten file. This behavior should stay and expect that to be the case with the target directory (if new created, if old overwrite)

Sure I have made those small changes will push it in few moments. Let me know if anything else is required.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@troy0820 now it is 100% similar to helm create. I have also written the test cases to prove the point and looked at them locally as well. Kindly take a look.

@sbdtu5498 sbdtu5498 force-pushed the adding-new-feature-in-porter-create branch from 2d4c508 to ee0ecf5 Compare June 23, 2023 00:52
@sbdtu5498 sbdtu5498 requested a review from troy0820 June 23, 2023 00:53
Short: "Create a bundle",
Long: "Create a bundle. This generates a porter bundle in the current directory.",
Long: "Create a bundle. This generates a porter bundle with the directory with the specified name or in the root directory if no name is provided.",
Copy link
Member

Choose a reason for hiding this comment

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

I would leave this as "current directory" or use "working directory" instead of "root directory"
Root directory can have a lot of different meanings depending on the users background, and in my interpretation that is not where I would want my bundle. :)

pkg/porter/create.go Show resolved Hide resolved
Comment on lines 17 to 18
if bundleName == "" {
bundleName = p.FileSystem.Getwd() // Use the current directory if no directory is passed
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if bundleName == "" {
bundleName = p.FileSystem.Getwd() // Use the current directory if no directory is passed
// Use the current directory if no directory is passed
if bundleName == "" {
bundleName = p.FileSystem.Getwd()

bundleName = p.FileSystem.Getwd() // Use the current directory if no directory is passed
}

fmt.Fprintf(p.Out, "creating porter configuration in %s\n", bundleName)
Copy link
Member

Choose a reason for hiding this comment

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

I feel like this should be moved to the end of the function, so if we succeed, this outputs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, will move it.

RunE: func(cmd *cobra.Command, args []string) error {
return p.Create()
bundleName := "" // Default value
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
bundleName := "" // Default value
// By default we create the bundle in the current directory
bundleName := ""

Minor comment nit

Copy link
Member

Choose a reason for hiding this comment

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

By the way it is hard to do suggestions for comments in github because it won't let me use tabs :( so it may look a little weird

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, but I got it anyways! would fix them up.

@schristoff
Copy link
Member

Hey @sbdtu5498 - just following up on this to see if you need any help! :)

@sbdtu5498 sbdtu5498 force-pushed the adding-new-feature-in-porter-create branch from ee0ecf5 to 1b4918b Compare July 6, 2023 19:39
@sbdtu5498
Copy link
Contributor Author

sbdtu5498 commented Jul 6, 2023

Extremely sorry for the delays @schristoff. This thing really got out of my mind. Thanks a lot for reminding me as well. Everything has been fixed. Take a look.

@sbdtu5498 sbdtu5498 force-pushed the adding-new-feature-in-porter-create branch 2 times, most recently from 02a9591 to 6b1f2b1 Compare July 6, 2023 19:52
// It takes both the relative path and absolute path into consideration.
// For example if we want to create a bundle named mybundle in an existing directory /home/user we can call porter create /home/user/mybundle or porter create mybundle in the /home/user directory.
// If we are in a directory /home/user and we want to create mybundle in the directory /home/user/directory given the directory exists,
// we can call porter create directory/mybundle from the /home/user directory or with any relative paths' combinations that one can come up with.
Copy link
Member

@troy0820 troy0820 Jul 7, 2023

Choose a reason for hiding this comment

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

To clarify, when we do this porter create scripts/bundles/porter is the name going to be this as well? I feel like we may have to split on the / to os.Stat the directory path if it doesn't/does exist but only use the last name from the / when creating the bundle. Do we not have to walk the directory structure?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No the name will be let say if you create /home/sbdtu5498/gentoo/nix/os. let say both gentoo and nix exist then it will work and will create bundle in the directory named os. If os doesn't exist, it will create a directory called os. But if nix doesn't exist, then it will throw error no such directory exist. This is the exact behavior that helm commands show. I tried to closely replicate it. Hope it makes sense. I will add few more descriptor comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

// Only condition to use porter create with absolute and relative paths is that all the directories in the path except the last one should strictly exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will add this line here. Now it will make sense.

if err != nil {
return fmt.Errorf("failed to create directory for bundle: %w", err)
}
} else if err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

nit: Because the err != nil in both places, you can check for the err != nil first and then checi to see if the os.IsNotExist(err)


func TestCreateInDirectory(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := ioutil.TempDir("", "porter-test")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
tempDir, err := ioutil.TempDir("", "porter-test")
tempDir, err := os.TempDir("", "porter-test")

ioutil.TempDir is deprecated and will not pass the gate for staticcheck/go vet


func TestCreateInChildDirectoryWithExistingParentDirectory(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := ioutil.TempDir("", "porter-test")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
tempDir, err := ioutil.TempDir("", "porter-test")
tempDir, err := os.TempDir("", "porter-test")


func TestCreateInChildDirectoryWithoutExistingParentDirectory(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := ioutil.TempDir("", "porter-test")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
tempDir, err := ioutil.TempDir("", "porter-test")
tempDir, err := os.TempDir("", "porter-test")

@@ -1,25 +1,28 @@
package porter

import (
"io/ioutil"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"io/ioutil"

Copy link
Member

@troy0820 troy0820 left a comment

Choose a reason for hiding this comment

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

Just some nits but passing through the gates for static check we need to change the ioutil import and use os.TempDir

This is looking good. Definitely appreciate your patience.

Also, a question about the bundlename to make sure we don't fail prematurely if we need to walk the directories before creating/not creating them.

@sbdtu5498
Copy link
Contributor Author

This is looking good. Definitely appreciate your patience.

No problem at all and sorry for some delays on my part as well.

Also, a question about the bundle name to make sure we don't fail prematurely if we need to walk the directories before creating/not creating them.

Have answered it above.

Just some nits but passing through the gates for static check we need to change the ioutil import and use os.TempDir

Fixing it ASAP.

@sbdtu5498 sbdtu5498 force-pushed the adding-new-feature-in-porter-create branch from 6b1f2b1 to c4d00bd Compare July 7, 2023 21:40
@sbdtu5498
Copy link
Contributor Author

@troy0820 please take a look. I think there would be some merge conflicts. I will rebase the branch later if that's fine.

Copy link
Member

@troy0820 troy0820 left a comment

Choose a reason for hiding this comment

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

Last change needed but this is so close @sbdtu5498. Thank you for your contribution and appreciate your patience with us.

// If we are in a directory /home/user and we want to create mybundle in the directory /home/user/directory given the directory exists,
// we can call porter create directory/mybundle from the /home/user directory or with any relative paths' combinations that one can come up with.
// Only condition to use porter create with absolute and relative paths is that all the directories in the path except the last one should strictly exist.
err = os.Mkdir(bundleName, os.ModePerm)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
err = os.Mkdir(bundleName, os.ModePerm)
err = os.MkdirAll(bundleName, os.ModePerm)

This will make sure that this creates bundles such as porter create mybundle/newestbundle

_, err := os.Stat(bundleName)
if err != nil {
if os.IsNotExist(err) {
// This code here attempts to create the directory in which bundle needs to be created,
Copy link
Member

Choose a reason for hiding this comment

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

This comment is HUGE. Can we shorten this some?

@schristoff
Copy link
Member

Oh @sbdtu5498 I am so sorry, I never saw that you updated this awhile back. Once those last comments of Troy's are merged I will look over and get this merged ASAP.

@ludfjig
Copy link
Contributor

ludfjig commented Aug 23, 2023

Hi @sbdtu5498 , are you still working on this?

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

Successfully merging this pull request may close these issues.

porter create command should create directory with bundle files included
4 participants