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

Support old project format with commitID in activestate.yaml. #2829

Merged
merged 12 commits into from
Oct 20, 2023

Conversation

mitchell-as
Copy link
Contributor

@mitchell-as mitchell-as commented Oct 18, 2023

StoryDX-2263 As a State Tool user, I should be able to use my project with the old commit ID format.

Instead of automatically migrating projects, prompt the user. Projects in the old format are read-only.

Instead of automatically migrating projects, prompt the user. Projects in the old format are read-only.
@mitchell-as mitchell-as requested a review from Naatan October 18, 2023 19:58
@mitchell-as mitchell-as marked this pull request as ready for review October 18, 2023 19:58
@mitchell-as
Copy link
Contributor Author

Test failures are not due to this PR, but are known, existing issues and the usual timeouts.

cmd/state/main.go Outdated Show resolved Hide resolved
Comment on lines 2085 to 2087
Your project is currently read-only until you migrate to the new project format.
After you migrate, older versions of the State Tool will not be able to use your project until they update.
Would you like to perform the migration now?
Copy link
Member

Choose a reason for hiding this comment

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

@rawktron please review

Copy link
Member

Choose a reason for hiding this comment

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

What's the full message? We have to give them some context for this. Is there another part of this message?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rawktron That is the full message. Whenever they run a state command that needs to read a commitId from activestate.yaml, this message is presented to them. The ticket did not specify what the prompt should look like, so I came up with this for the time being. Please advise what message you'd like to give.

Copy link
Member

Choose a reason for hiding this comment

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

It should be something like "State Tool has introduced a new project format to provide enhanced functionality. Your project is currently using the old format and will remain read-only until you migrate to the new project format.

WARNING: After you migrate, older versions of the State Tool will not be able to use your project.

Would you like to perform the migration now?"

internal/runbits/projectmigration/projectmigration.go Outdated Show resolved Hide resolved
internal/runbits/projectmigration/projectmigration.go Outdated Show resolved Hide resolved
pkg/localcommit/localcommit.go Outdated Show resolved Hide resolved
@mitchell-as mitchell-as requested a review from Naatan October 18, 2023 22:14
Comment on lines 30 to 33
func Register(prompt_ promptable, out_ output.Outputer) {
prompt = prompt_
out = out_
}
Copy link
Member

Choose a reason for hiding this comment

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

This is an antipattern for how we do this type of thing in our codebase. Either we should pass around a pointed struct that contains this context, or we always require these variables to be passed when invoking PromptAndMigrate.

That said I can see why you went this route as it feels really wasteful to add all this boilerplate for effectively a legacy use-case.

I feel like we need a pattern for handling legacy transitions like this, but that's probably too much to handle within the scope of this story.

Perhaps for this story we should clearly call out its legacy nature. I'm thinking add comments here clearly explaining that this is an antipattern and it's only ok because this is for a legacy use-case. I'm also thinking we should clearly mark packages meant for legacy use-cases as such, maybe by putting them a dir deeper under a parent dir called "legacy"? So you'd have runbits/legacy/projectmigration.

I'm not a big fan of any of these solutions, but I don't see a solution that doesn't have downsides. Main things I want to achieve here is maintainable code that doesn't start infecting other code, which I think is also where you were coming from. Happy to iterate with other ideas.

Copy link
Contributor Author

@mitchell-as mitchell-as Oct 19, 2023

Choose a reason for hiding this comment

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

The need for this arose because we were auto-migrating the project as soon as it was read, which did not allow for any prompt/output parameter passing (i.e. projectfile.Parse(configFilePath)), especially since analytics was not available yet (prompt needs this, and analytics needs to know the project; circular dependency).

However, after a couple of iterations, we're making prompting a lazy action, so we can pass around prompter and output interfaces as normal. It's quite verbose, but I've made the change.

From what I understand, there's no need for a legacy/ parent package.

