On Sat, May 30, 2020 at 3:08 PM Craig Russell <apache....@gmail.com> wrote: > > > On May 29, 2020, at 3:17 AM, sebb <seb...@gmail.com> wrote: > > > > On Fri, 29 May 2020 at 00:49, Craig Russell <apache....@gmail.com> wrote: > >> > >> It looks like the best approach is to do the svn operations in two steps: > >> > >> 1. Update the svn foundation/members.txt based on the request (active, > >> emeritus, deceased) which is already in place. > >> 2. Perform the moves in svn documents > >> (emeritus-request-received>emeritus-request-rescinded, > >> emeritus-request-received->emeritus) which is new code to be written. > >> > >> These are two different svn repositories so they need to be in two svn > >> commits anyway. > > > > Not AFAIK. All the ASF documents are in the same SVN repo, which is rooted > > at: > > > > https://svn.apache.org/repos/private > > Thanks for that. I have each repository checked out and didn't think to look > to see if they shared a root. > > > >> And if the operations are retried on failure there is nothing to be done > >> to coordinate the two operations. Meanwhile, I am sure that I do not know > >> how to make the roster ruby/svn code retriable. > > > > A problem arises if the second request fails even after retry. > > There will be an outstanding change which has to be performed at some > > later stage. > > So if I understand you, we can do both updates with the same svn commit, and > should do so to avoid a partial commit that then needs to be corrected by > hand.
Correct. In fact, if the commit is ONLY intended to have the move, it can be done via a single svn move command where both the source and destination are specified as URLs. http://svnbook.red-bean.com/en/1.7/svn.ref.svn.c.move.html > >> I plan to start on figuring out how to do svn move from emeritus to > >> emeritus-request-rescinded. > > > > Do you mean emeritus-request => emeritus-request-rescinded ? > > Yes. So I'm thinking that we should adapt the memstat.json.rb code to accept > another url parameter with the file name that we already know, and send that > file name to the _svn.update method. > > As long as we're looking at this method, isn't it a bit badly named? Its > purpose is specifically to modify the members.txt file to move an entry from > one place to another, so shouldn't it have a more specific name, like > update_members_info? > > Anyway, we now need to pass the emeritus_file_name from memstat.json.rb to > the update method. And then have the update method use that file name to move > the file from one emeritus directory to another, depending on the action: > emeritus: move the file from emeritus-requests-received to emeritus > rescind: move the file from emeritus-requests-received to > emeritus-requests-rescinded > active: move the file from emeritus to emeritus-rescinded > > I'd like to understand how this method call works: > _svn.update members_txt, message: message do |dir, text| > > Specifically, where did dir and text come from and why are they enclosed in > |...|? the ```do |args|.... end``` effectively defines an anonymous function. The parameters to that function are enclosed in vertical bars. Ruby calls this anonymous function a block. There are two syntaxes for calling blocks. In this case, the block is called via a yield statement. A more complete description can be found here: https://mixandgo.com/learn/mastering-ruby-blocks-in-less-than-5-minutes Taking a step back, what is happening here is that the update method does a checkout into a temporary directory, reads the current contents of the file in question and passes that directory and contents to the anonymous function which returns new contents. A commit is then attempted. Making the code that converts old contents into new contants a block means that the overall process (starting with the creating of a temporary directory to commit potentially common code that is independent of the update operation being attempted. > It looks like the code in memstat.json.rb is a co-routine with the code in > lib...svn.rb, where the svn.rb code opens the members_txt file, passes > control to the code in memstat.json.rb to update the members.txt data and > when that's done, svn.rb takes over and completes the commit operation. > > So now we are in the _svn.update do block and need to execute an svn mv > command. > > # determine where to put the entry > if @action == 'emeritus' > index = text.index(/^\s\*\)\s/, text.index(/^Emeritus/)) > entry.sub! %r{\s*/\* deceased, .+?\*/},'' # drop the deceased comment if > necessary > > dir = ASF:SVN:find!('documents') # this is the root directory > from = 'emeritus-requests-received' > to = 'emeritus' > # execute the code to move the file from one directory to another > svn.move(dir, from, to, @emeritus-file-name) > > Over to you... > > Craig > > > >> Thanks, > >> Craig > >> > >>> On May 26, 2020, at 10:37 PM, Sam Ruby <ru...@intertwingly.net> wrote: > >>> > >>> On Wed, May 27, 2020 at 12:38 AM Craig Russell <apache....@gmail.com> > >>> wrote: > >>>> > >>>> I'm not having any success understanding the memstat.json.rb code: > >>>> # update members.txt > >>>> _svn.update members_txt, message: message do |dir, text| > >>>> > >>>> Does this call the code in svn.rb? > >>>> def self.update(path, msg, env, _, options={}) > >>>> > >>>> I guess I'm not so good at reading the ruby... > >>> > >>> The definition of _svn is here: > >>> > >>> https://github.com/apache/whimsy/blob/4e89c0e2a1069fbe7b6f4472722836c12a846e6c/www/roster/models/svn.rb#L29 > >>> > >>> It does indeed call the update method in lib/whimsy/asf/svn.rb. > >>> > >>> As an aside, the JavaScript module system, like Python, requires each > >>> module to explicitly import what it needs, this makes it easier to > >>> identify where the definition of a given method is. Enough so that > >>> IDEs like VSCode allow you to control-click (or command-click on > >>> MacOS) on a function call and it will take you to its definition. > >>> > >>>> I'm more used to the read/update/write/repeat/commit style of database > >>>> access, where the memstat.json.rb would > >>>> - read the members.txt > >>>> - using the action (emeritus, active, deceased, request_emeritus, > >>>> rescind_emeritus) edit the members.txt > >>>> - move the file from emeritus-requests-received to emeritus (emeritus) > >>>> - remove the file from emeritus-requests-received (rescind) > >>>> - svn commit the changes > >>> > >>> That's indeed how it was done on the original whimsy_vm (effectively > >>> whimsy_vm1). It routinely would get 'wedged' (that's the term you > >>> used at the time) and I would have to ssh into that machine, run a > >>> combination of svn reverts and svn cleanups until the directory was > >>> clean again, then the operation could be attempted again. Perhaps you > >>> might remember this happening. > >>> > >>> The second iteration creates a fresh checkout of the directory in > >>> question, runs your block against that directory and commits the > >>> results. Should the directory get 'wedged', the operation will fail, > >>> but no matter what happens that temporary directory will be thrown > >>> away, so the operation can be attempted again. This is the code you > >>> are now looking at. > >>> > >>> The third iteration (present only in the Ruby board agenda tool at the > >>> moment) takes this a step further and retries operations. Unlike the > >>> secretary workbench and even to some extent the roster tool, the board > >>> agenda tool is often used by multiple people concurrently, often with > >>> changes to the same lines (most notably, the approval lines) on the > >>> day before the board meeting. If a commit fails, a sleep for a random > >>> time occurs and the operation is attempted again with a fresh checkout > >>> and re-invoking the same block. I even have a test tool that > >>> simulates 9 directors committing at once: > >>> > >>> https://github.com/apache/whimsy/blob/master/www/board/agenda/test/stresstest.rb > >>> > >>> The fourth iteration (currently being prototyped in > >>> JavaScript/Node.js) is intended to incorporate the above retry logic > >>> in production, but will also employ different strategies in > >>> development and test. > >>> > >>> In the fullness of time, all of this should hopefully converge. > >>> Meanwhile, build on the strategy that you feel most comfortable with, > >>> and over time it will likely be rewritten as new strategies emerge. > >>> > >>>> Craig > >>> > >>> - Sam Ruby > >>> > >>>>> On May 26, 2020, at 6:09 PM, Sam Ruby <ru...@intertwingly.net> wrote: > >>>>> > >>>>> On Tue, May 26, 2020 at 8:44 PM Craig Russell <apache....@gmail.com> > >>>>> wrote: > >>>>>> > >>>>>> Sorry for not being clear. In the whimsy/lib there is a helper file > >>>>>> svn.rb that has a number of functions including update(path, msg, env, > >>>>>> _, options={}) that is used by roster memstat.json.rb and it contains > >>>>>> the commit in the function. > >>>>>> > >>>>>> I did not see a move or remove function in svn.rb. Should I be looking > >>>>>> somewhere else for examples of svn commands? Should I look at adding > >>>>>> move and remove functions to svn.rb? > >>>>> > >>>>> Not currently. > >>>>> > >>>>> I'm convinced that the right way forward is for all svn access to be > >>>>> done via what you are calling helpers. This not only makes the code > >>>>> cleaner > >>>>> > >>>>> Ruby: File.read(File.join(ASF::SVN['foundation_board'], > >>>>> 'board_agenda_06_17.txt') > >>>>> JS: Board.read('board_agenda_06_17.txt') > >>>>> > >>>>> ... it also enables redirecting all commits to a local repository in > >>>>> development, and mocking the repository in test. > >>>>> > >>>>> In any case, all of the svn operations should be updated to make use > >>>>> of --password-from-stdin where available, which unfortunately won't be > >>>>> until whimsy-vm is upgraded to Ubuntu 20.04. > >>>>> > >>>>>> Thanks, > >>>>>> Craig > >>>>> > >>>>> - Sam Ruby > >>>>> > >>>>>>> On May 26, 2020, at 5:23 PM, Sam Ruby <ru...@intertwingly.net> wrote: > >>>>>>> > >>>>>>> On Tue, May 26, 2020 at 8:15 PM Craig Russell <apache....@gmail.com> > >>>>>>> wrote: > >>>>>>>> > >>>>>>>> The cancel button now works (thanks, Sam). On to the server side. > >>>>>>>> > >>>>>>>> To implement active->emeritus we need to update members.txt and move > >>>>>>>> the request file from emeritus-requests-received to emeritus. > >>>>>>>> > >>>>>>>> - Is there an svn function to move a file from one directory to > >>>>>>>> another? > >>>>>>> > >>>>>>> http://svnbook.red-bean.com/en/1.6/svn.ref.svn.c.move.html > >>>>>>> > >>>>>>>> - Is there a way to have both things done in the same svn commit? > >>>>>>> > >>>>>>> If both the source and target have a common parent, do the svn commit > >>>>>>> from that parent. > >>>>>>> > >>>>>>> When the secretary files board minutes, > >>>>>>> 1) the minutes are moved to the website. Those source and target > >>>>>>> don't share a common parent, so two commits are required. > >>>>>>> 2) the agenda is moved to a subdirectory. The source and target share > >>>>>>> a common parent, so one commit suffices. > >>>>>>> > >>>>>>>> To implement request_emeritus_status we need to create an email. > >>>>>>>> Easy.. > >>>>>>>> > >>>>>>>> To implement rescind_emeritus_request we need to svn rm the file > >>>>>>>> from emeritus-requests-received. > >>>>>>>> > >>>>>>>> - Is there an svn function to delete a file? > >>>>>>> > >>>>>>> http://svnbook.red-bean.com/en/1.6/svn.ref.svn.c.delete.html > >>>>>>> > >>>>>>>> Thanks, > >>>>>>>> Craig > >>>>>>> > >>>>>>> - Sam Ruby > >>>>>>> > >>>>>>>>> On May 26, 2020, at 3:20 PM, Craig Russell <apache....@gmail.com> > >>>>>>>>> wrote: > >>>>>>>>> > >>>>>>>>> Here are the files. > >>>>>>>>> <main.js.rb><memstat.js.rb> > >>>>>>>>> And the console logs: > >>>>>>>>> [Log] dblclick event.currentTarget: [object HTMLDivElement] > >>>>>>>>> (app.js, line 3268) > >>>>>>>>> [Log] dblclick event.currentTarget.dataset: [object DOMStringMap] > >>>>>>>>> (app.js, line 3269) > >>>>>>>>> [Log] dblclick event.currentTarget.dataset.edit: memstat (app.js, > >>>>>>>>> line 3270) > >>>>>>>>> [Log] canx called from Cancel button (app.js, line 4021) > >>>>>>>>> [Log] event: [object MouseEvent] parent: [object HTMLButtonElement] > >>>>>>>>> (app.js, line 4024) > >>>>>>>>> [Log] parent: [object HTMLButtonElement] memstatElement: [object > >>>>>>>>> HTMLDivElement] (app.js, line 4025) > >>>>>>>>> [Log] preventing default (app.js, line 4026) > >>>>>>>>> [Log] memstatElement.dataset: [object DOMStringMap] (app.js, line > >>>>>>>>> 4027) > >>>>>>>>> [Log] memstatElement.dataset.edit: memstat (app.js, line 4028) > >>>>>>>>> [Log] submit event: [object Object] (app.js, line 3291) > >>>>>>>>> [Log] submit target: [object HTMLButtonElement] (app.js, line 3292) > >>>>>>>>> [Log] submit parent: [object HTMLButtonElement] (app.js, line 3293) > >>>>>>>>> [Log] submit parent.getAttribute(data_cancel): null (app.js, line > >>>>>>>>> 3294) > >>>>>>>>> [Log] submit target.dataset_edit: undefined (app.js, line 3295) > >>>>>>>>> [Log] submit target.dataset: [object DOMStringMap] (app.js, line > >>>>>>>>> 3296) > >>>>>>>>> [Log] submit target.dataset.edit: undefined (app.js, line 3297) > >>>>>>>>> [Log] submit memstatElement.dataset.edit: memstat (app.js, line > >>>>>>>>> 3298) > >>>>>>>>> [Log] submit cancel_submit: null (app.js, line 3300) > >>>>>>>>> > >>>>>>>>>> On May 26, 2020, at 2:19 PM, Sam Ruby <ru...@intertwingly.net> > >>>>>>>>>> wrote: > >>>>>>>>>> > >>>>>>>>>> On Tue, May 26, 2020 at 1:32 AM Craig Russell > >>>>>>>>>> <apache....@gmail.com> wrote: > >>>>>>>>>>> > >>>>>>>>>>> But calling preventDefault on the event doesn't appear to do > >>>>>>>>>>> anything. It still calls the POST behavior, and does not cause > >>>>>>>>>>> the inline edit menu to disappear. And setting the edit function > >>>>>>>>>>> to nil doesn't do anything either. > >>>>>>>>>>> > >>>>>>>>>>> Maybe there is something else that I need to do? > >>>>>>>>>> > >>>>>>>>>> I'll admit that I'm not clear on what you are trying to accomplish, > >>>>>>>>>> but apparently the problem here is that there is another piece of > >>>>>>>>>> code > >>>>>>>>>> that attaches an event handler (and calls preventDefault): > >>>>>>>>>> > >>>>>>>>>> https://github.com/apache/whimsy/blob/d3246f107a35f4d989350f4c1ca64366c98ef423/www/roster/views/person/main.js.rb#L341 > >>>>>>>>>> > >>>>>>>>>> Perhaps it would be best to add an attribute to the button, and > >>>>>>>>>> have > >>>>>>>>>> the submit method remove the buttons and exit early: > >>>>>>>>>> > >>>>>>>>>> diff --git a/www/roster/views/person/main.js.rb > >>>>>>>>>> b/www/roster/views/person/main.js.rb > >>>>>>>>>> index 1b5ffdb8..f498489f 100644 > >>>>>>>>>> --- a/www/roster/views/person/main.js.rb > >>>>>>>>>> +++ b/www/roster/views/person/main.js.rb > >>>>>>>>>> @@ -355,6 +355,12 @@ class Person < Vue > >>>>>>>>>> form = jQuery(event.currentTarget).closest('form') > >>>>>>>>>> target = event.target > >>>>>>>>>> > >>>>>>>>>> + # if button is a cancel button, don't submit and remove > >>>>>>>>>> buttons > >>>>>>>>>> + if target.getAttribute('data-cancel') > >>>>>>>>>> + @edit = null > >>>>>>>>>> + return > >>>>>>>>>> + end > >>>>>>>>>> + > >>>>>>>>>> # serialize form > >>>>>>>>>> formData = form.serializeArray(); > >>>>>>>>>> > >>>>>>>>>> diff --git a/www/roster/views/person/memstat.js.rb > >>>>>>>>>> b/www/roster/views/person/memstat.js.rb > >>>>>>>>>> index 39367c40..e8d3d318 100644 > >>>>>>>>>> --- a/www/roster/views/person/memstat.js.rb > >>>>>>>>>> +++ b/www/roster/views/person/memstat.js.rb > >>>>>>>>>> @@ -35,6 +35,8 @@ class PersonMemberStatus < Vue > >>>>>>>>>> _button.btn.btn_primary 'move to emeritus', > >>>>>>>>>> name: 'action', value: 'emeritus' > >>>>>>>>>> end > >>>>>>>>>> + > >>>>>>>>>> + _button.btn.btn_secondary 'cancel', data_cancel: > >>>>>>>>>> true > >>>>>>>>>> end > >>>>>>>>>> end > >>>>>>>>>> end > >>>>>>>>>> > >>>>>>>>>> - Sam Ruby > >>>>>>>>> > >>>>>>>>> Craig L Russell > >>>>>>>>> c...@apache.org > >>>>>>>>> > >>>>>>>> > >>>>>>>> Craig L Russell > >>>>>>>> c...@apache.org > >>>>>>>> > >>>>>> > >>>>>> Craig L Russell > >>>>>> c...@apache.org > >>>>>> > >>>> > >>>> Craig L Russell > >>>> c...@apache.org > >>>> > >> > >> Craig L Russell > >> c...@apache.org > >> > > Craig L Russell > c...@apache.org >