Configuring apps with github



    Configuration is as important a part as code, especially in large projects. But often it is treated as a second-rate artifact of software development and operation. It is bad if the configuration does not go through the same full cycle as the software. They forget about the audit of changes and versioning, or they do not carry out the most suitable tools for this.

    I saw many projects where the configuration is embedded in the file system in the form of properties / json / xml files with incomprehensible overrides at the time of loading. And what the application actually uses becomes clear only after viewing the component log files or during debugging.

    You can find a script for automatic installation of your Git repository in the section “Configuration in your own git repository”.

    When choosing git, you can use all the tools that are used in development. Do reviews, compare configurations, support different configuration branches, link to tags, use both visual tools and command line tools.

    To take advantage of all this powerful arsenal, we only need to learn how to read the configuration from the git repository.

    To do this, use the Java class to read the configuration. It is based on a wrapper around hawtio-git (which in turn uses JGit under the hood ) and is available on github git-configuration and in maven central .

    Seeing the configurational chaos around, I will try to recall the bright and the beautiful.
    For the first time, the idea of ​​storing configuration in git inspired after exploring fuse fabric / fabric8 .

    The gorgeous spring-cloud-config project is also able to store the configuration in the git repository . But if we do not need a dependency on spring and its PropertySource abstraction, then the solution from this publication is better suited for a jvm application.


    Github configuration



    Let's start by reading the configuration that we posted in the github repository ...

    Java


    Configuration.java
    package com.github.igorsuhorukov.configuration;
    import com.github.igorsuhorukov.codehaus.plexus.util.IOUtil;
    import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader;
    import io.hawt.git.GitConfigurationHelper;
    import java.io.InputStream;
    public class Configuration {
        public static void main(String[] args) throws Exception{
            GitConfigurationHelper gitConfigurationHelper = new GitConfigurationHelper("https://github.com/igor-suhorukov/aspectj-scripting.git");
            System.out.println("CONFIGURATION FROM GIT: HEAD REVISON ----------------------------------");
            System.out.println(gitConfigurationHelper.getFileContent("master","pom.xml"));
            System.out.println("CONFIGURATION FROM GIT: BY TAG ----------------------------------------");
            System.out.println(gitConfigurationHelper.getFileContent("master","aspectj-scripting-1.2", "pom.xml"));
            gitConfigurationHelper.destroy();
            System.out.println("CONFIGURATION FROM MAVEN REPO -----------------------------------------");
            InputStream configStream = MavenClassLoader.usingCentralRepo().resolveArtifact("com.github.igor-suhorukov:aspectj-scripting:pom:1.3").openStream();
            System.out.println(IOUtil.toString(configStream));
        }
    }
    


    Dependencies necessary for the example to work:
    com.github.igor-suhorukovgit-configuration1.0com.github.igor-suhorukovmvn-classloader1.4


    To get the configuration, you need to specify the path to our repository:
    new GitConfigurationHelper("https://github.com/igor-suhorukov/aspectj-scripting.git")
    

    Possible options
    • Use the latest version of the file from the specified brunch:
      gitConfigurationHelper.getFileContent("master","pom.xml")
      
    • Or get a specific version by tag (in the example, this is the “aspectj-scripting-1.2” tag) or by revision:
      gitConfigurationHelper.getFileContent("master","aspectj-scripting-1.2", "pom.xml")
      

    And at the end of the work, close the connection to the repository:
    gitConfigurationHelper.destroy()
    


    As a nice addition to the ability to store configurations in git, you can also read the configuration from the maven repository. To do this, you need the mvn-classloader: 1.4 library, which is already part of groovy-grape-aether: 2.4.5.2.

    URL artifact = MavenClassLoader.usingCentralRepo (). ResolveArtifact ("com.github.igor-suhorukov: aspectj-scripting: pom: 1.3")
    • usingCentralRepo () - from the central repository.
    • using (repositoryPath) - for your corporate repository.


    Further work with the artifact is quite simple. Calling the artifact.getFile () method allows you to get a link to an artifact in the local file system, and artifact.openStream () opens an InputStream to this file.

    In what format to store the configuration and how to parse these files further - depends on the task and preferences and you decide. The configuration can be either simple java.util.Properties, Json (Gson / jackson), JAXB / XStream, or a configuration in the form of scripts in groovy, scala, javascript ...

    Groovy


    The same from the previous header about java is much more concisely written in groovy. You can run the example with the command:
    java -jar groovy-grape-aether-2.4.5.2.jar readGitConfig.groovy

    readGitConfig.groovy
    import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader
    @Grab(group = 'com.github.igor-suhorukov', module = 'git-configuration', version = '1.0')
    import io.hawt.git.GitConfigurationHelper
    def gitConfigurationHelper = new GitConfigurationHelper('https://github.com/igor-suhorukov/aspectj-scripting.git')
    println 'CONFIGURATION FROM GIT: HEAD REVISON ----------------------------------'
    println gitConfigurationHelper.getFileContent('master','pom.xml')
    println 'CONFIGURATION FROM GIT: BY TAG ----------------------------------------'
    println gitConfigurationHelper.getFileContent('master','aspectj-scripting-1.2', 'pom.xml')
    gitConfigurationHelper.destroy()
    println 'CONFIGURATION FROM MAVEN REPO -----------------------------------------'
    def configStream = MavenClassLoader.usingCentralRepo().resolveArtifact('com.github.igor-suhorukov:aspectj-scripting:pom:1.3').openStream()
    println configStream.text
    


    Configuration in native git repository



    Gitblit was chosen as the in-house repository - for those who know java it is easier to install and maintain, and the push hooks mechanism on Groovy allows you to work wonders. Alternatively, you can choose Gogs - Go Git Service or any other Git repository server.

    The launch and configuration of the Gitblit server is performed using the groovy autoinstall script.

    java -jar groovy-grape-aether-2.4.5.2.jar gitblit.groovy

    gitblit.groovy
    import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader
    @Grab(group='org.codehaus.plexus', module='plexus-archiver', version='2.10.2')
    import org.codehaus.plexus.archiver.zip.ZipUnArchiver
    @Grab(group='org.codehaus.plexus', module='plexus-container-default', version='1.6')
    import org.codehaus.plexus.logging.console.ConsoleLogger
    @Grab(group = 'org.eclipse.jetty', module = 'jetty-runner', version = '9.3.7.RC1' )
    import org.eclipse.jetty.runner.Runner
    def gitblit = new File(MavenClassLoader.using('http://gitblit.github.io/gitblit-maven').resolveArtifact('com.gitblit:gitblit:war:1.7.1').getFile())
    File gitblitDirectory = new File(System.getProperty('user.home'), gitblit.getName().replace('.war',''))
    if(!gitblitDirectory.exists()){
        gitblitDirectory.mkdir()
        ZipUnArchiver unArchiver = new ZipUnArchiver()
        unArchiver.setSourceFile(gitblit)
        unArchiver.enableLogging(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG,"Logger"))
        unArchiver.setDestDirectory(gitblitDirectory)
        unArchiver.extract()
        def dataPath = new File(System.getProperty('user.home'), '.gitblit_data')
        if(!dataPath.exists()){ dataPath.mkdir() }
        def webXml = new File(gitblitDirectory.getAbsoluteFile(), 'WEB-INF/web.xml')
        webXmlText = webXml.text
        webXml.withWriter { w -> w << webXmlText.replace('${contextFolder}/WEB-INF/data', dataPath.getAbsolutePath()) }
    }
    Runner.main([gitblitDirectory] as String[])
    


    The script downloads gitblit.war from the project repository, unpacks it into the user's home directory and replaces the path to the repository repository in the gitblit configuration. After that, it starts the jetty server and gitblit inside it.



    Here is the sequence of commands that I used to create the configuration in the new repository ssh: // admin @ localhost: 29418 / configuration.git

    vim configuration.properties
    git add configuration.properties 
    git commit -m "import config"
    git tag -a ver1.0 -m "configuration version 1.0"
    vim configuration.properties
    git add configuration.properties 
    git commit -m "update config"
    git push -u origin master --tags
    


    The configuration reading code is no different from the previous examples. It remains only to create an object in the code:
    new GitConfigurationHelper("http://admin@localhost:8080/r/configuration.git")
    

    And use the same API as in the github example.



    Summary



    In the publication, we looked at how to read the configuration in java / groovy from git and maven repositories. Using a groovy script, we were able to install and configure the gitblit repository in automatic mode.

    The code from the article is applicable in jvm projects and it would be interesting to hear from you how the same task is solved in other programming languages ​​and on other platforms.

    Also popular now: