-
Notifications
You must be signed in to change notification settings - Fork 13
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
Conversation
54ef0b1
to
59be65d
Compare
Instead of automatically migrating projects, prompt the user. Projects in the old format are read-only.
59be65d
to
95b3728
Compare
Test failures are not due to this PR, but are known, existing issues and the usual timeouts. |
internal/locale/locales/en-us.yaml
Outdated
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? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rawktron please review
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?"
func Register(prompt_ promptable, out_ output.Outputer) { | ||
prompt = prompt_ | ||
out = out_ | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
pkg/project/project.go
Outdated
func (p *Project) Namespace() *Namespaced { | ||
commitID, err := localcommit.GetCompatible(p) | ||
commitID, err := localcommit.Get(p.Dir()) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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()
?
There was a problem hiding this comment.
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.
c05892c
to
312e01a
Compare
15ad7f5
to
b700527
Compare
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) | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
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. |
return false, errs.Wrap(err, "Could not create local commit file") | ||
} | ||
|
||
if fileutils.DirExists(filepath.Join(proj.Dir(), ".git")) { |
There was a problem hiding this comment.
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:
cli/internal/fileutils/fileutils.go
Line 422 in 35d1e55
func FindFileInPath(dir, filename string) (string, error) { |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
pkg/project/project.go
Outdated
commitId := strfmt.UUID(p.projectfile.LegacyCommitID()) | ||
return &Namespaced{p.projectfile.Owner(), p.projectfile.Name(), &commitId, false} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
Instead of automatically migrating projects, prompt the user. Projects in the old format are read-only.