Skip to content
This repository has been archived by the owner on Aug 1, 2021. It is now read-only.

Simplify SQL and translation pipeline changes #9

Merged
merged 22 commits into from
May 15, 2018

Conversation

monishdeb
Copy link
Member

#1

@monishdeb monishdeb changed the title Simplify SQL and translation pipeline changes [WIP] Simplify SQL and translation pipeline changes Feb 13, 2018
@dsnopek
Copy link

dsnopek commented Feb 13, 2018

I took a peek at the code, but it's not super clear to me: where do these generated files get placed? The question I'm trying to answer is if the web user (when doing a web, as opposed to cli, install) will have permission to write the files? It's not uncommon for the web user to only have permission to write to a limited set of directories (for example, sites/default/files for public files on a Drupal site).

@monishdeb
Copy link
Member Author

monishdeb commented Feb 13, 2018

@dsnopek good point. Well these generated files are stored in respective directories e.g. SQL files in civicrm/sql/* and these are the set of tasks executed during schema generation https://github.com/civicrm/civicrm-core/blob/master/CRM/Core/CodeGen/Main.php#L112L120

For web-user I can't think of a alternative right now as those generated files must be placed inside civicrm directory as those will be required to configure and install Civi.

@dsnopek
Copy link

dsnopek commented Feb 13, 2018

Hm. For Drupal 8, we could maybe have a composer script run the codegen? The user running composer would have to be able to write to those directories.

For other Drupal versions wanting to do a web install, though, we'd need to be able write them somewhere else (maybe even just the temporary directory?) and then somehow get CiviCRM to find them at an alternative location.

@monishdeb
Copy link
Member Author

monishdeb commented Feb 14, 2018

For other Drupal versions wanting to do a web install, though, we'd need to be able write them somewhere else (maybe even just the temporary directory?) and then somehow get CiviCRM to find them at an alternative location.

Earlier I refrained to put my comment in this direction because I thought that it would be too much work to use the underlying code of each Codegen task so that it can use the generated files in temporary directory of choice, for installation purpose but then on second thought, I think that will be possible as we just need to make each CRM_Core_CodeGen_Tasks::run($this) flexible enough to do so.

I also like to bring @totten in this discussion :)

@totten
Copy link
Member

totten commented Feb 14, 2018

@monishdeb Kudos on getting into this code-structure. I know the patterns are a bit different from what we've seen in runtime Civi, so that's probably taken a bit of reading/experimenting.

Let me paraphrase b81ea0c: basically, it adds a new API function ($setup->generateSchema()) which is really a wrapper for calling GenCode. As you indicate, this is incomplete/different. Bear with me for a few minutes to dig in.

Meta

@monishdeb @dsnopek It sounds like you're both trying to negotiate a different approach which uses GenCode as a building-block (albeit with a couple variations -- either as a composer hook or as a different API entry-point). In your shoes (or several years back), I'd probably do the same. You probably didn't participate actively in previous negotiations of these subsystems; probably assume that the status-quo makes sense; and probably need some kind of tear-down or reasons to deviate.

My perspective (as someone who was in some of those previous rounds) is different: the status-quo is a collection of kludges because we were too scared or ignorant to fix underlying problems. The project-structure here (with the separate installer library, deployed on new turf) provides a rare opportunity where we can address some underlying problems without risking a major break. So let's take it!

General problem

The basic, gut-level problem (boiled down to the minimum) is that installing Civi from source doesn't feel like installing other things from source.

As applied to SQL generation...

Try to think of another PHP application/framework which generates SQL the way Civi does -- i.e. as a standard practice, the first step after downloading the code is to call a big script that pre-generates 100+ SQL files. And the second step is to run some other process which picks 1 or 2 of them.

Does D7 do that? No. D8? No. WP? No. Joomla? No. Backdrop? No. Symfony? No. Laravel? No. In typical usage, all of these systems generate and execute the SQL on-demand (after the DB has become available). No intermediate files needed.

(This not saying "SQL files suck". There are good use-cases for them. drush may sync SQL files as part of the dev/prod workflow. Symfony has a CLI option to dump to a SQL file. That's all good, but it's optional, based on the admin's desire, and it's not the standard workflow. Making it the standard for all installation is the atypical thing which increases the mental-load.)

Put another way... #1 is saying Let's do the work of CRM_Core_CodeGen_Schema without GenCode.

I'd expect that writing a patch for #1 would go roughly like this:

  1. Copy the code from CRM_Core_CodeGen_Schema
  2. Put it in InstallSchema.civi-setup.php
  3. Modify it so that it reads $e->getModel() instead of $this->config.
  4. Modify it so that it executes the SQL instead of writing it to a temp file.

@totten
Copy link
Member

totten commented Feb 14, 2018

Aside: my suggestion above was to copy+edit. This is OK by me since the original would eventually become irrelevant. Alternatively, it's also valid to take a more conservative tack and avoid any moment of duplication. Ex:

  • In civicrm-core, take most of the code from CRM_Core_CodeGen_Schema and move it in a helper/utility.
    • The helper accepts the DB metadata as input; for output, it returns the SQL code (string).
    • CRM_Core_CodeGen_Schema calls the helper to get SQL as string. Then it writes the SQL string(s) to file(s).
  • In civicrm-setup, InstallSchema.civi-setup.php calls the helper. to get SQL as a string. Then it executes the SQL string(s).

@nganivet
Copy link

nganivet commented Feb 14, 2018

This all goes in the right direction, kudos to all for working on this.

An issue with the current code is that the initial database population is dependent on a 'Primary language' as it populates a number of options/strings with their translated content. But when the 'Primary language' is later changed in the UI, those same options/strings are not 're-translated' into the new language.

Looking at the options you are now considering, I wonder if we could also split the database population into (a) schema generation, including all option/strings in English and (b) translation of options/strings into another language.

This way, we could call the (b) part when switching the Primary language in the admin UI.

Adding @mlutfy since this is related to i18n.

@monishdeb monishdeb force-pushed the issue-1 branch 3 times, most recently from da7d348 to 34dc61c Compare February 15, 2018 11:38
@monishdeb
Copy link
Member Author

monishdeb commented Feb 15, 2018

Thanks a lot @totten . I have now updated the PR and addressed all the 4 points. Here's what I have done against each:

  1. Copy the code from CRM_Core_CodeGen_Schema
  2. Put it in InstallSchema.civi-setup.php

Done. It needs me to do:

  1. Add 3 DbUtil helper functions
  2. Modified sourceSQL() to take both SQL content OR filename
  3. Add plugins/init/AvailableTables.civi-setup.php to extract Civi table information to $model->tables as in core https://github.com/civicrm/civicrm-core/blob/master/CRM/Core/CodeGen/Specification.php#L32
  4. Add 2 help function to FileUtil to create Directory.
  5. Add template Wrapper src/Setup/Template.php
  6. Add smarty Util wrappersrc/Setup/SmartyUtil.php
  1. Modify it so that it reads $e->getModel() instead of $this->config.

Done

  1. Modify it so that it executes the SQL instead of writing it to a temp file.

Done, made changes in InstallSchema.civi-setup.php which now generate and execute the SQL content. However, for generated data we need to fetch SQL content from multiple files, reason why I have used temp directory to store the content in a temp file and then return its content at one go. Here's an example

...
 \Civi\Setup\DbUtil::sourceSQL($model->db, \Civi\Setup\DbUtil::generateCreateSql($srcPath, $model->db['database'], $model->tables));
...
// where
function generateCreateSql($srcPath, $model->db['database'], $model->tables)) {
  ...
   return $template->getContent($srcPath . 'xml/templates/schema.tpl');
}

LAST and most important task remaining - testing :)

}

public function generateSample($sqlPath) {
$temporarySQLFilePath = implode(DIRECTORY_SEPARATOR, \Civi\Setup\FileUtil::createTempDir(), 'civicrm_generated.mysql');
Copy link
Member

Choose a reason for hiding this comment

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

Should this have []s?

* @param string $outpath
* Full path to the desired output file.
*/
public function getConcatContent($inputs, $tempOutputFilePath) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I'm not following something, but... can we just remove all the $tempOutputFilePath and file_*_contents() stuff?