Comment on lines 250 to 251
func (p *Project) Namespace() *Namespaced {
commitID, err := localcommit.GetCompatible(p)
commitID, err := localcommit.Get(p.Dir())
Copy link
Member

Choose a reason for hiding this comment

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

It just occurred to me we should not be exposing the commit ID through here at all. Could you see if it's easy to drop this from here or if not file a followup story? Effectively the project package should have zero awareness of localcommit, only of legacy commit.

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. After looking through the codebase, I cannot find a legitimate use for it anymore.

@@ -0,0 +1,33 @@
package commitid
Copy link
Member

Choose a reason for hiding this comment

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

Since this invoked the prompter I think it makes sense you put it in as a runbit, though the naming of the package and method is triggering my OCD a little.

Open to other naming, but how about commitmediator.Get()?

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 had no clue what name to use, so I'm glad for your suggestion.

Also renamed the package from the previous commit.
Comment on lines -472 to -501
func TestMigrateCommitFromASY(t *testing.T) {
tempDir := fileutils.TempDirUnsafe()
defer os.RemoveAll(tempDir)

commitID := "7BA74758-8665-4D3F-921C-757CD271A0C1"
asy := filepath.Join(tempDir, constants.ConfigFileName)
err := fileutils.WriteFile(asy, []byte("project: https://platform.activestate.com/Owner/Name?branch=main&commitID="+commitID))
require.NoError(t, err)

proj, err := Parse(asy)
require.NoError(t, err)
assert.Equal(t, "Owner", proj.Owner())
assert.Equal(t, "Name", proj.Name())
assert.Equal(t, "main", proj.BranchName())

commitIdFile := filepath.Join(tempDir, constants.ProjectConfigDirName, constants.CommitIdFileName)
require.FileExists(t, commitIdFile)
assert.Equal(t, commitID, string(fileutils.ReadFileUnsafe(commitIdFile)))

assert.NotContains(t, string(fileutils.ReadFileUnsafe(asy)), commitID)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Migration is no longer automatic. The new integration test covers this.

Copy link
Member

@Naatan Naatan left a comment

Choose a reason for hiding this comment

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

I'm sorry, but as I expressed during stand I wanted to avoid adding this much boilerplate for the purpose of a legacy transition mechanic. This is adding a ton of complexity and code that will have to be maintained and any new code will also have to satisfy this pattern, all to facilitate migration logic for when grabbing a commit ID.

I'm open to other solutions aside from the one I suggested earlier, but the design goal here is not to have the legacy handling code introduce tons of boilerplate or add complexity whenever we need to access a commit.

This feels like the type of problem that we can't have a non-compromising solution for, at least now without heavy investment, which we want to avoid for this story.

@mitchell-as
Copy link
Contributor Author

Based on your feedback, you left the door open to interpretation. Either avoid the anti-pattern and pass things around (which is what we should be doing), or call it out and make legacy packages, etc. You acknowledged that there is no solution that does not have downsides. Since your first bit of feedback was "this is an anti-pattern, we should be passing things around", I figured that was your preference. If I had known you didn't want parameter passing, I wouldn't have done it.

@mitchell-as mitchell-as requested a review from Naatan October 20, 2023 15:02
return false, errs.Wrap(err, "Could not create local commit file")
}

if fileutils.DirExists(filepath.Join(proj.Dir(), ".git")) {
Copy link
Member

Choose a reason for hiding this comment

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

Realize this probably wasn't introduced here but we should go up the directory tree to check for this also, since people may not checkout their activestate.yaml inside the same dir as their git repo (eg. TheHomeRepot).

You can use:

func FindFileInPath(dir, filename string) (string, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sadly, that's files only, not directories. Still, I'll do something to walk up the tree.

if fileutils.DirExists(filepath.Join(proj.Dir(), ".git")) {
err := localcommit.AddToGitIgnore(proj.Dir())
if err != nil {
multilog.Error("Unable to add local commit file to .gitignore: %v", err)
Copy link
Member

Choose a reason for hiding this comment

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

This would almost certainly be due to something client-side like permission errors I think? We should probably not log this to rollbar. Or maybe add a check to only log if it's not a permission or IO error.

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 wasn't able to find a generic ErrIO variable, but I did find ErrPermission, so we'll go with that.

Comment on lines 250 to 251
commitId := strfmt.UUID(p.projectfile.LegacyCommitID())
return &Namespaced{p.projectfile.Owner(), p.projectfile.Name(), &commitId, false}
Copy link
Member

Choose a reason for hiding this comment

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

Is the legacy commit ID still required as part of the namespace? Suggest dropping it altogether from the namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having an eye towards https://activestatef.atlassian.net/jira/software/c/projects/DX/issues/DX-2289, I'd say we probably shouldn't drop it yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Never mind. We abandoned during stand, so I removed it. Let's see what breaks.

@mitchell-as mitchell-as requested a review from Naatan October 20, 2023 17:29
Copy link
Member

@Naatan Naatan left a comment

Choose a reason for hiding this comment

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

Looks good! Thanks for sticking with it.

@mitchell-as mitchell-as reopened this Oct 20, 2023
@mitchell-as mitchell-as merged commit 17ec0f9 into version/0-42-0-RC1 Oct 20, 2023
9 of 12 checks passed
@mitchell-as mitchell-as deleted the mitchell/dx-2263 branch October 20, 2023 18:50
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.

3 participants