Basically:

$buffer = '';
foreach ($inputs as $infile) {
  $buffer .= $this->smarty->fetch($infile) . "\n";
}
return $buffer;

@totten
Copy link
Member

totten commented Feb 15, 2018

Those changes generally sound appropriate. 👍 While trying it out, I made a few related changes in civicrm/civicrm-core#11677 , and (so far) this small change was also useful:

diff --git a/plugins/init/AvailableTables.civi-setup.php b/plugins/init/AvailableTables.civi-setup.php
index 95484aa..0a4c5a5 100644
--- a/plugins/init/AvailableTables.civi-setup.php
+++ b/plugins/init/AvailableTables.civi-setup.php
@@ -22,7 +22,7 @@ if (!defined('CIVI_SETUP')) {
       $xmlBuilt = \CRM_Core_CodeGen_Util_Xml::parse($versionFile);
       $buildVersion = preg_replace('/^(\d{1,2}\.\d{1,2})\.(\d{1,2}|\w{4,7})$/i', '$1', $xmlBuilt->version_no);
       $specification = new \CRM_Core_CodeGen_Specification();
-      $specification->parse($schemaFile, $buildVersion);
+      $specification->parse($schemaFile, $buildVersion, FALSE);
       $tables = $specification->tables;
     }
     else {

* @property array $tables
* List of CiviCRM tables extracted from xml schema files.
* Values must only be array.
* Ex: ['civicrm_contact', 'civicrm_group'].
Copy link
Member

@totten totten Feb 15, 2018

Choose a reason for hiding this comment

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

I think putting some schema metadata in Model makes in terms of dataflows, although I wouldn't want downstream installer code (like cv core:install or D8 civicrm.install) to be aware of those parts of the model.

FWIW, if we wanted this to be private, it could go in something like $model->extras['schema.tables']

@totten
Copy link
Member

totten commented Feb 15, 2018

@monishdeb , I was trying to run locally and fixed a few issues in the process.

https://github.com/totten/civicrm-setup/commits/monishdeb-issue-1

but it now gets as far as:

$ ~/src/cv/bin/cv core:install --setup-path=$HOME/src/civicrm-setup  --cms-base-url=http://dmaster.l -f -vvv

...

Fatal error: Call to undefined function ts() in /Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/CRM/Core/Smarty/plugins/block.ts.php on line 57

Call Stack:
    0.0003     241320   1. {main}() /Users/totten/src/cv/bin/cv:0
    0.0090     902352   2. Civi\Cv\Application::main() /Users/totten/src/cv/bin/cv:27
    0.0458    3548888   3. Symfony\Component\Console\Application->run() /Users/totten/src/cv/src/Application.php:17
    0.0506    3911536   4. Symfony\Component\Console\Application->doRun() /Users/totten/src/cv/vendor/symfony/console/Application.php:124
    0.0509    3912592   5. Symfony\Component\Console\Application->doRunCommand() /Users/totten/src/cv/vendor/symfony/console/Application.php:193
    0.0510    3913168   6. Symfony\Component\Console\Command\Command->run() /Users/totten/src/cv/vendor/symfony/console/Application.php:850
    0.0519    3920152   7. Civi\Cv\Command\CoreInstallCommand->execute() /Users/totten/src/cv/vendor/symfony/console/Command/Command.php:257
    0.6581   29001832   8. Civi\Cv\Command\CoreInstallCommand->runSetup() /Users/totten/src/cv/src/Command/CoreInstallCommand.php:75
    0.6969   29365600   9. Civi\Setup->installDatabase() /Users/totten/src/cv/src/Command/CoreInstallCommand.php:179
    0.6989   29372712  10. Symfony\Component\EventDispatcher\EventDispatcher->dispatch() /Users/totten/src/civicrm-setup/src/Setup.php:204
    0.6989   29374144  11. Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() /Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:53
    0.6992   29375520  12. call_user_func:{/Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:164}() /Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:164
    0.6992   29376216  13. Civi\Setup::{closure:/Users/totten/src/civicrm-setup/plugins/installDatabase/InstallSchema.civi-setup.php:44-74}() /Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:164
    0.7650   30440552  14. Civi\Setup\DbUtil::generateNavigation() /Users/totten/src/civicrm-setup/plugins/installDatabase/InstallSchema.civi-setup.php:55
    0.7658   30445736  15. Civi\Setup\Template->getContent() /Users/totten/src/civicrm-setup/src/Setup/DbUtil.php:259
    0.7658   30445736  16. Smarty->fetch() /Users/totten/src/civicrm-setup/src/Setup/Template.php:42
    0.9973   32681176  17. include('/private/var/folders/s5/w16pvsx11q54y87_g91xwf_80000gn/T/templates_cBRYG8I.d/%%3E^3E2^3E245C50%%civicrm_navigation.tpl.php') /Users/totten/buildkit/build/dmaster/sites/all/modules/civicrm/packages/Smarty/Smarty.class.php:1270
    0.9974   32813584  18. smarty_block_ts() /private/var/folders/s5/w16pvsx11q54y87_g91xwf_80000gn/T/templates_cBRYG8I.d/%%3E^3E2^3E245C50%%civicrm_navigation.tpl.php:48

@monishdeb
Copy link
Member Author

monishdeb commented Feb 16, 2018

@totten sorry about that, I should have tested on my local to fix them all after making changes :( Thanks a lot for fixing these issues. I added your commits in this PR.

@totten
Copy link
Member

totten commented Feb 16, 2018

@monishdeb I've posted some more commits on https://github.com/totten/civicrm-setup/commits/monishdeb-issue-1 . In combination with civicrm/civicrm-core#11677 and civicrm/civicrm-core#11682, it's able to get the basic, empty tables created.

@monishdeb
Copy link
Member Author

monishdeb commented Feb 16, 2018

@totten great. I have applied both the core patches and after pulling your commits in this branch, when I executed the command it got stuck at:

cv core:install --settings-path=http://localhost:8888/test-civicrm/sites/default/civicrm.settings.php --src-path=/Users/monish/src/civicrm --cms-base-url=http://localhost:8888/test-civicrm/ --db=mysql://root:root@127.0.0.1:8889/test_civicrm --model=/Users/monish/www/civicrm-master/.core-install-settings.json 
Found code for civicrm-core in /Users/monish/src/civicrm
Found code for civicrm-setup in /Users/monish/src/civicrm/vendor/civicrm/civicrm-setup
Creating file http://localhost:8888/test-civicrm/sites/default/civicrm.settings.php
Creating civicrm_* database tables in test_civicrm

                                                                                                                                                                                
  [Civi\Setup\Exception\SqlException]                                                                                                                                           
  Cannot execute INSERT INTO civicrm_mail_settings (domain_id, name, is_default, domain) VALUES (@domainID, 'default', true, 'EXAMPLE.ORG'): Column 'domain_id' cannot be null  
                                                                                                                                                                                

Working on this fix.

@totten
Copy link
Member

totten commented Feb 16, 2018

Yup, I that's why I get too. :)

My gut sense is that either generateNavigation() isn't executing correctly -- e.g. maybe some inputs are wrong, or maybe there's another *.tpl that needs to be loaded first. Can you dig in on this error?

Aside: Yesterday, I tried to make a map of the various SQL+TPL files and the timing/ordering with which they traditionally loaded. May be useful: https://gist.github.com/totten/c2ab52dee8c8659944c9697616009f98

@monishdeb
Copy link
Member Author

Yup sure, I am already working on it and thanks for sharing https://gist.github.com/totten/c2ab52dee8c8659944c9697616009f98

@nganivet
Copy link

@totten @monishdeb I would really like to separate the i18n from this process as per #9 (comment) while we are working on this. Can you specify what would need to be done for this separation and I will do the work? IMO it's just removing translations from the .tpl files and adding this somewhere else, but I would need to know what the 'somewhere else' is - another .tpl file, a piece of PHP code, etc. Thanks.
@mlutfy FYI and comments.

@totten
Copy link
Member

totten commented Feb 16, 2018

@nganivet I agree it's a bit frustrating to change the language post-installation, and I see the appeal of re-translating, but I don't really see how coupling that problem to this one helps.

If the idea is to make more of these things translated in real-time, then that's going to be an across-the-board reworking.

If the idea is to update DB records post-install, then I think the algorithm would be the same with or without this patchset. It might look something like this pseudo-code:

function translateData() {
  $fixableColumns = [
    ['civicrm_location_type', 'display_name'],
    ['civicrm_option_value', 'label'],
    //...
  ];
  foreach ($fixableColumns as $fixMe) {
    list ($table, $column) = $fixMe;
    foreach (query("SELECT $column AS oldValue FROM $table") as $row) {
      $newValue = ts($row['value']);
      query("UPDATE $table SET $column = $newValue WHERE $column = $oldValue");
    }
  }
}

You'd have to read civicrm_data.tpl to make a list of tables/columns to fix-up. And it might take a few minutes. And it only works if the start-language is en_US (though that's fixable if you build a reverse-map of the *.po). But in any case, I don't really see why it needs to be tied into this PR/issue.

@nganivet
Copy link

@totten Thanks. I am discussing this change as part of this PR because I want to make sure that this new behavior (ie. always install in en_US and then translate by calling a PHP function) is compatible with the new 'SQL and translation pipeline' that you are building.

If it is, I will go ahead and work on this as part of a separate PR.

@monishdeb
Copy link
Member Author

monishdeb commented Feb 19, 2018

@totten I have resolved the remaining issues. Here's what I have done:

  1. When we execute the SQL files in the given order, it throws Column 'domain_id' cannot be null error triggered from navaigation.tpl because this file is executed too early before populating the necessary data. So I have placed the SQL-run for navigation at the end i.e. AFTER generate-data-sql execution that is responsible to insert domain record and other necessary data.

  2. After resolving the above, I got another set of issues where essential Civi constants (like CIVICRM_UF_DSN) were not defined. So when I looked at the sequence of plugins I found that civicrm setting file creation task is placed after installSchema/*. I think that's odd to include the uninstall events as part of civi setup. So I have defined the order in which the plugin files should be picked which fixes this issue. I then just need to include the civi setting file before the SQL run here

Here's the latest result:

$ cv core:install --settings-path=http://localhost:8888/test-civicrm/sites/default/civicrm.settings.php --src-path=/Users/monish/src/civicrm --cms-base-url=http://localhost:8888/test-civicrm/ --db=mysql://root:root@127.0.0.1:8889/test_civicrm --model=/Users/monish/www/civicrm-master/.core-install-settings.json 
Found code for civicrm-core in /Users/monish/src/civicrm
Found code for civicrm-setup in /Users/monish/src/civicrm/vendor/civicrm/civicrm-setup
Creating file http://localhost:8888/test-civicrm/sites/default/civicrm.settings.php
Creating civicrm_* database tables in test_civicrm

monishdeb and others added 16 commits April 26, 2018 00:03
1. Typo in variable name ($fileType)
2. Add `assign()`, because a few other spots seem to expect it
3. Remove unused param ($outputath)
The main issue here is that `schema.tpl` is getting the wrong data. It was getting the DB name

```php
generateCreateSql($model->srcPath, $model->db['database'], $model->tables)
```

But it should actually the full, parsed schema specification:

```
generateCreateSql($model->srcPath, $spec->database, $spec->tables)
```

So basically...  `InstallSchema` needs access to the full `$specification`
(which was only available in `AvailableTables`).  And I don't currently see
a use-case that requires exposing the schema as part of the installer model,
so I think it's simpler to merge `AvailableTables` into `InstallSchema`.
@monishdeb
Copy link
Member Author

monishdeb commented Apr 25, 2018

@totten in this last commit 4f0315a I have fixed

  1. Load sample date using sql/civicrm_generated.mysql as I found that using regen.sh we not only rely on php script GenerateData to populate sample data but it also pulls out other data from respective files and that all being dumped in that mysql file. So I felt why not use that generate mysql file directly.
  2. Now locale instance has civicrm_currency and civicrm_domain record
  3. civicrm_install_canary is present
  4. civicrm_menu is populated with new data.
  5. In civicrm_setting these are the settings present:
    screen shot 2018-05-07 at 5 33 26 pm
  6. Triggers are present

I have rebuilt the DB snapshots and here's the diff:

  1. DB instance on default locale install
    https://gist.github.com/monishdeb/63b1f4a1fd4a5c2b12904b2900f96c0d

  2. DB instance on es_ES locale install
    https://gist.github.com/monishdeb/7c6770e8192b083cd2835acb21d0a6e4

  3. DB instance on generatedSample install
    https://gist.github.com/monishdeb/bbb1196dbd37baa2c709fc9a2af7680c

@monishdeb
Copy link
Member Author

And here's the zip which contains the newly created DB snapshots
tmp.zip

totten added 3 commits May 14, 2018 23:39
This version number winds up in the database (`civicrm_domain.version`); it
needs to be the fully formed number so that future upgrades work correctly.
The behavior (prior to this commit) is not equivalent to published behavior
because the normal/minimalist installation includes a smattering of sample
records (e.g.  sample case-types).  This revision helps us do the old
behavior by distinguishing between:

* `generateBasicData()` is just the baseline data (countries, option-groups, etc). This is equivalent to the old behavior.
* `generateSampleData()` includes the baseline data as well as some hypothetical/org-specific data (case-types, etc).
  This is similar in spirit to `civicrm_generated.mysql`, but it's not complete.
There are a bunch of `*.tpl` files which are incorporated into the
baseline dataset. Most of these are listed in an array in `generateBasicData()`,
but `civicrm_navigation.tpl` was treated differently (with its own
`generateNavigation()`).

This cuts down several SLOC. It appears to be equivalent based on
reading and based on testing DB snapshots (before/after).
@totten
Copy link
Member

totten commented May 15, 2018

Thanks for the udpates, @monishdeb! I pulled down the code and ran DB dumps, the diff's were definitely closer than before. 👍 And I agree that it's easier to use civicrm_generate.mysql (which is currently committed/distributed via all channels) than to try to reproduce regen.sh.

There were a few issues that came up, and I've pushed up patches for these:

  1. In cv, there's a test case CoreLifecycleTest which installs and uninstalls using civicrm-setup. The test was failing for two reasons. (a) In the interim since it was developed, we've started flagging alphas/betas again -- and a version regex failed. (Patch: civicrm/cv@8cd12e4) (b) In the final data-set, civicrm_domain.version looked like 5.2 instead of the expected 5.2.beta1 -- which is significant for handling upgrades. (Patch: c3bed33)

  2. There were still some unexpected data-differences -- on a clean (non-demo) installation, the old and new behavior differed on whether to include civicrm_sample.tpl and case_sample.tpl. I think the old behavior was more correct -- i.e. we shouldn't registered "Adult Day Care Referral" and "Housing Support" on a clean site -- those should only show up on a demo site. (Patch: 839da8f)

@totten totten changed the title [WIP] Simplify SQL and translation pipeline changes Simplify SQL and translation pipeline changes May 15, 2018
@totten
Copy link
Member

totten commented May 15, 2018

Recap of QA steps that are passing:

  1. Run CoreLifecycleTest. Passed on all tested environments (drupal-empty,wp-empty,backdrop-empty).
  2. Run the bash script from Simplify SQL and translation pipeline changes #9 (comment) before and after. Compare the results. I ignored cache tables. The differences were few and trivial (e.g. different timestamps on the 1 contact record).
  3. Delete all locally-generated *.mysql files (based on grep sql .gitignore). Manually run cv core:install (both in basic/clean mode and with loadGenerated=1) and browse through the data in the UI. The site appeared to work.
  4. Manually run cv core:install (as above). Then use set-version.php and cv upgrade:db to simulate a DB upgrade. The civicrm_domain.version appeared to progress nicely.

So I think we can merge this. 🎉

@totten totten merged commit 556b312 into civicrm:master May 15, 2018
@monishdeb
Copy link
Member Author

This is awesome :) Thanks @totten and agree with the two patch. Just had a thought that as now the civicrm-version.php is merged to core so we can use its utility function \_CiviVersion_\Util::findVersion() to fetch version from xml. But that doesn't matter as I'll introduce this minor change in later PR.

@monishdeb monishdeb deleted the issue-1 branch May 15, 2018 09:27
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants